#!/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();