tailscale_tun.js 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import "./wasm_exec.js";
  2. import ipStackAwait from "./ipstack.js";
  3. export const State = {
  4. NoState: 0,
  5. InUseOtherUser: 1,
  6. NeedsLogin: 2,
  7. NeedsMachineAuth: 3,
  8. Stopped: 4,
  9. Starting: 5,
  10. Running: 6,
  11. };
  12. export async function init() {
  13. const {IpStack} = await ipStackAwait();
  14. IpStack.init();
  15. const listeners = {
  16. onstateupdate: () => {},
  17. onnetmap: () => {},
  18. onloginurl: () => {},
  19. }
  20. let ipn = null;
  21. let localIp = null;
  22. let dnsIp = null;
  23. const lazyRunIpn = async () => {
  24. const wasmUrl = new URL("tailscale.wasm", import.meta.url);
  25. const go = new window.Go();
  26. let {instance} = await WebAssembly.instantiateStreaming(fetch(wasmUrl),go.importObject);
  27. go.run(instance);
  28. const sessionStateStorage = {
  29. setState(id, value) {
  30. window.sessionStorage[`ipn-state-${id}`] = value
  31. },
  32. getState(id) {
  33. return window.sessionStorage[`ipn-state-${id}`] || ""
  34. },
  35. }
  36. ipn = newIPN({
  37. // Persist IPN state in sessionStorage in development, so that we don't need
  38. // to re-authorize every time we reload the page.
  39. stateStorage: sessionStateStorage,
  40. });
  41. const setupIpStack = () => {
  42. ipn.tun.onmessage = function(ev) {
  43. IpStack.input(ev.data)
  44. };
  45. IpStack.output(function(p){
  46. ipn.tun.postMessage(p);
  47. });
  48. };
  49. setupIpStack();
  50. ipn.run({
  51. notifyState: (s) => listeners.onstateupdate(s),
  52. notifyNetMap: (s) => {
  53. const netMap = JSON.parse(s);
  54. listeners.onnetmap(netMap);
  55. const newLocalIp = netMap.self.addresses[0];
  56. if (localIp != newLocalIp)
  57. {
  58. localIp = newLocalIp;
  59. IpStack.up({localIp, ipMap: {
  60. ["127.0.0.53"]: dnsIp,
  61. [dnsIp]: "127.0.0.53",
  62. }});
  63. }
  64. },
  65. notifyBrowseToURL: (l) => listeners.onloginurl(l),
  66. });
  67. };
  68. return {
  69. connect: IpStack.connect,
  70. listen: IpStack.listen,
  71. bind: IpStack.bind,
  72. parseIP: IpStack.parseIP,
  73. up: async (conf) => {
  74. if (ipn == null) {
  75. await lazyRunIpn();
  76. }
  77. ipn.up(conf);
  78. localIp = null;
  79. dnsIp = conf.dnsIp || "127.0.0.53";
  80. },
  81. down: () => {
  82. ipn.down();
  83. IpStack.down();
  84. },
  85. login: () => ipn.login(),
  86. logout: () => ipn.logout(),
  87. listeners
  88. };
  89. }