webvm/tun/tailscale_tun.js
2023-01-30 12:01:30 +01:00

107 lines
2.2 KiB
JavaScript

import "./wasm_exec.js";
import ipStackAwait from "./ipstack.js";
export const State = {
NoState: 0,
InUseOtherUser: 1,
NeedsLogin: 2,
NeedsMachineAuth: 3,
Stopped: 4,
Starting: 5,
Running: 6,
};
export async function init() {
const {IpStack} = await ipStackAwait();
IpStack.init();
const listeners = {
onstateupdate: () => {},
onnetmap: () => {},
onloginurl: () => {},
}
let ipn = null;
let localIp = null;
let dnsIp = null;
const lazyRunIpn = async () => {
const wasmUrl = new URL("tailscale.wasm", import.meta.url);
const go = new window.Go();
let {instance} = await fetch(wasmUrl).then(x => x.arrayBuffer()).then(x => WebAssembly.instantiate(x,go.importObject));
go.run(instance);
const sessionStateStorage = {
setState(id, value) {
window.sessionStorage[`ipn-state-${id}`] = value
},
getState(id) {
return window.sessionStorage[`ipn-state-${id}`] || ""
},
}
ipn = newIPN({
// Persist IPN state in sessionStorage in development, so that we don't need
// to re-authorize every time we reload the page.
//stateStorage: sessionStateStorage,
});
const setupIpStack = () => {
ipn.tun.onmessage = function(ev) {
IpStack.input(ev.data)
};
IpStack.output(function(p){
ipn.tun.postMessage(p, [p.buffer]);
});
};
setupIpStack();
ipn.run({
notifyState: (s) => listeners.onstateupdate(s),
notifyNetMap: (s) => {
const netMap = JSON.parse(s);
listeners.onnetmap(netMap);
const newLocalIp = netMap.self.addresses[0];
if (localIp != newLocalIp)
{
localIp = newLocalIp;
try{
IpStack.up({localIp, dnsIp, ipMap: {
["127.0.0.53"]: dnsIp,
[dnsIp]: "127.0.0.53",
}});
}catch(e){
console.log(e);
debugger;
}
}
},
notifyBrowseToURL: (l) => listeners.onloginurl(l),
});
};
return {
tcpSocket: IpStack.TCPSocket.create,
udpSocket: IpStack.UDPSocket.create,
parseIP: IpStack.parseIP,
resolve: IpStack.resolve,
up: async (conf) => {
if (ipn == null) {
await lazyRunIpn();
}
ipn.up(conf);
localIp = null;
dnsIp = conf.dnsIp || "127.0.0.53";
},
down: () => {
ipn.down();
IpStack.down();
},
login: () => ipn.login(),
logout: () => ipn.logout(),
listeners
};
}