From d2cb9d9e4382683abd125aa36ef2829e9de1a8fb Mon Sep 17 00:00:00 2001 From: Dushnilin Date: Tue, 28 Jul 2026 09:22:54 +0300 Subject: [PATCH] fix(awg): harden AmneziaWG validation, auto-convert plaintext headers to hex, and enforce optimal MTU/keepalive defaults --- tachyon/files/usr/lib/config/validator.uc | 10 +++++ tachyon/files/usr/lib/singbox/generator.uc | 13 ++++++- .../usr/lib/singbox/generator_outbounds.uc | 37 ++++++++++++++----- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/tachyon/files/usr/lib/config/validator.uc b/tachyon/files/usr/lib/config/validator.uc index e688ae1a..570e0ec2 100644 --- a/tachyon/files/usr/lib/config/validator.uc +++ b/tachyon/files/usr/lib/config/validator.uc @@ -1993,6 +1993,16 @@ function validate_extended_server_features(ctx, sing_box_version, sing_box_versi if (transport == "xhttp" && !sing_box_supports_xhttp(ctx, sing_box_version, sing_box_version_output)) fail_requirement("Server '" + name + "' uses XHTTP transport, but the installed sing-box binary does not support it. Install sing-box-extended or a binary with XHTTP support, or change the transport. Aborted.", "fatal"); } + + for (let section in sections_by_type("section")) { + if (!section_enabled(section)) + continue; + + let name = section_name(section); + let action = rule_action(section); + if (action == "awg" && !sing_box_is_extended(ctx, sing_box_version) && !sing_box_is_lx(ctx, sing_box_version)) + fail_requirement("Section '" + name + "' uses AmneziaWG, but the installed sing-box binary does not support it. Install sing-box-extended or sing-box-lx, or change the action. Aborted.", "fatal"); + } } function has_outbound_section(ctx) { diff --git a/tachyon/files/usr/lib/singbox/generator.uc b/tachyon/files/usr/lib/singbox/generator.uc index 58e9bc02..733e1445 100644 --- a/tachyon/files/usr/lib/singbox/generator.uc +++ b/tachyon/files/usr/lib/singbox/generator.uc @@ -59,7 +59,18 @@ function uci_bin_to_hex(val) { s = replace(s, /^0x/i, ""); s = replace(s, />$/, ""); s = replace(s, /\s+/g, ""); - return s; + + if (match(s, /^[0-9a-fA-F]+$/)) { + if (length(s) % 2 != 0) s = "0" + s; + return lc(s); + } + + let hex = ""; + for (let i = 0; i < length(val); i++) { + let code = ord(val, i); + hex += sprintf("%02x", code); + } + return hex; } let generator_outbounds = require("singbox.generator_outbounds"); diff --git a/tachyon/files/usr/lib/singbox/generator_outbounds.uc b/tachyon/files/usr/lib/singbox/generator_outbounds.uc index 26488252..83101a39 100644 --- a/tachyon/files/usr/lib/singbox/generator_outbounds.uc +++ b/tachyon/files/usr/lib/singbox/generator_outbounds.uc @@ -58,7 +58,18 @@ function uci_bin_to_hex(val) { s = replace(s, /^0x/i, ""); s = replace(s, />$/, ""); s = replace(s, /\s+/g, ""); - return s; + + if (match(s, /^[0-9a-fA-F]+$/)) { + if (length(s) % 2 != 0) s = "0" + s; + return lc(s); + } + + let hex = ""; + for (let i = 0; i < length(val); i++) { + let code = ord(val, i); + hex += sprintf("%02x", code); + } + return hex; } function internal_flag(value) { @@ -1164,19 +1175,25 @@ function add_awg_endpoint(config, section) { if (preshared_key != "") endpoint.peers[0].pre_shared_key = preshared_key; - let mtu = int_option(section, "awg_mtu", "0"); - if (mtu > 0) - endpoint.mtu = mtu; + let mtu = int_option(section, "awg_mtu", "1280"); + endpoint.mtu = mtu > 0 ? mtu : 1280; - let keepalive = int_option(section, "awg_keepalive", "0"); - if (keepalive > 0) - endpoint.peers[0].persistent_keepalive_interval = keepalive; + let keepalive = int_option(section, "awg_keepalive", "25"); + endpoint.peers[0].persistent_keepalive_interval = keepalive > 0 ? keepalive : 25; + + let jc = int_option(section, "awg_jc", "4"); + if (jc > 10) jc = 10; + + let jmin = int_option(section, "awg_jmin", "40"); + + let jmax = int_option(section, "awg_jmax", "70"); + if (jmax > 1200) jmax = 1200; // AmneziaWG obfuscation parameters let amnezia = { - jc: int_option(section, "awg_jc", "120"), - jmin: int_option(section, "awg_jmin", "23"), - jmax: int_option(section, "awg_jmax", "911"), + jc: jc, + jmin: jmin, + jmax: jmax, s1: int_option(section, "awg_s1", "0"), s2: int_option(section, "awg_s2", "0"), h1: int_option(section, "awg_h1", "1"),