diff --git a/luci-app-passwall/luasrc/controller/passwall.lua b/luci-app-passwall/luasrc/controller/passwall.lua
index cc6c63ca..da4b8a40 100644
--- a/luci-app-passwall/luasrc/controller/passwall.lua
+++ b/luci-app-passwall/luasrc/controller/passwall.lua
@@ -59,6 +59,7 @@ function index()
entry({"admin", "services", appname, "server_user"}, cbi(appname .. "/server/user")).leaf = true
--[[ API ]]
+ entry({"admin", "services", appname, "server_user_update"}, call("server_user_update")).leaf = true
entry({"admin", "services", appname, "server_user_status"}, call("server_user_status")).leaf = true
entry({"admin", "services", appname, "server_user_log"}, call("server_user_log")).leaf = true
entry({"admin", "services", appname, "server_get_log"}, call("server_get_log")).leaf = true
@@ -730,6 +731,23 @@ function rollback_rules()
http_write_json_ok()
end
+function server_user_update()
+ local id = http.formvalue("id") -- Node id
+ local data = http.formvalue("data") -- json new Data
+ if id and data then
+ local data_t = jsonParse(data) or {}
+ if next(data_t) then
+ for k, v in pairs(data_t) do
+ uci:set(appname .. "_server", id, k, v)
+ end
+ api.uci_save(uci, appname .. "_server")
+ http_write_json_ok()
+ return
+ end
+ end
+ http_write_json_error()
+end
+
function server_user_status()
local e = {}
e.index = http.formvalue("index")
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua
index 6e39b1b3..9cbb3a9e 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua
@@ -14,6 +14,7 @@ formvalue_key = "cbid." .. appname .. "." .. arg[1] .. "."
local header = Template(appname .. "/node_config/header")
header.api = api
+header.config = m.config
header.section = arg[1]
m:append(header)
@@ -117,6 +118,7 @@ end
local footer = Template(appname .. "/node_config/footer")
footer.api = api
+footer.config = m.config
footer.section = arg[1]
m:append(footer)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/hysteria2.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/hysteria2.lua
index d015a8af..954ce7d3 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/hysteria2.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/hysteria2.lua
@@ -1,7 +1,5 @@
local m, s = ...
-local api = require "luci.passwall.api"
-
if not api.finded_com("hysteria") then
return
end
@@ -10,21 +8,24 @@ local fs = api.fs
local type_name = "Hysteria2"
+-- [[ Hysteria2 ]]
+
+s.fields["type"]:value(type_name, "Hysteria2")
+
+if s.val["type"] and s.val["type"] ~= type_name then
+ return
+end
+
local option_prefix = "hysteria2_"
local function _n(name)
return option_prefix .. name
end
--- [[ Hysteria2 ]]
-
-s.fields["type"]:value(type_name, "Hysteria2")
-
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port"
-o.rmempty = false
o:depends({ [_n("custom")] = false })
o = s:option(Flag, _n("realms"), translate("Realms"))
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua
index f2545104..437f11c7 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua
@@ -1,15 +1,22 @@
local m, s = ...
-local api = require "luci.passwall.api"
-
if not api.finded_com("xray") then
return
end
-local fs = api.fs
-
local type_name = "Xray"
+-- [[ Xray ]]
+
+s.fields["type"]:value(type_name, "Xray")
+if not s.fields["type"].default then
+ s.fields["type"].default = type_name
+end
+
+if s.val["type"] and s.val["type"] ~= type_name then
+ return
+end
+
local option_prefix = "xray_"
local function _n(name)
@@ -24,10 +31,6 @@ local header_type_list = {
"none", "srtp", "utp", "wechat-video", "dtls", "wireguard", "dns"
}
--- [[ Xray ]]
-
-s.fields["type"]:value(type_name, "Xray")
-
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(ListValue, _n("protocol"), translate("Protocol"))
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua
index ce5766fc..c7ecb2ec 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua
@@ -1,34 +1,37 @@
local m, s = ...
-local api = require "luci.passwall.api"
-
local singbox_bin = api.finded_com("sing-box")
if not singbox_bin then
return
end
-local fs = api.fs
-
-local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'")
-
local type_name = "sing-box"
+-- [[ Sing-Box ]]
+
+s.fields["type"]:value(type_name, "Sing-Box")
+if not s.fields["type"].default then
+ s.fields["type"].default = type_name
+end
+
+if s.val["type"] and s.val["type"] ~= type_name then
+ return
+end
+
local option_prefix = "singbox_"
local function _n(name)
return option_prefix .. name
end
+local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'")
+
local ss_method_list = {
"none", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305",
"2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
}
--- [[ Sing-Box ]]
-
-s.fields["type"]:value(type_name, "Sing-Box")
-
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(ListValue, _n("protocol"), translate("Protocol"))
@@ -55,7 +58,6 @@ o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port"
-o.rmempty = false
o:depends({ [_n("custom")] = false })
o = s:option(Flag, _n("auth"), translate("Auth"))
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/socks.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/socks.lua
index 82cd0524..bfb00061 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/socks.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/socks.lua
@@ -1,7 +1,5 @@
local m, s = ...
-local api = require "luci.passwall.api"
-
if not api.is_finded("microsocks") then
return
end
@@ -17,6 +15,13 @@ end
-- [[ microsocks ]]
s.fields["type"]:value(type_name, "Socks")
+if not s.fields["type"].default then
+ s.fields["type"].default = type_name
+end
+
+if s.val["type"] and s.val["type"] ~= type_name then
+ return
+end
o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port"
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ss-rust.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ss-rust.lua
index e3ea0652..ed2a2863 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ss-rust.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ss-rust.lua
@@ -1,13 +1,19 @@
local m, s = ...
-local api = require "luci.passwall.api"
-
if not api.is_finded("ssserver") then
return
end
local type_name = "SS-Rust"
+-- [[ Shadowsocks Rust ]]
+
+s.fields["type"]:value(type_name, translate("Shadowsocks Rust"))
+
+if s.val["type"] and s.val["type"] ~= type_name then
+ return
+end
+
local option_prefix = "ssrust_"
local function _n(name)
@@ -20,10 +26,6 @@ local ssrust_encrypt_method_list = {
"2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
}
--- [[ Shadowsocks Rust ]]
-
-s.fields["type"]:value(type_name, translate("Shadowsocks Rust"))
-
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(Value, _n("port"), translate("Listen Port"))
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ssr.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ssr.lua
index 45fb79d2..02a94f61 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ssr.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ssr.lua
@@ -1,13 +1,19 @@
local m, s = ...
-local api = require "luci.passwall.api"
-
if not api.is_finded("ssr-server") then
return
end
local type_name = "SSR"
+-- [[ ShadowsocksR ]]
+
+s.fields["type"]:value(type_name, translate("ShadowsocksR"))
+
+if s.val["type"] and s.val["type"] ~= type_name then
+ return
+end
+
local option_prefix = "ssr_"
local function _n(name)
@@ -33,10 +39,6 @@ local ssr_obfs_list = {
"tls1.0_session_auth", "tls1.2_ticket_auth"
}
--- [[ ShadowsocksR ]]
-
-s.fields["type"]:value(type_name, translate("ShadowsocksR"))
-
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(Value, _n("port"), translate("Listen Port"))
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/user.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/user.lua
index 2d5a9bba..35312f53 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/user.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/user.lua
@@ -1,7 +1,6 @@
-local api = require "luci.passwall.api"
-local appname = api.appname
-local fs = api.fs
-local types_dir = "/usr/lib/lua/luci/model/cbi/" .. appname .. "/server/type/"
+api = require "luci.passwall.api"
+appname = api.appname
+fs = api.fs
m = Map("passwall_server", translate("Server Config"))
m.redirect = api.url("server")
@@ -11,12 +10,21 @@ if not arg[1] or not m:get(arg[1]) then
luci.http.redirect(m.redirect)
end
+local header = Template(appname .. "/server/config_header")
+header.api = api
+header.config = m.config
+header.section = arg[1]
+m:append(header)
+
m:append(Template(appname .. "/cbi/nodes_listvalue_com"))
s = m:section(NamedSection, arg[1], "user", "")
s.addremove = false
s.dynamic = false
+local types_dir = "/usr/lib/lua/luci/model/cbi/" .. appname .. "/server/type/"
+s.val = m:get(arg[1]) or {}
+
o = s:option(Flag, "enable", translate("Enable"))
o.default = "1"
o.rmempty = false
@@ -32,9 +40,9 @@ for filename in fs.dir(types_dir) do
table.insert(type_table, filename)
end
table.sort(type_table, function(a, b)
- if a == "socks.lua" then return true end
- if b == "socks.lua" then return false end
- return a < b
+ if a == "socks.lua" then return true end
+ if b == "socks.lua" then return false end
+ return a < b
end)
for index, value in ipairs(type_table) do
@@ -42,4 +50,10 @@ for index, value in ipairs(type_table) do
setfenv(p_func, getfenv(1))(m, s)
end
+local footer = Template(appname .. "/server/config_footer")
+footer.api = api
+footer.config = m.config
+footer.section = arg[1]
+m:append(footer)
+
return m
diff --git a/luci-app-passwall/luasrc/passwall/api.lua b/luci-app-passwall/luasrc/passwall/api.lua
index ebde80e4..fb54b982 100644
--- a/luci-app-passwall/luasrc/passwall/api.lua
+++ b/luci-app-passwall/luasrc/passwall/api.lua
@@ -1293,6 +1293,11 @@ function to_check_self()
end
function luci_types(id, m, s, type_name, option_prefix)
+ local fv_type
+ local field_type = s.fields["type"]
+ if field_type then
+ fv_type = field_type:formvalue(id)
+ end
local rewrite_option_table = {}
for key, value in pairs(s.fields) do
if key:find(option_prefix) == 1 then
@@ -1361,6 +1366,10 @@ function luci_types(id, m, s, type_name, option_prefix)
else
s.fields[key]:depends({ type = type_name })
end
+
+ if fv_type and fv_type ~= type_name then
+ s.fields[key].rmempty = true
+ end
end
end
end
diff --git a/luci-app-passwall/luasrc/view/passwall/node_config/footer.htm b/luci-app-passwall/luasrc/view/passwall/node_config/footer.htm
index 4cb26731..7a16884f 100644
--- a/luci-app-passwall/luasrc/view/passwall/node_config/footer.htm
+++ b/luci-app-passwall/luasrc/view/passwall/node_config/footer.htm
@@ -4,7 +4,7 @@ local api = self.api
diff --git a/luci-app-passwall/luasrc/view/passwall/server/config_header.htm b/luci-app-passwall/luasrc/view/passwall/server/config_header.htm
new file mode 100644
index 00000000..1957dec4
--- /dev/null
+++ b/luci-app-passwall/luasrc/view/passwall/server/config_header.htm
@@ -0,0 +1,56 @@
+<%
+local api = self.api
+-%>
+
diff --git a/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua b/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua
index 79430d37..7db25438 100644
--- a/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua
+++ b/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua
@@ -1322,7 +1322,7 @@ function act_ping()
if not e.ping then
local icmp_cmd = string.format("ping -c 1 -W 1 %s 2>/dev/null | grep -o 'time=[0-9.]*' | cut -d= -f2", domain)
- e.ping = tonumber(luci.sys.exec(icmp_cmd))
+ e.ping = normalize_ping_ms(tonumber(luci.sys.exec(icmp_cmd)))
end
if not e.ping then
e.ping = 0
@@ -1332,7 +1332,7 @@ function act_ping()
local result = ""
local success = false
local icmp_cmd = string.format("ping -c 1 -W 1 %s 2>/dev/null | grep -o 'time=[0-9.]*' | cut -d= -f2", domain)
- e.ping = tonumber(luci.sys.exec(icmp_cmd))
+ e.ping = normalize_ping_ms(tonumber(luci.sys.exec(icmp_cmd)))
-- WebSocket 探测 (适用于域名,或带 SNI 的 IP)
if not is_ip or probe_host ~= domain then
local resolve_arg = ""
@@ -1403,7 +1403,7 @@ function act_ping()
end
if not e.ping then
local icmp_cmd = string.format("ping -c 1 -W 1 %s 2>/dev/null | grep -o 'time=[0-9.]*' | cut -d= -f2", domain)
- e.ping = tonumber(luci.sys.exec(icmp_cmd))
+ e.ping = normalize_ping_ms(tonumber(luci.sys.exec(icmp_cmd)))
end
if not e.ping then
@@ -1453,10 +1453,6 @@ function act_ping()
})
end
- if e.ping then
- e.ping = math.floor(e.ping + 0.5)
- end
-
luci.http.prepare_content("application/json")
luci.http.write_json(e)
end
diff --git a/luci-app-ssr-plus/root/etc/init.d/shadowsocksr b/luci-app-ssr-plus/root/etc/init.d/shadowsocksr
index b4cafdcc..1970fa94 100755
--- a/luci-app-ssr-plus/root/etc/init.d/shadowsocksr
+++ b/luci-app-ssr-plus/root/etc/init.d/shadowsocksr
@@ -2271,16 +2271,41 @@ start() {
echolog "禁止连接的域名加载完毕。"
if [ "$(uci_get_by_type global adblock 0)" == "1" ]; then
echolog "未启动主节点,广告过滤正在加载。"
- cp -f /etc/ssrplus/ad.conf $TMP_DNSMASQ_PATH/
+ cp -f /etc/ssrplus/ad.conf "$TMP_DNSMASQ_PATH/"
if [ -f "$TMP_DNSMASQ_PATH/ad.conf" ]; then
# Optimize: Batch filter using grep instead of looping sed
for list_file in /etc/ssrplus/black.list /etc/ssrplus/white.list /etc/ssrplus/deny.list; do
if [ -s "$list_file" ]; then
# Clean list file (remove comments and empty lines)
- grep -vE '^\s*#|^\s*$' "$list_file" > "${list_file}.clean"
+ grep -vE '^\s*#|^\s*$' "$list_file" | sed 's/\r//g' > "${list_file}.clean"
if [ -s "${list_file}.clean" ]; then
- grep -v -F -f "${list_file}.clean" "$TMP_DNSMASQ_PATH/ad.conf" > "$TMP_DNSMASQ_PATH/ad.conf.tmp"
- mv "$TMP_DNSMASQ_PATH/ad.conf.tmp" "$TMP_DNSMASQ_PATH/ad.conf"
+ tmp_file="$TMP_DNSMASQ_PATH/ad.conf.tmp"
+ awk -v list="${list_file}.clean" '
+ BEGIN {
+ while ((getline line < list) > 0) {
+ gsub(/\r/, "", line)
+ if (line != "") {
+ domain[line] = 1
+ # 支持泛域名
+ domain["*." line] = 1
+ }
+ }
+ close(list)
+ }
+ {
+ keep = 1
+ # 匹配 server=/domain/
+ if (match($0, /^server=\/([^\/]+)\//, m)) {
+ if (m[1] in domain) keep = 0
+ }
+ # 匹配 ipset=/domain/
+ if (match($0, /^ipset=\/([^\/]+)\//, m)) {
+ if (m[1] in domain) keep = 0
+ }
+ if (keep) print
+ }
+ ' "$TMP_DNSMASQ_PATH/ad.conf" > "$tmp_file"
+ mv "$tmp_file" "$TMP_DNSMASQ_PATH/ad.conf"
fi
rm -f "${list_file}.clean"
fi
diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gfw2ipset.sh b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gfw2ipset.sh
index e3a405d7..fa168826 100755
--- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gfw2ipset.sh
+++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gfw2ipset.sh
@@ -45,13 +45,37 @@ done
# Optimize: Batch filter using grep
for list_file in /etc/ssrplus/black.list /etc/ssrplus/white.list /etc/ssrplus/deny.list; do
if [ -s "$list_file" ]; then
- grep -vE '^\s*#|^\s*$' "$list_file" > "${list_file}.clean"
+ # 清理注释和空行
+ grep -vE '^\s*#|^\s*$' "$list_file" | sed 's/\r//g' > "${list_file}.clean"
if [ -s "${list_file}.clean" ]; then
for target_file in "$TMP_DNSMASQ_PATH/gfw_list.conf" "$TMP_DNSMASQ_PATH/gfw_base.conf"; do
- if [ -f "$target_file" ]; then
- grep -v -F -f "${list_file}.clean" "$target_file" > "${target_file}.tmp"
- mv "${target_file}.tmp" "$target_file"
- fi
+ [ -f "$target_file" ] || continue
+ tmp_file="${target_file}.tmp"
+ awk -v list="${list_file}.clean" '
+ BEGIN {
+ while ((getline line < list) > 0) {
+ gsub(/\r/, "", line)
+ if (line != "") {
+ domain[line] = 1
+ # 同时支持 *.domain
+ domain["*." line] = 1
+ }
+ }
+ close(list)
+ }
+ {
+ # 提取 server=/domain/xxx
+ if (match($0, /^server=\/([^\/]+)\//, m)) {
+ if (m[1] in domain) next
+ }
+ # 提取 ipset=/domain/xxx
+ if (match($0, /^ipset=\/([^\/]+)\//, m)) {
+ if (m[1] in domain) next
+ }
+ print
+ }
+ ' "$target_file" > "$tmp_file"
+ mv "$tmp_file" "$target_file"
done
fi
rm -f "${list_file}.clean"
@@ -69,19 +93,45 @@ fi
cat /etc/ssrplus/deny.list | sed '/^$/d' | sed '/#/d' | sed "/.*/s/.*/address=\/&\//" >$TMP_DNSMASQ_PATH/denylist.conf
if [ "$(uci_get_by_type global adblock 0)" == "1" ]; then
- cp -f /etc/ssrplus/ad.conf $TMP_DNSMASQ_PATH/
+ cp -f /etc/ssrplus/ad.conf "$TMP_DNSMASQ_PATH/"
if [ -f "$TMP_DNSMASQ_PATH/ad.conf" ]; then
for list_file in /etc/ssrplus/black.list /etc/ssrplus/white.list /etc/ssrplus/deny.list; do
if [ -s "$list_file" ]; then
- grep -vE '^\s*#|^\s*$' "$list_file" > "${list_file}.clean"
+ # 清理注释 & 空行
+ grep -vE '^\s*#|^\s*$' "$list_file" | sed 's/\r//g' > "${list_file}.clean"
if [ -s "${list_file}.clean" ]; then
- grep -v -F -f "${list_file}.clean" "$TMP_DNSMASQ_PATH/ad.conf" > "$TMP_DNSMASQ_PATH/ad.conf.tmp"
- mv "$TMP_DNSMASQ_PATH/ad.conf.tmp" "$TMP_DNSMASQ_PATH/ad.conf"
+ tmp_file="$TMP_DNSMASQ_PATH/ad.conf.tmp"
+ awk -v list="${list_file}.clean" '
+ BEGIN {
+ while ((getline line < list) > 0) {
+ gsub(/\r/, "", line)
+ if (line != "") {
+ domain[line] = 1
+ # 支持泛域名
+ domain["*." line] = 1
+ }
+ }
+ close(list)
+ }
+ {
+ keep = 1
+ # 精确匹配 server=/domain/
+ if (match($0, /^server=\/([^\/]+)\//, m)) {
+ if (m[1] in domain) keep = 0
+ }
+ # 精确匹配 ipset=/domain/
+ if (match($0, /^ipset=\/([^\/]+)\//, m)) {
+ if (m[1] in domain) keep = 0
+ }
+ if (keep) print
+ }
+ ' "$TMP_DNSMASQ_PATH/ad.conf" > "$tmp_file"
+ mv "$tmp_file" "$TMP_DNSMASQ_PATH/ad.conf"
fi
rm -f "${list_file}.clean"
fi
done
fi
else
- rm -f $TMP_DNSMASQ_PATH/ad.conf
+ rm -f "$TMP_DNSMASQ_PATH/ad.conf"
fi