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