diff --git a/luci-app-passwall/luasrc/controller/passwall.lua b/luci-app-passwall/luasrc/controller/passwall.lua index f4c6393..2d62b8d 100644 --- a/luci-app-passwall/luasrc/controller/passwall.lua +++ b/luci-app-passwall/luasrc/controller/passwall.lua @@ -496,6 +496,27 @@ function delete_select_nodes() uci:delete(appname, t[".name"], "to_node") uci:delete(appname, t[".name"], "chain_proxy") end + local list_name = t["urltest_node"] and "urltest_node" or (t["balancing_node"] and "balancing_node") + if list_name then + local nodes = uci:get_list(appname, t[".name"], list_name) + if nodes then + local changed = false + local new_nodes = {} + for _, node in ipairs(nodes) do + if node ~= w then + table.insert(new_nodes, node) + else + changed = true + end + end + if changed then + uci:set_list(appname, t[".name"], list_name, new_nodes) + end + end + end + if t["fallback_node"] == w then + uci:delete(appname, t[".name"], "fallback_node") + end end) if (uci:get(appname, w, "add_mode") or "0") == "2" then local add_from = uci:get(appname, w, "add_from") or "" diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_list.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_list.lua index 5659632..49aa9e6 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_list.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_list.lua @@ -60,6 +60,37 @@ function s.remove(e, t) m:set(s[".name"], "udp_node", "default") end end) + m.uci:foreach(appname, "nodes", function(s) + if s["preproxy_node"] == t then + m:del(s[".name"], "preproxy_node") + m:del(s[".name"], "chain_proxy") + end + if s["to_node"] == t then + m:del(s[".name"], "to_node") + m:del(s[".name"], "chain_proxy") + end + local list_name = s["urltest_node"] and "urltest_node" or (s["balancing_node"] and "balancing_node") + if list_name then + local nodes = m.uci:get_list(appname, s[".name"], list_name) + if nodes then + local changed = false + local new_nodes = {} + for _, node in ipairs(nodes) do + if node ~= t then + table.insert(new_nodes, node) + else + changed = true + end + end + if changed then + m.uci:set_list(appname, s[".name"], list_name, new_nodes) + end + end + end + if s["fallback_node"] == t then + m:del(s[".name"], "fallback_node") + end + end) if (m:get(t, "add_mode") or "0") == "2" then local add_from = m:get(t, "add_from") or "" if add_from ~= "" then diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua index 85608a8..90d7939 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua @@ -240,6 +240,9 @@ if has_xray then end if has_singbox then + local version = api.get_app_version("sing-box"):match("[^v]+") + local version_ge_1_12_0 = api.compare_versions(version, ">=", "1.12.0") + s = m:section(TypedSection, "global_singbox", "Sing-Box " .. translate("Settings")) s.anonymous = true s.addremove = false @@ -248,6 +251,16 @@ if has_singbox then o.default = 0 o.rmempty = false o.description = translate("Override the connection destination address with the sniffed domain.
When enabled, traffic will match only by domain, ignoring IP rules.
If using shunt nodes, configure the domain shunt rules correctly.") + + if version_ge_1_12_0 then + o = s:option(Flag, "record_fragment", "TLS Record " .. translate("Fragment"), + translate("Split handshake data into multiple TLS records for better censorship evasion. Low overhead. Recommended to enable first.")) + o.default = 0 + + o = s:option(Flag, "fragment", "TLS TCP " .. translate("Fragment"), + translate("Split handshake into multiple TCP segments. Enhances obfuscation. May increase delay. Use only if needed.")) + o.default = 0 + end end return m diff --git a/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/luci-app-passwall/luasrc/passwall/util_sing-box.lua index b0058fb..8e8f988 100644 --- a/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/luci-app-passwall/luasrc/passwall/util_sing-box.lua @@ -7,16 +7,16 @@ local appname = "passwall" local fs = api.fs local split = api.split -local local_version = api.get_app_version("sing-box") -local version_ge_1_11_0 = api.compare_versions(local_version:match("[^v]+"), ">=", "1.11.0") -local version_ge_1_12_0 = api.compare_versions(local_version:match("[^v]+"), ">=", "1.12.0") +local local_version = api.get_app_version("sing-box"):match("[^v]+") +local version_ge_1_11_0 = api.compare_versions(local_version, ">=", "1.11.0") +local version_ge_1_12_0 = api.compare_versions(local_version, ">=", "1.12.0") local geosite_all_tag = {} local geoip_all_tag = {} local srss_path = "/tmp/etc/" .. appname .."_tmp/srss/" local function convert_geofile() - if api.compare_versions(local_version:match("[^v]+"), "<", "1.8.0") then + if api.compare_versions(local_version, "<", "1.8.0") then api.log("!!!注意:Sing-Box 版本低,Sing-Box 分流无法启用!请在[组件更新]中更新。") return end @@ -81,9 +81,13 @@ function gen_outbound(flag, node, tag, proxy_table) end local proxy_tag = nil + local fragment = nil + local record_fragment = nil local run_socks_instance = true if proxy_table ~= nil and type(proxy_table) == "table" then proxy_tag = proxy_table.tag or nil + fragment = proxy_table.fragment or nil + record_fragment = proxy_table.record_fragment or nil run_socks_instance = proxy_table.run_socks_instance end @@ -157,6 +161,8 @@ function gen_outbound(flag, node, tag, proxy_table) alpn = alpn, --支持的应用层协议协商列表,按优先顺序排列。如果两个对等点都支持 ALPN,则选择的协议将是此列表中的一个,如果没有相互支持的协议则连接将失败。 --min_version = "1.2", --max_version = "1.3", + fragment = fragment, + record_fragment = record_fragment, ech = { enabled = (node.ech == "1") and true or false, config = node.ech_config and split(node.ech_config:gsub("\\n", "\n"), "\n") or {} @@ -373,6 +379,8 @@ function gen_outbound(flag, node, tag, proxy_table) enabled = true, server_name = node.tls_serverName, insecure = (node.tls_allowInsecure == "1") and true or false, + fragment = fragment, + record_fragment = record_fragment, alpn = (node.hysteria_alpn and node.hysteria_alpn ~= "") and { node.hysteria_alpn } or nil, @@ -405,6 +413,8 @@ function gen_outbound(flag, node, tag, proxy_table) enabled = true, server_name = node.tls_serverName, insecure = (node.tls_allowInsecure == "1") and true or false, + fragment = fragment, + record_fragment = record_fragment, alpn = (node.tuic_alpn and node.tuic_alpn ~= "") and { node.tuic_alpn } or nil, @@ -440,6 +450,8 @@ function gen_outbound(flag, node, tag, proxy_table) enabled = true, server_name = node.tls_serverName, insecure = (node.tls_allowInsecure == "1") and true or false, + fragment = fragment, + record_fragment = record_fragment, ech = { enabled = (node.ech == "1") and true or false, config = node.ech_config and split(node.ech_config:gsub("\\n", "\n"), "\n") or {} @@ -1016,7 +1028,7 @@ function gen_config(var) end if is_new_ut_node then local ut_node = uci:get_all(appname, ut_node_id) - local outbound = gen_outbound(flag, ut_node, ut_node_tag, { run_socks_instance = not no_run }) + local outbound = gen_outbound(flag, ut_node, ut_node_tag, { fragment = singbox_settings.fragment == "1" or nil, record_fragment = singbox_settings.record_fragment == "1" or nil, run_socks_instance = not no_run }) if outbound then outbound.tag = outbound.tag .. ":" .. ut_node.remarks table.insert(outbounds, outbound) @@ -1182,8 +1194,19 @@ function gen_config(var) }) end end - - local _outbound = gen_outbound(flag, _node, rule_name, { tag = use_proxy and preproxy_tag or nil, run_socks_instance = not no_run }) + local proxy_table = { + tag = use_proxy and preproxy_tag or nil, + run_socks_instance = not no_run + } + if not proxy_table.tag then + if singbox_settings.fragment == "1" then + proxy_table.fragment = true + end + if singbox_settings.record_fragment == "1" then + proxy_table.record_fragment = true + end + end + local _outbound = gen_outbound(flag, _node, rule_name, proxy_table) if _outbound then _outbound.tag = _outbound.tag .. ":" .. _node.remarks rule_outboundTag, last_insert_outbound = set_outbound_detour(_node, _outbound, outbounds, rule_name) @@ -1432,7 +1455,7 @@ function gen_config(var) sys.call(string.format("mkdir -p %s && touch %s/%s", api.TMP_IFACE_PATH, api.TMP_IFACE_PATH, node.iface)) end else - local outbound = gen_outbound(flag, node, nil, { run_socks_instance = not no_run }) + local outbound = gen_outbound(flag, node, nil, { fragment = singbox_settings.fragment == "1" or nil, record_fragment = singbox_settings.record_fragment == "1" or nil, run_socks_instance = not no_run }) if outbound then outbound.tag = outbound.tag .. ":" .. node.remarks COMMON.default_outbound_tag, last_insert_outbound = set_outbound_detour(node, outbound, outbounds) diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua index c7876e7..2fba587 100644 --- a/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -1151,7 +1151,7 @@ function gen_config(var) sys.call(string.format("mkdir -p %s && touch %s/%s", api.TMP_IFACE_PATH, api.TMP_IFACE_PATH, node.iface)) end else - local outbound = gen_outbound(flag, node, nil, { fragment = xray_settings.fragment == "1" or nil, noise = xray_settings.fragment == "1" or nil, run_socks_instance = not no_run }) + local outbound = gen_outbound(flag, node, nil, { fragment = xray_settings.fragment == "1" or nil, noise = xray_settings.noise == "1" or nil, run_socks_instance = not no_run }) if outbound then outbound.tag = outbound.tag .. ":" .. node.remarks COMMON.default_outbound_tag, last_insert_outbound = set_outbound_detour(node, outbound, outbounds) diff --git a/luci-app-passwall/po/zh-cn/passwall.po b/luci-app-passwall/po/zh-cn/passwall.po index b590cfe..5a2800e 100644 --- a/luci-app-passwall/po/zh-cn/passwall.po +++ b/luci-app-passwall/po/zh-cn/passwall.po @@ -1750,6 +1750,12 @@ msgstr "分片间隔" msgid "Fragmentation interval (ms)" msgstr "分片间隔(ms)" +msgid "Split handshake data into multiple TLS records for better censorship evasion. Low overhead. Recommended to enable first." +msgstr 将握手数据拆分为多个 TLS 记录,提升抗封锁能力,几乎不增加延迟,建议优先启用。" + +msgid "Split handshake into multiple TCP segments. Enhances obfuscation. May increase delay. Use only if needed." +msgstr "将 TLS 握手数据分为多个 TCP 包发送,提高伪装性,可能增加延迟,仅在封锁严重时使用。" + msgid "Noise" msgstr "噪声" diff --git a/nikki/files/nikki.init b/nikki/files/nikki.init index 4d7326a..c51b662 100644 --- a/nikki/files/nikki.init +++ b/nikki/files/nikki.init @@ -4,7 +4,8 @@ START=99 STOP=10 USE_PROCD=1 -. "$IPKG_INSTROOT/lib/functions/network.sh" +PROG="/usr/bin/mihomo" + . "$IPKG_INSTROOT/etc/nikki/scripts/include.sh" extra_command 'update_subscription' 'Update subscription by section id' @@ -193,9 +194,9 @@ service_started() { # load config config_load nikki # check if proxy enabled - local enabled - config_get_bool enabled "proxy" "enabled" 0 - if [ "$enabled" = 0 ]; then + local proxy_enabled + config_get_bool proxy_enabled "proxy" "enabled" 0 + if [ "$proxy_enabled" = 0 ]; then log "Proxy" "Disabled." return fi diff --git a/nikki/files/scripts/firewall_include.sh b/nikki/files/scripts/firewall_include.sh index 4e05fce..f270f0e 100644 --- a/nikki/files/scripts/firewall_include.sh +++ b/nikki/files/scripts/firewall_include.sh @@ -4,12 +4,14 @@ . "$IPKG_INSTROOT/etc/nikki/scripts/include.sh" config_load nikki -config_get enabled "config" "enabled" 0 +config_get_bool enabled "config" "enabled" 0 +config_get_bool core_only "config" "core_only" 0 +config_get_bool proxy_enabled "proxy" "enabled" 0 config_get tcp_mode "proxy" "tcp_mode" config_get udp_mode "proxy" "udp_mode" config_get tun_device "mixin" "tun_device" -if [ "$enabled" = 1 ]; then +if [ "$enabled" = 1 ] && [ "$core_only" = 0 ] && [ "$proxy_enabled" = 1 ]; then if [ "$tcp_mode" = "tun" ] || [ "$udp_mode" = "tun" ]; then nft insert rule inet fw4 input iifname "$tun_device" counter accept comment "nikki" nft insert rule inet fw4 forward oifname "$tun_device" counter accept comment "nikki" diff --git a/nikki/files/scripts/include.sh b/nikki/files/scripts/include.sh index 502f271..918c139 100644 --- a/nikki/files/scripts/include.sh +++ b/nikki/files/scripts/include.sh @@ -1,7 +1,6 @@ #!/bin/sh # paths -PROG="/usr/bin/mihomo" HOME_DIR="/etc/nikki" PROFILES_DIR="$HOME_DIR/profiles" SUBSCRIPTIONS_DIR="$HOME_DIR/subscriptions" @@ -26,7 +25,7 @@ BRIDGE_NF_CALL_IP6TABLES_FLAG_PATH="$TEMP_DIR/bridge_nf_call_ip6tables.flag" # ucode UCODE_DIR="$HOME_DIR/ucode" -INCLUDE_UCODE="$UCODE_DIR/include.uc" +INCLUDE_UC="$UCODE_DIR/include.uc" MIXIN_UC="$UCODE_DIR/mixin.uc" HIJACK_UT="$UCODE_DIR/hijack.ut" @@ -44,26 +43,27 @@ GEOIP6_CN_NFT="$NFT_DIR/geoip6_cn.nft" # functions format_filesize() { - local kb; kb=1024 + local b; b=1 + local kb; kb=$((b * 1024)) local mb; mb=$((kb * 1024)) local gb; gb=$((mb * 1024)) local tb; tb=$((gb * 1024)) local pb; pb=$((tb * 1024)) local size; size="$1" - if [ -z "$size" ]; then - echo "" - elif [ "$size" -lt "$kb" ]; then - echo "$size B" - elif [ "$size" -lt "$mb" ]; then - echo "$(awk "BEGIN {print $size / $kb}") KB" - elif [ "$size" -lt "$gb" ]; then - echo "$(awk "BEGIN {print $size / $mb}") MB" - elif [ "$size" -lt "$tb" ]; then - echo "$(awk "BEGIN {print $size / $gb}") GB" - elif [ "$size" -lt "$pb" ]; then - echo "$(awk "BEGIN {print $size / $tb}") TB" - else - echo "$(awk "BEGIN {print $size / $pb}") PB" + if [ -n "$size" ]; then + if [ "$size" -lt "$kb" ]; then + echo "$(awk "BEGIN {print $size / $b}") B" + elif [ "$size" -lt "$mb" ]; then + echo "$(awk "BEGIN {print $size / $kb}") KB" + elif [ "$size" -lt "$gb" ]; then + echo "$(awk "BEGIN {print $size / $mb}") MB" + elif [ "$size" -lt "$tb" ]; then + echo "$(awk "BEGIN {print $size / $gb}") GB" + elif [ "$size" -lt "$pb" ]; then + echo "$(awk "BEGIN {print $size / $tb}") TB" + else + echo "$(awk "BEGIN {print $size / $pb}") PB" + fi fi } diff --git a/xray-core/Makefile b/xray-core/Makefile index 4d9dc20..eefd1d2 100644 --- a/xray-core/Makefile +++ b/xray-core/Makefile @@ -1,12 +1,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=xray-core -PKG_VERSION:=25.7.26 +PKG_VERSION:=25.8.3 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/XTLS/Xray-core/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=99f9bc67fd22a6e4fde277a4ba05fd873146154851aeebb6b4f406a59d3b0bc3 +PKG_HASH:=a7d3785fdd46f1b045b1ef49a2a06e595c327f514b5ee8cd2ae7895813970b2c PKG_MAINTAINER:=Tianling Shen PKG_LICENSE:=MPL-2.0