🐶 Sync 2026-05-01 20:23:08

This commit is contained in:
github-actions[bot] committed 2026-05-01 20:23:08 +08:00
1 parent 7baa6b7a60
commit 79374b95d9
44 files changed
+2280 -1514

No files matched your search

@@ -8,7 +8,7 @@ listen_port=$2
server_address=$3
server_port=$4
pgrep -af "${CONFIG}/" | awk '/app\.sh.*(start|stop)/ || /nftables\.sh/ || /iptables\.sh/ { found = 1 } END { exit !found }' && {
pgrep -af "${CONFIG}/" | grep -E 'app\.sh.*(start|stop)|nftables\.sh|iptables\.sh|subscribe\.lua' >/dev/null && {
exit 0
}
@@ -649,13 +649,9 @@ add_firewall_rule() {
ipset -! create $IPSET_LAN6 nethash family inet6 maxelem 1048576
ipset -! create $IPSET_VPS6 nethash family inet6 maxelem 1048576
ipset -! create $IPSET_WAN6 nethash family inet6 maxelem 1048576
ipset -! -R <<-EOF
$(ip address show | grep -w "inet" | awk '{print $2}' | awk -F '/' '{print $1}' | sed -e "s/^/add $IPSET_LOCAL /")
EOF
ipset -! -R <<-EOF
$(ip address show | grep -w "inet6" | awk '{print $2}' | awk -F '/' '{print $1}' | sed -e "s/^/add $IPSET_LOCAL6 /")
EOF
get_local_ips ip4 | sed "s/^/add $IPSET_LOCAL /" | ipset -! -R
get_local_ips ip6 | sed "s/^/add $IPSET_LOCAL6 /" | ipset -! -R
ipset -! -R <<-EOF
$(gen_lanlist | sed -e "s/^/add $IPSET_LAN /")
@@ -749,9 +745,9 @@ add_firewall_rule() {
$ipt_n -N PSW2_DNS
if [ $(config_t_get global dns_redirect "1") = "0" ]; then
#Only hijack when dest address is local IP
$ipt_n -I PREROUTING $(dst $IPSET_LOCAL) -j PSW2_DNS
$ipt_n -I PREROUTING -m set --match-set $IPSET_LAN src $(dst $IPSET_LOCAL) -j PSW2_DNS
else
$ipt_n -I PREROUTING -j PSW2_DNS
$ipt_n -I PREROUTING -m set --match-set $IPSET_LAN src -j PSW2_DNS
fi
$ipt_m -N PSW2_DIVERT
@@ -799,9 +795,9 @@ add_firewall_rule() {
$ip6t_n -N PSW2_DNS
if [ $(config_t_get global dns_redirect "1") = "0" ]; then
#Only hijack when dest address is local IP
$ip6t_n -I PREROUTING $(dst $IPSET_LOCAL6) -j PSW2_DNS
$ip6t_n -I PREROUTING -m set --match-set $IPSET_LAN6 src $(dst $IPSET_LOCAL6) -j PSW2_DNS
else
$ip6t_n -I PREROUTING -j PSW2_DNS
$ip6t_n -I PREROUTING -m set --match-set $IPSET_LAN6 src -j PSW2_DNS
fi
$ip6t_m -N PSW2_DIVERT
@@ -712,8 +712,8 @@ add_firewall_rule() {
gen_nftset $NFTSET_VPS6 ipv6_addr 0 "-1"
gen_nftset $NFTSET_WAN6 ipv6_addr 0 "-1"
ip address show | grep -w "inet" | awk '{print $2}' | awk -F '/' '{print $1}' | insert_nftset $NFTSET_LOCAL "-1"
ip address show | grep -w "inet6" | awk '{print $2}' | awk -F '/' '{print $1}' | insert_nftset $NFTSET_LOCAL6 "-1"
get_local_ips ip4 | insert_nftset $NFTSET_LOCAL "-1"
get_local_ips ip6 | insert_nftset $NFTSET_LOCAL6 "-1"
# Ignore special IP ranges
local lan_ifname lan_ip
@@ -786,10 +786,11 @@ add_firewall_rule() {
nft "flush chain $NFTABLE_NAME PSW2_DNS"
if [ $(config_t_get global dns_redirect "1") = "0" ]; then
#Only hijack when dest address is local IP
nft "insert rule $NFTABLE_NAME dstnat ip daddr @${NFTSET_LOCAL} jump PSW2_DNS"
nft "insert rule $NFTABLE_NAME dstnat ip6 daddr @${NFTSET_LOCAL6} jump PSW2_DNS"
nft "insert rule $NFTABLE_NAME dstnat ip saddr @${NFTSET_LAN} ip daddr @${NFTSET_LOCAL} jump PSW2_DNS"
nft "insert rule $NFTABLE_NAME dstnat ip6 saddr @${NFTSET_LAN6} ip6 daddr @${NFTSET_LOCAL6} jump PSW2_DNS"
else
nft "insert rule $NFTABLE_NAME dstnat jump PSW2_DNS"
nft "insert rule $NFTABLE_NAME dstnat ip saddr @${NFTSET_LAN} jump PSW2_DNS"
nft "insert rule $NFTABLE_NAME dstnat ip6 saddr @${NFTSET_LAN6} jump PSW2_DNS"
fi
# for ipv4 ipv6 tproxy mark
@@ -184,6 +184,34 @@ if geoip_update == "0" and geosite_update == "0" then
os.exit(0)
end
local function check_instance(action)
local rule_lock = "/var/lock/" .. name .. "_rule_update.lock"
local sub_lock = "/var/lock/" .. name .. "_subscribe.lock"
if action == "start" then
math.randomseed(os.time() + math.floor(os.clock() * 1000))
api.nixio.nanosleep(0, math.random(100, 1000) * 1000000)
if fs.access(rule_lock) then
log(0, api.i18n.translatef("[Rule update] instance is running; please try again later.") .. "\n")
os.exit(0)
else
luci.sys.call("touch " .. rule_lock)
end
elseif action == "end" then
luci.sys.call("rm -f " .. rule_lock)
return
end
if fs.access(sub_lock) then
log(0, api.i18n.translatef("[Subscription] instance is running; [Rule Update] queue and wait.") .. "\n")
end
while fs.access(sub_lock) do
api.nixio.nanosleep(2, 0)
end
end
check_instance("start")
log(0, api.i18n.translate("Start updating the rules..."))
local function safe_call(func, err_msg)
xpcall(func, function(e)
@@ -221,3 +249,5 @@ if reboot == 1 then
api.uci_save(uci, name, true, true)
end
log(0, api.i18n.translate("The rules have been updated..."))
check_instance("end")
@@ -5,6 +5,12 @@ APP_FILE=${APP_PATH}/app.sh
flag=0
check_process() {
while pgrep -af "${CONFIG}/" | grep -E 'app\.sh.*(start|stop)|nftables\.sh|iptables\.sh|subscribe\.lua' >/dev/null; do
sleep 6s
done
}
test_url() {
local url=$1
local try=1
@@ -48,6 +54,7 @@ test_node() {
local node_id=$1
local _type=$(echo $(config_n_get ${node_id} type) | tr 'A-Z' 'a-z')
[ -n "${_type}" ] && {
check_process
local _tmp_port=$(get_new_port 48800 tcp,udp)
NO_REC_PROCESS=1 $APP_FILE run_socks flag="test_node_${node_id}" node=${node_id} bind=127.0.0.1 socks_port=${_tmp_port} config_file=test_node_${node_id}.json
sleep 2s
@@ -92,6 +99,7 @@ test_auto_switch() {
if [ "$restore_switch" = "1" ] && [ -n "$main_node" ] && [ "$now_node" != "$main_node" ]; then
test_node ${main_node}
[ $? -eq 0 ] && {
check_process
# The main node is working properly; switch to the main node.
log_i18n 0 "Socks switch detection: Primary node 【%s: [%s]】 is normal. Switch to the primary node!" "${id}" "$(config_n_get $main_node type)" "$(config_n_get $main_node remarks)"
$APP_FILE socks_node_switch flag=${id} new_node=${main_node}
@@ -135,6 +143,7 @@ test_auto_switch() {
# [ -z "$(echo $b_nodes | grep $main_node)" ] && uci add_list $CONFIG.${id}.autoswitch_backup_node=$main_node
# uci commit $CONFIG
# }
check_process
log_i18n 0 "Socks switch detection: %s 【%s:[%s]】 normal, switch to this node!" "${id}" "$(config_n_get $new_node type)" "$(config_n_get $new_node remarks)"
$APP_FILE socks_node_switch flag=${id} new_node=${new_node}
[ $? -eq 0 ] && {
@@ -172,10 +181,7 @@ start() {
sleep 6s
continue
}
pgrep -af "${CONFIG}/" | awk '/app\.sh.*(start|stop)/ || /nftables\.sh/ || /iptables\.sh/ { found = 1 } END { exit !found }' && {
sleep 6s
continue
}
check_process
touch $LOCK_FILE
test_auto_switch "$backup_node"
rm -f $LOCK_FILE
@@ -23,7 +23,6 @@ local uci = api.uci
local fs = api.fs
local log = api.log
local i18n = api.i18n
uci:revert(appname)
local has_ss = api.is_finded("ss-redir")
local has_ss_rust = api.is_finded("sslocal")
@@ -301,7 +300,12 @@ do
currentNodes[#currentNodes + 1] = {
log = true,
node = node,
currentNode = node and uci:get_all(appname, node) or nil,
currentNode = (function()
if node and node:find("Socks_") then
return { Socks = node }
end
return node and uci:get_all(appname, node) or nil
end)(),
remarks = node,
set = function(o, server)
if o and server and server ~= "nil" then
@@ -325,7 +329,7 @@ do
-- Backup Node
local currentNode = uci:get_all(appname, node_id) or nil
if currentNode and currentNode.fallback_node then
if currentNode and currentNode.fallback_node and not currentNode.fallback_node:find("Socks_") then
CONFIG[#CONFIG + 1] = {
log = true,
id = node_id,
@@ -349,7 +353,12 @@ do
currentNodes[#currentNodes + 1] = {
log = true,
node = node,
currentNode = node and uci:get_all(appname, node) or nil,
currentNode = (function()
if node and node:find("Socks_") then
return { Socks = node }
end
return node and uci:get_all(appname, node) or nil
end)(),
remarks = node,
set = function(o, server)
if o and server and server ~= "nil" then
@@ -645,7 +654,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
if info.tls == "tls" or info.tls == "1" then
result.tls = "1"
result.tls_serverName = (info.sni and info.sni ~= "") and info.sni or info.host
result.tls_CertSha = info.pcs
result.tls_pinSHA256 = info.pcs
result.tls_CertByName = info.vcn
local insecure = info.allowinsecure or info.allowInsecure or info.insecure
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (sub_allowinsecure and "1" or "0")
@@ -915,7 +924,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.ech = "1"
result.ech_config = params.ech
end
result.tls_CertSha = params.pcs
result.tls_pinSHA256 = params.pcs
result.tls_CertByName = params.vcn
if params.security == "reality" then
result.reality = "1"
@@ -1028,7 +1037,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.tls = '1'
result.tls_serverName = params.peer or params.sni or ""
result.tls_CertSha = params.pcs
result.tls_pinSHA256 = params.pcs
result.tls_CertByName = params.vcn
local insecure = params.allowinsecure or params.allowInsecure or params.insecure
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (sub_allowinsecure and "1" or "0")
@@ -1271,7 +1280,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.ech = "1"
result.ech_config = params.ech
end
result.tls_CertSha = params.pcs
result.tls_pinSHA256 = params.pcs
result.tls_CertByName = params.vcn
if params.security == "reality" then
result.reality = "1"
@@ -1382,11 +1391,10 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.address = host_port
end
result.tls_serverName = params.sni
result.tls_CertSha = params.pcs
result.tls_pinSHA256 = params.pcs or params.pinsha256
result.tls_CertByName = params.vcn
local insecure = params.allowinsecure or params.insecure
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (sub_allowinsecure and "1" or "0")
result.hysteria2_tls_pinSHA256 = params.pinSHA256
result.hysteria2_hop = params.mport
if (sub_hysteria2_type == "sing-box" and has_singbox) or (sub_hysteria2_type == "xray" and has_xray) then
@@ -1608,9 +1616,9 @@ local function processData(szType, content, add_mode, group, sub_cfg)
end
local function curl(url, file, ua, mode)
if not url or url == "" then return 404 end
if not url or url == "" then return 22, 404 end
local curl_args = {
"-skL", "-w %{http_code}", "--retry 3", "--connect-timeout 3", "-H 'Accept-Encoding: identity'"
"-fskL", "-w %{http_code}", "--retry 3", "--connect-timeout 3", "-H 'Accept-Encoding: identity'"
}
if ua and ua ~= "" and ua ~= "curl" then
ua = (ua == "passwall2") and ("passwall2/" .. api.get_version()) or ua
@@ -1625,7 +1633,7 @@ local function curl(url, file, ua, mode)
else
return_code, result = api.curl_auto(url, file, curl_args)
end
return tonumber(result)
return return_code, tonumber(result)
end
function get_headers()
@@ -1733,6 +1741,10 @@ local function select_node(nodes, config, parentConfig)
end
if config.currentNode then
local server
-- Load balancing, keeping the original ID of the Socks [port] node in urltest.
if config.currentNode["Socks"] then
server = config.currentNode.Socks
end
-- Special priority: cfgid
if config.currentNode[".name"] then
for index, node in pairs(nodes) do
@@ -1945,7 +1957,6 @@ local function update_node(manual)
end
end
end
api.uci_save(uci, appname, true)
if next(CONFIG) then
local nodes = {}
@@ -1969,10 +1980,10 @@ local function update_node(manual)
select_node(nodes, config)
end
end
api.uci_save(uci, appname, true)
end
api.uci_save(uci, appname, true)
if arg[3] == "cron" then
if not fs.access("/var/lock/" .. appname .. ".lock") then
luci.sys.call("touch /tmp/lock/" .. appname .. "_cron.lock")
@@ -2111,8 +2122,9 @@ local execute = function()
local result = (not access_mode) and i18n.translatef("Auto") or (access_mode == "direct" and i18n.translatef("Direct") or (access_mode == "proxy" and i18n.translatef("Proxy") or i18n.translatef("Auto")))
log(1, i18n.translatef("Start subscribing: %s", '【' .. remark .. '】' .. url .. ' [' .. result .. ']'))
tmp_file = "/tmp/" .. cfgid
value.http_code = curl(url, tmp_file, ua, access_mode)
if value.http_code ~= 200 then
local return_code
return_code, value.http_code = curl(url, tmp_file, ua, access_mode)
if return_code ~= 0 then
fail_list[#fail_list + 1] = value
luci.sys.call("rm -f " .. tmp_file)
end
@@ -2151,7 +2163,36 @@ local execute = function()
end
end
local function check_instance(action)
local sub_lock = "/var/lock/" .. appname .. "_subscribe.lock"
local rule_lock = "/var/lock/" .. appname .. "_rule_update.lock"
if action == "start" then
math.randomseed(os.time() + math.floor(os.clock() * 1000))
api.nixio.nanosleep(0, math.random(100, 1000) * 1000000)
if fs.access(sub_lock) then
log(0, i18n.translatef("[Subscription] instance is running; please try again later.") .. "\n")
os.exit(0)
else
luci.sys.call("touch " .. sub_lock)
uci:revert(appname)
end
elseif action == "end" then
luci.sys.call("rm -f " .. sub_lock)
return
end
if fs.access(rule_lock) then
log(0, i18n.translatef("[Rule Update] instance is running; [Subscription] queue and wait.") .. "\n")
end
while fs.access(rule_lock) do
api.nixio.nanosleep(2, 0)
end
end
if arg[1] then
check_instance("start")
if arg[1] == "start" then
log(0, i18n.translatef("Start subscribing..."))
xpcall(execute, function(e)
@@ -2170,4 +2211,6 @@ if arg[1] then
elseif arg[1] == "truncate" then
truncate_nodes(arg[2])
end
check_instance("end")
end
@@ -484,3 +484,33 @@ get_wan_ips() {
done
echo "$NET_ADDR"
}
get_local_ips() {
local family="$1"
local ALL_IPS WAN_IPS ip NET_ADDR
if [ "$family" = "ip6" ]; then
ALL_IPS=$(ip -o -6 addr show scope global | awk '{print $4}' | cut -d/ -f1)
WAN_IPS=$(get_wan_ips ip6)
else
ALL_IPS=$(ip -o -4 addr show scope global | awk '{print $4}' | cut -d/ -f1)
WAN_IPS=$(get_wan_ips ip4)
fi
# Supplementary loop (not included in scope global)
[ "$family" = "ip6" ] && ALL_IPS="$ALL_IPS ::1"
[ "$family" != "ip6" ] && ALL_IPS="$ALL_IPS 127.0.0.1"
for ip in $ALL_IPS; do
case "$ip" in
""|0.0.0.0|::) continue ;;
esac
case " $WAN_IPS " in
*" $ip "*) continue ;;
esac
case " $NET_ADDR " in
*" $ip "*) ;;
*) NET_ADDR="${NET_ADDR:+$NET_ADDR }$ip" ;;
esac
done
for ip in $NET_ADDR; do
echo "$ip"
done
}