204 lines
5.2 KiB
Ucode
204 lines
5.2 KiB
Ucode
#!/bin/ucode
|
|
import * as uloop from 'uloop';
|
|
import { readfile, popen, pipe } from 'fs';
|
|
import { cursor } from 'uci';
|
|
// Aggregate all Endpoints
|
|
// Start pipe and loop and listen for set_endpoint commands
|
|
// set_endpoint command structure: userId,endpoint
|
|
//
|
|
// The User fetches vendor endpoints over the vendors backend directly from the provider, if not possible if will be fetchable over our service
|
|
// If the User has a matching plan, the user can provide thier wireguard backend / socks proxy
|
|
|
|
function log(msg,code) {
|
|
let prefix = "[+] ";
|
|
if(code == 1) {
|
|
prefix = "[!W] ";
|
|
}
|
|
|
|
if(code == 2) {
|
|
prefix = "[!!!Err] ";
|
|
}
|
|
|
|
print(prefix + msg + "\n");
|
|
}
|
|
|
|
function tunserverobj(ip_addr, endpoint_addr, endpoint_port) {
|
|
is_ipv6 = len(iptoarr(ip_addr)) == 16;
|
|
|
|
const endpoint = {
|
|
ip: endpoint_addr,
|
|
port: endpoint_addr
|
|
};
|
|
|
|
if(is_ipv6) {
|
|
return {
|
|
endpoint: endpoint,
|
|
tunip_v6: ip_addr
|
|
};
|
|
}
|
|
|
|
is_ipv4 = len(iptoarr(ip_addr)) == 4
|
|
if(!is_ipv4) {
|
|
log("ip is neither v6 or v4, Ignoring",1);
|
|
}
|
|
|
|
return {
|
|
endpoint: endpoint,
|
|
tunip_v4: ip_addr
|
|
};
|
|
}
|
|
|
|
function tuntypeobj_wireguard(if_name, pubkey, private_key_path, tunnel_props) {
|
|
return {
|
|
type: wireguard
|
|
if_name: if_name,
|
|
public_key: pubkey,
|
|
private_key: private_key
|
|
tunnel: tunserverobj(),
|
|
};
|
|
}
|
|
|
|
|
|
function tuntypeobj_socks5() {
|
|
return {
|
|
type: socks5,
|
|
if_name: "",
|
|
username: "",
|
|
password: "",
|
|
tunnel: tunserverobj
|
|
};
|
|
}
|
|
|
|
function tuntypeobj_socks4() {
|
|
return {
|
|
type: socks4,
|
|
if_name: "",
|
|
username: "",
|
|
password: "",
|
|
tunnel: ""
|
|
};
|
|
}
|
|
|
|
function tuntypeobj_http() {
|
|
return {
|
|
type: http,
|
|
if_name: "",
|
|
username: "",
|
|
password: "",
|
|
cert: "",
|
|
tunnel: "" // Should be tunserverobj
|
|
};
|
|
}
|
|
|
|
function basic_nm_provider(name, base_api_url, requires_basic_auth, credentials) {
|
|
return {
|
|
name: name,
|
|
api_urls: {
|
|
default: base_api_url
|
|
},
|
|
auth: {
|
|
basic_auth: requires_basic_auth,
|
|
credentials: credentials
|
|
}
|
|
}
|
|
}
|
|
|
|
function nm_unified_format(provider, data) {
|
|
return {
|
|
nm_unified: {
|
|
provider: provider, // Ein Objekt mit dem namen vom anbieter wovon die vpn tunnel stammen. Ein anbieter kann mehrere Tunnel Protokole verwenden
|
|
data: data // Should be array of wireguard or openvpn or socks format
|
|
}
|
|
};
|
|
}
|
|
|
|
// UCI Configuration
|
|
|
|
function wireguard_create_if() {
|
|
let ctx = uci.cursor();
|
|
}
|
|
|
|
function nm_setup(nm_unified) {
|
|
log("nm_setup called for " + nm_unified.provider.name);
|
|
|
|
}
|
|
|
|
|
|
// Converts mullvad endpoints respecting its config to nm wireguard endpoint obj
|
|
// TODO: Methode machen json config ließt um keys von vpn anbieter / endpoint der json response zu lesen um werte zu setzen
|
|
function mullvad_parse(provider_name='mullvad') {
|
|
const conf = json(readfile("config_"+provider_name+".json"));
|
|
let raw_apiresp = readfile('/tmp/mullvad_endpoints');
|
|
let wg_part = {};
|
|
|
|
log(raw_apiresp);
|
|
|
|
if(raw_apiresp == null) {
|
|
status = system('uclient-fetch -q -O /tmp/mullvad_endpoints https://api.mullvad.net/app/v1/relays');
|
|
log("uclient-fetch error",2);
|
|
|
|
raw_apiresp = readfile('/tmp/mullvad_endpoints');
|
|
}
|
|
|
|
const parsed_resp = json(raw_apiresp);
|
|
|
|
log("Loading... mullvad");
|
|
log(parsed_resp);
|
|
wg_part = parsed_resp['wireguard'];
|
|
|
|
const port = 51820;
|
|
let data = [];
|
|
|
|
let i = 0;
|
|
MAX_ENDPOINT_COUNT = 5;
|
|
OFFSET = 0;
|
|
for (relay in wg_part['relays']) {
|
|
if(i > MAX_ENDPOINT_COUNT || i < OFFSET) {
|
|
break;
|
|
}
|
|
log("Creating endpoint obj for " + relay);
|
|
e_v4 = endpoint_format(relay['ipv4_addr_in'],port);
|
|
e_v6 = endpoint_format(relay['ipv6_addr_in'],port);
|
|
|
|
// Create Mullvad tunnel, getting its internal ip address from the config files (should be set to a database later)
|
|
tunnel = tunnel_ip_format(conf.intunnel_v4, conf.intunnel_v6, e_v4, e_v6);
|
|
|
|
log("Created Endpoint -> "+ e_v4 + "\n" + e_v6 + "\n"+ tunnel);
|
|
|
|
print(tunnel);
|
|
push(data, wireguard_format(relay['hostname'], relay['public_key'], config.private_key_path, tunnel));
|
|
i += 1;
|
|
}
|
|
|
|
return nm_unified_format('mullvad',content);
|
|
}
|
|
|
|
// An array first containing the mullvad_endpoints and then a timestamp of the current time
|
|
// Used to calculate if the endpoints are old
|
|
mullvad_endpoints = [mullvad_parse(),time()];
|
|
|
|
const mainPipeHandle = pipe();
|
|
|
|
let uloop = uloop.init();
|
|
if(!uloop) {
|
|
log("Error initiating uloop, exiting ...", 2);
|
|
exit(1);
|
|
}
|
|
|
|
let p = pipe();
|
|
|
|
// 1. Read sessionID,CommandID. After reading the initation state is started. CommandID can be resolved to its CommandObject and the pre function can be executed
|
|
// 2. Read sessionID,commaseperatedvalues after the initation state and the pre function got executed the objects parameters can be populated for the after function
|
|
// 3. Read sessionID,OpendedCommandID. If the Command initation state was opened for that sessionID execute the apply function using the parameters from step 2 as parameters and then execute the post function
|
|
|
|
let i = 0;
|
|
log("+++ Creating uloop handle using fd: ");
|
|
const handle = uloop.handle(p[1],(e) => {
|
|
if(e & uloop.ULOOP_WRITE)
|
|
log("Write event " + p[0].read(1024));
|
|
},uloop.ULOOP_READ);
|
|
|
|
log("Created Handle for Event Messages - Event Handle:\n" + handle.fileno());
|
|
|
|
uloop.run();
|