Files
NeoTachyon/tachyon/files/usr/lib/service/warp_generator.uc
T
Dushnilin c788c86184 fix(warp): префлайт-проверка Cloudflare вместо XHR timeout
На сетях, где api.cloudflareclient.com недоступен (типичный случай из
issue #39), генератор сжигал весь временной бюджет - фронтенд умирал по
XHR timeout через 30 секунд, не показывая причины.

- префлайт: одна проба (4с connect / 6с max) напрямую и через доступный
  транспорт; если Cloudflare недостижим - мгновенная понятная ошибка
  «Cloudflare API недоступен...» вместо минутного зависания
- бюджеты ужаты до 20с на call_api и 20с на всю регистрацию, чтобы
  худший случай укладывался в XHR-таймаут LuCI
- все ошибочные выходы теперь печатают JSON-конверт и exit(0): фронтенд
  парсит data.message и показывает настоящую причину (ненулевой код
  заставлял его писать безликое Unknown error)
2026-08-22 10:07:40 +03:00

472 lines
24 KiB
Ucode

#!/usr/bin/env ucode
let fs = require("fs");
let common = require("core.common");
let uci_core = require("core.uci");
let as_string = common.as_string;
function trim(str) {
return replace(as_string(str), /^[ \t\r\n]+|[ \t\r\n]+$/g, "");
}
let write_json = common.write_json;
function get_clash_base_url() {
let host = "127.0.0.1:9090";
let config_data = fs.readfile("/etc/sing-box/config.json");
if (config_data) {
try {
let sb_cfg = json(config_data);
let ext = sb_cfg.experimental?.clash_api?.external_controller;
if (ext) {
let parts = split(ext, ":");
let ip = (length(parts) > 1) ? parts[0] : "";
let port = (length(parts) > 1) ? parts[length(parts) - 1] : "9090";
if (ip == "0.0.0.0" || ip == "")
host = "127.0.0.1:" + port;
else
host = ext;
}
}
catch (e) {}
}
return "http://" + host;
}
// Convert <b 0x...> ucode binary literals to plain hex string
function to_hex(s) {
s = replace(as_string(s), "<b 0x", "");
s = replace(s, ">", "");
return s;
}
let CONFIG_NAME = getenv("TACHYON_CONFIG_NAME") || "tachyon";
let uci = uci_core.cursor();
let warp_proxy_section = trim(uci.get(CONFIG_NAME, "settings", "warp_proxy_section") || "");
let proxy_port = "";
let proxy_interface = "";
if (warp_proxy_section != "") {
let section_action = uci.get(CONFIG_NAME, warp_proxy_section, "action") || "";
let section_iface = uci.get(CONFIG_NAME, warp_proxy_section, "section_interface") ||
uci.get(CONFIG_NAME, warp_proxy_section, "interface") || "";
let section_port = uci.get(CONFIG_NAME, warp_proxy_section, "mixed_proxy_port") || "";
if (section_iface != "") {
proxy_interface = section_iface;
} else if (section_action == "interface") {
proxy_interface = warp_proxy_section;
}
if (section_port != "" && match(section_port, /^[0-9]+$/) != null) {
proxy_port = section_port;
}
}
function error_response(message) {
write_json({
success: false,
message: as_string(message)
});
}
function exec_output(command) {
let pipe = fs.popen(command, "r");
if (!pipe) return "";
let data = pipe.read("all");
pipe.close();
return data == null ? "" : trim(data);
}
function now_ms() {
let c = clock();
if (type(c) != "array" || length(c) < 2)
return 0;
return c[0] * 1000 + int(c[1] / 1000000);
}
function contains(arr, val) {
for (let x in arr) {
if (x == val) return true;
}
return false;
}
function call_api(method, url, auth_header, body_file) {
let resolve_ips = [ "162.159.192.1", "162.159.193.1", "188.114.98.1", "188.114.99.1" ];
let last_res = "";
// Hard wall-clock budget: without it the full retry matrix (transports x
// resolve IPs x fallbacks) can block for minutes and trip the LuCI XHR
// timeout before any answer is produced.
let deadline = now_ms() + 20000;
let transport_flags = [];
if (proxy_interface != "") {
push(transport_flags, "--interface " + proxy_interface);
}
if (proxy_port != "") {
push(transport_flags, "-x socks5h://127.0.0.1:" + proxy_port);
}
// Check if default service mixed proxy (4534) is responsive
let mixed_4534_check = exec_output("curl -s --connect-timeout 2 --max-time 3 -x socks5h://127.0.0.1:4534 https://api.cloudflareclient.com/ >/dev/null 2>&1; echo $?");
if (trim(mixed_4534_check) == "0" && !contains(transport_flags, "-x socks5h://127.0.0.1:4534")) {
push(transport_flags, "-x socks5h://127.0.0.1:4534");
}
// Pre-flight: when the Cloudflare API is unreachable from this router
// (blocked ISP, dead proxy), the registration matrix below would burn its
// whole time budget and trip the LuCI XHR timeout before producing a
// readable answer. Probe once, fail fast with an actionable message.
let probe_cmd = "curl -s --connect-timeout 4 -m 6 -o /dev/null -w '%{http_code}' https://api.cloudflareclient.com/ 2>/dev/null";
let probe = trim(exec_output(probe_cmd));
if (probe == "" || probe == "000") {
let via_proxy = "";
for (let tr in transport_flags) {
if (index(tr, "socks5h") >= 0 || index(tr, "--interface") >= 0) {
via_proxy = exec_output("curl -s --connect-timeout 4 -m 6 -o /dev/null -w '%{http_code}' " + tr + " https://api.cloudflareclient.com/ 2>/dev/null");
break;
}
}
if (trim(via_proxy) == "" || trim(via_proxy) == "000") {
error_response("Cloudflare API недоступен с этого роутера (ни напрямую, ни через прокси). Генерация WARP невозможна — проверьте интернет или сгенерируйте конфиг через рабочую сеть.");
exit(0);
}
}
// 1. Try selected tunnel transport(s)
for (let tr in transport_flags) {
if (now_ms() > deadline) break;
// A. With --resolve to Cloudflare IPs
for (let ip in resolve_ips) {
if (now_ms() > deadline) break;
let auth_str = auth_header != "" ? "-H 'Authorization: Bearer " + auth_header + "' " : "";
let data_str = body_file != "" ? "-d @" + body_file + " " : "";
let cmd = "curl -s --connect-timeout 3 --max-time 7 " + tr + " --resolve api.cloudflareclient.com:443:" + ip + " -X " + method + " -H 'Content-Type: application/json' -H 'User-Agent: okhttp/3.12.1' " + auth_str + data_str + url;
let res = exec_output(cmd);
if (res != "") {
try {
let parsed = json(res);
if (parsed) return parsed;
}
catch (e) {
last_res = res;
}
}
}
if (now_ms() > deadline) break;
// B. Directly via DNS on tunnel
let auth_str = auth_header != "" ? "-H 'Authorization: Bearer " + auth_header + "' " : "";
let data_str = body_file != "" ? "-d @" + body_file + " " : "";
let cmd = "curl -s --connect-timeout 3 --max-time 7 " + tr + " -X " + method + " -H 'Content-Type: application/json' -H 'User-Agent: okhttp/3.12.1' " + auth_str + data_str + url;
let res = exec_output(cmd);
if (res != "") {
try {
let parsed = json(res);
if (parsed) return parsed;
}
catch (e) {
last_res = res;
}
}
}
if (now_ms() > deadline) {
return last_res != "" ? { success: false, message: last_res } : null;
}
// 2. Direct WAN fallback if no tunnel transport worked
for (let ip in resolve_ips) {
if (now_ms() > deadline) break;
let auth_str = auth_header != "" ? "-H 'Authorization: Bearer " + auth_header + "' " : "";
let data_str = body_file != "" ? "-d @" + body_file + " " : "";
let cmd = "curl -s --connect-timeout 3 --max-time 6 --resolve api.cloudflareclient.com:443:" + ip + " -X " + method + " -H 'Content-Type: application/json' -H 'User-Agent: okhttp/3.12.1' " + auth_str + data_str + url;
let res = exec_output(cmd);
if (res != "") {
try {
let parsed = json(res);
if (parsed) return parsed;
}
catch (e) {
last_res = res;
}
}
}
return last_res != "" ? { success: false, message: last_res } : null;
}
// Query current proxy selection from Clash API for automatic rate limit rotation if proxy is used
let original_server = "";
let available_servers = [];
let clash_data_str = exec_output("curl -s -m 5 " + get_clash_base_url() + "/proxies/MAIN-out");
if (clash_data_str != "") {
try {
let parsed = json(clash_data_str);
if (parsed) {
original_server = parsed.now || "";
available_servers = parsed.all || [];
}
}
catch (e) {}
}
function restore_original_server() {
if (original_server != "") {
let body = { name: original_server };
let tmp_file = "/tmp/restore_clash.json";
fs.writefile(tmp_file, sprintf("%J", body));
exec_output("curl -s -m 5 -X PUT -H 'Content-Type: application/json' -d @" + tmp_file + " " + get_clash_base_url() + "/proxies/MAIN-out");
fs.unlink(tmp_file);
}
}
function switch_server(srv_name) {
let body = { name: srv_name };
let tmp_file = "/tmp/switch_clash.json";
fs.writefile(tmp_file, sprintf("%J", body));
exec_output("curl -s -m 5 -X PUT -H 'Content-Type: application/json' -d @" + tmp_file + " " + get_clash_base_url() + "/proxies/MAIN-out");
fs.unlink(tmp_file);
exec_output("sleep 1");
}
let keypair_data = exec_output("/usr/bin/sing-box generate wg-keypair 2>/dev/null");
let private_key = null;
let public_key = null;
for (let line in split(keypair_data, "\n")) {
let m_priv = match(line, /^PrivateKey:\s*(.+)$/);
if (m_priv) private_key = trim(m_priv[1]);
let m_pub = match(line, /^PublicKey:\s*(.+)$/);
if (m_pub) public_key = trim(m_pub[1]);
}
// Fallback to wg genkey/pubkey if sing-box generate wg-keypair fails
if (!private_key || !public_key) {
let priv = exec_output("wg genkey 2>/dev/null");
if (priv != "") {
private_key = priv;
public_key = exec_output("echo '" + priv + "' | wg pubkey 2>/dev/null");
}
}
if (!private_key || !public_key) {
restore_original_server();
error_response("Failed to generate WireGuard keypair");
exit(0);
}
let install_id = "";
let fcm_token = "";
let tos = exec_output("date -u +'%Y-%m-%dT%H:%M:%SZ' 2>/dev/null") || "2026-07-17T20:52:00Z";
let serial_number = exec_output('head -c 8 /dev/urandom | hexdump -ve \'1/1 "%02x"\' 2>/dev/null') || "abcdef1234567890";
let reg_request = {
key: public_key,
install_id: install_id,
fcm_token: fcm_token,
tos: tos,
model: "PC",
serial_number: serial_number,
locale: "en_US"
};
let tmp_req_file = exec_output("mktemp 2>/dev/null") || "/tmp/warp_req.json";
if (fs.writefile(tmp_req_file, sprintf("%J", reg_request)) == null) {
restore_original_server();
error_response("Failed to write temporary registration request file");
exit(0);
}
let api_prefixes = [
"v0i1909051800",
"v0a1909051800",
"v0b1909051800",
"v0c1909051800",
"v0d1909051800",
"v0e1909051800",
"v0f1909051800",
"v0g1909051800",
"v0h1909051800",
"v0i1604021500",
"v0a1604021500"
];
let response_data = null;
let last_error = "";
let chosen_prefix = "";
let server_try_index = 0;
// Overall budget for the whole registration attempt matrix: each call_api()
// is bounded, but the prefix list is long enough to multiply into minutes.
let registration_deadline = now_ms() + 20000;
for (let prefix in api_prefixes) {
if (now_ms() > registration_deadline) {
last_error = "Registration aborted: overall time budget exceeded";
break;
}
let url = "https://api.cloudflareclient.com/" + prefix + "/reg";
let parsed = call_api("POST", url, "", tmp_req_file);
if (!parsed) {
last_error = "Timeout or connection failure (prefix: " + prefix + ")";
continue;
}
if (parsed.success && parsed.result) {
response_data = parsed.result;
chosen_prefix = prefix;
break;
}
let msg = parsed.message || (parsed.errors ? parsed.errors[0].message : "Unsuccessful registration");
let code = parsed.errors ? parsed.errors[0].code : null;
if (code == 1015 || index(as_string(msg), "1015") >= 0) {
if (length(available_servers) > 0 && server_try_index < 4) {
let next_srv = available_servers[(server_try_index + 1) % length(available_servers)];
server_try_index++;
switch_server(next_srv);
parsed = call_api("POST", url, "", tmp_req_file);
if (parsed && parsed.success && parsed.result) {
response_data = parsed.result;
chosen_prefix = prefix;
break;
}
msg = parsed ? (parsed.message || (parsed.errors ? parsed.errors[0].message : "Unsuccessful registration")) : "Timeout after proxy rotation";
code = parsed && parsed.errors ? parsed.errors[0].code : null;
}
if (code == 1015 || index(as_string(msg), "1015") >= 0) {
msg = "Rate limit exceeded (Cloudflare error 1015). Cloudflare blocks registrations from this IP. Please switch your active server in the Tachyon Dashboard tab and try again.";
}
}
last_error = msg;
}
fs.unlink(tmp_req_file);
if (!response_data) {
restore_original_server();
let hint = "";
if (warp_proxy_section == "")
hint = " Провайдер может блокировать Cloudflare API на WAN. Выберите секцию с туннелем (WireGuard/AWG/VPN) или включите Mixed-прокси на прокси-секции в 'Расширенных настройках'.";
error_response("Ошибка регистрации в Cloudflare WARP API: " + last_error + hint);
exit(0);
}
if (!response_data.warp_enabled) {
let patch_body = { warp_enabled: true };
let tmp_patch = exec_output("mktemp 2>/dev/null") || "/tmp/warp_patch.json";
fs.writefile(tmp_patch, sprintf("%J", patch_body));
let url = "https://api.cloudflareclient.com/" + chosen_prefix + "/reg/" + response_data.id;
call_api("PATCH", url, response_data.token, tmp_patch);
fs.unlink(tmp_patch);
}
let license_key = ARGV[0] || "";
if (license_key != "") {
let patch_body = { license_key: license_key };
let tmp_patch = exec_output("mktemp 2>/dev/null") || "/tmp/warp_patch.json";
fs.writefile(tmp_patch, sprintf("%J", patch_body));
let url = "https://api.cloudflareclient.com/" + chosen_prefix + "/reg/" + response_data.id;
call_api("PATCH", url, response_data.token, tmp_patch);
fs.unlink(tmp_patch);
}
// Restore original proxy server selection
restore_original_server();
let probe_ips = [
"162.159.192.1", "162.159.192.6",
"162.159.193.1", "162.159.193.6",
"188.114.98.1", "188.114.98.6",
"188.114.99.1", "188.114.99.6",
"8.6.112.0"
];
// Try to resolve engage.cloudflareclient.com and add resolved IPs
let resolved_ips = exec_output("nslookup engage.cloudflareclient.com 2>/dev/null | grep -E 'Address[ 0-9]*:' | awk '{print $2}'");
for (let ip in split(resolved_ips, "\n")) {
ip = trim(ip);
if (ip != "" && index(ip, "127.0.0.") < 0 && index(ip, ":") < 0 && !contains(probe_ips, ip)) {
push(probe_ips, ip);
}
}
let best_ip = "162.159.192.1";
let best_time = 9999.0;
for (let ip in probe_ips) {
ip = trim(ip);
if (ip == "") continue;
let iface_flag = proxy_interface != "" ? "--interface " + proxy_interface + " " : "";
let cmd = "curl -w '%{time_connect}' -o /dev/null -s --max-time 0.8 " + iface_flag + "https://" + ip;
let t_str = exec_output(cmd);
let t = (t_str || "9999.0") * 1.0;
if (t > 0.0 && t < best_time) {
best_time = t;
best_ip = ip;
}
}
let warp_ports = [
854, 859, 864, 878, 880, 890, 891, 894, 903, 908,
928, 934, 939, 942, 943, 945, 946, 955, 968, 987,
988, 1002, 1010, 1014, 1018, 1070, 1074, 1180, 1387, 1843,
2371, 2506, 3138, 3476, 3581, 3854, 4177, 4198, 4233, 5279,
5956, 7103, 7152, 7156, 7281, 7559, 8319, 8742, 8854, 8886, 2408
];
let random_port = warp_ports[time() % length(warp_ports)];
let warp_cps_payloads = [
"<b 0xce000000010897a297ecc34cd6dd000044d0ec2e2e1ea2991f467ace4222129b5a098823784694b4897b9986ae0b7280135fa85e196d9ad980b150122129ce2a9379531b0fd3e871ca5fdb883c369832f730e272d7b8b74f393f9f0fa43f11e510ecb2219a52984410c204cf875585340c62238e14ad04dff382f2c200e0ee22fe743b9c6b8b043121c5710ec289f471c91ee414fca8b8be8419ae8ce7ffc53837f6ade262891895f3f4cecd31bc93ac5599e18e4f01b472362b8056c3172b513051f8322d1062997ef4a383b01706598d08d48c221d30e74c7ce000cdad36b706b1bf9b0607c32ec4b3203a4ee21ab64df336212b9758280803fcab14933b0e7ee1e04a7becce3e2633f4852585c567894a5f9efe9706a151b615856647e8b7dba69ab357b3982f554549bef9256111b2d67afde0b496f16962d4957ff654232aa9e845b61463908309cfd9de0a6abf5f425f577d7e5f6440652aa8da5f73588e82e9470f3b21b27b28c649506ae1a7f5f15b876f56abc4615f49911549b9bb39dd804fde182bd2dcec0c33bad9b138ca07d4a4a1650a2c2686acea05727e2a78962a840ae428f55627516e73c83dd8893b02358e81b524b4d99fda6df52b3a8d7a5291326e7ac9d773c5b43b8444554ef5aea104a738ed650aa979674bbed38da58ac29d87c29d387d80b526065baeb073ce65f075ccb56e47533aef357dceaa8293a523c5f6f790be90e4731123d3c6152a70576e90b4ab5bc5ead01576c68ab633ff7d36dcde2a0b2c68897e1acfc4d6483aaaeb635dd63c96b2b6a7a2bfe042f6aed82e5363aa850aace12ee3b1a93f30d8ab9537df483152a5527faca21efc9981b304f11fc95336f5b9637b174c5a0659e2b22e159a9fed4b8e93047371175b1d6d9cc8ab745f3b2281537d1c75fb9451871864efa5d184c38c185fd203de206751b92620f7c369e031d2041e152040920ac2c5ab5340bfc9d0561176abf10a147287ea90758575ac6a9f5ac9f390d0d5b23ee12af583383d994e22c0cf42383834bcd3ada1b3825a0664d8f3fb678261d57601ddf94a8a68a7c273a18c08aa99c7ad8c6c42eab67718843597ec9930457359dfdfbce024afc2dcf9348579a57d8d3490b2fa99f278f1c37d87dad9b221acd575192ffae1784f8e60ec7cee4068b6b988f0433d96d6a1b1865f4e155e9fe020279f434f3bf1bd117b717b92f6cd1cc9bea7d45978bcc3f24bda631a36910110a6ec06da35f8966c9279d130347594f13e9e07514fa370754d1424c0a1545c5070ef9fb2acd14233e8a50bfc5978b5bdf8bc1714731f798d21e2004117c61f2989dd44f0cf027b27d4019e81ed4b5c31db347c4a3a4d85048d7093cf16753d7b0d15e078f5c7a5205dc2f87e330a1f716738dce1c6180e9d02869b5546f1c4d2748f8c90d9693cba4e0079297d22fd61402dea32ff0eb69ebd65a5d0b687d87e3a8b2c42b648aa723c7c7daf37abcc4bb85caea2ee8f55bec20e913b3324ab8f5c3304f820d42ad1b9f2ffc1a3af9927136b4419e1e579ab4c2ae3c776d293d397d575df181e6cae0a4ada5d67ecea171cca3288d57c7bbdaee3befe745fb7d634f70386d873b90c4d6c6596bb65af68f9e5121e67ebf0d89d3c909ceedfb32ce9575a7758ff080724e1ab5d5f43074ecb53a479af21ed03d7b6899c36631c0166f9d47e5e1d4528a5d3d3f744029c4b1c190cbfbad06f5f83f7ad0429fa9a2719c56ffe3783460e166de2d8>",
"<b 0xc7000000010809a1ed4edbbe7615000044d017a61a0d774f04290f119e701ef0035df2b0ed571b0b575e6a07246b856eb6ec036fef07f1e07b861251ad737abeb67e64be714c1dcd865312b1b6c35c089c997aeb5c18f808696fe97289513945d84ca846467603e94e44224877f2c1d3261e4ac18740be4bd064369c94fc08978d99b54bf615250998639010c1284248e1d73004b81fcb20b559d8a17eced7eab3964b5b88ca7a3b8579fc8c1c934189e77143b4ac434138114b1048651b56545b87acbef0952763538f3ddeb37cfc6d58b4881c3b719d7ff78f6ee1324a2914a32381c05a64c700466d280be007253bb030d179c4f1b3dc221e1974e2ee6d6e2b9e8d709159b5ef22e1783dbba845c20ca1c83b066c73835920ad70b806df0aee0351e3fc9ab1e42e8b2a30fe235ff0612eee19744949cecee0463b76514ad90c1f7ceaa557c18586ab561d49482e73c85d0143785da14a441bf82f78783b61cccd44aecb1947516e79b5ca5a6b3a8aed6040fae0eeabdc55a88dc19ade832d99fca90c7a629cacc07192d7e47e3c6a271b95b0ea3392562a06a1cab79f40ea92916ebee197b7b5f14b251824e1ed20ff2ca80b1f03a43e45157589bc61b978e97851025b3b7ccc17d291e1cb60fe48a5c26829dce11dd23c2e73265a9ebf8617c985e4fee4681e863f990061f4dea465a7d2524bd0edcf4b48d4b8f25fc359b15babd2637284a4774077dca60091f1a781cfee1bef9713dd5943a579d7470bc5970542fbb27fdf77880a8d8751b1f642c7a3f019a05ab94bf63d3525ef34e9290b5c8d477f2714e6d6e3e4d35c1983f5e16fda57fcdf071b513f8f088dbe8d5a97577d17a5383a496c3f313adfdd47c962bbaebd6aa13b46439eb742622c29ca067db0ec1853064c3cbbffe0a215a19fce47d49703ed58ebbd89721172d256d1cf30188106fb2f863186511401fad54d087aa2fb3d1b85768db386bd7102e8060ac157bac011acdcdae2799b9aee1467c3424013455bd028fcaacdc3c77d28ea199967d617ea7d0d0815f3cc407934a76d1293dccba210d1709a13e5dd67c9ba47cd113f5bdd740358eff13164159fd09bc2f7ec6cfa64d9df7e2e2f88706b0ff3a92ccf6f078456cfe0bdd89292cfe2680badc1eac9f7d36efe8eb6912c7b164508d13e6c0911c15f73c233cbe4fc70ff2ade1e1be4bbb738e0939159e2078a9438f05b756a003371f4861481c38f1cdd2d7b06deb62869e9fe79a8abaa920646fa2e8fa28f0d80c136376c7b56046bae4c05c0cdf64efb8c47bbfc5a1a4c0b045061ef0d71618e0d206a1d7f245fd5c03191b152673ba8dff8e1b8de7c50234a93cba91e3888adb228cc02beded4b1c0946797d3ef02dec2edb6ad0ac21f89f4be364c317da7c22440e9f358d512203f4b7ab20388af68b8915d0152db2c8a0687bfaea870f7529bb92a22b35bd79bc6d490591406346ecd78342ee3563c4883a8251679691c2d4e963397e24653520795511b018915374c954bddb940a9d7a16d1c8bd798fc7dbfb0599a7074e13f87e14efa8d511bb2579ec029b1bda18fe971b30fbe19e986ff2686a69bf3f1bb929de93ae70345ebca998b11e0a2b41890cba628d8f6e7c4e94790735e5299b4ff07cd3080f7d53c9cbe1911d2cd5925b3213e033c272506a87886cf761a283a779564d3241e3c28f632e166b5d756e1786ce077614c4444e3f2aed5decb3613b925ea3e558c21d4faf8ba54edd0f3a5d4>",
"<b 0xc10000000114367096bb0fb3f58f3a3fb8aaacd61d63a1c8a40e14f7374b8a62dccba6431716c3abf6f5afbcfb39bd008000047c32e268567c652e6f4db58bff759bc8c5aaca183b87cb4d22938fe7d8dca22a679a79e4d9ee62e4bbb3a380dd78d4e8e48f26b38a1d42d76b371a5a9a0444827a69d1ab5872a85749f65a4104e931740b4dc1e2dd77733fc7fac4f93011cd622f2bb47e85f71992e2d585f8dc765a7a12ddeb879746a267393ad023d267c4bd79f258703e27345155268bd3cc0506ebd72e2e3c6b5b0f005299cd94b67ddabe30389c4f9b5c2d512dcc298c14f14e9b7f931e1dc397926c31fbb7cebfc668349c218672501031ecce151d4cb03c4c660b6c6fe7754e75446cd7de09a8c81030c5f6fb377203f551864f3d83e27de7b86499736cbbb549b2f37f436db1cae0a4ea39930f0534aacdd1e3534bc87877e2afabe959ced261f228d6362e6fd277c88c312d966c8b9f67e4a92e757773db0b0862fb8108d1d8fa262a40a1b4171961f0704c8ba314da2482ac8ed9bd28d4b50f7432d89fd800c25a50c5e2f5c0710544fef5273401116aa0572366d8e49ad758fcb29e6a92912e644dbe227c247cb3417eabfab2db16796b2fba420de3b1dc94e8361f1f324a331ddaf1e626553138860757fd0bf687566108b77b70fb9f8f8962eca599c4a70ed373666961a8cb506b96756d9e28b94122b20f16b54f118c0e603ce0b831efea614ad836df6cf9affbdd09596412547496967da758cec9080295d853b0861670b71d9abde0d562b1a6de82782a5b0c14d297f27283a895abc889a5f6703f0e6eb95f67b2da45f150d0d8ab805612d570c2d5cb6997ac3a7756226c2f5c8982ffbd480c5004b0660a3c9468945efde90864019a2b519458724b55d766e16b0da25c0557c01f3c11ddeb024b62e303640e17fdd57dedb3aeb4a2c1b7c93059f9c1d7118d77caac1cd0f6556e46cbc991c1bb16970273dea833d01e5090d061a0c6d25af2415cd2878af97f6d0e7f1f936247b394ecb9bd484da6be936dee9b0b92dc90101a1b4295e97a9772f2263eb09431995aa173df4ca2abd687d87706f0f93eaa5e13cbe3b574fa3cfe94502ace25265778da6960d561381769c24e0cbd7aac73c16f95ae74ff7ec38124f7c722b9cb151d4b6841343f29be8f35145e1b27021056820fed77003df8554b4155716c8cf6049ef5e318481460a8ce3be7c7bfac695255be84dc491c19e9dedc449dd3471728cd2a3ee51324ccb3eef121e3e08f8e18f0006ea8957371d9f2f739f0b89e4db11e5c6430ada61572e589519fbad4498b460ce6e4407fc2d8f2dd4293a50a0cb8fcaaf35cd9a8cc097e3603fbfa08d9036f52b3e7fcce11b83ad28a4ac12dba0395a0cc871cefd1a2856fffb3f28d82ce35cf80579974778bab13d9b3578d8c75a2d196087a2cd439aff2bb33f2db24ac175fff4ed91d36a4cdbfaf3f83074f03894ea40f17034629890da3efdbb41141b38368ab532209b69f057ddc559c19bc8ae62bf3fd564c9a35d9a83d14a95834a92bae6d9a29ae5e8ece07910d16433e4c6230c9bd7d68b47de0de9843988af6cdc88b5301820443bd4d0537778bf6b4c1dd067fcf14b81015f2a67c7f2a28f9cb7e0684d3cb4b1c24d9b343122a086611b489532f1c3a26779da1706c6759d96d8ab>"
];
function generate_random_hex(len) {
return exec_output('head -c ' + int(len) + ' /dev/urandom | hexdump -ve \'1/1 "%02x"\' 2>/dev/null') || "";
}
function generate_extra_cps() {
let rand_val = (time() + int(exec_output("echo $PPID 2>/dev/null") || "1")) % 3 + 1;
let result = "";
for (let i = 0; i < rand_val; i++) {
let length = (time() + i * 7) % 48 + 16;
result += "<b 0x" + generate_random_hex(length) + ">";
}
return result;
}
let i1 = to_hex(warp_cps_payloads[time() % length(warp_cps_payloads)]);
let i2 = to_hex(generate_extra_cps());
let i3 = to_hex(generate_extra_cps());
let i4 = to_hex(generate_extra_cps());
let i5 = to_hex(generate_extra_cps());
write_json({
success: true,
local_address: response_data.config.interface.addresses.v4 + "/32 " + response_data.config.interface.addresses.v6 + "/128",
private_key: private_key,
peer_public_key: response_data.config.peers[0].public_key,
server_address: best_ip,
server_port: random_port,
awg_jc: 4,
awg_jmin: 40,
awg_jmax: 70,
awg_s1: 0, awg_s2: 0, awg_s3: 0, awg_s4: 0,
awg_h1: 1, awg_h2: 2, awg_h3: 3, awg_h4: 4,
awg_i1: i1,
awg_i2: i2,
awg_i3: i3,
awg_i4: i4,
awg_i5: i5
});