diff --git a/lean/mt/drivers/mt7615d/Makefile b/lean/mt/drivers/mt7615d/Makefile index 6ac9ec4e..8338bf0e 100644 --- a/lean/mt/drivers/mt7615d/Makefile +++ b/lean/mt/drivers/mt7615d/Makefile @@ -11,6 +11,7 @@ P4REV:=9 PKG_VERSION:=5.0.4.0 PKG_BUILD_PARALLEL:=1 +PATCH_DIR:=./patches-$(KERNEL_PATCHVER) # PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME) PKG_KCONFIG:= \ diff --git a/lean/mt/drivers/mt7615d/patches/100-linux-6.18-kbuild-ccflags.patch b/lean/mt/drivers/mt7615d/patches-6.18/100-linux-6.18-kbuild-ccflags.patch similarity index 99% rename from lean/mt/drivers/mt7615d/patches/100-linux-6.18-kbuild-ccflags.patch rename to lean/mt/drivers/mt7615d/patches-6.18/100-linux-6.18-kbuild-ccflags.patch index 68e93fa6..ea6d819a 100644 --- a/lean/mt/drivers/mt7615d/patches/100-linux-6.18-kbuild-ccflags.patch +++ b/lean/mt/drivers/mt7615d/patches-6.18/100-linux-6.18-kbuild-ccflags.patch @@ -4,7 +4,7 @@ Subject: [PATCH] mtwifi: add Linux 6.18 build compatibility Pass the legacy compiler flags through modern Kbuild, use kernel-owned headers and drop obsolete address-limit state. -Signed-off-by: coolsnowwolf +Signed-off-by: lean --- --- a/mt_wifi_ap/Makefile +++ b/mt_wifi_ap/Makefile diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua index 3008a514..468484cb 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua @@ -620,6 +620,7 @@ if singbox_tags:find("with_utls") then o:depends({ protocol = "shadowsocks", tls = true }) o:depends({ protocol = "trojan", tls = true }) o:depends({ protocol = "anytls", tls = true }) + o:depends({ protocol = "http", tls = true }) o = s:option(Value, "reality_publicKey", translate("Public Key")) o:depends({ reality = true }) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/2_xray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/2_xray.lua index 5684127d..52d5df67 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/2_xray.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/2_xray.lua @@ -401,6 +401,7 @@ o = s:option(Flag, "tls", translate("TLS")) o.default = 0 o:depends({ protocol = "vmess" }) o:depends({ protocol = "vless" }) +o:depends({ protocol = "http" }) o:depends({ protocol = "trojan" }) o:depends({ protocol = "shadowsocks" }) @@ -719,6 +720,8 @@ o:depends({ protocol = "vless", transport = "raw" }) o:depends({ protocol = "vless", transport = "ws" }) o:depends({ protocol = "vless", transport = "grpc" }) o:depends({ protocol = "vless", transport = "httpupgrade" }) +o:depends({ protocol = "http" }) +o:depends({ protocol = "socks" }) o:depends({ protocol = "shadowsocks" }) o:depends({ protocol = "trojan" }) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/2_xray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/2_xray.lua index 02dfc68d..078de237 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/2_xray.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/2_xray.lua @@ -206,13 +206,18 @@ o.validate = function(self, value, t) end o:depends({ protocol = "vmess" }) o:depends({ protocol = "vless" }) +o:depends({ protocol = "http" }) o:depends({ protocol = "shadowsocks" }) o:depends({ protocol = "trojan" }) -- [[ REALITY部分 ]] -- o = s:option(Flag, "reality", translate("REALITY")) o.default = 0 -o:depends({ tls = true }) +o:depends({ tls = true, transport = "raw" }) +o:depends({ tls = true, transport = "ws" }) +o:depends({ tls = true, transport = "grpc" }) +o:depends({ tls = true, transport = "httpupgrade" }) +o:depends({ tls = true, transport = "xhttp" }) o = s:option(Value, "reality_private_key", translate("Private Key")) o:depends({ reality = true }) diff --git a/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/luci-app-passwall/luasrc/passwall/util_sing-box.lua index 6c0b8da4..ee91ac35 100644 --- a/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/luci-app-passwall/luasrc/passwall/util_sing-box.lua @@ -481,9 +481,9 @@ function gen_outbound(flag, node, tag, proxy_table) obfs = node.hysteria_obfs, auth = (node.hysteria_auth_type == "base64") and node.hysteria_auth_password or nil, auth_str = (node.hysteria_auth_type == "string") and node.hysteria_auth_password or nil, - recv_window_conn = tonumber(node.hysteria_recv_window_conn), --1.14 将变更为 stream_receive_window - recv_window = tonumber(node.hysteria_recv_window), --1.14 将变更为 connection_receive_window - disable_mtu_discovery = (node.hysteria_disable_mtu_discovery == "1") and true or false, --1.14 将变更为 disable_path_mtu_discovery + stream_receive_window = tonumber(node.hysteria_recv_window_conn), + connection_receive_window = tonumber(node.hysteria_recv_window), + disable_path_mtu_discovery = (node.hysteria_disable_mtu_discovery == "1") and true or false, tls = tls } end @@ -910,10 +910,10 @@ function gen_config_server(node) down_mbps = tonumber(node.hysteria_down_mbps), obfs = node.hysteria_obfs, users = users, - recv_window_conn = node.hysteria_recv_window_conn and tonumber(node.hysteria_recv_window_conn) or nil, --1.14 to stream_receive_window - recv_window_client = node.hysteria_recv_window_client and tonumber(node.hysteria_recv_window_client) or nil, --1.14 to connection_receive_window - max_conn_client = node.hysteria_max_conn_client and tonumber(node.hysteria_max_conn_client) or nil, --1.14 to max_concurrent_streams - disable_mtu_discovery = (node.hysteria_disable_mtu_discovery == "1") and true or false, --1.14 to disable_path_mtu_discover + stream_receive_window = node.hysteria_recv_window_conn and tonumber(node.hysteria_recv_window_conn) or nil, + connection_receive_window = node.hysteria_recv_window_client and tonumber(node.hysteria_recv_window_client) or nil, + max_concurrent_streams = node.hysteria_max_conn_client and tonumber(node.hysteria_max_conn_client) or nil, + disable_path_mtu_discover = (node.hysteria_disable_mtu_discovery == "1") and true or false, tls = tls } end diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua index 519497dd..73c89017 100644 --- a/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -120,6 +120,10 @@ function gen_outbound(flag, node, tag, proxy_table) node.stream_security = "tls" end + if node.protocol == "http" and node.stream_security == "tls" then + node.transport = "raw" + end + if remarks then tag = tag .. ":" .. remarks end @@ -138,7 +142,7 @@ function gen_outbound(flag, node, tag, proxy_table) xudpConcurrency = (node.mux == "1" and ((node.xudp_concurrency) and tonumber(node.xudp_concurrency) or 8)) or nil } or nil, -- 底层传输配置 - streamSettings = (node.streamSettings or dialer_proxy_tag or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan" or node.protocol == "hysteria") and { + streamSettings = (node.streamSettings or dialer_proxy_tag or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan" or node.protocol == "hysteria" or node.protocol == "http") and { sockopt = { mark = 255, domainStrategy = node.domain_strategy or "UseIP", @@ -544,7 +548,7 @@ function gen_config_server(node) allowTransparent = false, users = users } - node.transport = "tcp" + node.transport = "raw" node.tcp_guise = "none" elseif node.protocol == "shadowsocks" then settings = { diff --git a/luci-app-passwall/luasrc/view/passwall/node_config/link_share_man.htm b/luci-app-passwall/luasrc/view/passwall/node_config/link_share_man.htm index bc84d28d..c806e569 100644 --- a/luci-app-passwall/luasrc/view/passwall/node_config/link_share_man.htm +++ b/luci-app-passwall/luasrc/view/passwall/node_config/link_share_man.htm @@ -759,14 +759,6 @@ local current_node = map:get(section) return fromUrl(link); } - function tofromUrl(btn) { - let link = prompt('<%:Paste Share URL Here%>', ''); - if (link === null || link === "") { - return false; - } - return fromUrl(link); - } - function fromUrl(link, from_cache) { if (!link) { return false; diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index e787e41c..68ef9ecb 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 -PKG_VERSION:=26.9.9 +PKG_VERSION:=26.9.12 PKG_RELEASE:=2 PKG_PO_VERSION:=$(PKG_VERSION) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/1_sing-box.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/1_sing-box.lua index 50e7b1ef..366a9336 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/1_sing-box.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/1_sing-box.lua @@ -668,7 +668,8 @@ if singbox_tags:find("with_utls") then o:depends({ protocol = "socks", tls = true }) o:depends({ protocol = "trojan", tls = true }) o:depends({ protocol = "anytls", tls = true }) - + o:depends({ protocol = "http", tls = true }) + o = s:option(Value, "reality_publicKey", translate("Public Key")) o:depends({ reality = true }) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/2_xray.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/2_xray.lua index 447535df..6bc3b899 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/2_xray.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/2_xray.lua @@ -213,7 +213,11 @@ o:depends({ protocol = "trojan" }) -- [[ REALITY ]] -- o = s:option(Flag, "reality", translate("REALITY")) o.default = 0 -o:depends({ tls = true }) +o:depends({ tls = true, transport = "raw" }) +o:depends({ tls = true, transport = "ws" }) +o:depends({ tls = true, transport = "grpc" }) +o:depends({ tls = true, transport = "httpupgrade" }) +o:depends({ tls = true, transport = "xhttp" }) o = s:option(Value, "reality_private_key", translate("Private Key")) o:depends({ reality = true }) diff --git a/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua b/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua index 92f13163..e58d7f6b 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua @@ -502,9 +502,9 @@ function gen_outbound(flag, node, tag, proxy_table) obfs = node.hysteria_obfs, auth = (node.hysteria_auth_type == "base64") and node.hysteria_auth_password or nil, auth_str = (node.hysteria_auth_type == "string") and node.hysteria_auth_password or nil, - recv_window_conn = tonumber(node.hysteria_recv_window_conn), --1.14 将变更为 stream_receive_window - recv_window = tonumber(node.hysteria_recv_window), --1.14 将变更为 connection_receive_window - disable_mtu_discovery = (node.hysteria_disable_mtu_discovery == "1") and true or false, --1.14 将变更为 disable_path_mtu_discovery + stream_receive_window = tonumber(node.hysteria_recv_window_conn), + connection_receive_window = tonumber(node.hysteria_recv_window), + disable_path_mtu_discovery = (node.hysteria_disable_mtu_discovery == "1") and true or false, tls = tls } end @@ -931,10 +931,10 @@ function gen_config_server(node) down_mbps = tonumber(node.hysteria_down_mbps), obfs = node.hysteria_obfs, users = users, - recv_window_conn = node.hysteria_recv_window_conn and tonumber(node.hysteria_recv_window_conn) or nil, --1.14 to stream_receive_window - recv_window_client = node.hysteria_recv_window_client and tonumber(node.hysteria_recv_window_client) or nil, --1.14 to connection_receive_window - max_conn_client = node.hysteria_max_conn_client and tonumber(node.hysteria_max_conn_client) or nil, --1.14 to max_concurrent_streams - disable_mtu_discovery = (node.hysteria_disable_mtu_discovery == "1") and true or false, --1.14 to disable_path_mtu_discover + stream_receive_window = node.hysteria_recv_window_conn and tonumber(node.hysteria_recv_window_conn) or nil, + connection_receive_window = node.hysteria_recv_window_client and tonumber(node.hysteria_recv_window_client) or nil, + max_concurrent_streams = node.hysteria_max_conn_client and tonumber(node.hysteria_max_conn_client) or nil, + disable_path_mtu_discover = (node.hysteria_disable_mtu_discovery == "1") and true or false, tls = tls } end diff --git a/luci-app-passwall2/luasrc/passwall2/util_xray.lua b/luci-app-passwall2/luasrc/passwall2/util_xray.lua index 6befb203..b9025682 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_xray.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_xray.lua @@ -131,6 +131,10 @@ function gen_outbound(flag, node, tag, proxy_table) node.stream_security = "tls" end + if node.protocol == "http" and node.stream_security == "tls" then + node.transport = "raw" + end + if remarks then tag = tag .. ":" .. remarks end @@ -148,7 +152,7 @@ function gen_outbound(flag, node, tag, proxy_table) concurrency = (node.mux == "1" and ((node.mux_concurrency) and tonumber(node.mux_concurrency) or -1)) or nil, xudpConcurrency = (node.mux == "1" and ((node.xudp_concurrency) and tonumber(node.xudp_concurrency) or 8)) or nil } or nil, - streamSettings = (node.streamSettings or dialer_proxy_tag or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan" or node.protocol == "hysteria") and { + streamSettings = (node.streamSettings or dialer_proxy_tag or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan" or node.protocol == "hysteria" or node.protocol == "http") and { sockopt = { mark = 255, domainStrategy = node.domain_strategy or "UseIP", @@ -552,7 +556,7 @@ function gen_config_server(node) allowTransparent = false, users = users } - node.transport = "tcp" + node.transport = "raw" node.tcp_guise = "none" elseif node.protocol == "shadowsocks" then settings = { diff --git a/luci-app-ssr-plus/Makefile b/luci-app-ssr-plus/Makefile index 9b377004..3d03088d 100644 --- a/luci-app-ssr-plus/Makefile +++ b/luci-app-ssr-plus/Makefile @@ -32,7 +32,7 @@ LUCI_PKGARCH:=all LUCI_DEPENDS:= \ +libuci-lua +lua +luci-compat +coreutils +coreutils-base64 +dns2tcp +dnsmasq-full \ +jq +ip-full +lua-neturl +libuci-lua +microsocks +ipt2socks +lyaml \ - +resolveip +curl +nping +unzip +xz-utils +xz \ + +resolveip +bind-dig +curl +nping +unzip +xz-utils +xz \ +PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG:chinadns-ng \ +PACKAGE_$(PKG_NAME)_INCLUDE_MosDNS:mosdns \ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadow_TLS:shadow-tls \ diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua index c2d789e6..54d54fe0 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua @@ -5,24 +5,27 @@ local m, s, sec, o local uci = require "luci.model.uci".cursor() local URL = require "url" +local sys = require "luci.sys" +local util = require "luci.util" +local datatypes = require "luci.cbi.datatypes" -- 获取 LAN IP 地址 function lanip() local lan_ip -- 尝试从 UCI 直接读取 - lan_ip = luci.sys.exec("uci -q get network.lan.ipaddr 2>/dev/null | awk -F'/' '{print $1}' | tr -d '\\n'") + lan_ip = sys.exec("uci -q get network.lan.ipaddr 2>/dev/null | awk -F'/' '{print $1}' | tr -d '\\n'") -- 尝试从 LAN 接口信息中读取(优先 ifname,再 fallback 到 device) if not lan_ip or lan_ip == "" then - lan_ip = luci.sys.exec([[ + lan_ip = sys.exec([[ ip -4 addr show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) 2>/dev/null \ | grep -w 'inet' | awk '{print $2}' | cut -d'/' -f1 | grep -v '^127\.' | head -n1 | tr -d '\n']]) end -- 取任意一个 global IPv4 地址 if not lan_ip or lan_ip == "" then - lan_ip = luci.sys.exec([[ + lan_ip = sys.exec([[ ip -4 addr show scope global 2>/dev/null \ | grep -w 'inet' | awk '{print $2}' | cut -d'/' -f1 | grep -v '^127\.' | head -n1 | tr -d '\n']]) end @@ -31,10 +34,9 @@ ip -4 addr show scope global 2>/dev/null \ end local lan_ip = lanip() -local validation = require "luci.cbi.datatypes" local clash_nodes = {} local function is_finded(e) - return luci.sys.exec(string.format('type -t -p "%s" -p "/usr/libexec/%s" 2>/dev/null', e, e)) ~= "" + return sys.exec(string.format('type -t -p "%s" -p "/usr/libexec/%s" 2>/dev/null', e, e)) ~= "" end local function clash_display_name(s) @@ -48,6 +50,28 @@ local function clash_display_name(s) return "[CLASH]" end +local function is_valid_dns(str) + if datatypes.ip4addrport(str) then + return true + end + + local scheme, target = str:match("^([a-zA-Z0-9%+%-%.]+)://(.+)$") + if scheme and target and #target > 0 then + return true + end + + local host = str:match("^([^:]+):%d+$") or str + if host:match("[a-zA-Z]") + and not host:match("[^%w%.%-]") + and not host:match("^[%.%-]") + and not host:match("[%.%-]$") + and not host:match("%.%.") then + return true + end + + return false +end + m = Map("shadowsocksr", translate("ShadowSocksR Plus+ Settings"), translate("

Support SS/SSR/V2RAY/XRAY/TROJAN/TUIC/HYSTERIA2/NAIVEPROXY/SOCKS5/CLASH etc.

")) m:section(SimpleSection).template = "shadowsocksr/status" @@ -131,7 +155,7 @@ o:value("7", translate("Prefer module built-in DNS")) o:value("0", translate("Use Local DNS Service listen port 5335")) o.default = 1 -o = s:option(Value, "tunnel_forward", translate("Anti-pollution DNS Server")) +o = s:option(Value, "dns2tcp_tunnel_forward", translate("Anti-pollution DNS Server")) o:value("8.8.4.4:53", translate("Google Public DNS (8.8.4.4)")) o:value("8.8.8.8:53", translate("Google Public DNS (8.8.8.8)")) o:value("208.67.222.222:53", translate("OpenDNS (208.67.222.222)")) @@ -144,11 +168,55 @@ o:value("4.2.2.3:53", translate("Level 3 Public DNS (4.2.2.3)")) o:value("4.2.2.4:53", translate("Level 3 Public DNS (4.2.2.4)")) o:value("1.1.1.1:53", translate("Cloudflare DNS (1.1.1.1)")) o:depends("pdnsd_enable", "1") -o:depends("pdnsd_enable", "7") o.description = translate("Custom DNS Server format as IP:PORT (default: 8.8.4.4:53)") o.datatype = "ip4addrport" o.default = "8.8.4.4:53" +o = s:option(Value, "tunnel_forward", translate("Anti-pollution DNS Server")) +o:value("8.8.4.4:53", translate("Google Public DNS (8.8.4.4)")) +o:value("8.8.8.8:53", translate("Google Public DNS (8.8.8.8)")) +o:value("208.67.222.222:53", translate("OpenDNS (208.67.222.222)")) +o:value("208.67.220.220:53", translate("OpenDNS (208.67.220.220)")) +o:value("209.244.0.3:53", translate("Level 3 Public DNS (209.244.0.3)")) +o:value("209.244.0.4:53", translate("Level 3 Public DNS (209.244.0.4)")) +o:value("4.2.2.1:53", translate("Level 3 Public DNS (4.2.2.1)")) +o:value("4.2.2.2:53", translate("Level 3 Public DNS (4.2.2.2)")) +o:value("4.2.2.3:53", translate("Level 3 Public DNS (4.2.2.3)")) +o:value("4.2.2.4:53", translate("Level 3 Public DNS (4.2.2.4)")) +o:value("1.1.1.1:53", translate("Cloudflare DNS (1.1.1.1)")) +o:depends("pdnsd_enable", "7") +o.datatype = nil +o.description = + "" +o.default = "8.8.4.4:53" +o.validate = function(self, value, section) + if section and value and value ~= "" then + local parts = {} + for part in (value .. ","):gmatch("(.-),") do + part = part:gsub("^%s*", ""):gsub("%s*$", "") + if part ~= "" then + if not is_valid_dns(part) then + return nil, translate("Expecting: %s"):format(translate("IP:PORT, Domain, or Protocol URL (e.g. 8.8.8.8:53, dns.google, https://...).") .. + "
".. translate("Note: Pure IP without port is not allowed.")) + end + table.insert(parts, part) + end + end + + if #parts > 0 then + return table.concat(parts, ",") + end + + return nil, translate("Expecting: %s"):format(translate("valid address:port")) -- 有效的地址:端口 + end + + return value +end + o = s:option(Value, "tunnel_forward_mosdns", translate("Anti-pollution DNS Server")) o:value("tcp://8.8.4.4:53,tcp://8.8.8.8:53", translate("Google Public DNS")) o:value("tcp://208.67.222.222:53,tcp://208.67.220.220:53", translate("OpenDNS")) @@ -225,7 +293,7 @@ if is_finded("chinadns-ng") then local parts = {} for part in string.gmatch(value, "[^,]+") do part = part:gsub("^%s*", ""):gsub("%s*$", "") - if not validation.ip4addrport(part) then + if not datatypes.ip4addrport(part) then return nil, translate("Expecting: %s"):format(translate("valid address:port (comma separated)")) end table.insert(parts, part) @@ -236,7 +304,7 @@ if is_finded("chinadns-ng") then return table.concat(parts, ",") end - if validation.ip4addrport(value) then + if datatypes.ip4addrport(value) then return value end diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua index 0d92887f..8dc62941 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua @@ -1,8 +1,11 @@ require "luci.ip" require "nixio.fs" require "luci.sys" +local ucic = luci.model.uci.cursor() local m, s, o +local enable_mihomo = ucic:get_first('shadowsocksr', 'server_subscribe', 'enable_mihomo') or '' + m = Map("shadowsocksr") s = m:section(TypedSection, "access_control") @@ -116,7 +119,7 @@ o.rows = 13 o.wrap = "off" o.rmempty = true o.cfgvalue = function(self, section) - return nixio.fs.readfile(denydomainconf) or " " + return nixio.fs.readfile(denydomainconf) or "" end o.write = function(self, section, value) nixio.fs.writefile(denydomainconf, value:gsub("\r\n", "\n")) @@ -125,6 +128,54 @@ o.remove = function(self, section, value) nixio.fs.writefile(denydomainconf, "") end +if enable_mihomo == "1" then + s:tab("fake_ip_filter", translate("Fake-IP Filter and Fallback Lists")) + local fake_ip_filter_conf = "/etc/ssrplus/fake_ip_filter.list" + o = s:taboption("fake_ip_filter", TextValue, "fake_ip_filter_conf", "", "" .. translate("Specifically for editing the Fake-IP filter list.") .. "") -- 专用于编辑 Fake-IP 过滤规则文件。 + o.rows = 13 + o.wrap = "off" + o.rmempty = true + o.cfgvalue = function(self, section) + return nixio.fs.readfile(fake_ip_filter_conf) or "" + end + o.write = function(self, section, value) + nixio.fs.writefile(fake_ip_filter_conf, value:gsub("\r\n", "\n")) + end + o.remove = function(self, section, value) + nixio.fs.writefile(fake_ip_filter_conf, "") + end + + local fallback_ipcidr_conf = "/etc/ssrplus/fallback_ipcidr.list" + o = s:taboption("fake_ip_filter", TextValue, "fallback_ipcidr_conf", "", "" .. translate("Specifically for editing the Fallback IP-CIDR list.") .. "") -- 专用于编辑 Fallback IP-CIDR 规则文件。 + o.rows = 13 + o.wrap = "off" + o.rmempty = true + o.cfgvalue = function(self, section) + return nixio.fs.readfile(fallback_ipcidr_conf) or "" + end + o.write = function(self, section, value) + nixio.fs.writefile(fallback_ipcidr_conf, value:gsub("\r\n", "\n")) + end + o.remove = function(self, section, value) + nixio.fs.writefile(fallback_ipcidr_conf, "") + end + + local fallback_domain_conf = "/etc/ssrplus/fallback_domain.list" + o = s:taboption("fake_ip_filter", TextValue, "fallback_domain_conf", "", "" .. translate("Specifically for editing the Fallback domain filter list.") .. "") -- 专用于编辑 Fallback 域名过滤规则文件。 + o.rows = 13 + o.wrap = "off" + o.rmempty = true + o.cfgvalue = function(self, section) + return nixio.fs.readfile(fallback_domain_conf) or "" + end + o.write = function(self, section, value) + nixio.fs.writefile(fallback_domain_conf, value:gsub("\r\n", "\n")) + end + o.remove = function(self, section, value) + nixio.fs.writefile(fallback_domain_conf, "") + end +end + if luci.sys.call('[ -f "/www/luci-static/resources/uci.js" ]') == 0 then m.apply_on_parse = true function m.on_apply(self) diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua index e7b13faa..e55596d5 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua @@ -188,9 +188,10 @@ local function save_uploaded_clash_node(upload_name, final_path) local alias if not sid then - sid = uci:add("shadowsocksr", "servers") + local sid_output = luci.sys.exec("uci add shadowsocksr servers 2>/dev/null") + sid = trim(sid_output) end - if not sid then + if not sid or sid == "" then return nil end @@ -200,20 +201,50 @@ local function save_uploaded_clash_node(upload_name, final_path) alias = upload_alias(upload_name) end - uci:set("shadowsocksr", sid, "type", "clash") - uci:set("shadowsocksr", sid, "alias", alias) - uci:set("shadowsocksr", sid, "server", "127.0.0.1") - uci:set("shadowsocksr", sid, "server_port", "0") - uci:delete("shadowsocksr", sid, "clash_url") - uci:set("shadowsocksr", sid, "clash_path", final_path) - uci:set("shadowsocksr", sid, "clash_user_agent", uci:get("shadowsocksr", sid, "clash_user_agent") or "clash") - if not uci:get("shadowsocksr", sid, "switch_enable") then - uci:set("shadowsocksr", sid, "switch_enable", uci:get_first("shadowsocksr", "server_subscribe", "switch", "1") or "1") + local switch_enable = uci:get("shadowsocksr", sid, "switch_enable") + if not switch_enable or switch_enable == "" then + switch_enable = uci:get_first("shadowsocksr", "server_subscribe", "switch", "1") or "1" + end + + local clash_user_agent = uci:get("shadowsocksr", sid, "clash_user_agent") + if not clash_user_agent or clash_user_agent == "" then + clash_user_agent = "clash" + end + + local safe_sid = luci.util.shellquote(sid) + local safe_alias = luci.util.shellquote(alias) + local safe_path = luci.util.shellquote(final_path) + local safe_upload_name = luci.util.shellquote(upload_name) + local safe_switch_enable = luci.util.shellquote(switch_enable) + local safe_user_agent = luci.util.shellquote(clash_user_agent) + + local cmd = string.format( + "uci set shadowsocksr.%s.type=clash && " .. + "uci set shadowsocksr.%s.alias=%s && " .. + "uci set shadowsocksr.%s.server=127.0.0.1 && " .. + "uci set shadowsocksr.%s.server_port=0 && " .. + "uci delete shadowsocksr.%s.clash_url 2>/dev/null; " .. + "uci set shadowsocksr.%s.clash_path=%s && " .. + "uci set shadowsocksr.%s.clash_user_agent=%s && " .. + "uci set shadowsocksr.%s.switch_enable=%s && " .. + "uci set shadowsocksr.%s.yaml_upload=1 && " .. + "uci set shadowsocksr.%s.yaml_upload_name=%s && " .. + "uci commit shadowsocksr", + safe_sid, + safe_sid, safe_alias, + safe_sid, + safe_sid, + safe_sid, + safe_sid, safe_path, + safe_sid, safe_user_agent, + safe_sid, safe_switch_enable, + safe_sid, + safe_sid, safe_upload_name + ) + + if luci.sys.call(cmd) ~= 0 then + return nil end - uci:set("shadowsocksr", sid, "yaml_upload", "1") - uci:set("shadowsocksr", sid, "yaml_upload_name", upload_name) - uci:save("shadowsocksr") - uci:commit("shadowsocksr") cleanup_old_clash_path(old_path, final_path, sid) luci.sys.call(string.format("/etc/init.d/shadowsocksr clash_cache %s >/dev/null 2>&1 &", luci.util.shellquote(sid))) @@ -267,32 +298,48 @@ if has_mihomo then local tmp_output = string.format("%s/.upload-%d-%d.yaml", CLASH_YAML_DIR, nixio.getpid(), os.time()) local sid local alias + local redirect_message_url nixio.fs.mkdirr(CLASH_YAML_DIR) nixio.fs.remove(tmp_output) if preprocess_clash_yaml(upload_tmp_path, tmp_output) then hash = hash_file(tmp_output) - if hash == "" then - nixio.fs.remove(tmp_output) + if not hash or hash == "" then upload_errmessage = translate("Uploaded YAML validation or preprocessing failed.") else final_path = string.format("%s/%s.yaml", CLASH_YAML_DIR, hash) - luci.sys.call(string.format("mv -f %s %s", luci.util.shellquote(tmp_output), luci.util.shellquote(final_path))) - sid, alias = save_uploaded_clash_node(upload_filename, final_path) - if sid then - upload_message = string.format(translate("Custom YAML imported successfully: %s"), alias or sid) + local mv_ret = luci.sys.call(string.format("mv -f %s %s", luci.util.shellquote(tmp_output), luci.util.shellquote(final_path))) + if mv_ret == 0 and nixio.fs.access(final_path) then + sid, alias = save_uploaded_clash_node(upload_filename, final_path) + if sid then + local message = string.format(translate("Custom YAML imported successfully: %s"), alias or sid) + local redirect_url = luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers") + redirect_message_url = redirect_url .. "?upload_message=" .. luci.http.urlencode(message) + else + upload_errmessage = translate("Uploaded YAML validation or preprocessing failed.") + if final_path and nixio.fs.access(final_path) then + nixio.fs.remove(final_path) + end + end else - upload_errmessage = translate("Uploaded YAML validation or preprocessing failed.") + upload_errmessage = translate("Failed to move uploaded YAML to target directory.") end end else - nixio.fs.remove(tmp_output) - upload_errmessage = translate("Uploaded YAML validation or preprocessing failed.") + upload_errmessage = upload_errmessage or translate("Uploaded YAML validation or preprocessing failed.") end - end - if upload_tmp_path then - nixio.fs.remove(upload_tmp_path) + if upload_tmp_path and nixio.fs.access(upload_tmp_path) then + nixio.fs.remove(upload_tmp_path) + end + if tmp_output and nixio.fs.access(tmp_output) then + nixio.fs.remove(tmp_output) + end + + if redirect_message_url then + luci.http.redirect(redirect_message_url) + return + end end end end @@ -407,8 +454,11 @@ end m = Map("shadowsocksr", translate("Servers subscription and manage")) if upload_errmessage then m.errmessage = upload_errmessage -elseif upload_message then - m.message = upload_message +else + local message = luci.http.formvalue("upload_message") + if message and message ~= "" then + m.message = message + end end local style_section = m:section(SimpleSection) @@ -566,6 +616,29 @@ if has_mihomo then o.rmempty = true o.description = translate("Disabled means use Xray or ShadowSocks-Rust core.") + o = s:option(Flag, "enable_fake_ip", string.format("%s", translate("Enable Fake-IP Mode"))) + o.default = "0" + o.rmempty = true + o:depends("enable_mihomo", "1") + o.description = translate( + "" + ) + o = s:option(Flag, "sub_convert", translate("Subscribe Convert Online")) o.description = translate("Convert subscriptions to Clash/Mihomo YAML with a subscription template URL.") o.default = "0" diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_yaml_upload.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_yaml_upload.htm index 830193af..b9438b85 100644 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_yaml_upload.htm +++ b/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_yaml_upload.htm @@ -1,4 +1,4 @@ <%+cbi/valueheader%> - + <%+cbi/valuefooter%> diff --git a/luci-app-ssr-plus/po/templates/ssr-plus.pot b/luci-app-ssr-plus/po/templates/ssr-plus.pot index 013227a8..35eef481 100644 --- a/luci-app-ssr-plus/po/templates/ssr-plus.pot +++ b/luci-app-ssr-plus/po/templates/ssr-plus.pot @@ -12,11 +12,11 @@ msgstr "" msgid "0" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:94 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:118 msgid "1 Thread" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:101 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:125 msgid "128 Threads" msgstr "" @@ -24,15 +24,15 @@ msgstr "" msgid "16" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:98 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:122 msgid "16 Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:95 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:119 msgid "2 Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:99 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:123 msgid "32 Threads" msgstr "" @@ -40,19 +40,19 @@ msgstr "" msgid "360" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:207 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:275 msgid "360 Security DNS (China Telecom) (101.226.4.6)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:208 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:276 msgid "360 Security DNS (China Unicom) (123.125.81.6)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:96 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:120 msgid "4 Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:100 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:124 msgid "64 Threads" msgstr "" @@ -60,7 +60,7 @@ msgstr "" msgid "8" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:97 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:121 msgid "8 Threads" msgstr "" @@ -74,7 +74,7 @@ msgstr "" msgid "" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:51 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:75 msgid "" "

Support SS/SSR/V2RAY/XRAY/TROJAN/TUIC/HYSTERIA2/NAIVEPROXY/SOCKS5/CLASH " "etc.

" @@ -86,8 +86,9 @@ msgstr "" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1654 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1667 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1680 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:186 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:213 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:254 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:281 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:624 msgid "
  • " msgstr "" @@ -141,12 +142,12 @@ msgstr "" msgid "Advertising Data" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:205 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:273 msgid "AliYun Public DNS (223.5.5.5)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:611 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:723 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:684 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:796 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:187 msgid "Alias" msgstr "" @@ -159,7 +160,7 @@ msgstr "" msgid "All" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:112 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:136 msgid "All Ports" msgstr "" @@ -175,15 +176,15 @@ msgstr "" msgid "All settings saved successfully." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:35 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:38 msgid "Allow all except listed" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:34 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:37 msgid "Allow listed only" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:486 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:536 msgid "Allow subscribe Insecure nodes By default" msgstr "" @@ -205,9 +206,10 @@ msgstr "" msgid "An FinalMaskObject in JSON format, used for sharing." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:134 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:152 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:171 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:158 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:175 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:220 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:239 msgid "Anti-pollution DNS Server" msgstr "" @@ -227,12 +229,12 @@ msgstr "" msgid "Apple domains optimization" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:783 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:789 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:856 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:862 msgid "Apply" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:426 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:476 msgid "Appointment Mode" msgstr "" @@ -244,19 +246,19 @@ msgstr "" msgid "Are you sure you want to restore the client to default settings?" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:800 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:873 msgid "Auto Switch" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:93 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:117 msgid "Auto Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:421 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:471 msgid "Auto Update" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:423 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:473 msgid "Auto Update Server subscription, GFW list and CHN route" msgstr "" @@ -283,7 +285,7 @@ msgstr "" msgid "Baidu Connectivity" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:206 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:274 msgid "Baidu Public DNS (180.76.76.76)" msgstr "" @@ -300,7 +302,7 @@ msgstr "" msgid "BitTorrent (uTP)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:96 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:99 msgid "Black Domain List" msgstr "" @@ -308,7 +310,7 @@ msgstr "" msgid "Bloom Filter" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:80 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:83 msgid "Bypass Domain List" msgstr "" @@ -316,7 +318,7 @@ msgstr "" msgid "CLOSE WIN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:209 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:277 msgid "CNNIC SDNS (1.2.4.8)" msgstr "" @@ -401,7 +403,7 @@ msgstr "" msgid "China IP Data" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:192 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:260 msgid "ChinaDNS-NG query protocol" msgstr "" @@ -421,7 +423,7 @@ msgstr "" msgid "Clash" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:88 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:112 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:893 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1096 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:3 @@ -456,6 +458,10 @@ msgstr "" msgid "Clear logs" msgstr "" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:633 +msgid "Click here to manage" +msgstr "" + #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:309 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1162 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1518 @@ -484,12 +490,13 @@ msgstr "" msgid "Close" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:158 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:226 msgid "Cloudflare DNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:145 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:182 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:169 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:186 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:250 msgid "Cloudflare DNS (1.1.1.1)" msgstr "" @@ -533,11 +540,11 @@ msgid "" "Controls the policy used when performing DNS queries for ECH configuration." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:575 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:648 msgid "Convert Address" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:570 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:643 msgid "" "Convert subscriptions to Clash/Mihomo YAML with a subscription template URL." msgstr "" @@ -584,16 +591,21 @@ msgstr "" msgid "Custom Client Proxies Rules" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:148 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:187 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:191 +msgid "" +"Custom DNS Server (supports format IP:PORT, domain name, or scheme://...)." +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:171 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:255 msgid "Custom DNS Server format as IP:PORT (default: 8.8.4.4:53)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:214 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:282 msgid "Custom DNS Server format as IP:PORT (default: disabled)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:160 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:228 msgid "" "Custom DNS Server format as tcp://IP:PORT or tls://DOMAIN:PORT " "(tcp://8.8.8.8 or tls://dns.google:853)" @@ -603,11 +615,11 @@ msgstr "" msgid "Custom Plugin Path" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:114 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:138 msgid "Custom Ports" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:283 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:315 msgid "Custom YAML imported successfully: %s" msgstr "" @@ -637,7 +649,7 @@ msgstr "" msgid "DNS Anti-pollution" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:204 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:272 msgid "DNSPod Public DNS (119.29.29.29)" msgstr "" @@ -717,7 +729,7 @@ msgstr "" msgid "Delete" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:519 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:569 msgid "Delete All Subscribe Servers" msgstr "" @@ -725,22 +737,22 @@ msgstr "" msgid "Delete failed:" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:112 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:115 msgid "Deny Domain List" msgstr "" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:726 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1037 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:81 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:33 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:105 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:36 msgid "Disable" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:200 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:268 msgid "Disable ChinaDNS-NG" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:163 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:231 msgid "Disable IPv6 for Overseas FQDN" msgstr "" @@ -756,7 +768,7 @@ msgstr "" msgid "Disable TCP No_delay" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:567 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:617 msgid "Disabled means use Xray or ShadowSocks-Rust core." msgstr "" @@ -768,7 +780,7 @@ msgstr "" msgid "Do you want to restore the client to default settings?" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:196 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:264 msgid "DoT upstream (Need use wolfssl version)" msgstr "" @@ -780,7 +792,7 @@ msgstr "" msgid "DomainSocket Path" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:199 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:267 msgid "Domestic DNS Server" msgstr "" @@ -827,7 +839,7 @@ msgstr "" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:323 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:54 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:101 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:603 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:676 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1114 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:184 msgid "Enable" @@ -850,6 +862,18 @@ msgstr "" msgid "Enable ECH(optional)" msgstr "" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:619 +msgid "Enable Fake-IP Mode" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:626 +msgid "Enable Fake-IP mode for better performance." +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:625 +msgid "Enable Fake-IP mode; disable to use redir-host mode." +msgstr "" + #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:720 msgid "Enable Lazy Mode" msgstr "" @@ -858,7 +882,7 @@ msgstr "" msgid "Enable ML-DSA-65(optional)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:564 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:614 msgid "Enable Mihomo core" msgstr "" @@ -937,7 +961,7 @@ msgstr "" msgid "Encrypt Method" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:115 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:139 msgid "Enter Custom Ports" msgstr "" @@ -946,35 +970,35 @@ msgstr "" msgid "Error" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:433 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:483 msgid "Every Day" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:438 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:488 msgid "Every Friday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:434 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:484 msgid "Every Monday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:439 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:489 msgid "Every Saturday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:440 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:490 msgid "Every Sunday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:437 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:487 msgid "Every Thursday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:435 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:485 msgid "Every Tuesday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:436 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:486 msgid "Every Wednesday" msgstr "" @@ -982,9 +1006,11 @@ msgstr "" msgid "Example:" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:229 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:234 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:243 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:203 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:214 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:297 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:302 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:311 msgid "Expecting: %s" msgstr "" @@ -1008,7 +1034,7 @@ msgstr "" msgid "Failed to create temp directory" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:244 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:275 msgid "Failed to create temporary YAML upload file." msgstr "" @@ -1017,6 +1043,10 @@ msgstr "" msgid "Failed to fetch release metadata" msgstr "" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:325 +msgid "Failed to move uploaded YAML to target directory." +msgstr "" + #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:112 msgid "Failed to query component information." msgstr "" @@ -1029,6 +1059,10 @@ msgstr "" msgid "Failed to save custom client proxy rules." msgstr "" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:132 +msgid "Fake-IP Filter and Fallback Lists" +msgstr "" + #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_header.htm:21 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_header.htm:61 msgid "Fetch Failed" @@ -1043,7 +1077,7 @@ msgstr "" msgid "File Not Exist" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:476 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:526 msgid "Filter Words splited by /" msgstr "" @@ -1104,11 +1138,11 @@ msgstr "" msgid "GFW List Data" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:106 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:130 msgid "GFW List Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:64 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:67 msgid "Game Mode Host List" msgstr "" @@ -1154,7 +1188,7 @@ msgstr "" msgid "Global HTTP/HTTPS Proxy Server" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:108 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:132 msgid "Global Mode" msgstr "" @@ -1175,17 +1209,19 @@ msgstr "" msgid "Google Connectivity" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:153 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:221 msgid "Google Public DNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:135 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:172 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:159 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:176 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:240 msgid "Google Public DNS (8.8.4.4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:136 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:173 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:160 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:177 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:241 msgid "Google Public DNS (8.8.8.8)" msgstr "" @@ -1287,7 +1323,7 @@ msgstr "" msgid "Hysterir QUIC parameters" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:107 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:131 msgid "IP Route Mode" msgstr "" @@ -1295,6 +1331,16 @@ msgstr "" msgid "IP Stack Preference" msgstr "" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:203 +msgid "" +"IP:PORT, Domain, or Protocol URL (e.g. 8.8.8.8:53, dns.google, https://...)." +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:627 +msgid "" +"If disabled, Redir-Host mode will be used which returns real IP addresses." +msgstr "" + #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:148 msgid "If empty, Not change Apple domains parsing DNS (Default is empty)" msgstr "" @@ -1364,11 +1410,11 @@ msgstr "" msgid "Installed package check failed" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:13 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:16 msgid "Interface" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:12 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:15 msgid "Interface control" msgstr "" @@ -1440,23 +1486,23 @@ msgstr "" msgid "KcpTun Version" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:32 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:35 msgid "LAN Access Control" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:48 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:51 msgid "LAN Bypassed Host List" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:56 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:59 msgid "LAN Force Proxy Host List" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:38 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:41 msgid "LAN Host List" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:30 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:33 msgid "LAN IP AC" msgstr "" @@ -1465,45 +1511,51 @@ msgstr "" msgid "Latest Version" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:139 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:176 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:163 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:180 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:244 msgid "Level 3 Public DNS (209.244.0.3)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:140 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:177 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:164 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:181 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:245 msgid "Level 3 Public DNS (209.244.0.4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:141 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:178 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:165 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:182 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:246 msgid "Level 3 Public DNS (4.2.2.1)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:142 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:179 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:166 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:183 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:247 msgid "Level 3 Public DNS (4.2.2.2)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:143 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:180 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:167 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:184 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:248 msgid "Level 3 Public DNS (4.2.2.3)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:144 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:181 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:168 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:185 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:249 msgid "Level 3 Public DNS (4.2.2.4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:155 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:223 msgid "Level 3 Public DNS-1 (209.244.0.3-4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:156 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:224 msgid "Level 3 Public DNS-2 (4.2.2.1-2)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:157 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:225 msgid "Level 3 Public DNS-3 (4.2.2.3-4)" msgstr "" @@ -1516,7 +1568,7 @@ msgid "" "Linux kernel TUN virtual NIC requires system support and root privileges." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:18 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:21 msgid "Listen only on the given interface or, if unspecified, on all" msgstr "" @@ -1543,7 +1595,7 @@ msgstr "" msgid "Log" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:427 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:477 msgid "Loop Mode" msgstr "" @@ -1567,11 +1619,11 @@ msgstr "" msgid "MTU" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:80 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:104 msgid "Main Server" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:601 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:674 msgid "" "Manage multiple subscribe URLs, including Clash subscriptions. Only enabled " "entries are included when updating all subscriptions." @@ -1652,8 +1704,9 @@ msgstr "" msgid "Move up" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:188 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:215 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:192 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:256 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:283 msgid "Muitiple DNS server can saperate with ','" msgstr "" @@ -1661,7 +1714,7 @@ msgstr "" msgid "Multi" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:92 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:116 msgid "Multi Threads Option" msgstr "" @@ -1693,7 +1746,7 @@ msgstr "" msgid "Name" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:203 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:271 msgid "Nanjing Xinfeng 114DNS (114.114.114.114)" msgstr "" @@ -1733,7 +1786,7 @@ msgstr "" msgid "No available core (Shadowsocks, Mihomo or Xray) to import this node." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:263 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:294 msgid "No custom YAML file was selected." msgstr "" @@ -1758,7 +1811,7 @@ msgstr "" msgid "No switchable proxy groups found." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:625 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:698 msgid "" "Node order can be dragged with the mouse and takes effect immediately. The " "automatic switch order of server nodes is consistent with the node order in " @@ -1774,8 +1827,8 @@ msgstr "" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1269 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1281 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1291 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:720 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:725 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:793 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:798 msgid "None" msgstr "" @@ -1797,6 +1850,14 @@ msgstr "" msgid "Not installed" msgstr "" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:193 +msgid "Note: IP addresses MUST specify a port." +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:204 +msgid "Note: Pure IP without port is not allowed." +msgstr "" + #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua:27 msgid "" "Note: Restoring configurations across different versions may cause " @@ -1847,7 +1908,7 @@ msgstr "" msgid "Once set, connects only when the server’s chain fingerprint matches." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:113 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:137 msgid "Only Common Ports" msgstr "" @@ -1872,17 +1933,19 @@ msgstr "" msgid "OpenClash GeoSite Database" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:154 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:222 msgid "OpenDNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:138 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:175 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:162 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:179 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:243 msgid "OpenDNS (208.67.220.220)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:137 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:174 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:161 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:178 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:242 msgid "OpenDNS (208.67.222.222)" msgstr "" @@ -1933,7 +1996,7 @@ msgstr "" msgid "Permit Without Stream" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:768 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:841 msgid "Ping Latency" msgstr "" @@ -1973,7 +2036,7 @@ msgstr "" msgid "Pre-shared key" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:130 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:154 msgid "Prefer module built-in DNS" msgstr "" @@ -2004,7 +2067,7 @@ msgstr "" msgid "Protocol param (optional)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:111 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:135 msgid "Proxy Ports" msgstr "" @@ -2092,7 +2155,7 @@ msgstr "" msgid "Realm URL" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:787 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:860 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:348 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:17 msgid "Reapply" @@ -2126,11 +2189,11 @@ msgstr "" msgid "Refresh..." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:445 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:495 msgid "Regular update (Hour)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:453 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:503 msgid "Regular update (Min)" msgstr "" @@ -2202,7 +2265,7 @@ msgstr "" msgid "Resetting Defaults..." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:120 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:144 msgid "Resolve Dns Mode" msgstr "" @@ -2233,7 +2296,7 @@ msgstr "" msgid "Running" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:105 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:129 msgid "Running Mode" msgstr "" @@ -2266,15 +2329,15 @@ msgstr "" msgid "Save" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:507 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:557 msgid "Save Subscribe Settings" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:482 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:532 msgid "Save Words splited by /" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:509 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:559 msgid "Save current subscribe settings" msgstr "" @@ -2300,7 +2363,7 @@ msgstr "" msgid "Server Address" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:521 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:571 msgid "Server Count" msgstr "" @@ -2335,7 +2398,7 @@ msgstr "" msgid "Servers Nodes" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:407 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:454 msgid "Servers subscription and manage" msgstr "" @@ -2373,7 +2436,7 @@ msgstr "" msgid "ShadowSocksR Plus+" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:51 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:75 msgid "ShadowSocksR Plus+ Settings" msgstr "" @@ -2420,7 +2483,7 @@ msgstr "" msgid "Snell Version" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:728 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:801 msgid "Socket Connected" msgstr "" @@ -2453,6 +2516,18 @@ msgstr "" msgid "Socks5 User" msgstr "" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:134 +msgid "Specifically for editing the Fake-IP filter list." +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:149 +msgid "Specifically for editing the Fallback IP-CIDR list." +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:164 +msgid "Specifically for editing the Fallback domain filter list." +msgstr "" + #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:129 msgid "Start Detection" msgstr "" @@ -2479,19 +2554,19 @@ msgstr "" msgid "Stop Detection" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:467 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:517 msgid "Subscribe Advanced Settings" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:569 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:642 msgid "Subscribe Convert Online" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:493 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:543 msgid "Subscribe Default Auto-Switch" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:473 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:523 msgid "Subscribe Filter Words" msgstr "" @@ -2499,16 +2574,16 @@ msgstr "" msgid "Subscribe Log" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:480 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:530 msgid "Subscribe Save Words" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:583 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:656 msgid "Subscribe Template URL" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:594 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:618 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:667 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:691 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:189 msgid "Subscribe URL" msgstr "" @@ -2517,11 +2592,11 @@ msgstr "" msgid "Subscribe failed, refreshing page..." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:495 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:545 msgid "Subscribe new add server default Auto-Switch on" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:488 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:538 msgid "Subscribe nodes allows insecure connection as TLS client (insecure)" msgstr "" @@ -2582,7 +2657,7 @@ msgid "" "as bypassing SNI blacklists." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:194 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:262 msgid "TCP upstream" msgstr "" @@ -2658,11 +2733,10 @@ msgstr "" msgid "The keep-alive period.(Unit:second)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:6 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:18 msgid "" -"The online upgrade downloads the latest luci-app-ssr-plus package from fw876/" -"helloworld releases and installs the matching IPK or APK package for this " -"system." +"The online upgrade downloads and installs the matching NaiveProxy package " +"for this system from fw876/helloworld releases." msgstr "" #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:10 @@ -2671,6 +2745,13 @@ msgid "" "this system from fw876/helloworld releases." msgstr "" +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:6 +msgid "" +"The online upgrade downloads the latest luci-app-ssr-plus package from fw876/" +"helloworld releases and installs the matching IPK or APK package for this " +"system." +msgstr "" + #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:14 msgid "" "The online upgrade only tracks the latest stable Mihomo release and " @@ -2678,12 +2759,6 @@ msgid "" "GitHub release page." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:18 -msgid "" -"The online upgrade downloads and installs the matching NaiveProxy package " -"for this system from fw876/helloworld releases." -msgstr "" - #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:816 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:871 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:89 @@ -2701,11 +2776,11 @@ msgstr "" msgid "This section contains no values yet" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:500 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:550 msgid "Through proxy update" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:502 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:552 msgid "Through proxy update list, Not Recommended" msgstr "" @@ -2717,6 +2792,10 @@ msgstr "" msgid "Timeout for establishing a connection to server(second)" msgstr "" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:628 +msgid "Tips: Fake-IP Filter and Fallback Lists:" +msgstr "" + #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:305 msgid "To send noise packets, select \"Noise\" in Xray Settings." msgstr "" @@ -2749,7 +2828,7 @@ msgid "Try Count" msgstr "" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:327 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:717 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:790 msgid "Type" msgstr "" @@ -2771,11 +2850,11 @@ msgstr "" msgid "UDP relay mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:195 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:263 msgid "UDP upstream" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:193 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:261 msgid "UDP/TCP upstream" msgstr "" @@ -2783,7 +2862,7 @@ msgstr "" msgid "UL Restore" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:539 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:589 msgid "URL Test Address" msgstr "" @@ -2832,19 +2911,19 @@ msgstr "" msgid "Update" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:512 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:562 msgid "Update All Subscribe Servers" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:461 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:511 msgid "Update Interval(min)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:425 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:475 msgid "Update Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:432 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:482 msgid "Update cycle (Day/Week)" msgstr "" @@ -2901,43 +2980,43 @@ msgstr "" msgid "Upload" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:560 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:610 msgid "Upload Custom YAML File" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:562 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:612 msgid "" "Upload a custom Clash/Mihomo YAML file. The file will be preprocessed and " "saved as a local Clash node." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:277 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:285 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:290 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:308 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:319 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:329 msgid "Uploaded YAML validation or preprocessing failed." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:128 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:152 msgid "Use ChinaDNS-NG query and cache" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:201 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:269 msgid "Use DNS from WAN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:202 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:270 msgid "Use DNS from WAN and 114DNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:122 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:146 msgid "Use DNS2TCP query" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:131 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:155 msgid "Use Local DNS Service listen port 5335" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:125 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:149 msgid "Use MosDNS query" msgstr "" @@ -2955,7 +3034,7 @@ msgid "User cancelled." msgstr "" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1373 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:550 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:600 msgid "User-Agent" msgstr "" @@ -3025,15 +3104,15 @@ msgstr "" msgid "Vmess/VLESS ID (UUID)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:26 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:29 msgid "WAN Force Proxy IP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:21 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:24 msgid "WAN IP AC" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:23 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:26 msgid "WAN White List IP" msgstr "" @@ -3342,12 +3421,13 @@ msgstr "" msgid "v2ray-plugin" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:234 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:243 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:214 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:302 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:311 msgid "valid address:port" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:229 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:297 msgid "valid address:port (comma separated)" msgstr "" diff --git a/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po b/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po index 8cd8c8ea..7558982f 100644 --- a/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po +++ b/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po @@ -14,11 +14,11 @@ msgstr "" msgid "0" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:94 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:118 msgid "1 Thread" msgstr "单线程" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:101 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:125 msgid "128 Threads" msgstr "128 线程" @@ -26,15 +26,15 @@ msgstr "128 线程" msgid "16" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:98 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:122 msgid "16 Threads" msgstr "16 线程" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:95 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:119 msgid "2 Threads" msgstr "2 线程" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:99 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:123 msgid "32 Threads" msgstr "32 线程" @@ -42,19 +42,19 @@ msgstr "32 线程" msgid "360" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:207 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:275 msgid "360 Security DNS (China Telecom) (101.226.4.6)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:208 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:276 msgid "360 Security DNS (China Unicom) (123.125.81.6)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:96 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:120 msgid "4 Threads" msgstr "4 线程" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:100 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:124 msgid "64 Threads" msgstr "64 线程" @@ -62,7 +62,7 @@ msgstr "64 线程" msgid "8" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:97 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:121 msgid "8 Threads" msgstr "8 线程" @@ -76,7 +76,7 @@ msgstr "" msgid "" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:51 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:75 msgid "" "

    Support SS/SSR/V2RAY/XRAY/TROJAN/TUIC/HYSTERIA2/NAIVEPROXY/SOCKS5/CLASH " "etc.

    " @@ -90,8 +90,9 @@ msgstr "" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1654 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1667 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1680 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:186 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:213 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:254 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:281 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:624 msgid "
    • " msgstr "" @@ -145,12 +146,12 @@ msgstr "高级设置" msgid "Advertising Data" msgstr "【广告屏蔽】数据库" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:205 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:273 msgid "AliYun Public DNS (223.5.5.5)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:611 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:723 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:684 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:796 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:187 msgid "Alias" msgstr "别名" @@ -163,7 +164,7 @@ msgstr "别名(可选)" msgid "All" msgstr "全部" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:112 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:136 msgid "All Ports" msgstr "所有端口(默认)" @@ -179,15 +180,15 @@ msgstr "所有客户端代理规则已清空。" msgid "All settings saved successfully." msgstr "所有设置保存成功。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:35 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:38 msgid "Allow all except listed" msgstr "除列表外主机皆允许" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:34 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:37 msgid "Allow listed only" msgstr "仅允许列表内主机" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:486 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:536 msgid "Allow subscribe Insecure nodes By default" msgstr "订阅节点允许不验证 TLS 证书" @@ -209,9 +210,10 @@ msgstr "" msgid "An FinalMaskObject in JSON format, used for sharing." msgstr "JSON 格式的 FinalMaskObject,用来实现分享。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:134 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:152 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:171 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:158 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:175 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:220 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:239 msgid "Anti-pollution DNS Server" msgstr "访问国外域名 DNS 服务器" @@ -231,12 +233,12 @@ msgstr "Apple 域名更新 URL" msgid "Apple domains optimization" msgstr "Apple 域名解析优化" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:783 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:789 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:856 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:862 msgid "Apply" msgstr "应用" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:426 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:476 msgid "Appointment Mode" msgstr "定时模式" @@ -248,19 +250,19 @@ msgstr "确定要删除此订阅链接:%s 吗?" msgid "Are you sure you want to restore the client to default settings?" msgstr "是否真的要恢复客户端默认配置?" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:800 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:873 msgid "Auto Switch" msgstr "自动切换" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:93 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:117 msgid "Auto Threads" msgstr "自动(CPU 线程数)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:421 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:471 msgid "Auto Update" msgstr "自动更新" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:423 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:473 msgid "Auto Update Server subscription, GFW list and CHN route" msgstr "自动更新服务器订阅、GFW 列表和中国大陆 IP 段" @@ -287,7 +289,7 @@ msgstr "备份或还原客户端及服务端配置。" msgid "Baidu Connectivity" msgstr "【百度】连通性检查" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:206 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:274 msgid "Baidu Public DNS (180.76.76.76)" msgstr "" @@ -304,7 +306,7 @@ msgstr "仅绑定本地端口" msgid "BitTorrent (uTP)" msgstr "BT 下载(uTP)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:96 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:99 msgid "Black Domain List" msgstr "强制走代理的域名" @@ -312,7 +314,7 @@ msgstr "强制走代理的域名" msgid "Bloom Filter" msgstr "布隆过滤器" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:80 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:83 msgid "Bypass Domain List" msgstr "不走代理的域名" @@ -320,7 +322,7 @@ msgstr "不走代理的域名" msgid "CLOSE WIN" msgstr "关闭窗口" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:209 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:277 msgid "CNNIC SDNS (1.2.4.8)" msgstr "" @@ -405,7 +407,7 @@ msgstr "检查中..." msgid "China IP Data" msgstr "【中国大陆 IP 段】数据库" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:192 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:260 msgid "ChinaDNS-NG query protocol" msgstr "ChinaDNS-NG 查询协议" @@ -425,7 +427,7 @@ msgstr "" msgid "Clash" msgstr "Clash" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:88 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:112 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:893 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1096 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:3 @@ -460,6 +462,10 @@ msgstr "清空所有自定义客户端代理规则,并恢复为空白状态吗 msgid "Clear logs" msgstr "清空日志" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:633 +msgid "Click here to manage" +msgstr "点击此处前往管理" + #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:309 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1162 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1518 @@ -488,12 +494,13 @@ msgstr "客户端支持手动输入 IP 或 IP/CIDR。" msgid "Close" msgstr "关闭" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:158 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:226 msgid "Cloudflare DNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:145 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:182 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:169 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:186 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:250 msgid "Cloudflare DNS (1.1.1.1)" msgstr "" @@ -537,11 +544,11 @@ msgid "" "Controls the policy used when performing DNS queries for ECH configuration." msgstr "控制使用 DNS 查询 ECH 配置时的策略。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:575 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:648 msgid "Convert Address" msgstr "转换订阅模板API服务器" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:570 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:643 msgid "" "Convert subscriptions to Clash/Mihomo YAML with a subscription template URL." msgstr "使用订阅转换模板 URL 将订阅转换为 Clash/Mihomo YAML。" @@ -588,16 +595,21 @@ msgstr "自定义" msgid "Custom Client Proxies Rules" msgstr "自定义客户端代理规则" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:148 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:187 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:191 +msgid "" +"Custom DNS Server (supports format IP:PORT, domain name, or scheme://...)." +msgstr "支持格式: IP:端口、域名或 scheme://... 等。" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:171 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:255 msgid "Custom DNS Server format as IP:PORT (default: 8.8.4.4:53)" msgstr "格式为 IP:Port(默认:8.8.4.4:53)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:214 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:282 msgid "Custom DNS Server format as IP:PORT (default: disabled)" msgstr "格式为 IP:PORT(默认:禁用)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:160 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:228 msgid "" "Custom DNS Server format as tcp://IP:PORT or tls://DOMAIN:PORT " "(tcp://8.8.8.8 or tls://dns.google:853)" @@ -608,11 +620,11 @@ msgstr "" msgid "Custom Plugin Path" msgstr "自定义插件路径" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:114 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:138 msgid "Custom Ports" msgstr "自定义端口" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:283 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:315 msgid "Custom YAML imported successfully: %s" msgstr "自定义 YAML 导入成功:%s" @@ -642,7 +654,7 @@ msgstr "" msgid "DNS Anti-pollution" msgstr "DNS 防污染服务" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:204 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:272 msgid "DNSPod Public DNS (119.29.29.29)" msgstr "" @@ -726,7 +738,7 @@ msgstr "延迟(ms)" msgid "Delete" msgstr "删除" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:519 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:569 msgid "Delete All Subscribe Servers" msgstr "删除所有订阅节点" @@ -734,22 +746,22 @@ msgstr "删除所有订阅节点" msgid "Delete failed:" msgstr "删除失败:" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:112 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:115 msgid "Deny Domain List" msgstr "禁止连接的域名" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:726 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1037 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:81 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:33 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:105 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:36 msgid "Disable" msgstr "停用" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:200 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:268 msgid "Disable ChinaDNS-NG" msgstr "直通模式(禁用 ChinaDNS-NG)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:163 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:231 msgid "Disable IPv6 for Overseas FQDN" msgstr "禁止海外域名返回 IPv6 记录" @@ -765,7 +777,7 @@ msgstr "关闭 SNI 服务器名称指示" msgid "Disable TCP No_delay" msgstr "禁用 TCP 无延迟" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:567 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:617 msgid "Disabled means use Xray or ShadowSocks-Rust core." msgstr "禁用则使用 Xray 或 ShadowSocks-Rust 核心。" @@ -777,7 +789,7 @@ msgstr "执行重置" msgid "Do you want to restore the client to default settings?" msgstr "是否要恢复客户端默认配置?" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:196 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:264 msgid "DoT upstream (Need use wolfssl version)" msgstr "DoT 上游(需使用 wolfssl 版本)" @@ -789,7 +801,7 @@ msgstr "域名解析策略" msgid "DomainSocket Path" msgstr "域 Socket 路径" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:199 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:267 msgid "Domestic DNS Server" msgstr "国内 DNS 服务器" @@ -836,7 +848,7 @@ msgstr "编辑服务器配置" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:323 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:54 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:101 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:603 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:676 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1114 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:184 msgid "Enable" @@ -859,6 +871,18 @@ msgstr "启用自动切换" msgid "Enable ECH(optional)" msgstr "启用 ECH (可选)" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:619 +msgid "Enable Fake-IP Mode" +msgstr "开启 Fake-IP 模式" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:626 +msgid "Enable Fake-IP mode for better performance." +msgstr "开启 Fake-IP 模式以获取更佳的解析性能。" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:625 +msgid "Enable Fake-IP mode; disable to use redir-host mode." +msgstr "启用 Fake-IP 模式;禁用则使用 redir-host 模式。" + #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:720 msgid "Enable Lazy Mode" msgstr "启用懒狗模式" @@ -867,7 +891,7 @@ msgstr "启用懒狗模式" msgid "Enable ML-DSA-65(optional)" msgstr "启用 ML-DSA-65 (可选)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:564 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:614 msgid "Enable Mihomo core" msgstr "启用 Mihomo 核心" @@ -946,7 +970,7 @@ msgstr "启用 TCP 快速打开需要服务端支持。" msgid "Encrypt Method" msgstr "加密方式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:115 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:139 msgid "Enter Custom Ports" msgstr "输入自定义端口" @@ -955,35 +979,35 @@ msgstr "输入自定义端口" msgid "Error" msgstr "错误" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:433 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:483 msgid "Every Day" msgstr "每天" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:438 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:488 msgid "Every Friday" msgstr "每周五" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:434 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:484 msgid "Every Monday" msgstr "每周一" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:439 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:489 msgid "Every Saturday" msgstr "每周六" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:440 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:490 msgid "Every Sunday" msgstr "每周日" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:437 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:487 msgid "Every Thursday" msgstr "每周四" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:435 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:485 msgid "Every Tuesday" msgstr "每周二" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:436 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:486 msgid "Every Wednesday" msgstr "每周三" @@ -991,9 +1015,11 @@ msgstr "每周三" msgid "Example:" msgstr "示例:" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:229 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:234 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:243 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:203 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:214 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:297 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:302 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:311 msgid "Expecting: %s" msgstr "应为:%s" @@ -1017,7 +1043,7 @@ msgstr "清空所有客户端代理规则失败。" msgid "Failed to create temp directory" msgstr "创建临时目录失败" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:244 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:275 msgid "Failed to create temporary YAML upload file." msgstr "创建临时 YAML 上传文件失败。" @@ -1026,6 +1052,10 @@ msgstr "创建临时 YAML 上传文件失败。" msgid "Failed to fetch release metadata" msgstr "获取发布信息失败" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:325 +msgid "Failed to move uploaded YAML to target directory." +msgstr "无法将上传的 YAML 文件移动到目标目录。" + #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:112 msgid "Failed to query component information." msgstr "获取组件信息失败。" @@ -1038,6 +1068,10 @@ msgstr "获取 Geo 数据库信息失败。" msgid "Failed to save custom client proxy rules." msgstr "保存自定义客户端代理规则失败。" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:132 +msgid "Fake-IP Filter and Fallback Lists" +msgstr "Fake-IP 过滤器与 Fallback 列表" + #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_header.htm:21 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_header.htm:61 msgid "Fetch Failed" @@ -1052,7 +1086,7 @@ msgstr "手动获取" msgid "File Not Exist" msgstr "文件不存在" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:476 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:526 msgid "Filter Words splited by /" msgstr "命中关键字的节点将被丢弃。多个关键字用 / 分隔" @@ -1113,11 +1147,11 @@ msgstr "分片包长 (byte)" msgid "GFW List Data" msgstr "【GFW 列表】数据库" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:106 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:130 msgid "GFW List Mode" msgstr "GFW 列表模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:64 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:67 msgid "Game Mode Host List" msgstr "增强游戏模式客户端 LAN IP" @@ -1163,7 +1197,7 @@ msgstr "TCP 透明代理" msgid "Global HTTP/HTTPS Proxy Server" msgstr "HTTP/HTTPS 代理服务端(全局)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:108 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:132 msgid "Global Mode" msgstr "全局模式" @@ -1184,17 +1218,19 @@ msgstr "前往相关配置页面" msgid "Google Connectivity" msgstr "【谷歌】连通性检查" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:153 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:221 msgid "Google Public DNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:135 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:172 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:159 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:176 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:240 msgid "Google Public DNS (8.8.4.4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:136 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:173 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:160 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:177 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:241 msgid "Google Public DNS (8.8.8.8)" msgstr "" @@ -1296,7 +1332,7 @@ msgstr "" msgid "Hysterir QUIC parameters" msgstr "QUIC 参数" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:107 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:131 msgid "IP Route Mode" msgstr "绕过中国大陆 IP 模式" @@ -1304,6 +1340,17 @@ msgstr "绕过中国大陆 IP 模式" msgid "IP Stack Preference" msgstr "IP 栈优先级" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:203 +msgid "" +"IP:PORT, Domain, or Protocol URL (e.g. 8.8.8.8:53, dns.google, https://...)." +msgstr "" +"IP:端口,域名,或者协议 URL (例如:8.8.8.8:53,dns.google,https://...)。" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:627 +msgid "" +"If disabled, Redir-Host mode will be used which returns real IP addresses." +msgstr "若禁用,将使用返回真实 IP 地址的 Redir-Host 模式。" + #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:148 msgid "If empty, Not change Apple domains parsing DNS (Default is empty)" msgstr "如果为空,则不更改 Apple 域名解析 DNS(默认为空)" @@ -1374,11 +1421,11 @@ msgstr "新安装的二进制无法运行" msgid "Installed package check failed" msgstr "安装后软件包检查失败" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:13 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:16 msgid "Interface" msgstr "接口" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:12 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:15 msgid "Interface control" msgstr "接口控制" @@ -1450,23 +1497,23 @@ msgstr "KcpTun 端口" msgid "KcpTun Version" msgstr "KcpTun 版本号" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:32 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:35 msgid "LAN Access Control" msgstr "内网客户端分流代理控制" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:48 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:51 msgid "LAN Bypassed Host List" msgstr "不走代理的局域网 LAN IP" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:56 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:59 msgid "LAN Force Proxy Host List" msgstr "全局代理的 LAN IP" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:38 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:41 msgid "LAN Host List" msgstr "内网主机列表" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:30 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:33 msgid "LAN IP AC" msgstr "LAN IP 访问控制" @@ -1475,45 +1522,51 @@ msgstr "LAN IP 访问控制" msgid "Latest Version" msgstr "最新版本" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:139 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:176 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:163 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:180 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:244 msgid "Level 3 Public DNS (209.244.0.3)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:140 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:177 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:164 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:181 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:245 msgid "Level 3 Public DNS (209.244.0.4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:141 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:178 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:165 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:182 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:246 msgid "Level 3 Public DNS (4.2.2.1)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:142 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:179 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:166 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:183 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:247 msgid "Level 3 Public DNS (4.2.2.2)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:143 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:180 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:167 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:184 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:248 msgid "Level 3 Public DNS (4.2.2.3)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:144 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:181 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:168 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:185 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:249 msgid "Level 3 Public DNS (4.2.2.4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:155 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:223 msgid "Level 3 Public DNS-1 (209.244.0.3-4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:156 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:224 msgid "Level 3 Public DNS-2 (4.2.2.1-2)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:157 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:225 msgid "Level 3 Public DNS-3 (4.2.2.3-4)" msgstr "" @@ -1526,7 +1579,7 @@ msgid "" "Linux kernel TUN virtual NIC requires system support and root privileges." msgstr "Linux 内核 TUN 虚拟网卡需要系统支持和 root 权限。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:18 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:21 msgid "Listen only on the given interface or, if unspecified, on all" msgstr "仅监听指定的接口,未指定则监听全部。" @@ -1553,7 +1606,7 @@ msgstr "本地地址" msgid "Log" msgstr "日志" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:427 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:477 msgid "Loop Mode" msgstr "循环模式" @@ -1577,11 +1630,11 @@ msgstr "" msgid "MTU" msgstr "最大传输单元" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:80 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:104 msgid "Main Server" msgstr "主服务器" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:601 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:674 msgid "" "Manage multiple subscribe URLs, including Clash subscriptions. Only enabled " "entries are included when updating all subscriptions." @@ -1666,8 +1719,9 @@ msgstr "下移" msgid "Move up" msgstr "上移" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:188 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:215 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:192 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:256 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:283 msgid "Muitiple DNS server can saperate with ','" msgstr "多个上游 DNS 服务器请用 ',' 分隔(注意用英文逗号)" @@ -1675,7 +1729,7 @@ msgstr "多个上游 DNS 服务器请用 ',' 分隔(注意用英文逗号)" msgid "Multi" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:92 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:116 msgid "Multi Threads Option" msgstr "多线程并发转发" @@ -1707,7 +1761,7 @@ msgstr "" msgid "Name" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:203 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:271 msgid "Nanjing Xinfeng 114DNS (114.114.114.114)" msgstr "" @@ -1747,7 +1801,7 @@ msgstr "没有可用的核心(Mihomo 或 Xray)可以导入此节点。" msgid "No available core (Shadowsocks, Mihomo or Xray) to import this node." msgstr "没有可用的核心(Shadowsocks, Mihomo 或 Xray)可以导入此节点。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:263 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:294 msgid "No custom YAML file was selected." msgstr "没有选择自定义 YAML 文件。" @@ -1772,7 +1826,7 @@ msgstr "没有找到任何订阅项" msgid "No switchable proxy groups found." msgstr "未找到可切换的代理组。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:625 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:698 msgid "" "Node order can be dragged with the mouse and takes effect immediately. The " "automatic switch order of server nodes is consistent with the node order in " @@ -1789,8 +1843,8 @@ msgstr "噪声" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1269 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1281 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1291 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:720 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:725 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:793 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:798 msgid "None" msgstr "" @@ -1812,6 +1866,14 @@ msgstr "未安装可执行文件" msgid "Not installed" msgstr "未安装" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:193 +msgid "Note: IP addresses MUST specify a port." +msgstr "注意:IP 地址必须指定端口。" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:204 +msgid "Note: Pure IP without port is not allowed." +msgstr "注意:不允许使用没有端口的纯 IP。" + #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua:27 msgid "" "Note: Restoring configurations across different versions may cause " @@ -1862,7 +1924,7 @@ msgstr "混淆类型" msgid "Once set, connects only when the server’s chain fingerprint matches." msgstr "设置后,仅在服务器证书链指纹匹配时连接。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:113 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:137 msgid "Only Common Ports" msgstr "仅常用端口(不走 P2P 流量到代理)" @@ -1887,17 +1949,19 @@ msgstr "仅当 Socks5 认证方式为 Password 时有效,非必填。" msgid "OpenClash GeoSite Database" msgstr "OpenClash GeoSite 数据库" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:154 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:222 msgid "OpenDNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:138 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:175 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:162 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:179 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:243 msgid "OpenDNS (208.67.220.220)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:137 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:174 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:161 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:178 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:242 msgid "OpenDNS (208.67.222.222)" msgstr "" @@ -1948,7 +2012,7 @@ msgstr "执行重置" msgid "Permit Without Stream" msgstr "允许无数据流" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:768 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:841 msgid "Ping Latency" msgstr "Ping 延迟" @@ -1988,7 +2052,7 @@ msgstr "预连接" msgid "Pre-shared key" msgstr "预共享密钥" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:130 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:154 msgid "Prefer module built-in DNS" msgstr "优先使用模块内置 DNS" @@ -2019,7 +2083,7 @@ msgstr "传输协议" msgid "Protocol param (optional)" msgstr "传输协议参数(可选)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:111 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:135 msgid "Proxy Ports" msgstr "需要代理的端口" @@ -2107,7 +2171,7 @@ msgstr "" msgid "Realm URL" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:787 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:860 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:348 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:17 msgid "Reapply" @@ -2141,11 +2205,11 @@ msgstr "更新成功!" msgid "Refresh..." msgstr "正在更新,请稍候..." -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:445 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:495 msgid "Regular update (Hour)" msgstr "定时更新(小时)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:453 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:503 msgid "Regular update (Min)" msgstr "定时更新(分钟)" @@ -2217,7 +2281,7 @@ msgstr "恢复出厂设置" msgid "Resetting Defaults..." msgstr "正在重置默认值..." -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:120 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:144 msgid "Resolve Dns Mode" msgstr "DNS 解析方式" @@ -2248,7 +2312,7 @@ msgstr "恢复默认配置" msgid "Running" msgstr "运行中" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:105 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:129 msgid "Running Mode" msgstr "运行模式" @@ -2281,16 +2345,16 @@ msgstr "服务端" msgid "Save" msgstr "保存" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:507 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:557 msgid "Save Subscribe Settings" msgstr "保存订阅设置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:482 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:532 msgid "Save Words splited by /" msgstr "" "命中关键字的节点将被保留。多个关键字用 / 分隔。此项为空则不启用保留匹配" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:509 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:559 msgid "Save current subscribe settings" msgstr "保存当前订阅设置" @@ -2316,7 +2380,7 @@ msgstr "自签证书" msgid "Server Address" msgstr "服务器地址" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:521 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:571 msgid "Server Count" msgstr "服务器节点数量" @@ -2351,7 +2415,7 @@ msgstr "服务器节点故障自动切换/广告屏蔽/中国大陆 IP 段数据 msgid "Servers Nodes" msgstr "服务器节点" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:407 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:454 msgid "Servers subscription and manage" msgstr "服务器节点订阅与管理" @@ -2389,7 +2453,7 @@ msgstr "ShadowSocks-rust 版本" msgid "ShadowSocksR Plus+" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:51 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:75 msgid "ShadowSocksR Plus+ Settings" msgstr "ShadowSocksR Plus+ 设置" @@ -2436,7 +2500,7 @@ msgstr "" msgid "Snell Version" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:728 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:801 msgid "Socket Connected" msgstr "连接测试" @@ -2469,6 +2533,18 @@ msgstr "Socks5 密码" msgid "Socks5 User" msgstr "Socks5 用户名" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:134 +msgid "Specifically for editing the Fake-IP filter list." +msgstr "专用于编辑 Fake-IP 过滤规则文件。" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:149 +msgid "Specifically for editing the Fallback IP-CIDR list." +msgstr "专用于编辑 Fallback IP-CIDR 规则文件。" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:164 +msgid "Specifically for editing the Fallback domain filter list." +msgstr "专用于编辑 Fallback 域名过滤规则文件。" + #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:129 msgid "Start Detection" msgstr "开始探测" @@ -2495,19 +2571,19 @@ msgstr "状态" msgid "Stop Detection" msgstr "停止探测" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:467 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:517 msgid "Subscribe Advanced Settings" msgstr "订阅高级设置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:569 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:642 msgid "Subscribe Convert Online" msgstr "在线订阅转换" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:493 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:543 msgid "Subscribe Default Auto-Switch" msgstr "订阅新节点自动切换设置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:473 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:523 msgid "Subscribe Filter Words" msgstr "订阅节点关键字过滤" @@ -2515,16 +2591,16 @@ msgstr "订阅节点关键字过滤" msgid "Subscribe Log" msgstr "订阅日志" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:480 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:530 msgid "Subscribe Save Words" msgstr "订阅节点关键字保留检查" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:583 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:656 msgid "Subscribe Template URL" msgstr "订阅转换模板 URL" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:594 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:618 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:667 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:691 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:189 msgid "Subscribe URL" msgstr "订阅 URL (支持SS/SSR/V2/TROJAN/HY2/TUIC/CLASH等)" @@ -2533,11 +2609,11 @@ msgstr "订阅 URL (支持SS/SSR/V2/TROJAN/HY2/TUIC/CLASH等)" msgid "Subscribe failed, refreshing page..." msgstr "订阅失败,正在刷新页面..." -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:495 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:545 msgid "Subscribe new add server default Auto-Switch on" msgstr "订阅加入的新节点默认开启自动切换" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:488 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:538 msgid "Subscribe nodes allows insecure connection as TLS client (insecure)" msgstr "订阅节点强制开启 不验证TLS客户端证书 (insecure)" @@ -2600,7 +2676,7 @@ msgid "" "as bypassing SNI blacklists." msgstr "TCP 分片,在某些情况下可以欺骗审查系统,比如绕过 SNI 黑名单。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:194 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:262 msgid "TCP upstream" msgstr "TCP 上游" @@ -2678,6 +2754,22 @@ msgstr "输入的内容不正确!" msgid "The keep-alive period.(Unit:second)" msgstr "心跳包发送间隔(单位:秒)" +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:18 +msgid "" +"The online upgrade downloads and installs the matching NaiveProxy package " +"for this system from fw876/helloworld releases." +msgstr "" +"在线升级会从 fw876/helloworld 发布页下载并安装适配当前系统的 NaiveProxy 软件" +"包。" + +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:10 +msgid "" +"The online upgrade downloads and installs the matching Xray-core package for " +"this system from fw876/helloworld releases." +msgstr "" +"在线升级会从 fw876/helloworld 发布页下载并安装适配当前系统的 Xray-core 软件" +"包。" + #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:6 msgid "" "The online upgrade downloads the latest luci-app-ssr-plus package from fw876/" @@ -2687,13 +2779,6 @@ msgstr "" "在线更新会从 fw876/helloworld 发布页下载最新 luci-app-ssr-plus,并根据当前系" "统安装匹配的 IPK 或 APK 包。" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:10 -msgid "" -"The online upgrade downloads and installs the matching Xray-core package for " -"this system from fw876/helloworld releases." -msgstr "" -"在线升级会从 fw876/helloworld 发布页下载并安装适配当前系统的 Xray-core 软件包。" - #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:14 msgid "" "The online upgrade only tracks the latest stable Mihomo release and " @@ -2703,13 +2788,6 @@ msgstr "" "在线升级只跟踪 Mihomo 最新稳定版,并根据当前架构从官方 GitHub 发布页下载匹配" "的 Linux 压缩包。" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:18 -msgid "" -"The online upgrade downloads and installs the matching NaiveProxy package " -"for this system from fw876/helloworld releases." -msgstr "" -"在线升级会从 fw876/helloworld 发布页下载并安装适配当前系统的 NaiveProxy 软件包。" - #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:816 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:871 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:89 @@ -2727,11 +2805,11 @@ msgstr "该面板仅在当前 Clash 总节点已启用时可用。" msgid "This section contains no values yet" msgstr "该部分目前无任何内容。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:500 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:550 msgid "Through proxy update" msgstr "通过代理更新" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:502 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:552 msgid "Through proxy update list, Not Recommended" msgstr "通过路由器自身代理更新订阅" @@ -2743,6 +2821,10 @@ msgstr "超时" msgid "Timeout for establishing a connection to server(second)" msgstr "连接超时时间(单位:秒)" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:628 +msgid "Tips: Fake-IP Filter and Fallback Lists:" +msgstr "提示:Fake-IP 过滤与 Fallback 规则列表:" + #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:305 msgid "To send noise packets, select \"Noise\" in Xray Settings." msgstr "在 Xray 设置中勾选 “噪声” 以发送噪声包。" @@ -2775,7 +2857,7 @@ msgid "Try Count" msgstr "重试次数" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:327 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:717 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:790 msgid "Type" msgstr "类型" @@ -2797,11 +2879,11 @@ msgstr "" msgid "UDP relay mode" msgstr "UDP 中继模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:195 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:263 msgid "UDP upstream" msgstr "UDP 上游" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:193 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:261 msgid "UDP/TCP upstream" msgstr "UDP/TCP 上游" @@ -2809,7 +2891,7 @@ msgstr "UDP/TCP 上游" msgid "UL Restore" msgstr "上传恢复" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:539 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:589 msgid "URL Test Address" msgstr "URL 测试地址" @@ -2858,19 +2940,19 @@ msgstr "不支持的包管理器" msgid "Update" msgstr "更新" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:512 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:562 msgid "Update All Subscribe Servers" msgstr "更新所有订阅节点" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:461 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:511 msgid "Update Interval(min)" msgstr "更新间隔(分钟)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:425 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:475 msgid "Update Mode" msgstr "更新模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:432 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:482 msgid "Update cycle (Day/Week)" msgstr "更新周期(天/周)" @@ -2927,11 +3009,11 @@ msgstr "上行链路容量(默认:Mbps)" msgid "Upload" msgstr "上传" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:560 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:610 msgid "Upload Custom YAML File" msgstr "上传自定义 YAML 文件" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:562 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:612 msgid "" "Upload a custom Clash/Mihomo YAML file. The file will be preprocessed and " "saved as a local Clash node." @@ -2939,33 +3021,33 @@ msgstr "" "上传自定义 Clash/Mihomo YAML 文件。文件会先做预处理,再保存为本地 Clash 节" "点。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:277 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:285 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:290 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:308 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:319 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:329 msgid "Uploaded YAML validation or preprocessing failed." msgstr "上传的 YAML 校验或预处理失败。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:128 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:152 msgid "Use ChinaDNS-NG query and cache" msgstr "使用 ChinaDNS-NG 查询并缓存" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:201 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:269 msgid "Use DNS from WAN" msgstr "使用 WAN 下发的 DNS" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:202 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:270 msgid "Use DNS from WAN and 114DNS" msgstr "使用 WAN 下发的 DNS 和 114DNS" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:122 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:146 msgid "Use DNS2TCP query" msgstr "使用 DNS2TCP 查询" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:131 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:155 msgid "Use Local DNS Service listen port 5335" msgstr "使用本机端口为 5335 的 DNS 服务" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:125 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:149 msgid "Use MosDNS query" msgstr "使用 MosDNS 查询" @@ -2983,7 +3065,7 @@ msgid "User cancelled." msgstr "用户已取消。" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1373 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:550 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:600 msgid "User-Agent" msgstr "用户代理(User-Agent)" @@ -3053,15 +3135,15 @@ msgstr "" msgid "Vmess/VLESS ID (UUID)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:26 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:29 msgid "WAN Force Proxy IP" msgstr "强制走代理的 WAN IP" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:21 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:24 msgid "WAN IP AC" msgstr "WAN IP 访问控制" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:23 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:26 msgid "WAN White List IP" msgstr "不走代理的 WAN IP" @@ -3371,12 +3453,13 @@ msgstr "" msgid "v2ray-plugin" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:234 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:243 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:214 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:302 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:311 msgid "valid address:port" msgstr "有效的地址:端口" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:229 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:297 msgid "valid address:port (comma separated)" msgstr "有效地址:端口(用逗号分隔)" diff --git a/luci-app-ssr-plus/root/etc/init.d/shadowsocksr b/luci-app-ssr-plus/root/etc/init.d/shadowsocksr index 87c944a3..3893d763 100755 --- a/luci-app-ssr-plus/root/etc/init.d/shadowsocksr +++ b/luci-app-ssr-plus/root/etc/init.d/shadowsocksr @@ -608,6 +608,7 @@ prepare_clash_runtime_config() { local dns_mode local client_policy_stats local client_rules + local enable_fake_ip cache_file="$(get_clash_cache_file "$sid")" workdir="$(get_clash_workdir "$sid")" @@ -623,6 +624,7 @@ prepare_clash_runtime_config() { dns_mode="$(uci_get_by_type global pdnsd_enable 0)" client_policy_stats="" client_rules=0 + enable_fake_ip="$(uci_get_by_type server_subscribe enable_fake_ip "")" [ -s "$cache_file" ] || return 1 @@ -640,15 +642,33 @@ prepare_clash_runtime_config() { routing-mark: $CLASH_OUTBOUND_MARK profile: store-selected: true + store-fake-ip: true tun: enable: false - dns: - enable: $( [ "$dns_mode" = "7" ] && echo "true" || echo "false" ) - enhanced-mode: redir-host - listen: 127.0.0.1:$dns_port - ipv6: $( [ "$dns_ipv4_only" = "1" ] && echo "false" || echo "true" ) EOF + # 根据 dns_mode 添加不同的 dns 配置 + if [ "$dns_mode" = "7" ]; then + # 根据 enable_fake_ip 决定 enhanced-mode + if [ "$enable_fake_ip" = "1" ]; then + ENHANCED_MODE="fake-ip" + else + ENHANCED_MODE="redir-host" + fi + cat >> "$overlay_file" <<-EOF + dns: + enable: true + enhanced-mode: $ENHANCED_MODE + listen: 127.0.0.1:$dns_port + ipv6: $( [ "$dns_ipv4_only" = "1" ] && echo "false" || echo "true" ) + EOF + else + cat >> "$overlay_file" <<-EOF + dns: + enable: false + EOF + fi + if [ -n "$socks_port" ] && [ "$socks_port" != "0" ]; then echo "socks-port: $socks_port" >>"$overlay_file" fi @@ -1230,14 +1250,24 @@ start_dns() { ssrplus_dns="$(uci_get_by_type global pdnsd_enable 0)" global_server_type="$(uci_get_by_name "$GLOBAL_SERVER" type)" builtin_dns_enabled=0 - dnsserver="$(uci_get_by_type global tunnel_forward 8.8.4.4:53)" if [ "$ssrplus_dns" = "5" ]; then ssrplus_dns="$(force_dns2tcp_fallback "旧版 DNSPROXY 模式已移除")" || return 1 uci_set_by_type global pdnsd_enable "$ssrplus_dns" - elif [ "$ssrplus_dns" = "6" ]; then - dnsserver="$(uci_get_by_type global chinadns_ng_tunnel_forward 8.8.4.4:53)" fi + case "$ssrplus_dns" in + 1) + dnsserver="$(uci_get_by_type global dns2tcp_tunnel_forward 8.8.4.4:53)" + ;; + 6) + dnsserver="$(uci_get_by_type global chinadns_ng_tunnel_forward 8.8.4.4:53)" + ;; + 7) + dnsserver="$(uci_get_by_type global tunnel_forward 8.8.4.4:53)" + ;; + *) + ;; + esac run_mode="$(normalize_run_mode)" if [ "$ssrplus_dns" = "4" ] && ! is_finded "mosdns"; then @@ -1503,15 +1533,15 @@ generate_xray_config() { { "log": { "loglevel": "warning" - }, - "inbounds": [$inbound_json], - "outbounds": [ - { - "protocol": "freedom", - "settings": {} - } - ] - } + }, + "inbounds": [$inbound_json], + "outbounds": [ + { + "protocol": "freedom", + "settings": {} + } + ] + } EOF return 0 } @@ -2887,12 +2917,18 @@ start_rules() { local ac_ips local custom_ports local proxyport + local enable_fake_ip server=$(get_host_ip "$GLOBAL_SERVER") local_port=$(get_default_node_local_port) lan_ac_ips=$(uci_get_by_type access_control lan_ac_ips) lan_ac_mode=$(uci_get_by_type access_control lan_ac_mode) + enable_fake_ip=$(uci_get_by_type server_subscribe enable_fake_ip "") + if [ -z "$enable_fake_ip" ]; then + enable_fake_ip="0" + fi + if [ "$kcp_enable_flag" = "0" ] && [ "$redir_udp" = "1" ]; then udp_server=$(get_host_ip "$UDP_RELAY_SERVER") udp_local_port=$tmp_udp_port @@ -2937,26 +2973,27 @@ start_rules() { fi elif [ "$USE_TABLES" = "iptables" ]; then ARG_A="" - fi - /usr/share/shadowsocksr/gfw2ipset.sh - /usr/bin/ssr-rules \ - -s "$server" \ - -l "$local_port" \ - -S "$udp_server" \ - -L "$udp_local_port" \ - -a "$ac_ips" \ - -i "/etc/ssrplus/china_ssr.txt" \ - -b "$(uci_get_by_type access_control wan_bp_ips)" \ - -w "$(uci_get_by_type access_control wan_fw_ips)" \ - -B "$(uci_get_by_type access_control lan_bp_ips)" \ - -p "$(uci_get_by_type access_control lan_fp_ips)" \ - -G "$(uci_get_by_type access_control lan_gm_ips)" \ - -m "$(uci_get_by_type access_control Interface)" \ - -D "$proxyport" \ - "$(get_arg_out)" "$(gfwmode)" "$ARG_UDP" "$ARG_UDP_RULES" "$ARG_A" + fi + /usr/share/shadowsocksr/gfw2ipset.sh + /usr/bin/ssr-rules \ + -s "$server" \ + -l "$local_port" \ + -S "$udp_server" \ + -L "$udp_local_port" \ + -a "$ac_ips" \ + -i "/etc/ssrplus/china_ssr.txt" \ + -b "$(uci_get_by_type access_control wan_bp_ips)" \ + -w "$(uci_get_by_type access_control wan_fw_ips)" \ + -B "$(uci_get_by_type access_control lan_bp_ips)" \ + -p "$(uci_get_by_type access_control lan_fp_ips)" \ + -G "$(uci_get_by_type access_control lan_gm_ips)" \ + -m "$(uci_get_by_type access_control Interface)" \ + -D "$proxyport" \ + -E "$enable_fake_ip" \ + "$(get_arg_out)" "$(gfwmode)" "$ARG_UDP" "$ARG_UDP_RULES" "$ARG_A" - return $? - } + return $? +} start() { local run_mode diff --git a/luci-app-ssr-plus/root/etc/ssrplus/fake_ip_filter.list b/luci-app-ssr-plus/root/etc/ssrplus/fake_ip_filter.list new file mode 100644 index 00000000..27a84480 --- /dev/null +++ b/luci-app-ssr-plus/root/etc/ssrplus/fake_ip_filter.list @@ -0,0 +1,78 @@ +*.lan +*.localdomain +*.example +*.invalid +*.localhost +*.test +*.local +*.home.arpa +time.*.com +time.*.gov +time.*.edu.cn +time.*.apple.com +time1.*.com +time2.*.com +time3.*.com +time4.*.com +time5.*.com +time6.*.com +time7.*.com +ntp.*.com +ntp1.*.com +ntp2.*.com +ntp3.*.com +ntp4.*.com +ntp5.*.com +ntp6.*.com +ntp7.*.com +*.time.edu.cn +*.ntp.org.cn ++.pool.ntp.org +time1.cloud.tencent.com +stun.*.* +stun.*.*.* +swscan.apple.com +mesu.apple.com +music.163.com +*.music.163.com +*.126.net +musicapi.taihe.com +music.taihe.com +songsearch.kugou.com +trackercdn.kugou.com +*.kuwo.cn +api-jooxtt.sanook.com +api.joox.com +y.qq.com +*.y.qq.com +streamoc.music.tc.qq.com +mobileoc.music.tc.qq.com +isure.stream.qqmusic.qq.com +dl.stream.qqmusic.qq.com +aqqmusic.tc.qq.com +amobile.music.tc.qq.com +localhost.ptlogin2.qq.com +*.msftconnecttest.com +*.msftncsi.com +*.xiami.com +*.music.migu.cn +music.migu.cn ++.wotgame.cn ++.wggames.cn ++.wowsgame.cn ++.wargaming.net +*.*.*.srv.nintendo.net +*.*.stun.playstation.net +xbox.*.*.microsoft.com +*.*.xboxlive.com +*.ipv6.microsoft.com +teredo.*.*.* +teredo.*.* +speedtest.cros.wr.pvp.net ++.jjvip8.com +www.douyu.com +activityapi.huya.com +activityapi.huya.com.w.cdngslb.com +www.bilibili.com +api.bilibili.com +a.w.bilicdn1.com \ No newline at end of file diff --git a/luci-app-ssr-plus/root/etc/ssrplus/fallback_domain.list b/luci-app-ssr-plus/root/etc/ssrplus/fallback_domain.list new file mode 100644 index 00000000..7f66e598 --- /dev/null +++ b/luci-app-ssr-plus/root/etc/ssrplus/fallback_domain.list @@ -0,0 +1,9 @@ ++.google.com ++.facebook.com ++.youtube.com ++.twitter.com ++.telegram.org ++.githubusercontent.com ++.googlevideo.com ++.msftconnecttest.com ++.msftncsi.com \ No newline at end of file diff --git a/luci-app-ssr-plus/root/etc/ssrplus/fallback_ipcidr.list b/luci-app-ssr-plus/root/etc/ssrplus/fallback_ipcidr.list new file mode 100644 index 00000000..5f71fa72 --- /dev/null +++ b/luci-app-ssr-plus/root/etc/ssrplus/fallback_ipcidr.list @@ -0,0 +1,15 @@ +0.0.0.0/8 +10.0.0.0/8 +100.64.0.0/10 +127.0.0.0/8 +169.254.0.0/16 +172.16.0.0/12 +192.0.0.0/24 +192.0.2.0/24 +192.88.99.0/24 +192.168.0.0/16 +198.51.100.0/24 +203.0.113.0/24 +224.0.0.0/4 +240.0.0.0/4 +255.255.255.255/32 \ No newline at end of file diff --git a/luci-app-ssr-plus/root/etc/uci-defaults/luci-ssr-plus b/luci-app-ssr-plus/root/etc/uci-defaults/luci-ssr-plus index 3e69e08a..0fa213b6 100755 --- a/luci-app-ssr-plus/root/etc/uci-defaults/luci-ssr-plus +++ b/luci-app-ssr-plus/root/etc/uci-defaults/luci-ssr-plus @@ -39,6 +39,18 @@ if [ -s "/etc/config/shadowsocksr" ]; then uci -q set shadowsocksr.@server_subscribe[0].auto_update_min_time='0' fi + if ! uci -q get shadowsocksr.@server_subscribe[0].enable_mihomo > /dev/null; then + uci -q set shadowsocksr.@server_subscribe[0].enable_mihomo='1' + fi + + if ! uci -q get shadowsocksr.@server_subscribe[0].enable_fake_ip > /dev/null; then + uci -q set shadowsocksr.@server_subscribe[0].enable_fake_ip='1' + fi + + if ! uci -q get shadowsocksr.@server_subscribe[0].sub_convert > /dev/null; then + uci -q set shadowsocksr.@server_subscribe[0].sub_convert='1' + fi + if ! uci -q get shadowsocksr.@server_subscribe[0].config_auto_update_mode > /dev/null; then uci -q set shadowsocksr.@server_subscribe[0].config_auto_update_mode='0' fi diff --git a/luci-app-ssr-plus/root/usr/bin/ssr-rules b/luci-app-ssr-plus/root/usr/bin/ssr-rules index 801077ba..9c3fed88 100755 --- a/luci-app-ssr-plus/root/usr/bin/ssr-rules +++ b/luci-app-ssr-plus/root/usr/bin/ssr-rules @@ -46,6 +46,7 @@ CHECK_STATUS=0 RESTORE_RULES=0 FLUSH_RULES=0 CLEANUP_PERSISTENCE=0 +ENABLE_FAKE_IP=0 # ASCII code for SSRP.Use whatever,just not the same. FWMARK="0x53535250" @@ -83,14 +84,15 @@ usage() { -m Interface name -I a file content is bypassed shunt ip list -e extra options for iptables + -E <0|1> enable_fake_ip status -o apply the rules to the OUTPUT chain -O apply the global rules to the OUTPUT chain - -u enable udprelay mode, TPROXY is required - -U enable udprelay mode, using different IP - and ports for TCP and UDP - -y disable all auxiliary UDP rules when UDP - transparent proxy is unavailable - -f flush the rules + -u enable udprelay mode, TPROXY is required + -U enable udprelay mode, using different IP + and ports for TCP and UDP + -y disable all auxiliary UDP rules when UDP + transparent proxy is unavailable + -f flush the rules -g gfwlist mode -r router mode -z all mode @@ -232,6 +234,12 @@ cleanup_persistence_files() { loger 5 "Removed xhttp hash file: /tmp/.last_xhttp_hash" fi + # Remove Fake_IP Mode state file + if [ -f "$ENABLE_FAKE_IP_STATE_FILE" ]; then + rm -f "$ENABLE_FAKE_IP_STATE_FILE" 2>/dev/null + loger 5 "Removed Fake_IP Mode state file: $ENABLE_FAKE_IP_STATE_FILE" + fi + loger 5 "Persistence cleanup completed" return 0 } @@ -315,25 +323,64 @@ flush_nftables() { flush_iptables_legacy() { flush_iptables() { - local ipt="iptables -t $1" - local DAT=$(iptables-save -t $1) - eval $(echo "$DAT" | grep "$TAG" | sed -e 's/^-A/$ipt -D/' -e 's/$/;/') - for chain in $(echo "$DAT" | awk '/^:SS_SPEC/{print $1}'); do - $ipt -F ${chain:1} 2>/dev/null && $ipt -X ${chain:1} + local table=$1 + local ipt="iptables -t $table" + local DAT + + DAT=$(iptables-save -t $table 2>/dev/null) + + [ -z "$DAT" ] && return 0 + + # 1. 解除所有引用 SS_SPEC* 链的规则 + echo "$DAT" | grep -E "^-A .*SS_SPEC" | while read -r line; do + local chain rule + chain=$(echo "$line" | awk '{print $2}') + rule=$(echo "$line" | sed 's/^-A [^ ]* //') + [ -n "$chain" ] && [ -n "$rule" ] && \ + eval "$ipt -D \"$chain\" $rule 2>/dev/null" done + + # 2. 删除带 TAG 或 mark 的残留规则(同样加上 eval) + echo "$DAT" | grep -E "^-A " | grep -E "$TAG|-m mark|--mark" | while read -r line; do + local chain rule + chain=$(echo "$line" | awk '{print $2}') + rule=$(echo "$line" | sed 's/^-A [^ ]* //') + [ -n "$chain" ] && [ -n "$rule" ] && \ + eval "$ipt -D \"$chain\" $rule 2>/dev/null" + done + + # 3. 提取所有以 SS_SPEC 开头的自定义链 + local chains + chains=$(echo "$DAT" | awk '/^:SS_SPEC/{sub(/^:/,"",$1); print $1}') + + # 4. 清空并彻底删除 SS_SPEC* 自定义链 + for chain in $chains; do + $ipt -F "$chain" 2>/dev/null + $ipt -X "$chain" 2>/dev/null + done + + return 0 } + + # 依次对 nat 和 mangle 表执行清理 flush_iptables nat flush_iptables mangle - if ip rule show | grep -Eq "fwmark ${FWMARK}.*lookup 999"; then + + # 清理策略路由与路由表 + if ip rule show | grep -Eiq "fwmark ${FWMARK}.*lookup 999"; then ip rule del fwmark ${FWMARK} table 999 2>/dev/null fi if ip route show table 999 | grep -Eq "^local.*dev lo"; then ip route del local 0.0.0.0/0 dev lo table 999 2>/dev/null fi + + # 清理 IPSET 集合(先 -F 清空,后 -X 销毁) for setname in ss_spec_lan_ac ss_spec_wan_ac ssr_gen_router \ china fplan bplan gmlan whitelist blacklist gfwlist music; do + ipset -F $setname 2>/dev/null ipset -X $setname 2>/dev/null done + [ -n "$FWI" ] && echo '#!/bin/sh' >$FWI return 0 } @@ -524,6 +571,11 @@ fw_rule() { } fw_rule_nft() { + # 优先将 Fake-IP (198.18.0.0/16) 的 TCP 流量重定向至代理端口 + if [ "$ENABLE_FAKE_IP" = "1" ]; then + $NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 198.18.0.0/16 meta l4proto tcp redirect to :$local_port comment "\"$TAG\"" 2>/dev/null + fi + # redirect/translation: when PROXY_PORTS present, redirect those tcp ports to local_port if [ -n "$PROXY_PORTS" ]; then PORTS_ARGS=$(echo "$PROXY_PORTS" | sed 's/-m multiport --dports //') @@ -559,6 +611,10 @@ fw_rule_iptables() { $IPT -A SS_SPEC_WAN_FW -d "$net" -j RETURN done + if [ "$ENABLE_FAKE_IP" = "1" ]; then + $IPT -A SS_SPEC_WAN_FW -d 198.18.0.0/16 -p tcp -j REDIRECT --to-ports "$local_port" -m comment --comment "$TAG" + fi + $IPT -A SS_SPEC_WAN_FW -p tcp $PROXY_PORTS -j REDIRECT --to-ports "$local_port" 2>/dev/null || { loger 3 "Can't redirect TCP, please check the iptables." exit 1 @@ -611,6 +667,33 @@ ac_rule_nft() { fi $NFT flush chain inet ss_spec ss_spec_prerouting 2>/dev/null + # Fake-IP 重定向处理 (引入 Interface 匹配,防止 WAN 口越权) + if [ "$ENABLE_FAKE_IP" = "1" ]; then + if [ -z "$Interface" ]; then + if [ -n "$MATCH_SET" ]; then + $NFT add rule inet ss_spec ss_spec_prerouting ip daddr 198.18.0.0/16 $MATCH_SET meta l4proto tcp redirect to :$local_port comment "\"$TAG\"" 2>/dev/null + $NFT add rule inet ss_spec ss_spec_prerouting ip daddr 198.18.0.0/16 $MATCH_SET meta l4proto udp redirect to :$local_port comment "\"$TAG\"" 2>/dev/null + else + $NFT add rule inet ss_spec ss_spec_prerouting ip daddr 198.18.0.0/16 meta l4proto tcp redirect to :$local_port comment "\"$TAG\"" 2>/dev/null + $NFT add rule inet ss_spec ss_spec_prerouting ip daddr 198.18.0.0/16 meta l4proto udp redirect to :$local_port comment "\"$TAG\"" 2>/dev/null + fi + else + for name in $Interface; do + local IFNAME=$(uci -P /var/state get network."$name".ifname 2>/dev/null) + [ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network."$name".device 2>/dev/null) + if [ -n "$IFNAME" ]; then + if [ -n "$MATCH_SET" ]; then + $NFT add rule inet ss_spec ss_spec_prerouting meta iifname "$IFNAME" ip daddr 198.18.0.0/16 $MATCH_SET meta l4proto tcp redirect to :$local_port comment "\"$TAG\"" 2>/dev/null + $NFT add rule inet ss_spec ss_spec_prerouting meta iifname "$IFNAME" ip daddr 198.18.0.0/16 $MATCH_SET meta l4proto udp redirect to :$local_port comment "\"$TAG\"" 2>/dev/null + else + $NFT add rule inet ss_spec ss_spec_prerouting meta iifname "$IFNAME" ip daddr 198.18.0.0/16 meta l4proto tcp redirect to :$local_port comment "\"$TAG\"" 2>/dev/null + $NFT add rule inet ss_spec ss_spec_prerouting meta iifname "$IFNAME" ip daddr 198.18.0.0/16 meta l4proto udp redirect to :$local_port comment "\"$TAG\"" 2>/dev/null + fi + fi + done + fi + fi + # Exclude special local addresses if $NFT list chain inet ss_spec ss_spec_prerouting >/dev/null 2>&1; then for net in 0.0.0.0/8 10.0.0.0/8 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.168.0.0/16 224.0.0.0/4 240.0.0.0/4; do @@ -625,16 +708,6 @@ ac_rule_nft() { # done #fi - # Build a rule in the prerouting hook chain that jumps to business chain with conditions - if [ -n "$PROXY_PORTS" ]; then - PORTS_ARGS=$(echo "$PROXY_PORTS" | sed 's/-m multiport --dports //') - if [ -n "$PORTS_ARGS" ]; then - TCP_EXT_ARGS="meta l4proto tcp tcp dport { $PORTS_ARGS }" - fi - else - TCP_EXT_ARGS="meta l4proto tcp" - fi - # Block UDP port 443 when TPROXY not Enable if [ -z "$TPROXY" ] && [ "$DISABLE_UDP_RULES" != "1" ]; then # Add UDP 443 block rule @@ -658,6 +731,17 @@ ac_rule_nft() { done fi fi + + # Build a rule in the prerouting hook chain that jumps to business chain with conditions + if [ -n "$PROXY_PORTS" ]; then + PORTS_ARGS=$(echo "$PROXY_PORTS" | sed 's/-m multiport --dports //') + if [ -n "$PORTS_ARGS" ]; then + TCP_EXT_ARGS="meta l4proto tcp tcp dport { $PORTS_ARGS }" + fi + else + TCP_EXT_ARGS="meta l4proto tcp" + fi + if [ -z "$Interface" ]; then # generic prerouting jump already exists (see ipset_nft), but if we have MATCH_SET_CONDITION we add a more specific rule if [ -n "$MATCH_SET" ]; then @@ -683,11 +767,16 @@ ac_rule_nft() { case "$OUTPUT" in 1) # Create ss_spec_output tcp chain - if ! $NFT list chain inet ss_spec ss_spec_output >/dev/null 2>&1; then - $NFT add chain inet ss_spec ss_spec_output '{ type nat hook output priority 0; policy accept; }' - fi - $NFT flush chain inet ss_spec ss_spec_output 2>/dev/null - $NFT add rule inet ss_spec ss_spec_output meta mark 255 return 2>/dev/null + if ! $NFT list chain inet ss_spec ss_spec_output >/dev/null 2>&1; then + $NFT add chain inet ss_spec ss_spec_output '{ type nat hook output priority 0; policy accept; }' + fi + $NFT flush chain inet ss_spec ss_spec_output 2>/dev/null + $NFT add rule inet ss_spec ss_spec_output meta mark 255 return 2>/dev/null + + if [ "$ENABLE_FAKE_IP" = "1" ]; then + $NFT add rule inet ss_spec ss_spec_output ip daddr 198.18.0.0/16 meta l4proto tcp redirect to :$local_port comment "\"$TAG\"" 2>/dev/null + $NFT add rule inet ss_spec ss_spec_output ip daddr 198.18.0.0/16 meta l4proto udp redirect to :$local_port comment "\"$TAG\"" 2>/dev/null + fi # Exclude special local addresses if $NFT list chain inet ss_spec ss_spec_output >/dev/null 2>&1; then @@ -708,11 +797,16 @@ ac_rule_nft() { ;; 2) # Create ss_spec_output tcp chain - if ! $NFT list chain inet ss_spec ss_spec_output >/dev/null 2>&1; then - $NFT add chain inet ss_spec ss_spec_output '{ type nat hook output priority 0; policy accept; }' - fi - $NFT flush chain inet ss_spec ss_spec_output 2>/dev/null - $NFT add rule inet ss_spec ss_spec_output meta mark 255 return 2>/dev/null + if ! $NFT list chain inet ss_spec ss_spec_output >/dev/null 2>&1; then + $NFT add chain inet ss_spec ss_spec_output '{ type nat hook output priority 0; policy accept; }' + fi + $NFT flush chain inet ss_spec ss_spec_output 2>/dev/null + $NFT add rule inet ss_spec ss_spec_output meta mark 255 return 2>/dev/null + + if [ "$ENABLE_FAKE_IP" = "1" ]; then + $NFT add rule inet ss_spec ss_spec_output ip daddr 198.18.0.0/16 meta l4proto tcp redirect to :$local_port comment "\"$TAG\"" 2>/dev/null + $NFT add rule inet ss_spec ss_spec_output ip daddr 198.18.0.0/16 meta l4proto udp redirect to :$local_port comment "\"$TAG\"" 2>/dev/null + fi # Exclude special local addresses if $NFT list chain inet ss_spec ss_spec_output >/dev/null 2>&1; then @@ -754,11 +848,38 @@ ac_rule_iptables() { return 2 ;; esac + + local ip_list="${LAN_AC_IP#?}" + ipset -! create ss_spec_lan_ac hash:net 2>/dev/null + ipset flush ss_spec_lan_ac 2>/dev/null + if [ -n "$ip_list" ]; then + for ip in $ip_list; do + ipset add ss_spec_lan_ac "$ip" 2>/dev/null + done + fi + fi + + # 2. PREROUTING 链处理 + if [ -z "$Interface" ]; then + # Global rules + if [ -n "$MATCH_SET" ]; then + $IPT -I PREROUTING 1 -p tcp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_WAN_AC + else + $IPT -I PREROUTING 1 -p tcp $EXT_ARGS -m comment --comment "$TAG" -j SS_SPEC_WAN_AC + fi + else + for name in $Interface; do + local IFNAME=$(uci -P /var/state get network."$name".ifname 2>/dev/null) + [ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network."$name".device 2>/dev/null) + if [ -n "$IFNAME" ]; then + if [ -n "$MATCH_SET" ]; then + $IPT -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p tcp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_WAN_AC + else + $IPT -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p tcp $EXT_ARGS -m comment --comment "$TAG" -j SS_SPEC_WAN_AC + fi + fi + done fi - ipset -! -R <<-EOF || return 1 - create ss_spec_lan_ac hash:net - $(for ip in ${LAN_AC_IP#?}; do echo "add ss_spec_lan_ac $ip"; done) - EOF # Block UDP port 443 when TPROXY not Enable if [ -z "$TPROXY" ] && [ "$DISABLE_UDP_RULES" != "1" ]; then @@ -784,42 +905,67 @@ ac_rule_iptables() { done fi fi - if [ -z "$Interface" ]; then - # Global rules - if [ -n "$MATCH_SET" ]; then - $IPT -I PREROUTING 1 -p tcp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_WAN_AC - else - $IPT -I PREROUTING 1 -p tcp $EXT_ARGS -m comment --comment "$TAG" -j SS_SPEC_WAN_AC - fi - else - for name in $Interface; do - local IFNAME=$(uci -P /var/state get network."$name".ifname 2>/dev/null) - [ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network."$name".device 2>/dev/null) - if [ -n "$IFNAME" ]; then - if [ -n "$MATCH_SET" ]; then - $IPT -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p tcp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_WAN_AC - else - $IPT -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p tcp $EXT_ARGS -m comment --comment "$TAG" -j SS_SPEC_WAN_AC - fi + + # 拦截 Fake-IP 流量 (198.18.0.0/16),受 Interface 和 LAN_AC 控制 + if [ "$ENABLE_FAKE_IP" = "1" ]; then + if [ -z "$Interface" ]; then + if [ -n "$MATCH_SET" ]; then + $IPT -I PREROUTING 1 -p tcp -d 198.18.0.0/16 $MATCH_SET -j REDIRECT --to-ports "$local_port" -m comment --comment "$TAG" + $IPT -I PREROUTING 2 -p udp -d 198.18.0.0/16 $MATCH_SET -j REDIRECT --to-ports "$local_port" -m comment --comment "$TAG" + else + $IPT -I PREROUTING 1 -p tcp -d 198.18.0.0/16 -j REDIRECT --to-ports "$local_port" -m comment --comment "$TAG" + $IPT -I PREROUTING 2 -p udp -d 198.18.0.0/16 -j REDIRECT --to-ports "$local_port" -m comment --comment "$TAG" fi - done + else + for name in $Interface; do + local IFNAME=$(uci -P /var/state get network."$name".ifname 2>/dev/null) + [ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network."$name".device 2>/dev/null) + if [ -n "$IFNAME" ]; then + if [ -n "$MATCH_SET" ]; then + $IPT -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p tcp -d 198.18.0.0/16 $MATCH_SET -j REDIRECT --to-ports "$local_port" -m comment --comment "$TAG" + $IPT -I PREROUTING 2 ${IFNAME:+-i $IFNAME} -p udp -d 198.18.0.0/16 $MATCH_SET -j REDIRECT --to-ports "$local_port" -m comment --comment "$TAG" + else + $IPT -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p tcp -d 198.18.0.0/16 -j REDIRECT --to-ports "$local_port" -m comment --comment "$TAG" + $IPT -I PREROUTING 2 ${IFNAME:+-i $IFNAME} -p udp -d 198.18.0.0/16 -j REDIRECT --to-ports "$local_port" -m comment --comment "$TAG" + fi + fi + done + fi fi case "$OUTPUT" in 1) - $IPT -I OUTPUT 1 -p tcp $EXT_ARGS -m comment --comment "$TAG" -j SS_SPEC_WAN_AC + # fake-ip first + if [ "$ENABLE_FAKE_IP" = "1" ]; then + $IPT -I OUTPUT 1 -m mark --mark 255 -j RETURN 2>/dev/null + $IPT -I OUTPUT 2 -p tcp -d 198.18.0.0/16 -j REDIRECT --to-ports "$local_port" -m comment --comment "$TAG" + $IPT -I OUTPUT 3 -p udp -d 198.18.0.0/16 -j REDIRECT --to-ports "$local_port" -m comment --comment "$TAG" + $IPT -I OUTPUT 4 -p tcp $EXT_ARGS -m comment --comment "$TAG" -j SS_SPEC_WAN_AC + else + $IPT -I OUTPUT 1 -m mark --mark 255 -j RETURN 2>/dev/null + $IPT -I OUTPUT 2 -p tcp $EXT_ARGS -m comment --comment "$TAG" -j SS_SPEC_WAN_AC + fi ;; 2) ipset -! -R <<-EOF || return 1 create ssr_gen_router hash:net $(gen_spec_iplist | sed -e "s/^/add ssr_gen_router /") EOF - $IPT -N SS_SPEC_ROUTER 2>/dev/null - $IPT -F SS_SPEC_ROUTER 2>/dev/null - $IPT -A SS_SPEC_ROUTER -m mark --mark 255 -j RETURN && \ - $IPT -A SS_SPEC_ROUTER -m set --match-set ssr_gen_router dst -j RETURN && \ - $IPT -A SS_SPEC_ROUTER -j SS_SPEC_WAN_FW - $IPT -I OUTPUT 1 -p tcp -m comment --comment "$TAG" -j SS_SPEC_ROUTER + $IPT -N SS_SPEC_ROUTER 2>/dev/null + $IPT -F SS_SPEC_ROUTER 2>/dev/null + # $IPT -A SS_SPEC_ROUTER -m mark --mark 255 -j RETURN + $IPT -A SS_SPEC_ROUTER -m set --match-set ssr_gen_router dst -j RETURN + $IPT -A SS_SPEC_ROUTER -j SS_SPEC_WAN_FW + # fake-ip first + if [ "$ENABLE_FAKE_IP" = "1" ]; then + $IPT -I OUTPUT 1 -m mark --mark 255 -j RETURN 2>/dev/null + $IPT -I OUTPUT 2 -p tcp -d 198.18.0.0/16 -j REDIRECT --to-ports "$local_port" -m comment --comment "$TAG" + $IPT -I OUTPUT 3 -p udp -d 198.18.0.0/16 -j REDIRECT --to-ports "$local_port" -m comment --comment "$TAG" + $IPT -I OUTPUT 4 -p tcp -m comment --comment "$TAG" -j SS_SPEC_ROUTER + else + $IPT -I OUTPUT 1 -m mark --mark 255 -j RETURN 2>/dev/null + $IPT -I OUTPUT 2 -p tcp -m comment --comment "$TAG" -j SS_SPEC_ROUTER + fi ;; esac return $? @@ -855,29 +1001,29 @@ tp_rule_nft() { fi local MATCH_SET="" + local EXT_ARGS="" if [ -n "$PROXY_PORTS" ]; then - PORTS_ARGS=$(echo "$PROXY_PORTS" | sed 's/-m multiport --dports //') - if [ -n "$PORTS_ARGS" ]; then - EXT_ARGS="udp dport { $PORTS_ARGS }" - else - EXT_ARGS="" - fi + local PORTS_ARGS=$(echo "$PROXY_PORTS" | sed 's/-m multiport --dports //') + [ -n "$PORTS_ARGS" ] && EXT_ARGS="udp dport { $PORTS_ARGS }" fi if [ -n "$LAN_AC_IP" ]; then # Create LAN access control set if needed + local mode="${LAN_AC_IP:0:1}" + local ips="${LAN_AC_IP:1}" + if ! $NFT list set ip ss_spec_mangle ss_spec_lan_ac >/dev/null 2>&1; then $NFT add set ip ss_spec_mangle ss_spec_lan_ac '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null else $NFT flush set ip ss_spec_mangle ss_spec_lan_ac 2>/dev/null fi - for ip in ${LAN_AC_IP#?}; do + for ip in $ips; do [ -n "$ip" ] && $NFT add element ip ss_spec_mangle ss_spec_lan_ac "{ $ip }" 2>/dev/null done - case "${LAN_AC_IP%${LAN_AC_IP#?}}" in + case "$mode" in w | W) MATCH_SET="ip saddr @ss_spec_lan_ac" ;; @@ -906,8 +1052,10 @@ tp_rule_nft() { fi # Bulk import xhttp ip list into nft whitelist (server + shunt) - if [ -f "${xhttp_ip:=/etc/ssrplus/xhttp_address.txt}" ]; then - $NFT add element ip ss_spec_mangle whitelist "{ $(tr '\n' ',' < "${xhttp_ip}" | sed 's/,$//') }" 2>/dev/null + local xhttp_file="${xhttp_ip:=/etc/ssrplus/xhttp_address.txt}" + if [ -s "$xhttp_file" ]; then + local xhttp_content=$(tr '\n' ',' < "$xhttp_file" | sed 's/,$//') + [ -n "$xhttp_content" ] && $NFT add element ip ss_spec_mangle whitelist "{ $xhttp_content }" 2>/dev/null fi # use priority mangle for compatibility with other rules @@ -917,6 +1065,12 @@ tp_rule_nft() { $NFT flush chain ip ss_spec_mangle ss_spec_tproxy 2>/dev/null fi + # 优先对 Fake-IP 进行 TPROXY 重定向 (无需受限于 PROXY_PORTS 限制) + if [ "$ENABLE_FAKE_IP" = "1" ]; then + $NFT add rule ip ss_spec_mangle ss_spec_tproxy ip daddr 198.18.0.0/16 counter tproxy ip to :"$LOCAL_PORT" meta mark set ${FWMARK} 2>/dev/null + fi + + # Exclude special local addresses if $NFT list chain ip ss_spec_mangle ss_spec_tproxy >/dev/null 2>&1; then for net in 0.0.0.0/8 10.0.0.0/8 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.168.0.0/16 224.0.0.0/4 240.0.0.0/4; do $NFT add rule ip ss_spec_mangle ss_spec_tproxy ip daddr $net return 2>/dev/null @@ -934,9 +1088,9 @@ tp_rule_nft() { $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp dport 53 return 2>/dev/null # avoid redirecting to udp server address - if [ -n "$server" ]; then - $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp dport != 53 ip daddr "$server" return 2>/dev/null - fi + # if [ -n "$server" ]; then + # $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp dport != 53 ip daddr "$server" return 2>/dev/null + # fi # if server != SERVER add SERVER to whitelist set (so tproxy won't touch it) if [ -n "$server" ]; then @@ -946,6 +1100,9 @@ tp_rule_nft() { $NFT add element ip ss_spec_mangle whitelist "{ $SERVER }" 2>/dev/null fi + # 显式豁免白名单集合中的 IP + $NFT add rule ip ss_spec_mangle ss_spec_tproxy ip daddr @whitelist return 2>/dev/null + # access control and tproxy rules $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip saddr @bplan return 2>/dev/null $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp $EXT_ARGS ip saddr @fplan counter tproxy ip to :"$LOCAL_PORT" meta mark set ${FWMARK} 2>/dev/null @@ -965,7 +1122,9 @@ tp_rule_nft() { $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip daddr @ss_spec_wan_ac return 2>/dev/null $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip daddr @china return 2>/dev/null + # 80 端口规则:非国内 IP 的 80 端口,走 TPROXY $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp udp dport 80 counter drop comment "\"$TAG\"" 2>/dev/null + # 443 端口规则:非国内 IP 的 443 端口,走 TPROXY $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp udp dport 443 counter drop comment "\"$TAG\"" 2>/dev/null $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip saddr @gmlan ip daddr != @china counter tproxy ip to :"$LOCAL_PORT" meta mark set ${FWMARK} 2>/dev/null $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp $EXT_ARGS ip daddr != @ss_spec_wan_ac counter tproxy ip to :"$LOCAL_PORT" meta mark set ${FWMARK} 2>/dev/null @@ -975,7 +1134,9 @@ tp_rule_nft() { $NFT add set ip ss_spec_mangle gfwlist '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null fi $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip daddr @china return 2>/dev/null + # 80 端口规则:非国内 IP 的 80 端口,走 TPROXY $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp udp dport 80 counter drop comment "\"$TAG\"" 2>/dev/null + # 443 端口规则:非国内 IP 的 443 端口,走 TPROXY $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp udp dport 443 counter drop comment "\"$TAG\"" 2>/dev/null $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp $EXT_ARGS ip daddr @gfwlist counter tproxy ip to :"$LOCAL_PORT" meta mark set ${FWMARK} 2>/dev/null $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip saddr @gmlan ip daddr != @china counter tproxy ip to :"$LOCAL_PORT" meta mark set ${FWMARK} 2>/dev/null @@ -988,6 +1149,8 @@ tp_rule_nft() { # finally, ensure prerouting hook entry to jump to tproxy chain if ! $NFT list chain ip ss_spec_mangle prerouting >/dev/null 2>&1; then $NFT add chain ip ss_spec_mangle prerouting '{ type filter hook prerouting priority mangle; policy accept; }' + else + $NFT flush chain ip ss_spec_mangle prerouting 2>/dev/null fi # add prerouting jump (idempotent) @@ -1056,8 +1219,14 @@ tp_rule_iptables() { do $ipt -A SS_SPEC_TPROXY -p udp -d "$net" -j RETURN done + # fake-ip 规则 + if [ "$ENABLE_FAKE_IP" = "1" ]; then + $ipt -A SS_SPEC_TPROXY -p udp $MATCH_SET -d 198.18.0.0/16 -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} + fi + [ -n "$SERVER" ] && $ipt -A SS_SPEC_TPROXY -p udp ! --dport 53 -d "$SERVER" -j RETURN [ -n "$SERVER" ] && [ "$server" != "$SERVER" ] && ipset -! add whitelist "$SERVER" + $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set whitelist dst -j RETURN if [ -f "${xhttp_ip:=/etc/ssrplus/xhttp_address.txt}" ]; then while IFS= read -r ip; do [ -n "$ip" ] && ipset add whitelist "$ip" -exist @@ -1065,6 +1234,7 @@ tp_rule_iptables() { fi $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set bplan src -j RETURN $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set fplan src -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} + $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set blacklist dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} case "$RUNMODE" in router) ipset -! -R <<-EOF || return 1 @@ -1073,15 +1243,27 @@ tp_rule_iptables() { EOF $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set ss_spec_wan_ac dst -j RETURN $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set china dst -j RETURN + # 80 端口规则:非国内 IP 的 80 端口,走 TPROXY $ipt -A SS_SPEC_TPROXY -p udp --dport 80 -j DROP - $ipt -A SS_SPEC_TPROXY -p udp --dport 443 -j DROP + # 443 端口规则:非国内 IP 的 443 端口,走 TPROXY + $ipt -A SS_SPEC_TPROXY -p udp --dport 443 -j DROP + # 保留海外 QUIC 代理 + # $ipt -A SS_SPEC_TPROXY -p udp --dport 80 -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} + # $ipt -A SS_SPEC_TPROXY -p udp --dport 443 -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} + # $ipt -A SS_SPEC_TPROXY -p udp -m set ! --match-set china dst --dport 80 -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} + # $ipt -A SS_SPEC_TPROXY -p udp -m set ! --match-set china dst --dport 443 -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set ! --match-set china dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set ! --match-set ss_spec_wan_ac dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} ;; gfw) $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set china dst -j RETURN + # 80 端口规则:非国内 IP 的 80 端口,走 TPROXY $ipt -A SS_SPEC_TPROXY -p udp --dport 80 -j DROP - $ipt -A SS_SPEC_TPROXY -p udp --dport 443 -j DROP + # 443 端口规则:非国内 IP 的 443 端口,走 TPROXY + $ipt -A SS_SPEC_TPROXY -p udp --dport 443 -j DROP + # 保留海外 QUIC 代理 + # $ipt -A SS_SPEC_TPROXY -p udp --dport 80 -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} + # $ipt -A SS_SPEC_TPROXY -p udp --dport 443 -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set gfwlist dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set ! --match-set china dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} ;; @@ -1463,7 +1645,7 @@ restore_from_persistence() { fi } -while getopts ":m:s:l:S:L:i:e:a:B:b:w:p:G:D:F:N:M:I:oOuUyfgrzAKPCRXh" arg; do +while getopts ":m:s:l:S:L:i:e:E:a:B:b:w:p:G:D:F:N:M:I:oOuUyfgrzAKPCRXh" arg; do case "$arg" in m) Interface=$OPTARG @@ -1486,6 +1668,9 @@ while getopts ":m:s:l:S:L:i:e:a:B:b:w:p:G:D:F:N:M:I:oOuUyfgrzAKPCRXh" arg; do e) EXT_ARGS=$OPTARG ;; + E) + ENABLE_FAKE_IP=$OPTARG + ;; a) LAN_AC_IP=$OPTARG ;; @@ -1689,6 +1874,14 @@ if [ -n "$local_port" ]; then if [ "$USE_NFT" = "1" ]; then # NFTables + # Detect Fake_IP Mode state change (execute first) + ENABLE_FAKE_IP_STATE_FILE="/tmp/.last_enable_fake_ip" + if [ -f "$ENABLE_FAKE_IP_STATE_FILE" ]; then + LAST_ENABLE_FAKE_IP=$(cat "$ENABLE_FAKE_IP_STATE_FILE") + else + LAST_ENABLE_FAKE_IP="" + fi + # Save previous TPROXY state file TPROXY_STATE_FILE="/tmp/.last_tproxy" if [ -f "$TPROXY_STATE_FILE" ]; then @@ -1778,6 +1971,13 @@ if [ -n "$local_port" ]; then LAST_XHTTP_FILE_HASH="" fi + # Check if Fake_IP Mode state has changed + ENABLE_FAKE_IP_CHANGED=0 + if [ "$LAST_ENABLE_FAKE_IP" != "$ENABLE_FAKE_IP" ]; then + loger 6 "Fake_IP Mode state changed: $LAST_ENABLE_FAKE_IP -> $ENABLE_FAKE_IP" + ENABLE_FAKE_IP_CHANGED=1 + fi + # STEP 1: Check if TPROXY has value (1 or 2) if [ "$TPROXY" = "1" ] || [ "$TPROXY" = "2" ]; then TPROXY_HAS_VALUE=1 @@ -1873,7 +2073,9 @@ if [ -n "$local_port" ]; then # 1. TPROXY changes from empty ↔ has value # 2. PROXY_PORTS changes from empty ↔ has value # 3. Any IP list has changed - if [ "$TPROXY_HAS_VALUE" != "$LAST_HAS_VALUE" ] || \ + # 4. ENABLE_FAKE_IP state changed + if [ "$ENABLE_FAKE_IP_CHANGED" = "1" ] || \ + [ "$TPROXY_HAS_VALUE" != "$LAST_HAS_VALUE" ] || \ [ "$PROXY_HAS_VALUE" != "$LAST_PROXY_HAS_VALUE" ] || \ [ "$ANY_IP_LIST_CHANGED" = "1" ]; then FORCE_RECREATE=1 @@ -1891,6 +2093,7 @@ if [ -n "$local_port" ]; then fi # STEP 4: Save current state + echo "$ENABLE_FAKE_IP" > "$ENABLE_FAKE_IP_STATE_FILE" echo "$TPROXY" > "$TPROXY_STATE_FILE" echo "$PROXY_PORTS" > "$PROXY_PORTS_STATE_FILE" echo "$(normalize_ip_list "$WAN_BP_IP")" > "$WAN_BP_IP_STATE_FILE" diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/clash_yaml.lua b/luci-app-ssr-plus/root/usr/share/shadowsocksr/clash_yaml.lua index 8d439f3e..c87d448a 100644 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/clash_yaml.lua +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/clash_yaml.lua @@ -4,6 +4,9 @@ require "nixio" require "nixio.fs" require "luci.model.uci" +local command_cache = {} +local ech_cache = {} + local ok_lyaml, lyaml = pcall(require, "lyaml") if not ok_lyaml then io.stderr:write("lyaml_not_found\n") @@ -13,6 +16,19 @@ end local uci = require "luci.model.uci".cursor() local ok_jsonc, jsonc = pcall(require, "luci.jsonc") +local dns_mode = uci:get_first("shadowsocksr", "global", "pdnsd_enable", "0") +if dns_mode == nil or dns_mode == "" then + dns_mode = "0" +end + +local enable_fake_ip = uci:get_first("shadowsocksr", "server_subscribe", "enable_fake_ip", "") +if enable_fake_ip == nil or enable_fake_ip == "" then + enable_fake_ip = "0" +end + +-- ==================== 基础工具函数 ================================= +-- ==================== Basic Utility Functions ==================== + local function read_file(path) local data = nixio.fs.readfile(path) if not data or data == "" then @@ -39,12 +55,32 @@ local function load_yaml(path) return parsed end +local function quote_nameserver_policy_keys(rendered) + rendered = rendered:gsub("[^\n]*", function(line) + local indent = line:match("^(%s*)geosite:geolocation%-!cn:%s*$") + if indent then + return indent .. '"geosite:geolocation-!cn":' + end + + indent = line:match("^(%s*)geosite:cn,private,apple:%s*$") + if indent then + return indent .. '"geosite:cn,private,apple":' + end + + return line + end) + + return rendered +end + local function dump_yaml(path, data) local ok, rendered = pcall(lyaml.dump, { data }) if not ok or not rendered then return nil, "dump_failed" end + rendered = quote_nameserver_policy_keys(rendered) + write_file(path, rendered) return true end @@ -91,6 +127,110 @@ local function parse_csv_line(line) return cols end +local function split_csv(value) + local items = {} + for part in tostring(value or ""):gmatch("[^,%s]+") do + items[#items + 1] = part + end + return items +end + +local function split_host_port(value) + local text = tostring(value or "") + if text == "" then + return "", "" + end + local host, port = text:match("^%[(.-)%]:(%d+)$") + if host and port then + return host, port + end + host, port = text:match("^(.-):(%d+)$") + if host and port then + return host, port + end + return text, "" +end + +local function split_alpn(value) + local items = {} + for part in tostring(value or ""):gmatch("[^,;|%s]+") do + items[#items + 1] = part + end + return items +end + +local function split_local_addresses(value) + local items = {} + if type(value) == "table" then + for _, item in ipairs(value) do + if item and item ~= "" then + items[#items + 1] = tostring(item) + end + end + elseif value and value ~= "" then + for item in tostring(value):gmatch("[^,%s]+") do + items[#items + 1] = item + end + end + return items +end + +local function split_wireguard_addresses(value) + local ip, ipv6 + for _, item in ipairs(split_local_addresses(value)) do + if item:find(":", 1, true) then + ipv6 = ipv6 or item + else + ip = ip or item + end + end + return ip, ipv6 +end + +local function first_nonempty(...) + for i = 1, select("#", ...) do + local value = select(i, ...) + if value ~= nil and value ~= "" then + return value + end + end + return nil +end + +local function clone_table(src) + if type(src) ~= "table" then + return nil + end + + local dst = {} + + for k, v in pairs(src) do + if type(v) == "table" then + dst[k] = clone_table(v) + else + dst[k] = v + end + end + + return dst +end + +local function deep_merge(dst, src) + if type(dst) ~= "table" or type(src) ~= "table" then + return src + end + + for k, v in pairs(src) do + if type(v) == "table" and type(dst[k]) == "table" then + dst[k] = deep_merge(dst[k], v) + else + dst[k] = v + end + end + + return dst +end + local function read_clash_client_rules_csv(sid) local rows = {} sid = trim(sid) @@ -128,6 +268,511 @@ local function read_clash_client_rules_csv(sid) return rows end +local function get_server_field(sid, option, default) + local value = uci:get("shadowsocksr", sid, option) + if value == nil or value == "" then + return default + end + return value +end + +-- ==================== ECH 配置获取函数 ========================================= +-- ==================== ECH Configuration Fetching Function ==================== + +-- ============================================================================ +-- 检查命令是否存在 +-- @param cmd 命令名称 +-- @return Boolean 是否存在 +-- ============================================================================ +local function command_exists(cmd) + if command_cache[cmd] ~= nil then + return command_cache[cmd] + end + + local safe_cmd = cmd:match("^[%w_%-]+$") + if not safe_cmd then + command_cache[cmd] = false + return false + end + + local handle = io.popen(string.format("command -v %s 2>/dev/null", safe_cmd)) + if not handle then + command_cache[cmd] = false + return false + end + + local result = handle:read("*a") + handle:close() + + command_cache[cmd] = (result and result ~= "") + return command_cache[cmd] +end + +-- ============================================================================ +-- 获取 ECH 配置 +-- @param domain 域名 +-- @param dns_server DNS 服务器地址 +-- @return String ECH Base64 值 或 nil +-- ============================================================================ +local function fetch_ech_config(domain, dns_server) + if not domain or domain == "" or not dns_server or dns_server == "" then + return nil + end + + local cache_key = domain .. "|" .. dns_server + if ech_cache[cache_key] ~= nil then + return ech_cache[cache_key] or nil + end + + if not command_exists("dig") then + ech_cache[cache_key] = false + return nil + end + + local proto = dns_server:match("^([a-zA-Z0-9%+%-%.]+)://") or "" + local port = dns_server:match(":(%d+)") + local server = dns_server + :gsub("^[a-zA-Z0-9%+%-%.]+://", "") + :gsub("/.*$", "") + :gsub(":%d+$", "") + + if server == "" then + ech_cache[cache_key] = false + return nil + end + + local safe_domain = domain:match("^[%w%-%._]+$") + local safe_server = server:match("^[%w%-%._]+$") + local safe_port = port and port:match("^%d+$") or nil + + if not safe_domain or not safe_server then + ech_cache[cache_key] = false + return nil + end + + local dig_opts = "" + proto = proto:lower() + + if proto == "https" or proto == "doh" then + dig_opts = "+https" + if safe_port and safe_port ~= "443" then + dig_opts = dig_opts .. " -p " .. safe_port + end + elseif proto == "tls" or proto == "dot" then + dig_opts = "+tls" + if safe_port and safe_port ~= "853" then + dig_opts = dig_opts .. " -p " .. safe_port + end + else + if safe_port and safe_port ~= "53" then + dig_opts = "-p " .. safe_port + end + end + + local cmd = string.format("dig %s +short TYPE65 %s @%s 2>/dev/null", dig_opts, safe_domain, safe_server) + local handle = io.popen(cmd) + if not handle then + ech_cache[cache_key] = false + return nil + end + + local output = handle:read("*a") + handle:close() + + if not output or output == "" then + ech_cache[cache_key] = false + return nil + end + + local ech = output:match('ech="?([^"%s]+)"?') + if ech and ech ~= "" then + ech_cache[cache_key] = ech + return ech + end + + ech_cache[cache_key] = false + return nil +end + +local function get_filter_aaaa() + local value = uci:get_first("shadowsocksr", "global", "filter_aaaa", "1") + if value == nil or value == "" then + value = uci:get_first("shadowsocksr", "global", "mosdns_ipv6", "1") + end + return value +end + +local function bool_enabled(value) + return value == "1" or value == 1 or value == true or value == "true" +end + +local function bool_default(value, default) + if value == nil or value == "" then + return default + end + return bool_enabled(value) +end + +local function number_or_nil(value) + if value == nil or value == "" then + return nil + end + return tonumber(value) +end + +local function string_or_nil(value) + if value == nil or value == "" then + return nil + end + return tostring(value) +end + +local function get_uptime_ms() + local f = io.open("/proc/uptime", "r") + if f then + local line = f:read("*l") + f:close() + if line then + local sec, frac = line:match("^(%d+)%.(%d+)") + if sec and frac then + frac = (frac .. "00"):sub(1, 3) + return tonumber(sec) * 1000 + tonumber(frac) + end + end + end + return os.time() * 1000 +end + +local function load_list_file(file_path) + local list = {} + local file = io.open(file_path, "r") + if not file then + return nil + end + + for line in file:lines() do + line = line:match("^%s*(.-)%s*$") + if line ~= "" and not line:match("^#") then + table.insert(list, line) + end + end + file:close() + return #list > 0 and list or nil +end + +-- ==================== DNS 相关函数 ============================== +-- ==================== DNS-related Functions ==================== + +local function format_dns_server(proxy) + if not proxy or proxy == "" then + return proxy + end + + local scheme, rest = proxy:match("^([a-zA-Z0-9%+%-%.]+)://(.+)$") + if scheme then + scheme = scheme:lower() + if scheme == "tls" or scheme == "dot" then + if not rest:match(":%d+$") then + rest = rest .. ":853" + end + return "tls://" .. rest + elseif scheme == "https" or scheme == "doh" or scheme == "dohl" or scheme == "doq" or scheme == "doql" then + local host, path = rest:match("^([^/]+)(.*)$") + host = host or rest + path = path or "" + if path == "" or path == "/" then + path = "/dns-query" + end + return "https://" .. host .. path + elseif scheme == "tcp" or scheme == "udp" then + if not rest:match(":%d+$") then + rest = rest .. ":53" + end + return scheme .. "://" .. rest + else + return proxy + end + end + + local host, port = proxy:match("^([^:]+):(%d+)$") + if host and port then + if port == "853" then + return "tls://" .. host .. ":853" + elseif port == "443" then + return "https://" .. host .. "/dns-query" + elseif port == "53" then + return host + else + return "udp://" .. host .. ":" .. port + end + end + + if proxy:match("[a-zA-Z]") and not proxy:match("[^%w%.%-]") then + local path = "" + if not proxy:match("/") then + path = "/dns-query" + end + return "https://" .. proxy .. path + end + + return proxy +end + +local function get_fastest_dns() + local dns_list = { + "223.5.5.5", "119.29.29.29", + "114.114.114.114", "180.76.76.76", + "114.114.115.115", "223.6.6.6", + "1.2.4.8", "1.12.12.12", + "101.226.4.6", "180.184.1.1", + } + local test_domain = "www.baidu.com" + local valid_dns_results = {} + + for _, dns in ipairs(dns_list) do + local start_time = get_uptime_ms() + + local cmd = string.format( + "timeout 2 nslookup %s %s 2>/dev/null", + test_domain, + dns + ) + + local f = io.popen(cmd) + if f then + local output = f:read("*a") or "" + f:close() + + local elapsed = get_uptime_ms() - start_time + local parsed_ip + for ip in output:gmatch("Address%s*%d*%s*:%s*(%d+%.%d+%.%d+%.%d+)") do + if ip ~= dns then + parsed_ip = ip + break + end + end + local is_success = + parsed_ip + and not output:match("[Cc]an't find") + and not output:match("[Tt]imed out") + and not output:match("[Nn]o servers could be reached") + if is_success and elapsed >= 0 and elapsed < 2500 then + table.insert(valid_dns_results, { + dns = dns, + latency = elapsed, + }) + end + end + end + + table.sort(valid_dns_results, function(a, b) + return a.latency < b.latency + end) + + local result = {} + local used = {} + + for i = 1, math.min(3, #valid_dns_results) do + local dns = valid_dns_results[i].dns + table.insert(result, dns) + used[dns] = true + end + + local fallbacks = { + "223.5.5.5", + "119.29.29.29", + "114.114.114.114", + } + + for _, dns in ipairs(fallbacks) do + if #result >= 3 then + break + end + + if not used[dns] then + table.insert(result, dns) + used[dns] = true + end + end + + return result +end + +local function get_forward_dns_list() + local forward = uci:get_first("shadowsocksr", "global", "tunnel_forward", "8.8.4.4:53") + if not forward or forward == "" then + forward = "8.8.4.4:53" + end + + local forward_list = {} + local used = {} + + for proxy in tostring(forward):gmatch("[^%s,;]+") do + if proxy ~= "" then + local formatted = format_dns_server(proxy) + if not used[formatted] then + table.insert(forward_list, formatted) + used[formatted] = true + end + end + end + + if #forward_list == 0 then + forward_list = { format_dns_server(forward) } + end + + return forward_list +end + +local function build_dns_upstreams() + local fastest_list = get_fastest_dns() + local nameserver_list = {} + local proxy_server_list = {} + --local used_dns = {} + + local proxy_server_list = { + "https://cn.ali-oss.cn:44443/dns-query/6dafe708-d9d6-48cc-a768-e6ed3018a9ec", + "https://hk.ali-oss.cn:44443/dns-query/6dafe708-d9d6-48cc-a768-e6ed3018a9ec" + } + --local used_dns = {} + + for _, dns_ip in ipairs(fastest_list) do + local formatted = format_dns_server(dns_ip) + table.insert(nameserver_list, formatted) + -- + -- if not used_dns[dns_ip] then + -- table.insert(proxy_server_list, dns_ip) + -- used_dns[dns_ip] = true + -- end + end + + return { + ["respect-rules"] = true, + ["nameserver"] = nameserver_list, + ["proxy-server-nameserver"] = proxy_server_list + } +end + +local function build_dns_section(dns_mode, user_dns, is_external_dns) + local result + local has_user_dns = type(user_dns) == "table" and next(user_dns) + + if not has_user_dns then + if is_external_dns then + return { enable = false } + end + result = { + enable = true, + listen = "127.0.0.1:5335" + } + else + result = clone_table(user_dns) + result.enable = true + end + + if enable_fake_ip == "1" then + result["enhanced-mode"] = "fake-ip" + -- if not result["fake-ip-range"] then + -- result["fake-ip-range"] = "198.18.0.1/16" + -- end + -- Must match the range redirected by ssr-rules; a value supplied by the + -- subscription would leave those redirects pointing at the wrong network. + -- result["fake-ip-range"] = nil + result["fake-ip-range"] = "198.18.0.1/16" + if not result["fake-ip-filter"] then + local filter_file = "/etc/ssrplus/fake_ip_filter.list" + local loaded_filter = load_list_file(filter_file) or { "*.lan", "*.local", "time.*.com", "ntp.*.com" } + if loaded_filter then + result["fake-ip-filter"] = loaded_filter + end + end + if result["use-hosts"] == nil then + result["use-hosts"] = true + end + + -- if not result["fallback"] then + -- result["fallback"] = get_forward_dns_list() + -- end + result["fallback"] = nil + result["fallback"] = get_forward_dns_list() + + if not result["default-nameserver"] then + result["default-nameserver"] = get_fastest_dns() + end + if result["respect-rules"] == nil then + result["respect-rules"] = true + end + if not result["fallback-filter"] then + local domain_file = "/etc/ssrplus/fallback_domain.list" + local domain_list = load_list_file(domain_file) or { "+.google.com", "+.facebook.com", "+.youtube.com" } + local ipcidr_file = "/etc/ssrplus/fallback_ipcidr.list" + local ipcidr_list = load_list_file(ipcidr_file) or { "240.0.0.0/4" } + result["fallback-filter"] = { + domain = domain_list, + ipcidr = ipcidr_list, + geoip = true, + ["geoip-code"] = "CN" + } + else + if result["fallback-filter"].geosite then + result["fallback-filter"].geosite = nil + end + end + + -- if not result["nameserver-policy"] then + -- result["nameserver-policy"] = {} + -- end + -- if not result["nameserver-policy"]["geosite:gfw"] then + -- result["nameserver-policy"]["geosite:gfw"] = result["fallback"] or get_forward_dns_list() + -- end + -- if not result["nameserver-policy"]["geosite:cn,private,apple"] then + -- result["nameserver-policy"]["geosite:cn,private,apple"] = get_fastest_dns() + -- end + result["nameserver-policy"] = nil + result["nameserver-policy"] = { + ["geosite:geolocation-!cn"] = result["fallback"] or get_forward_dns_list(), + ["geosite:cn,private,apple"] = get_fastest_dns() + } + + else + result["enhanced-mode"] = "redir-host" + result["fake-ip-range"] = nil + result["fake-ip-filter"] = nil + result["use-hosts"] = nil + result["fallback"] = nil + result["respect-rules"] = nil + result["fallback-filter"] = nil + result["nameserver-policy"] = nil + end + + local upstreams = build_dns_upstreams() + for k, v in pairs(upstreams) do + if k == "proxy-server-nameserver" then + result[k] = v + elseif result[k] == nil then + result[k] = v + end + end + + if dns_mode == "7" then + -- Must match the address dnsmasq forwards to; a value supplied by the + -- subscription would make every forwarded query hit a closed port. + -- result.listen = nil + result.listen = "127.0.0.1:5335" + else + result.listen = nil + end + + if result.ipv6 == nil then + result.ipv6 = get_filter_aaaa() ~= "1" + end + + return result +end + +-- ==================== 配置处理函数 ============================================ +-- ==================== Configuration Processing Functions ==================== + local function has_proxy_sections(doc) return type(doc.proxies) == "table" or type(doc["proxy-providers"]) == "table" end @@ -192,22 +837,6 @@ local function filter(path, filter_words) return true end -local function deep_merge(dst, src) - if type(dst) ~= "table" or type(src) ~= "table" then - return src - end - - for k, v in pairs(src) do - if type(v) == "table" and type(dst[k]) == "table" then - dst[k] = deep_merge(dst[k], v) - else - dst[k] = v - end - end - - return dst -end - local function strip_runtime_conflicts(doc) doc.tun = nil doc.listeners = nil @@ -225,6 +854,60 @@ local function strip_runtime_conflicts(doc) end end +local function apply_sniffer_config(doc, enable_fake_ip) + if type(doc) ~= "table" then return end + -- local is_fake_ip = (enable_fake_ip == "1") + local sniffer_config = { + enable = true, + ["override-destination"] = true, + sniff = { + HTTP = { + ports = { 80, 2052, 2082, 2086, 2095, "8080-8880" } + }, + TLS = { + ports = { 443, 2053, 2083, 2087, 2096, 8443 } + }, + QUIC = { + ports = { 443, 8443 } + } + }, + ["skip-domain"] = { "Mijia Cloud", "dlg.io.mi.com" }, + ["force-domain"] = { "+.v2ex.com" }, + -- ["force-dns-mapping"] = not is_fake_ip, -- fake-ip: false, redir-host: true + -- ["parse-pure-ip"] = not is_fake_ip -- fake-ip: false, redir-host: true + ["force-dns-mapping"] = true, + ["parse-pure-ip"] = true + } + + if not doc.sniffer then + doc.sniffer = sniffer_config + else + if doc.sniffer.enable == nil then + doc.sniffer.enable = true + end + if doc.sniffer["override-destination"] == nil then + doc.sniffer["override-destination"] = true + end + if not doc.sniffer.sniff then + doc.sniffer.sniff = sniffer_config.sniff + end + if not doc.sniffer["skip-domain"] then + doc.sniffer["skip-domain"] = sniffer_config["skip-domain"] + end + if not doc.sniffer["force-domain"] then + doc.sniffer["force-domain"] = sniffer_config["force-domain"] + end + if doc.sniffer["force-dns-mapping"] == nil then + -- doc.sniffer["force-dns-mapping"] = not is_fake_ip + doc.sniffer["force-dns-mapping"] = true + end + if doc.sniffer["parse-pure-ip"] == nil then + -- doc.sniffer["parse-pure-ip"] = not is_fake_ip + doc.sniffer["parse-pure-ip"] = true + end + end +end + local function group_requires_candidates(group) local gtype = tostring(group and group.type or ""):lower() return gtype == "select" @@ -281,259 +964,35 @@ local function strip_incompatible_script_rules(doc) return removed end -local function prepare(input_path, output_path) - local doc, err = load_yaml(input_path) - if not doc then - io.stderr:write(err or "parse_failed", "\n") - return false - end - if not has_proxy_sections(doc) then - io.stderr:write("missing_proxy_sections\n") - return false - end +local function merge_rules_with_direct(existing_rules) + local new_rules = {} + local existing_set = {} + local match_rule = nil - strip_runtime_conflicts(doc) - local filled_groups = fill_empty_proxy_groups(doc) - local stripped_rules = strip_incompatible_script_rules(doc) - local ok, rendered = pcall(lyaml.dump, { doc }) - if not ok or not rendered then - io.stderr:write("dump_failed\n") - return false - end - - write_file(output_path, rendered) - io.stdout:write(string.format("filled_groups=%d stripped_script_rules=%d\n", filled_groups, stripped_rules)) - return true -end - -local function merge(raw_path, overlay_path, output_path) - local raw_doc, raw_err = load_yaml(raw_path) - if not raw_doc then - io.stderr:write(raw_err or "parse_failed", "\n") - return false - end - - local overlay_doc, overlay_err = load_yaml(overlay_path) - if not overlay_doc then - io.stderr:write(overlay_err or "parse_failed", "\n") - return false - end - - strip_runtime_conflicts(raw_doc) - local filled_groups = fill_empty_proxy_groups(raw_doc) - local stripped_rules = strip_incompatible_script_rules(raw_doc) - local merged = deep_merge(raw_doc, overlay_doc) - local ok, rendered = pcall(lyaml.dump, { merged }) - if not ok or not rendered then - io.stderr:write("dump_failed\n") - return false - end - - write_file(output_path, rendered) - io.stdout:write(string.format("filled_groups=%d stripped_script_rules=%d\n", filled_groups, stripped_rules)) - return true -end - -local function append_client_policy_rules(runtime_path, sid) - local doc, err = load_yaml(runtime_path) - if not doc then - io.stderr:write(err or "parse_failed", "\n") - return false - end - - local valid_policies = {} - for _, proxy in ipairs(doc.proxies or {}) do - if type(proxy) == "table" and proxy.name and proxy.name ~= "" then - valid_policies[tostring(proxy.name)] = true - end - end - for _, group in ipairs(doc["proxy-groups"] or {}) do - if type(group) == "table" and group.name and group.name ~= "" then - valid_policies[tostring(group.name)] = true - end - end - - local custom_rules = {} - for _, section in ipairs(read_clash_client_rules_csv(sid)) do - if tostring(section.enabled or "0") == "1" then - local ip_addr = tostring(section.ip_addr or "") - local policy_group = tostring(section.policy_group or "") - if ip_addr ~= "" and policy_group ~= "" and valid_policies[policy_group] then - if not ip_addr:find("/", 1, true) then - ip_addr = ip_addr .. "/32" + if existing_rules then + for _, rule in ipairs(existing_rules) do + local clean_rule = rule:match("^%s*(.-)%s*$") or rule + + if clean_rule:upper():find("^MATCH,") then + if not match_rule then + match_rule = clean_rule + end + else + if not existing_set[clean_rule] and clean_rule ~= "" then + table.insert(new_rules, clean_rule) + existing_set[clean_rule] = true end - custom_rules[#custom_rules + 1] = string.format("SRC-IP-CIDR,%s,%s", ip_addr, policy_group) end end end - if #custom_rules == 0 then - io.stdout:write("client_rules=0\n") - return true - end + table.insert(new_rules, match_rule or "MATCH,PROXY") - local existing_rules = {} - for _, rule in ipairs(doc.rules or {}) do - local text = tostring(rule or "") - if not text:match("^SRC%-IP%-CIDR,") then - existing_rules[#existing_rules + 1] = rule - end - end - - doc.rules = {} - for _, rule in ipairs(custom_rules) do - doc.rules[#doc.rules + 1] = rule - end - for _, rule in ipairs(existing_rules) do - doc.rules[#doc.rules + 1] = rule - end - - local ok, rendered = pcall(lyaml.dump, { doc }) - if not ok or not rendered then - io.stderr:write("dump_failed\n") - return false - end - - write_file(runtime_path, rendered) - io.stdout:write(string.format("client_rules=%d\n", #custom_rules)) - return true + return new_rules end -local function bool_enabled(value) - return value == "1" or value == 1 or value == true or value == "true" -end - -local function split_csv(value) - local items = {} - for part in tostring(value or ""):gmatch("[^,%s]+") do - items[#items + 1] = part - end - return items -end - -local function get_server_field(sid, option, default) - local value = uci:get("shadowsocksr", sid, option) - if value == nil or value == "" then - return default - end - return value -end - -local function get_filter_aaaa() - local value = uci:get_first("shadowsocksr", "global", "filter_aaaa", "1") - if value == nil or value == "" then - value = uci:get_first("shadowsocksr", "global", "mosdns_ipv6", "1") - end - return value -end - -local function build_tuic_runtime_doc(sid, local_port, socks_port, mode) - local server = get_server_field(sid, "server", "") - local server_port = tonumber(get_server_field(sid, "server_port", "0")) or 0 - local tuic_ip = get_server_field(sid, "tuic_ip", "") - local tls_host = get_server_field(sid, "tls_host", "") - local ipstack_prefer = get_server_field(sid, "ipstack_prefer", "") - local dns_mode = uci:get_first("shadowsocksr", "global", "pdnsd_enable", "0") - - local proxy = { - name = sid, - type = "tuic", - server = server, - port = server_port, - uuid = get_server_field(sid, "tuic_uuid", ""), - password = get_server_field(sid, "tuic_passwd", ""), - ["udp-relay-mode"] = get_server_field(sid, "udp_relay_mode", "native"), - ["congestion-controller"] = get_server_field(sid, "congestion_control", "cubic"), - ["skip-cert-verify"] = bool_enabled(get_server_field(sid, "insecure", "0")), - ["disable-sni"] = bool_enabled(get_server_field(sid, "disable_sni", "0")), - ["reduce-rtt"] = bool_enabled(get_server_field(sid, "zero_rtt_handshake", "0")) - } - - if tuic_ip ~= "" then - proxy.ip = tuic_ip - end - if tls_host ~= "" then - proxy.sni = tls_host - end - - local alpn = split_csv(get_server_field(sid, "tuic_alpn", "")) - if #alpn > 0 then - proxy.alpn = alpn - end - - local heartbeat = tonumber(get_server_field(sid, "heartbeat", "0")) - if heartbeat and heartbeat > 0 then - proxy["heartbeat-interval"] = heartbeat * 1000 - end - - local timeout = tonumber(get_server_field(sid, "timeout", "0")) - if timeout and timeout > 0 then - proxy["request-timeout"] = timeout * 1000 - end - - local max_udp_packet_size = tonumber(get_server_field(sid, "tuic_max_package_size", "0")) - if max_udp_packet_size and max_udp_packet_size > 0 then - proxy["max-udp-relay-packet-size"] = max_udp_packet_size - end - - if ipstack_prefer ~= "" then - proxy["ip-version"] = ipstack_prefer == "v6first" and "ipv6-prefer" or "ipv4-prefer" - end - - local listen_port = tonumber(local_port) - local socks_listen = tonumber(socks_port) - - local doc = { - ["allow-lan"] = true, - ["bind-address"] = "0.0.0.0", - mode = "rule", - ["log-level"] = "silent", - ["find-process-mode"] = "off", - ["unified-delay"] = true, - ["tcp-concurrent"] = true, - ["routing-mark"] = 255, - proxies = { proxy }, - ["proxy-groups"] = { - { - name = "PROXY", - type = "select", - proxies = { sid } - } - }, - rules = { "MATCH,PROXY" }, - tun = { enable = false }, - profile = { ["store-selected"] = true }, - dns = { - enable = dns_mode == "7", - ["enhanced-mode"] = "redir-host", - listen = "127.0.0.1:5335", - ipv6 = get_filter_aaaa() ~= "1" - } - } - - if mode == "socks" then - doc["socks-port"] = listen_port - else - doc["redir-port"] = listen_port - doc["tproxy-port"] = listen_port - if socks_listen and socks_listen > 0 then - doc["socks-port"] = socks_listen - end - end - - return doc -end - -local function generate_tuic_runtime(sid, output_path, local_port, socks_port, mode) - local doc = build_tuic_runtime_doc(sid, local_port, socks_port, mode) - local ok, rendered = pcall(lyaml.dump, { doc }) - if not ok or not rendered then - io.stderr:write("dump_failed\n") - return false - end - write_file(output_path, rendered) - return true -end +-- ==================== Shadowsocks 插件处理函数 ===================================== +-- ==================== Shadowsocks Plugin Processing Functions ==================== local function parse_plugin_opts(value) local result = {} @@ -546,48 +1005,78 @@ local function parse_plugin_opts(value) return result end -local function split_host_port(value) - local text = tostring(value or "") - if text == "" then - return "", "" +local function parse_plugin_headers(plugin_opts) + local headers = {} + local raw_headers = pick_plugin_opt(plugin_opts, "headers", "header") + + if raw_headers and ok_jsonc and jsonc then + local decoded = jsonc.parse(raw_headers) + if type(decoded) == "table" then + for key, value in pairs(decoded) do + headers[tostring(key)] = tostring(value) + end + end end - local host, port = text:match("^%[(.-)%]:(%d+)$") - if host and port then - return host, port + + if raw_headers and next(headers) == nil then + for part in tostring(raw_headers):gmatch("[^|,]+") do + local key, value = part:match("^%s*([^=:]+)%s*[:=]%s*(.-)%s*$") + if key and key ~= "" and value and value ~= "" then + headers[key] = value + end + end end - host, port = text:match("^(.-):(%d+)$") - if host and port then - return host, port + + for key, value in pairs(plugin_opts) do + local header_name = key:match("^headers[%.:](.+)$") + or key:match("^header[%.:](.+)$") + or key:match("^header_(.+)$") + if header_name and header_name ~= "" and value ~= "" then + headers[header_name] = value + end end - return text, "" + + return next(headers) and headers or nil end -local function bool_default(value, default) - if value == nil or value == "" then - return default - end - return bool_enabled(value) +local function get_plugin_client_fingerprint(sid, plugin_opts) + return string_or_nil( + pick_plugin_opt( + plugin_opts, + "client-fingerprint", + "client_fingerprint", + "fingerprint" + ) or get_server_field(sid, "fingerprint", "") + ) end -local function number_or_nil(value) - if value == nil or value == "" then - return nil +local function normalize_plugin_name(plugin) + local value = tostring(plugin or ""):lower() + if value == "" or value == "none" then + return "" end - return tonumber(value) + if value == "simple-obfs" then + return "obfs-local" + end + if value == "obfs" then + return "obfs-local" + end + if value == "shadowtls" then + return "shadow-tls" + end + if value == "gost" then + return "gost-plugin" + end + if value == "kcp-tun" then + return "kcptun" + end + return value end -local function string_or_nil(value) - if value == nil or value == "" then - return nil - end - return tostring(value) -end - -local build_shadowsocks_plugin - -local function first_nonempty(...) +local function pick_plugin_opt(plugin_opts, ...) for i = 1, select("#", ...) do - local value = select(i, ...) + local key = select(i, ...) + local value = plugin_opts[key] if value ~= nil and value ~= "" then return value end @@ -595,14 +1084,141 @@ local function first_nonempty(...) return nil end -local function split_alpn(value) - local items = {} - for part in tostring(value or ""):gmatch("[^,;|%s]+") do - items[#items + 1] = part +local function build_shadowsocks_plugin(proxy, sid) + local plugin = normalize_plugin_name(get_server_field(sid, "plugin", "")) + local plugin_opts = parse_plugin_opts(get_server_field(sid, "plugin_opts", "")) + + if plugin == "" then + return + end + + if plugin == "obfs-local" then + proxy.plugin = "obfs" + proxy["plugin-opts"] = { + mode = pick_plugin_opt(plugin_opts, "obfs", "mode") or "http", + host = string_or_nil(pick_plugin_opt(plugin_opts, "obfs-host", "obfs_host", "host")) + } + return + end + + if plugin == "v2ray-plugin" or plugin == "xray-plugin" then + proxy.plugin = "v2ray-plugin" + proxy["plugin-opts"] = { + mode = pick_plugin_opt(plugin_opts, "mode") or "websocket", + tls = bool_default(pick_plugin_opt(plugin_opts, "tls"), false), + fingerprint = string_or_nil(pick_plugin_opt(plugin_opts, "fingerprint")), + ["skip-cert-verify"] = bool_default(pick_plugin_opt(plugin_opts, "skip-cert-verify", "skip_cert_verify", "insecure"), false), + host = string_or_nil(pick_plugin_opt(plugin_opts, "host")), + path = string_or_nil(pick_plugin_opt(plugin_opts, "path")), + mux = bool_default(pick_plugin_opt(plugin_opts, "mux"), false), + headers = parse_plugin_headers(plugin_opts), + ["v2ray-http-upgrade"] = bool_default(pick_plugin_opt(plugin_opts, "v2ray-http-upgrade", "v2ray_http_upgrade"), false) + } + return + end + + if plugin == "gost-plugin" then + proxy.plugin = "gost-plugin" + proxy["plugin-opts"] = { + mode = pick_plugin_opt(plugin_opts, "mode") or "websocket", + tls = bool_default(pick_plugin_opt(plugin_opts, "tls"), false), + fingerprint = string_or_nil(pick_plugin_opt(plugin_opts, "fingerprint")), + ["skip-cert-verify"] = bool_default(pick_plugin_opt(plugin_opts, "skip-cert-verify", "skip_cert_verify", "insecure"), false), + host = string_or_nil(pick_plugin_opt(plugin_opts, "host")), + path = string_or_nil(pick_plugin_opt(plugin_opts, "path")), + mux = bool_default(pick_plugin_opt(plugin_opts, "mux"), false), + headers = parse_plugin_headers(plugin_opts) + } + return + end + + if plugin == "shadow-tls" then + local host, port = split_host_port(pick_plugin_opt(plugin_opts, "host") or "") + local version + if plugin_opts.v3 == "1" or plugin_opts.version == "3" then + version = 3 + elseif plugin_opts.v2 == "1" or plugin_opts.version == "2" then + version = 2 + elseif plugin_opts.v1 == "1" or plugin_opts.version == "1" then + version = 1 + end + proxy.plugin = "shadow-tls" + proxy["client-fingerprint"] = get_plugin_client_fingerprint(sid, plugin_opts) + proxy["plugin-opts"] = { + host = host ~= "" and host or nil, + port = number_or_nil(port), + password = string_or_nil(pick_plugin_opt(plugin_opts, "passwd", "password")), + version = version + } + return + end + + if plugin == "restls" then + proxy.plugin = "restls" + proxy["client-fingerprint"] = get_plugin_client_fingerprint(sid, plugin_opts) + proxy["plugin-opts"] = { + host = string_or_nil(pick_plugin_opt(plugin_opts, "host")), + password = string_or_nil(pick_plugin_opt(plugin_opts, "passwd", "password")), + ["version-hint"] = string_or_nil(pick_plugin_opt(plugin_opts, "version-hint", "version_hint")), + ["restls-script"] = string_or_nil(pick_plugin_opt(plugin_opts, "restls-script", "restls_script")) + } + return + end + + if plugin == "kcptun" then + proxy.plugin = "kcptun" + proxy["plugin-opts"] = { + key = string_or_nil(pick_plugin_opt(plugin_opts, "key", "passwd", "password")), + crypt = string_or_nil(pick_plugin_opt(plugin_opts, "crypt")), + mode = string_or_nil(pick_plugin_opt(plugin_opts, "mode")), + conn = number_or_nil(pick_plugin_opt(plugin_opts, "conn")), + autoexpire = number_or_nil(pick_plugin_opt(plugin_opts, "autoexpire")), + scavengettl = number_or_nil(pick_plugin_opt(plugin_opts, "scavengettl")), + mtu = number_or_nil(pick_plugin_opt(plugin_opts, "mtu")), + ratelimit = number_or_nil(pick_plugin_opt(plugin_opts, "ratelimit")), + sndwnd = number_or_nil(pick_plugin_opt(plugin_opts, "sndwnd")), + rcvwnd = number_or_nil(pick_plugin_opt(plugin_opts, "rcvwnd")), + datashard = number_or_nil(pick_plugin_opt(plugin_opts, "datashard")), + parityshard = number_or_nil(pick_plugin_opt(plugin_opts, "parityshard")), + dscp = number_or_nil(pick_plugin_opt(plugin_opts, "dscp")), + nocomp = bool_default(pick_plugin_opt(plugin_opts, "nocomp"), false), + acknodelay = bool_default(pick_plugin_opt(plugin_opts, "acknodelay"), false), + nodelay = number_or_nil(pick_plugin_opt(plugin_opts, "nodelay")), + interval = number_or_nil(pick_plugin_opt(plugin_opts, "interval")), + resend = number_or_nil(pick_plugin_opt(plugin_opts, "resend")), + sockbuf = number_or_nil(pick_plugin_opt(plugin_opts, "sockbuf")), + smuxver = number_or_nil(pick_plugin_opt(plugin_opts, "smuxver")), + smuxbuf = number_or_nil(pick_plugin_opt(plugin_opts, "smuxbuf")), + framesize = number_or_nil(pick_plugin_opt(plugin_opts, "framesize")), + streambuf = number_or_nil(pick_plugin_opt(plugin_opts, "streambuf")), + keepalive = number_or_nil(pick_plugin_opt(plugin_opts, "keepalive")) + } + return + end + + proxy.plugin = plugin + if next(plugin_opts) then + proxy["plugin-opts"] = plugin_opts end - return items end +local function build_kcptun_plugin(proxy, sid) + if not bool_enabled(get_server_field(sid, "kcp_enable", "0")) then + return + end + + proxy.plugin = "kcptun" + proxy.port = tonumber(get_server_field(sid, "kcp_port", "0")) or proxy.port + proxy["plugin-opts"] = { + key = get_server_field(sid, "kcp_password", ""), + mode = "fast", + mtu = 1350 + } +end + +-- ==================== V2Ray 节点构建函数 ===================================== +-- ==================== V2Ray Node Construction Functions ==================== + local function parse_wireguard_reserved(sid) local raw = get_server_field(sid, "reserved", nil) local values = {} @@ -636,34 +1252,6 @@ local function parse_wireguard_reserved(sid) return #bytes > 0 and bytes or nil end -local function split_local_addresses(value) - local items = {} - if type(value) == "table" then - for _, item in ipairs(value) do - if item and item ~= "" then - items[#items + 1] = tostring(item) - end - end - elseif value and value ~= "" then - for item in tostring(value):gmatch("[^,%s]+") do - items[#items + 1] = item - end - end - return items -end - -local function split_wireguard_addresses(value) - local ip, ipv6 - for _, item in ipairs(split_local_addresses(value)) do - if item:find(":", 1, true) then - ipv6 = ipv6 or item - else - ip = ip or item - end - end - return ip, ipv6 -end - local function apply_v2ray_tls_options(proxy, sid) local tls = get_server_field(sid, "tls", "0") local reality = get_server_field(sid, "reality", "0") @@ -690,30 +1278,52 @@ local function apply_v2ray_tls_options(proxy, sid) } end + -- ECH 配置处理 if get_server_field(sid, "enable_ech", "0") == "1" then - proxy["ech-opts"] = { - enable = true, - config = string_or_nil(get_server_field(sid, "ech_config", "")) - } - end -end + local raw_ech_cfg = get_server_field(sid, "ech_config", "") + local raw_domain = get_server_field(sid, "ech_domain", "") -local function apply_trojan_tls_options(proxy, sid) - proxy.sni = string_or_nil(get_server_field(sid, "tls_host", "")) - proxy["client-fingerprint"] = string_or_nil(get_server_field(sid, "fingerprint", "")) - proxy.fingerprint = string_or_nil(get_server_field(sid, "tls_CertSha", "")) - proxy["skip-cert-verify"] = bool_enabled(get_server_field(sid, "insecure", "0")) + local ech_base64_result = nil + local query_server_name = nil - local alpn = split_alpn(get_server_field(sid, "tls_alpn", "")) - if #alpn > 0 then - proxy.alpn = alpn - end + local function is_strict_domain(str) + if not str or str == "" then return false end + return str:match("^[%w%-%_]+%.[%w%-%._]+$") ~= nil + end - if get_server_field(sid, "reality", "0") == "1" then - proxy["reality-opts"] = { - ["public-key"] = string_or_nil(get_server_field(sid, "reality_publickey", "")), - ["short-id"] = string_or_nil(get_server_field(sid, "reality_shortid", "")) - } + local function is_dns_input(str) + if not str or str == "" then return false end + return str:match("^https?://") ~= nil + or str:match("^tls://") ~= nil + or str:match("^tcp://") ~= nil + or str:match("^udp://") ~= nil + or str:match("^%d+%.%d+%.%d+%.%d+") ~= nil + end + + local domain_part, dns_part = raw_ech_cfg:match("^([%w%-%_]+%.[%w%-%._]+)%+(.+)$") + if domain_part and dns_part and is_dns_input(dns_part) then + ech_base64_result = string_or_nil(fetch_ech_config(domain_part, dns_part)) + query_server_name = domain_part + elseif is_dns_input(raw_ech_cfg) and is_strict_domain(raw_domain) then + ech_base64_result = string_or_nil(fetch_ech_config(raw_domain, raw_ech_cfg)) + query_server_name = raw_domain + elseif raw_ech_cfg:match("^[A-Za-z0-9%+%/%-%_%=]+$") and #raw_ech_cfg >= 32 then + ech_base64_result = raw_ech_cfg + if is_strict_domain(raw_domain) then + query_server_name = raw_domain + end + end + + if ech_base64_result then + proxy["ech-opts"] = { + enable = true, + config = ech_base64_result + } + + if query_server_name and query_server_name ~= "" then + proxy["ech-opts"]["query-server-name"] = query_server_name + end + end end end @@ -762,6 +1372,73 @@ local function apply_v2ray_transport_options(proxy, sid) end end +local function apply_trojan_tls_options(proxy, sid) + proxy.sni = string_or_nil(get_server_field(sid, "tls_host", "")) + proxy["client-fingerprint"] = string_or_nil(get_server_field(sid, "fingerprint", "")) + proxy.fingerprint = string_or_nil(get_server_field(sid, "tls_CertSha", "")) + proxy["skip-cert-verify"] = bool_enabled(get_server_field(sid, "insecure", "0")) + + local alpn = split_alpn(get_server_field(sid, "tls_alpn", "")) + if #alpn > 0 then + proxy.alpn = alpn + end + + if get_server_field(sid, "reality", "0") == "1" then + proxy["reality-opts"] = { + ["public-key"] = string_or_nil(get_server_field(sid, "reality_publickey", "")), + ["short-id"] = string_or_nil(get_server_field(sid, "reality_shortid", "")) + } + end + + -- ECH 配置处理 + if get_server_field(sid, "enable_ech", "0") == "1" then + local raw_ech_cfg = get_server_field(sid, "ech_config", "") + local raw_domain = get_server_field(sid, "ech_domain", "") + + local ech_base64_result = nil + local query_server_name = nil + + local function is_strict_domain(str) + if not str or str == "" then return false end + return str:match("^[%w%-%_]+%.[%w%-%._]+$") ~= nil + end + + local function is_dns_input(str) + if not str or str == "" then return false end + return str:match("^https?://") ~= nil + or str:match("^tls://") ~= nil + or str:match("^tcp://") ~= nil + or str:match("^udp://") ~= nil + or str:match("^%d+%.%d+%.%d+%.%d+") ~= nil + end + + local domain_part, dns_part = raw_ech_cfg:match("^([%w%-%_]+%.[%w%-%._]+)%+(.+)$") + if domain_part and dns_part and is_dns_input(dns_part) then + ech_base64_result = string_or_nil(fetch_ech_config(domain_part, dns_part)) + query_server_name = domain_part + elseif is_dns_input(raw_ech_cfg) and is_strict_domain(raw_domain) then + ech_base64_result = string_or_nil(fetch_ech_config(raw_domain, raw_ech_cfg)) + query_server_name = raw_domain + elseif raw_ech_cfg:match("^[A-Za-z0-9%+%/%-%_%=]+$") and #raw_ech_cfg >= 32 then + ech_base64_result = raw_ech_cfg + if is_strict_domain(raw_domain) then + query_server_name = raw_domain + end + end + + if ech_base64_result then + proxy["ech-opts"] = { + enable = true, + config = ech_base64_result + } + + if query_server_name and query_server_name ~= "" then + proxy["ech-opts"]["query-server-name"] = query_server_name + end + end + end +end + local function can_mihomo_handle_v2ray_transport(protocol, sid) local transport = get_server_field(sid, "transport", "raw") if transport == "" or transport == "raw" or transport == "tcp" then @@ -920,10 +1597,15 @@ local function build_v2ray_mihomo_proxy(sid) return proxy end +-- ==================== 节点运行时文档构建函数 ============================================== +-- ==================== Node Runtime Document Construction Functions ==================== + local function build_single_proxy_runtime_doc(proxy, local_port, socks_port, mode) - local dns_mode = uci:get_first("shadowsocksr", "global", "pdnsd_enable", "0") local listen_port = tonumber(local_port) local socks_listen = tonumber(socks_port) + local mode_str = tostring(dns_mode or "") + local is_ext_dns = (mode_str ~= "7") + local doc = { ["allow-lan"] = true, ["bind-address"] = "0.0.0.0", @@ -943,13 +1625,11 @@ local function build_single_proxy_runtime_doc(proxy, local_port, socks_port, mod }, rules = { "MATCH,PROXY" }, tun = { enable = false }, - profile = { ["store-selected"] = true }, - dns = { - enable = dns_mode == "7", - ["enhanced-mode"] = "redir-host", - listen = "127.0.0.1:5335", - ipv6 = get_filter_aaaa() ~= "1" - } + profile = { + ["store-selected"] = true, + ["store-fake-ip"] = true + }, + dns = build_dns_section(dns_mode, nil, is_ext_dns) } if mode == "socks" then @@ -964,223 +1644,109 @@ local function build_single_proxy_runtime_doc(proxy, local_port, socks_port, mod return doc end -local function pick_plugin_opt(plugin_opts, ...) - for i = 1, select("#", ...) do - local key = select(i, ...) - local value = plugin_opts[key] - if value ~= nil and value ~= "" then - return value - end - end - return nil -end +local function build_tuic_runtime_doc(sid, local_port, socks_port, mode) + local server = get_server_field(sid, "server", "") + local server_port = tonumber(get_server_field(sid, "server_port", "0")) or 0 + local tuic_ip = get_server_field(sid, "tuic_ip", "") + local tls_host = get_server_field(sid, "tls_host", "") + local ipstack_prefer = get_server_field(sid, "ipstack_prefer", "") + local mode_str = tostring(dns_mode or "") + local is_ext_dns = (mode_str ~= "7") -local function parse_plugin_headers(plugin_opts) - local headers = {} - local raw_headers = pick_plugin_opt(plugin_opts, "headers", "header") - - if raw_headers and ok_jsonc and jsonc then - local decoded = jsonc.parse(raw_headers) - if type(decoded) == "table" then - for key, value in pairs(decoded) do - headers[tostring(key)] = tostring(value) - end - end - end - - if raw_headers and next(headers) == nil then - for part in tostring(raw_headers):gmatch("[^|,]+") do - local key, value = part:match("^%s*([^=:]+)%s*[:=]%s*(.-)%s*$") - if key and key ~= "" and value and value ~= "" then - headers[key] = value - end - end - end - - for key, value in pairs(plugin_opts) do - local header_name = key:match("^headers[%.:](.+)$") - or key:match("^header[%.:](.+)$") - or key:match("^header_(.+)$") - if header_name and header_name ~= "" and value ~= "" then - headers[header_name] = value - end - end - - return next(headers) and headers or nil -end - -local function get_plugin_client_fingerprint(sid, plugin_opts) - return string_or_nil( - pick_plugin_opt( - plugin_opts, - "client-fingerprint", - "client_fingerprint", - "fingerprint" - ) or get_server_field(sid, "fingerprint", "") - ) -end - -local function normalize_plugin_name(plugin) - local value = tostring(plugin or ""):lower() - if value == "" or value == "none" then - return "" - end - if value == "simple-obfs" then - return "obfs-local" - end - if value == "obfs" then - return "obfs-local" - end - if value == "shadowtls" then - return "shadow-tls" - end - if value == "gost" then - return "gost-plugin" - end - if value == "kcp-tun" then - return "kcptun" - end - return value -end - -function build_shadowsocks_plugin(proxy, sid) - local plugin = normalize_plugin_name(get_server_field(sid, "plugin", "")) - local plugin_opts = parse_plugin_opts(get_server_field(sid, "plugin_opts", "")) - - if plugin == "" then - return - end - - if plugin == "obfs-local" then - proxy.plugin = "obfs" - proxy["plugin-opts"] = { - mode = pick_plugin_opt(plugin_opts, "obfs", "mode") or "http", - host = string_or_nil(pick_plugin_opt(plugin_opts, "obfs-host", "obfs_host", "host")) - } - return - end - - if plugin == "v2ray-plugin" or plugin == "xray-plugin" then - proxy.plugin = "v2ray-plugin" - proxy["plugin-opts"] = { - mode = pick_plugin_opt(plugin_opts, "mode") or "websocket", - tls = bool_default(pick_plugin_opt(plugin_opts, "tls"), false), - fingerprint = string_or_nil(pick_plugin_opt(plugin_opts, "fingerprint")), - ["skip-cert-verify"] = bool_default(pick_plugin_opt(plugin_opts, "skip-cert-verify", "skip_cert_verify", "insecure"), false), - host = string_or_nil(pick_plugin_opt(plugin_opts, "host")), - path = string_or_nil(pick_plugin_opt(plugin_opts, "path")), - mux = bool_default(pick_plugin_opt(plugin_opts, "mux"), false), - headers = parse_plugin_headers(plugin_opts), - ["v2ray-http-upgrade"] = bool_default(pick_plugin_opt(plugin_opts, "v2ray-http-upgrade", "v2ray_http_upgrade"), false) - } - return - end - - if plugin == "gost-plugin" then - proxy.plugin = "gost-plugin" - proxy["plugin-opts"] = { - mode = pick_plugin_opt(plugin_opts, "mode") or "websocket", - tls = bool_default(pick_plugin_opt(plugin_opts, "tls"), false), - fingerprint = string_or_nil(pick_plugin_opt(plugin_opts, "fingerprint")), - ["skip-cert-verify"] = bool_default(pick_plugin_opt(plugin_opts, "skip-cert-verify", "skip_cert_verify", "insecure"), false), - host = string_or_nil(pick_plugin_opt(plugin_opts, "host")), - path = string_or_nil(pick_plugin_opt(plugin_opts, "path")), - mux = bool_default(pick_plugin_opt(plugin_opts, "mux"), false), - headers = parse_plugin_headers(plugin_opts) - } - return - end - - if plugin == "shadow-tls" then - local host, port = split_host_port(pick_plugin_opt(plugin_opts, "host") or "") - local version - if plugin_opts.v3 == "1" or plugin_opts.version == "3" then - version = 3 - elseif plugin_opts.v2 == "1" or plugin_opts.version == "2" then - version = 2 - elseif plugin_opts.v1 == "1" or plugin_opts.version == "1" then - version = 1 - end - proxy.plugin = "shadow-tls" - proxy["client-fingerprint"] = get_plugin_client_fingerprint(sid, plugin_opts) - proxy["plugin-opts"] = { - host = host ~= "" and host or nil, - port = number_or_nil(port), - password = string_or_nil(pick_plugin_opt(plugin_opts, "passwd", "password")), - version = version - } - return - end - - if plugin == "restls" then - proxy.plugin = "restls" - proxy["client-fingerprint"] = get_plugin_client_fingerprint(sid, plugin_opts) - proxy["plugin-opts"] = { - host = string_or_nil(pick_plugin_opt(plugin_opts, "host")), - password = string_or_nil(pick_plugin_opt(plugin_opts, "passwd", "password")), - ["version-hint"] = string_or_nil(pick_plugin_opt(plugin_opts, "version-hint", "version_hint")), - ["restls-script"] = string_or_nil(pick_plugin_opt(plugin_opts, "restls-script", "restls_script")) - } - return - end - - if plugin == "kcptun" then - proxy.plugin = "kcptun" - proxy["plugin-opts"] = { - key = string_or_nil(pick_plugin_opt(plugin_opts, "key", "passwd", "password")), - crypt = string_or_nil(pick_plugin_opt(plugin_opts, "crypt")), - mode = string_or_nil(pick_plugin_opt(plugin_opts, "mode")), - conn = number_or_nil(pick_plugin_opt(plugin_opts, "conn")), - autoexpire = number_or_nil(pick_plugin_opt(plugin_opts, "autoexpire")), - scavengettl = number_or_nil(pick_plugin_opt(plugin_opts, "scavengettl")), - mtu = number_or_nil(pick_plugin_opt(plugin_opts, "mtu")), - ratelimit = number_or_nil(pick_plugin_opt(plugin_opts, "ratelimit")), - sndwnd = number_or_nil(pick_plugin_opt(plugin_opts, "sndwnd")), - rcvwnd = number_or_nil(pick_plugin_opt(plugin_opts, "rcvwnd")), - datashard = number_or_nil(pick_plugin_opt(plugin_opts, "datashard")), - parityshard = number_or_nil(pick_plugin_opt(plugin_opts, "parityshard")), - dscp = number_or_nil(pick_plugin_opt(plugin_opts, "dscp")), - nocomp = bool_default(pick_plugin_opt(plugin_opts, "nocomp"), false), - acknodelay = bool_default(pick_plugin_opt(plugin_opts, "acknodelay"), false), - nodelay = number_or_nil(pick_plugin_opt(plugin_opts, "nodelay")), - interval = number_or_nil(pick_plugin_opt(plugin_opts, "interval")), - resend = number_or_nil(pick_plugin_opt(plugin_opts, "resend")), - sockbuf = number_or_nil(pick_plugin_opt(plugin_opts, "sockbuf")), - smuxver = number_or_nil(pick_plugin_opt(plugin_opts, "smuxver")), - smuxbuf = number_or_nil(pick_plugin_opt(plugin_opts, "smuxbuf")), - framesize = number_or_nil(pick_plugin_opt(plugin_opts, "framesize")), - streambuf = number_or_nil(pick_plugin_opt(plugin_opts, "streambuf")), - keepalive = number_or_nil(pick_plugin_opt(plugin_opts, "keepalive")) - } - return - end - - proxy.plugin = plugin - if next(plugin_opts) then - proxy["plugin-opts"] = plugin_opts - end -end - -local function build_kcptun_plugin(proxy, sid) - if not bool_enabled(get_server_field(sid, "kcp_enable", "0")) then - return - end - - proxy.plugin = "kcptun" - proxy.port = tonumber(get_server_field(sid, "kcp_port", "0")) or proxy.port - proxy["plugin-opts"] = { - key = get_server_field(sid, "kcp_password", ""), - mode = "fast", - mtu = 1350 + local proxy = { + name = sid, + type = "tuic", + server = server, + port = server_port, + uuid = get_server_field(sid, "tuic_uuid", ""), + password = get_server_field(sid, "tuic_passwd", ""), + ["udp-relay-mode"] = get_server_field(sid, "udp_relay_mode", "native"), + ["congestion-controller"] = get_server_field(sid, "congestion_control", "cubic"), + ["skip-cert-verify"] = bool_enabled(get_server_field(sid, "insecure", "0")), + ["disable-sni"] = bool_enabled(get_server_field(sid, "disable_sni", "0")), + ["reduce-rtt"] = bool_enabled(get_server_field(sid, "zero_rtt_handshake", "0")) } + + if tuic_ip ~= "" then + proxy.ip = tuic_ip + end + if tls_host ~= "" then + proxy.sni = tls_host + end + + local alpn = split_csv(get_server_field(sid, "tuic_alpn", "")) + if #alpn > 0 then + proxy.alpn = alpn + end + + local heartbeat = tonumber(get_server_field(sid, "heartbeat", "0")) + if heartbeat and heartbeat > 0 then + proxy["heartbeat-interval"] = heartbeat * 1000 + end + + local timeout = tonumber(get_server_field(sid, "timeout", "0")) + if timeout and timeout > 0 then + proxy["request-timeout"] = timeout * 1000 + end + + local max_udp_packet_size = tonumber(get_server_field(sid, "tuic_max_package_size", "0")) + if max_udp_packet_size and max_udp_packet_size > 0 then + proxy["max-udp-relay-packet-size"] = max_udp_packet_size + end + + if ipstack_prefer ~= "" then + proxy["ip-version"] = ipstack_prefer == "v6first" and "ipv6-prefer" or "ipv4-prefer" + end + + local listen_port = tonumber(local_port) + local socks_listen = tonumber(socks_port) + + local doc = { + ["allow-lan"] = true, + ["bind-address"] = "0.0.0.0", + mode = "rule", + ["log-level"] = "silent", + ["find-process-mode"] = "off", + ["unified-delay"] = true, + ["tcp-concurrent"] = true, + ["routing-mark"] = 255, + proxies = { proxy }, + ["proxy-groups"] = { + { + name = "PROXY", + type = "select", + proxies = { sid } + } + }, + rules = { "MATCH,PROXY" }, + tun = { enable = false }, + profile = { + ["store-selected"] = true, + ["store-fake-ip"] = true + }, + dns = build_dns_section(dns_mode, nil, is_ext_dns) + } + + if mode == "socks" then + doc["socks-port"] = listen_port + else + doc["redir-port"] = listen_port + doc["tproxy-port"] = listen_port + if socks_listen and socks_listen > 0 then + doc["socks-port"] = socks_listen + end + end + + return doc end local function build_shadowsocks_runtime_doc(sid, local_port, socks_port, mode) - local dns_mode = uci:get_first("shadowsocksr", "global", "pdnsd_enable", "0") local server = get_server_field(sid, "server", "") local server_port = tonumber(get_server_field(sid, "server_port", "0")) or 0 local method = get_server_field(sid, "encrypt_method_ss", "none") local password = get_server_field(sid, "password", "") + local mode_str = tostring(dns_mode or "") + local is_ext_dns = (mode_str ~= "7") local proxy = { name = sid, type = "ss", @@ -1218,13 +1784,11 @@ local function build_shadowsocks_runtime_doc(sid, local_port, socks_port, mode) }, rules = { "MATCH,PROXY" }, tun = { enable = false }, - profile = { ["store-selected"] = true }, - dns = { - enable = dns_mode == "7", - ["enhanced-mode"] = "redir-host", - listen = "127.0.0.1:5335", - ipv6 = get_filter_aaaa() ~= "1" - } + profile = { + ["store-selected"] = true, + ["store-fake-ip"] = true + }, + dns = build_dns_section(dns_mode, nil, is_ext_dns) } local listen_port = tonumber(local_port) @@ -1242,32 +1806,8 @@ local function build_shadowsocks_runtime_doc(sid, local_port, socks_port, mode) return doc end -local function generate_shadowsocks_runtime(sid, output_path, local_port, socks_port, mode) - local doc = build_shadowsocks_runtime_doc(sid, local_port, socks_port, mode) - local ok, rendered = pcall(lyaml.dump, { doc }) - if not ok or not rendered then - io.stderr:write("dump_failed\n") - return false - end - write_file(output_path, rendered) - return true -end - -local function generate_v2ray_runtime(sid, output_path, local_port, socks_port, mode) - local proxy = build_v2ray_mihomo_proxy(sid) - if not proxy then - io.stderr:write("unsupported_or_invalid_v2ray_node\n") - return false - end - local doc = build_single_proxy_runtime_doc(proxy, local_port, socks_port, mode) - local ok, rendered = pcall(lyaml.dump, { doc }) - if not ok or not rendered then - io.stderr:write("dump_failed\n") - return false - end - write_file(output_path, rendered) - return true -end +-- ==================== 服务端文档构建函数 =========================================== +-- ==================== Server Document Construction Functions ==================== local function build_shadowsocks_server_doc(sid) local server_port = tonumber(get_server_field(sid, "server_port", "0")) or 0 @@ -1303,17 +1843,6 @@ local function build_shadowsocks_server_doc(sid) } end -local function generate_shadowsocks_server(sid, output_path) - local doc = build_shadowsocks_server_doc(sid) - local ok, rendered = pcall(lyaml.dump, { doc }) - if not ok or not rendered then - io.stderr:write("dump_failed\n") - return false - end - write_file(output_path, rendered) - return true -end - local function build_mihomo_listener_doc(sid) local ltype = get_server_field(sid, "type", "") local server_port = tonumber(get_server_field(sid, "server_port", "0")) or 0 @@ -1379,21 +1908,246 @@ local function build_mihomo_listener_doc(sid) } end +-- ==================== 生成配置函数 ============================================ +-- ==================== Configuration Generation Functions ==================== + +local function generate_tuic_runtime(sid, output_path, local_port, socks_port, mode) + local doc = build_tuic_runtime_doc(sid, local_port, socks_port, mode) + if not dump_yaml(output_path, doc) then + io.stderr:write("dump_failed\n") + return false + end + return true +end + +local function generate_shadowsocks_runtime(sid, output_path, local_port, socks_port, mode) + local doc = build_shadowsocks_runtime_doc(sid, local_port, socks_port, mode) + if not dump_yaml(output_path, doc) then + io.stderr:write("dump_failed\n") + return false + end + return true +end + +local function generate_v2ray_runtime(sid, output_path, local_port, socks_port, mode) + local proxy = build_v2ray_mihomo_proxy(sid) + if not proxy then + io.stderr:write("unsupported_or_invalid_v2ray_node\n") + return false + end + local doc = build_single_proxy_runtime_doc(proxy, local_port, socks_port, mode) + if not dump_yaml(output_path, doc) then + io.stderr:write("dump_failed\n") + return false + end + return true +end + +local function generate_shadowsocks_server(sid, output_path) + local doc = build_shadowsocks_server_doc(sid) + if not dump_yaml(output_path, doc) then + io.stderr:write("dump_failed\n") + return false + end + return true +end + local function generate_mihomo_listener(sid, output_path) local doc = build_mihomo_listener_doc(sid) if not doc then io.stderr:write("unsupported_listener\n") return false end - local ok, rendered = pcall(lyaml.dump, { doc }) - if not ok or not rendered then + if not dump_yaml(output_path, doc) then io.stderr:write("dump_failed\n") return false end - write_file(output_path, rendered) return true end +-- ==================== 主要功能函数 ====================================== +-- ==================== Main Functionality Functions ==================== + +local function prepare(input_path, output_path) + local doc, err = load_yaml(input_path) + if not doc then + io.stderr:write(err or "parse_failed", "\n") + return false + end + if not has_proxy_sections(doc) then + io.stderr:write("missing_proxy_sections\n") + return false + end + + local user_dns = nil + if type(doc.dns) == "table" and next(doc.dns) then + user_dns = clone_table(doc.dns) + end + + strip_runtime_conflicts(doc) + local filled_groups = fill_empty_proxy_groups(doc) + local stripped_rules = strip_incompatible_script_rules(doc) + + local dns_config = build_dns_section(dns_mode, user_dns, false) + if dns_config and next(dns_config) then + doc.dns = dns_config + end + + doc.rules = merge_rules_with_direct(doc.rules) + apply_sniffer_config(doc, enable_fake_ip) + + if doc["unified-delay"] == nil then + doc["unified-delay"] = true + end + if doc["tcp-concurrent"] == nil then + doc["tcp-concurrent"] = true + end + if doc["find-process-mode"] == nil then + doc["find-process-mode"] = "off" + end + + if not dump_yaml(output_path, doc) then + io.stderr:write("dump_failed\n") + return false + end + io.stdout:write(string.format("filled_groups=%d stripped_script_rules=%d\n", filled_groups, stripped_rules)) + return true +end + +local function merge(raw_path, overlay_path, output_path) + local raw_doc, raw_err = load_yaml(raw_path) + if not raw_doc then + io.stderr:write(raw_err or "parse_failed", "\n") + return false + end + + local overlay_doc, overlay_err = load_yaml(overlay_path) + if not overlay_doc then + io.stderr:write(overlay_err or "parse_failed", "\n") + return false + end + + local user_dns = nil + if type(raw_doc.dns) == "table" and next(raw_doc.dns) then + user_dns = clone_table(raw_doc.dns) + end + + strip_runtime_conflicts(raw_doc) + local filled_groups = fill_empty_proxy_groups(raw_doc) + local stripped_rules = strip_incompatible_script_rules(raw_doc) + + if user_dns then + if dns_mode ~= "7" then + overlay_doc.dns = nil + end + end + + local merged = deep_merge(raw_doc, overlay_doc) + if user_dns then + merged.dns = build_dns_section(dns_mode, user_dns, false) + elseif type(merged.dns) == "table" and next(merged.dns) then + merged.dns = build_dns_section(dns_mode, merged.dns, false) + else + merged.dns = build_dns_section(dns_mode, nil, false) + end + + merged.rules = merge_rules_with_direct(merged.rules) + apply_sniffer_config(merged, enable_fake_ip) + + if merged["unified-delay"] == nil then + merged["unified-delay"] = true + end + if merged["tcp-concurrent"] == nil then + merged["tcp-concurrent"] = true + end + if merged["find-process-mode"] == nil then + merged["find-process-mode"] = "off" + end + + if not dump_yaml(output_path, merged) then + io.stderr:write("dump_failed\n") + return false + end + io.stdout:write(string.format("filled_groups=%d stripped_script_rules=%d\n", filled_groups, stripped_rules)) + return true +end + +local function append_client_policy_rules(runtime_path, sid) + local doc, err = load_yaml(runtime_path) + if not doc then + io.stderr:write(err or "parse_failed", "\n") + return false + end + + local valid_policies = {} + for _, proxy in ipairs(doc.proxies or {}) do + if type(proxy) == "table" and proxy.name and proxy.name ~= "" then + valid_policies[tostring(proxy.name)] = true + end + end + for _, group in ipairs(doc["proxy-groups"] or {}) do + if type(group) == "table" and group.name and group.name ~= "" then + valid_policies[tostring(group.name)] = true + end + end + + local custom_rules = {} + for _, section in ipairs(read_clash_client_rules_csv(sid)) do + if tostring(section.enabled or "0") == "1" then + local ip_addr = tostring(section.ip_addr or "") + local policy_group = tostring(section.policy_group or "") + if ip_addr ~= "" and policy_group ~= "" and valid_policies[policy_group] then + if not ip_addr:find("/", 1, true) then + ip_addr = ip_addr .. "/32" + end + custom_rules[#custom_rules + 1] = string.format("SRC-IP-CIDR,%s,%s", ip_addr, policy_group) + end + end + end + + if #custom_rules == 0 then + io.stdout:write("client_rules=0\n") + return true + end + + local existing_rules = {} + for _, rule in ipairs(doc.rules or {}) do + local text = tostring(rule or "") + if not text:match("^SRC%-IP%-CIDR,") then + table.insert(existing_rules, rule) + end + end + + local new_rules = {} + local existing_set = {} + + for _, rule in ipairs(custom_rules) do + if not existing_set[rule] then + table.insert(new_rules, rule) + existing_set[rule] = true + end + end + + for _, rule in ipairs(existing_rules) do + if not existing_set[rule] then + table.insert(new_rules, rule) + existing_set[rule] = true + end + end + + doc.rules = merge_rules_with_direct(new_rules) + + if not dump_yaml(runtime_path, doc) then + io.stderr:write("dump_failed\n") + return false + end + io.stdout:write(string.format("client_rules=%d\n", #custom_rules)) + return true +end + +-- ==================== 命令行入口 ==================== +-- ==================== Command-line Entry Point ==================== + local action = arg[1] if action == "validate" then os.exit(validate(arg[2]) and 0 or 1) diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua index 75133640..4a5af864 100755 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua @@ -3,6 +3,7 @@ require "luci.sys" local ucursor = require "luci.model.uci".cursor() local json = require "luci.jsonc" +local datatypes = require "luci.cbi.datatypes" -- An omitted value reaches us either as a missing argument or as an empty -- string, depending on whether the caller quoted the expansion. Empty strings @@ -181,6 +182,62 @@ local function format_host_port(host, port) return host .. ":" .. tostring(port) end +local function format_dns_server(proxy) + if not proxy or proxy == "" then + return proxy + end + + local scheme, rest = proxy:match("^([a-zA-Z0-9%+%-%.]+)://(.+)$") + if scheme then + scheme = scheme:lower() + if scheme == "tls" or scheme == "dot" then + if not rest:match(":%d+$") then + rest = rest .. ":853" + end + return "tls://" .. rest + elseif scheme == "https" or scheme == "doh" or scheme == "dohl" or scheme == "doq" or scheme == "doql" then + local host, path = rest:match("^([^/]+)(.*)$") + host = host or rest + path = path or "" + if path == "" or path == "/" then + path = "/dns-query" + end + return "https://" .. host .. path + elseif scheme == "tcp" or scheme == "udp" then + if not rest:match(":%d+$") then + rest = rest .. ":53" + end + return scheme .. "://" .. rest + else + return proxy + end + end + + local host, port = proxy:match("^([^:]+):(%d+)$") + if host and port then + if port == "853" then + return "tls://" .. host .. ":853" + elseif port == "443" then + return "https://" .. host .. "/dns-query" + elseif port == "53" then + return host -- 53 端口输出纯 IP / Host (如 8.8.4.4) + else + return "udp://" .. host .. ":" .. port + end + end + + -- 确保包含字母,防止把 IP 当成域名 + if proxy:match("[a-zA-Z]") and not proxy:match("[^%w%.%-]") then + local path = "" + if not proxy:match("/") then + path = "/dns-query" + end + return "https://" .. proxy .. path + end + + return proxy +end + -- 确保正确判断程序是否存在 local function is_finded(e) return luci.sys.exec(string.format('type -t -p "%s" -p "/usr/libexec/%s" 2>/dev/null', e, e)) ~= "" @@ -391,31 +448,141 @@ local Xray = { } if server.type == "v2ray" and dns_mode == "7" and os.getenv("SSR_SWITCH_PROBE") ~= "1" then - local dns_host = builtin_dns_server:match("^([^:]+)") or "8.8.4.4" - local dns_port = tonumber(builtin_dns_server:match(":(%d+)$")) or 53 + local raw_servers_str = builtin_dns_server or "8.8.4.4:53" + local dns_servers = {} + local host_list = {} + local port_list = {} + local first_host = nil + local first_port = nil + + -- 按逗号或空格分割多个 DNS 地址 + for raw_server in string.gmatch(raw_servers_str, "[^,%s\r\n]+") do + if raw_server and raw_server ~= "" then + -- 1. 先进行格式化处理 + local formatted = format_dns_server(raw_server) + + local host = nil + local port = nil + + -- 2. 解析 host 和对应的实际端口 + if formatted:match("^https://") then + local target = formatted:match("^https://([^/]+)") + if target:match(":%d+$") then + host, port = target:match("^([^:]+):(%d+)$") + port = tonumber(port) + else + host = target + port = 443 + end + elseif formatted:match("^tls://") then + local target = formatted:match("^tls://([^/]+)") + if target:match(":%d+$") then + host, port = target:match("^([^:]+):(%d+)$") + port = tonumber(port) + else + host = target + port = 853 + end + elseif formatted:match("^tcp://") or formatted:match("^udp://") then + local target = formatted:match("^[a-zA-Z0-9%+%-%.]+://([^/]+)") + if target:match(":%d+$") then + host, port = target:match("^([^:]+):(%d+)$") + port = tonumber(port) + else + host = target + port = 53 + end + else + if formatted:match(":%d+$") then + host, port = formatted:match("^([^:]+):(%d+)$") + port = tonumber(port) + else + host = formatted + port = 53 + end + end + + -- 保存格式化后的 Xray.dns.servers 条目 + table.insert(dns_servers, formatted) + + -- 分别收集 Host 与 Port + if host and port then + table.insert(host_list, host) + table.insert(port_list, port) + -- 保存第一个 DNS 的 host 和 port + -- if not first_host then --dokodemo-door 入站的 address 单个地址使用。 + -- first_host = host --dokodemo-door 入站的 address 单个地址使用。 + -- first_port = port --dokodemo-door 入站的 address 单个地址使用。 + -- end + end + end + end + + -- 如果没有有效的 DNS 服务器,使用默认值 + if #dns_servers == 0 then + table.insert(dns_servers, "8.8.4.4") + table.insert(host_list, "8.8.4.4") + table.insert(port_list, 53) + -- first_host = "8.8.4.4" --dokodemo-door 入站的 address 单个地址使用。 + -- first_port = 53 --dokodemo-door 入站的 address 单个地址使用。 + end + + -- 构建 dns 出站地址(支持逗号分隔的多个地址) + -- 检查所有 DNS 端口是否一致 + --local outbound_address = "" --dokodemo-door 入站的 address 单个地址使用。 + local all_same_port = true + local common_port = port_list[1] + for i = 2, #port_list do + if port_list[i] ~= common_port then + all_same_port = false + break + end + end + + -- 根据端口一致性计算 address 与 target_port + local address_str = "" + local target_port = 0 + + if all_same_port then + -- outbound_address = table.concat(host_list, ",") --dokodemo-door 入站的 address 单个地址时使用。 + address_str = table.concat(host_list, ",") + target_port = common_port + else + local combined = {} + for i = 1, #host_list do + table.insert(combined, string.format("%s:%d", host_list[i], port_list[i])) + end + -- outbound_address = table.concat(combined, ",") --dokodemo-door 入站的 address 单个地址时使用。 + address_str = table.concat(combined, ",") + target_port = 0 + end + + -- 构建 Xray.dns 配置 Xray.dns = { queryStrategy = (dns_ipv4_only == "1") and "UseIPv4" or "UseIP", - servers = { - string.format("tcp://%s:%d", dns_host, dns_port) - } + servers = dns_servers } + -- 构建 dokodemo-door 入站 table.insert(Xray.inbounds, { listen = "127.0.0.1", port = 5335, protocol = "dokodemo-door", settings = { - address = dns_host, - port = dns_port, + address = address_str, + -- address = first_host, -- 单个地址 + port = target_port, + -- port = first_port, -- 对应端口 network = "tcp,udp" }, tag = "builtin-dns-in" }) - + xray_builtin_dns = { - address = dns_host, - port = dns_port + address = address_str, + -- address = outbound_address, --dokodemo-door 入站的 address 单个地址时使用。 + port = target_port } end -- 传入连接 diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/shadowsocksr.config b/luci-app-ssr-plus/root/usr/share/shadowsocksr/shadowsocksr.config index 819ce764..67c3af72 100644 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/shadowsocksr.config +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/shadowsocksr.config @@ -27,6 +27,9 @@ config server_subscribe option auto_update_week_time '*' option auto_update_day_time '2' option auto_update_min_time '0' + option enable_mihomo '1' + option enable_fake_ip '1' + option sub_convert '1' option url_test_url 'https://www.google.com/generate_204' option user_agent 'v2rayN/9.99' option filter_words '过期/重置/套餐/剩余/网址/QQ群/官网/防失联/回国' diff --git a/luci-app-syncthing/Makefile b/luci-app-syncthing/Makefile deleted file mode 100644 index 2219fcb2..00000000 --- a/luci-app-syncthing/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (C) 2020 Gyj1109 -# 适配 OpenWrt 25.12 修改版 - -include $(TOPDIR)/rules.mk - -PKG_NAME:=luci-app-syncthing -PKG_VERSION:=1.0 -PKG_RELEASE:=3 - -LUCI_TITLE:=LuCI support for Syncthing -LUCI_PKGARCH:=all -# 适配 25.12:确保安装了 syncthing 后,LuCI 界面能正确拉起 -LUCI_DEPENDS:=+syncthing - -include $(TOPDIR)/feeds/luci/luci.mk - -# 明确定义配置文件的归属,这对 25.12 的 apk 管理器非常重要 -define Package/$(PKG_NAME)/conffiles -/etc/config/syncthing -endef - -$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/luci-app-syncthing/README.md b/luci-app-syncthing/README.md deleted file mode 100644 index b07298c1..00000000 --- a/luci-app-syncthing/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# luci-app-syncthing -在Potat0000源码基础上进行了汉化优化,官方openwrt23.05.3编译后可使用 diff --git a/luci-app-syncthing/luasrc/controller/syncthing.lua b/luci-app-syncthing/luasrc/controller/syncthing.lua deleted file mode 100644 index ee2ca7ef..00000000 --- a/luci-app-syncthing/luasrc/controller/syncthing.lua +++ /dev/null @@ -1,17 +0,0 @@ -module("luci.controller.syncthing", package.seeall) - -function index() - if not nixio.fs.access("/etc/config/syncthing") then - return - end - - entry({"admin", "services", "syncthing"}, cbi("syncthing"), _("文件同步"), 10).dependent = true - entry({"admin", "services", "syncthing", "status"}, call("act_status")).leaf = true -end - -function act_status() - local e = {} - e.running = luci.sys.call("pgrep syncthing >/dev/null") == 0 - luci.http.prepare_content("application/json") - luci.http.write_json(e) -end diff --git a/luci-app-syncthing/luasrc/model/cbi/syncthing.lua b/luci-app-syncthing/luasrc/model/cbi/syncthing.lua deleted file mode 100644 index 324ea054..00000000 --- a/luci-app-syncthing/luasrc/model/cbi/syncthing.lua +++ /dev/null @@ -1,48 +0,0 @@ -require("nixio.fs") - -m = Map("syncthing", translate("Syncthing同步工具")) - -m:section(SimpleSection).template = "syncthing/syncthing_status" - -s = m:section(TypedSection, "syncthing") - -s.anonymous = true - -o = s:option(Flag, "enabled", translate("启用")) -o.default = 0 -o.rmempty = false - -gui_address = s:option(Value, "gui_address", translate("GUI访问地址")) -gui_address.description = translate("使用0.0.0.0以监控所有访问。") -gui_address.default = "http://0.0.0.0:8384" -gui_address.placeholder = "http://0.0.0.0:8384" -gui_address.rmempty = false - -home = s:option(Value, "home", translate("配置文件目录")) -home.description = translate("只有保存在/etc/syncthing中的配置会自动备份!") -home.default = "/etc/syncthing" -home.placeholder = "/etc/syncthing" -home.rmempty = false - -user = s:option(ListValue, "user", translate("用户")) -user.description = translate("默认是syncthing,但这可能会导致权限被拒绝。Syncthing官方不建议以root身份运行。") -user:value("", translate("syncthing")) -for u in luci.util.execi("cat /etc/passwd | cut -d ':' -f1") do - user:value(u) -end - -macprocs = s:option(Value, "macprocs", translate("线程限制")) -macprocs.description = translate("0表示匹配CPU数量(默认),>0表示显式指定并发数。") -macprocs.default = "0" -macprocs.placeholder = "0" -macprocs.datatype = "range(0,32)" -macprocs.rmempty = false - -nice = s:option(Value, "nice", translate("优先级")) -nice.description = translate("显式指定优先级值。0是最高,19是最低。(暂时不允许设置负值)") -nice.default = "19" -nice.placeholder = "19" -nice.datatype = "range(0,19)" -nice.rmempty = false - -return m diff --git a/luci-app-syncthing/luasrc/view/syncthing/syncthing_status.htm b/luci-app-syncthing/luasrc/view/syncthing/syncthing_status.htm deleted file mode 100644 index 566cc020..00000000 --- a/luci-app-syncthing/luasrc/view/syncthing/syncthing_status.htm +++ /dev/null @@ -1,27 +0,0 @@ - - -
      -

      - <%:正在收集数据...%> -

      -
      diff --git a/luci-app-syncthing/root/etc/uci-defaults/luci-syncthing b/luci-app-syncthing/root/etc/uci-defaults/luci-syncthing deleted file mode 100644 index 3adb7997..00000000 --- a/luci-app-syncthing/root/etc/uci-defaults/luci-syncthing +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -touch /etc/config/syncthing - -uci -q batch <<-EOF >/dev/null - delete ucitrack.@syncthing[-1] - add ucitrack syncthing - set ucitrack.@syncthing[-1].exec='/etc/init.d/syncthing stop && /etc/init.d/syncthing start' - commit ucitrack -EOF -# remove LuCI cache -rm -f /tmp/luci* -exit 0 diff --git a/luci-app-syncthing/root/usr/share/rpcd/acl.d/luci-app-syncthing.json b/luci-app-syncthing/root/usr/share/rpcd/acl.d/luci-app-syncthing.json deleted file mode 100644 index 9fc9cc54..00000000 --- a/luci-app-syncthing/root/usr/share/rpcd/acl.d/luci-app-syncthing.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "luci-app-syncthing": { - "description": "Grant UCI access for luci-app-syncthing", - "read": { - "uci": [ "syncthing" ] - }, - "write": { - "uci": [ "syncthing" ] - } - } -} diff --git a/v2raya/Makefile b/v2raya/Makefile index f7c2f207..1ba4c289 100644 --- a/v2raya/Makefile +++ b/v2raya/Makefile @@ -5,12 +5,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=v2rayA -PKG_VERSION:=2.4.18 +PKG_VERSION:=2.4.19 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/v2rayA/v2rayA/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=4799ba0212aa2681f501768d0b54e2bc77668b775e9fb0da4d1fc2a04253c550 +PKG_HASH:=dadf109788454fa10795974e780a0651431f9dfa5d163629766bff4ce36a7b27 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)/service PKG_LICENSE:=AGPL-3.0-only @@ -60,7 +60,7 @@ define Download/v2raya-web URL:=https://github.com/v2rayA/v2rayA/releases/download/v$(PKG_VERSION)/ URL_FILE:=web.tar.gz FILE:=$(WEB_FILE) - HASH:=df8f9d4dd79eac8ba5edb9ad1d816c11edca757b61cda8dd6f9763a39b76a170 + HASH:=b194bd1e0242d5e3b18fc60069b6560f924f3c14657ddf80953c098df96735ba endef define Build/Prepare