🏅 Sync 2026-10-10 12:03:15

This commit is contained in:
github-actions[bot] committed 2026-10-10 12:03:15 +08:00
1 parent ad68a3cd65
commit f080de4b89
109 files changed
+72311 -621

No files matched your search

+2 -1
View File
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall
PKG_VERSION:=26.10.4
PKG_RELEASE:=323
PKG_RELEASE:=325
PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \
@@ -66,6 +66,7 @@ config PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy
select PACKAGE_iptables
select PACKAGE_iptables-zz-legacy
select PACKAGE_iptables-mod-conntrack-extra
select PACKAGE_iptables-mod-extra
select PACKAGE_iptables-mod-iprange
select PACKAGE_iptables-mod-socket
select PACKAGE_iptables-mod-tproxy
+83 -6
View File
@@ -4,6 +4,7 @@ c_config = "passwall"
s_config = "passwall_server"
local com = require "luci.passwall.com"
nixio = require "nixio"
require "nixio.util"
fs = require "nixio.fs"
sys = require "luci.sys"
uci = require "luci.model.uci".cursor()
@@ -14,6 +15,7 @@ i18n = require "luci.i18n"
curl_args = { "-skfL", "--connect-timeout 3", "--retry 3", "-H 'Accept: */*'" }
command_timeout = 300
DIRECT_GID = 9911
OPENWRT_ARCH = nil
DISTRIB_ARCH = nil
OPENWRT_BOARD = nil
@@ -195,6 +197,30 @@ function exec_call(cmd)
return tonumber(rc), trim(out)
end
function exec_call_as_gid(cmd, gid)
local reader, writer = nixio.pipe()
if not reader then return 255, "Unable to create command pipe" end
local pid = nixio.fork()
if not pid then
reader:close()
writer:close()
return 255, "Unable to fork command"
elseif pid == 0 then
reader:close()
nixio.dup(writer, nixio.stdout)
nixio.dup(writer, nixio.stderr)
writer:close()
if not nixio.setgid(gid) then os.exit(1) end
nixio.exec("/bin/sh", "-c", cmd)
os.exit(127)
end
writer:close()
local out = reader:readall() or ""
reader:close()
local _, status, code = nixio.waitpid(pid)
return status == "exited" and code or 255, trim(out)
end
function base64Decode(text)
if type(text) ~= "string" then return "" end
local encoded = text:gsub("%z", ""):gsub("%c", ""):gsub("_", "/"):gsub("-", "+"):gsub("=+$", "")
@@ -261,12 +287,38 @@ function get_domain_port_from_url(url)
return domain, port
end
function curl_base(url, file, args)
function resolve_domain(domain, dns)
dns = dns or get_cache_var("LOCAL_DNS") or "223.5.5.5"
local address, port = dns:match("^(.-)#(%d+)$")
if not address then address, port = dns:match("^%[(.-)%]:(%d+)$") end
if not address then address, port = dns:match("^([^:]+):(%d+)$") end
address = (address or dns):gsub("^%[(.-)%]$", "%1")
port = port or "53"
local server = datatypes.ip6addr(address) and ("[" .. address .. "]") or address
local rc, result
for _, dns_server in ipairs({server .. ":" .. port, address .. "#" .. port, "223.5.5.5"}) do
rc, result = exec_call_as_gid("LC_ALL=C nslookup " .. util.shellquote(domain) .. " " .. util.shellquote(dns_server), DIRECT_GID)
local ips, seen, answer = {}, {}, false
for line in result:gmatch("[^\r\n]+") do
if line:match("^%s*Name:") then answer = true end
local ip = answer and line:match("^%s*Address%s*%d*:%s*(%S+)")
if ip and (datatypes.ip4addr(ip) or datatypes.ip6addr(ip)) and not seen[ip] then
ips[#ips + 1] = ip
seen[ip] = true
end
end
if #ips > 0 then return ips end
end
return nil, result, rc
end
function curl_base(url, file, args, gid)
if not args then args = {} end
if file then
args[#args + 1] = "-o " .. file
end
local cmd = string.format('curl %s "%s"', table_join(args), url)
if gid then return exec_call_as_gid(cmd, gid) end
return exec_call(cmd)
end
@@ -285,11 +337,36 @@ end
function curl_logic(url, file, args)
local return_code, result = curl_proxy(url, file, args)
if not return_code or return_code ~= 0 then
return_code, result = curl_base(url, file, args)
return_code, result = curl_direct(url, file, args)
end
return return_code, result
end
function curl_direct(url, file, args)
if get_cache_var("ENABLED_DEFAULT_ACL") ~= "1" and get_cache_var("ENABLED_ACLS") ~= "1" then
return curl_base(url, file, args)
end
local tmp_args = clone(args or {})
tmp_args[#tmp_args + 1] = "--noproxy '*'"
local domain, port = get_domain_port_from_url(url)
if domain then
local ips, err = resolve_domain(domain)
if not ips then return 6, err end
for i, ip in ipairs(ips) do
if datatypes.ip6addr(ip) then ips[i] = "[" .. ip .. "]" end
end
tmp_args[#tmp_args + 1] = "--resolve " .. util.shellquote(domain .. ":" .. port .. ":" .. table.concat(ips, ","))
end
return curl_base(url, file, tmp_args, DIRECT_GID)
end
function curl_auto(url, file, args)
if (uci_get_c("@global[0]", "localhost_proxy") or "1") == "1" then
return curl_base(url, file, args)
end
return curl_logic(url, file, args)
end
function url(...)
local url = string.format("admin/services/%s", appname)
local args = { ... }
@@ -1103,9 +1180,9 @@ local function get_api_json(url)
local return_code, content
if gh_proxy ~= "" then
url = gh_proxy .. url
return_code, content = curl_base(url, nil, curl_args)
return_code, content = curl_direct(url, nil, curl_args)
else
return_code, content = curl_logic(url, nil, curl_args)
return_code, content = curl_auto(url, nil, curl_args)
end
if return_code ~= 0 or content == "" then return {} end
return jsonc.parse(content) or {}
@@ -1233,9 +1310,9 @@ function to_download(app_name, url, size, task_id, keep_files)
local return_code, result
if gh_proxy ~= "" then
url = gh_proxy .. url
return_code, result = curl_base(url, tmp_file, _curl_args)
return_code, result = curl_direct(url, tmp_file, _curl_args)
else
return_code, result = curl_logic(url, tmp_file, _curl_args)
return_code, result = curl_auto(url, tmp_file, _curl_args)
end
result = return_code == 0
+1 -1
View File
@@ -3,7 +3,7 @@
START=99
STOP=15
if [ -z "$IPKG_INSTROOT" ]; then
if [ -z "$IPKG_INSTROOT" ] && [ -f /usr/share/passwall/utils.sh ]; then
. /usr/share/passwall/utils.sh
APP_FILE=${APP_PATH}/app.sh
LOCK_FILE=${LOCK_PATH}/${CONFIG}.lock
@@ -51,7 +51,7 @@ check_run_environment() {
[ -d "/lib/apk/packages" ] && { file_path="/lib/apk/packages"; file_ext=".list"; }
if [ "$USE_TABLES" = "iptables" ]; then
dep_list="iptables-mod-tproxy iptables-mod-socket iptables-mod-iprange iptables-mod-conntrack-extra kmod-ipt-nat"
dep_list="iptables-mod-tproxy iptables-mod-socket iptables-mod-iprange iptables-mod-conntrack-extra iptables-mod-extra kmod-ipt-nat"
else
dep_list="kmod-nft-socket kmod-nft-tproxy kmod-nft-nat kmod-nf-reject kmod-nf-reject6"
nftflag=1
@@ -150,9 +150,8 @@ run_singbox() {
direct_dns_port=$(echo ${direct_dns_tcp_server} | awk -F '#' '{print $2}')
json_add_string "direct_dns_tcp_server" "$(echo ${direct_dns_tcp_server} | awk -F '#' '{print $1}')"
else
local local_dns=$(echo -n $(echo "${LOCAL_DNS}" | sed "s/,/\n/g" | head -n1) | tr " " ",")
json_add_string "direct_dns_udp_server" "$(echo ${local_dns} | awk -F '#' '{print $1}')"
direct_dns_port=$(echo ${local_dns} | awk -F '#' '{print $2}')
json_add_string "direct_dns_udp_server" "$(echo ${LOCAL_DNS} | awk -F '#' '{print $1}')"
direct_dns_port=$(echo ${LOCAL_DNS} | awk -F '#' '{print $2}')
fi
json_add_string "direct_dns_port" "${direct_dns_port:-53}"
direct_dns_query_strategy=${direct_dns_query_strategy:-UseIP}
@@ -259,9 +258,8 @@ run_xray() {
direct_dns_port=$(echo ${direct_dns_tcp_server} | awk -F '#' '{print $2}')
json_add_string "direct_dns_tcp_server" "$(echo ${direct_dns_tcp_server} | awk -F '#' '{print $1}')"
else
local local_dns=$(echo -n $(echo "${LOCAL_DNS}" | sed "s/,/\n/g" | head -n1) | tr " " ",")
json_add_string "direct_dns_udp_server" "$(echo ${local_dns} | awk -F '#' '{print $1}')"
direct_dns_port=$(echo ${local_dns} | awk -F '#' '{print $2}')
json_add_string "direct_dns_udp_server" "$(echo ${LOCAL_DNS} | awk -F '#' '{print $1}')"
direct_dns_port=$(echo ${LOCAL_DNS} | awk -F '#' '{print $2}')
fi
json_add_string "direct_dns_port" "${direct_dns_port:-53}"
@@ -1095,7 +1093,7 @@ start_adblock() {
start_dns() {
echolog "DNS域名解析:"
local china_ng_local_dns=$(IFS=','; set -- $LOCAL_DNS; [ "${1%%[#:]*}" = "127.0.0.1" ] && echo "$1" || ([ -n "$2" ] && echo "$*" || echo "$1"))
local china_ng_local_dns="${LOCAL_DNS}"
local v2ray_local_dns
local direct_dns_mode=$(config_n_get @global[0] direct_dns_mode "auto")
@@ -1112,6 +1110,7 @@ start_dns() {
case "$direct_dns_mode" in
udp)
LOCAL_DNS=$(normalize_dns "$(config_n_get @global[0] direct_dns 223.5.5.5:53)")
set_cache_var "LOCAL_DNS" "$LOCAL_DNS"
china_ng_local_dns=${LOCAL_DNS}
v2ray_local_dns="direct_dns_udp_server=${LOCAL_DNS}"
;;
@@ -1123,6 +1122,7 @@ start_dns() {
#当全局(包括访问控制节点)开启chinadns-ng时,不启动新进程。
[ "$DNS_SHUNT" != "chinadns-ng" ] || [ "$ACL_RULE_DNSMASQ" = "1" ] && {
LOCAL_DNS="127.0.0.1#${NEXT_DNS_LISTEN_PORT}"
set_cache_var "LOCAL_DNS" "$LOCAL_DNS"
ln_run "$(first_type chinadns-ng)" chinadns-ng "/dev/null" -b :: -l ${NEXT_DNS_LISTEN_PORT} -c ${china_ng_local_dns} -d chn
echolog " - ChinaDNS-NG(${LOCAL_DNS}) -> ${china_ng_local_dns}"
echolog " * 请确保上游直连 DNS 支持 TCP 查询。"
@@ -1140,6 +1140,7 @@ start_dns() {
[ -z "$1" ] && echo "" || echo "$1" | awk -F',' '{for(i=1;i<=NF;i++){if($i !~ /#/) $i=$i"#53";} print $0;}' OFS=','
}
LOCAL_DNS=$(add_default_port "$LOCAL_DNS")
set_cache_var "LOCAL_DNS" "$LOCAL_DNS"
IPT_APPEND_DNS=$(add_default_port "${IPT_APPEND_DNS:-$LOCAL_DNS}")
echo "$IPT_APPEND_DNS" | grep -q -E "(^|,)$LOCAL_DNS(,|$)" || IPT_APPEND_DNS="${IPT_APPEND_DNS:+$IPT_APPEND_DNS,}$LOCAL_DNS"
[ -n "$DIRECT_DNS" ] && {
@@ -1573,7 +1574,7 @@ acl_app() {
chinadns_port=$(expr $chinadns_port + 1)
_china_ng_listen="127.0.0.1#${chinadns_port},::1#${chinadns_port}"
_chinadns_local_dns=$(IFS=','; set -- $LOCAL_DNS; [ "${1%%[#:]*}" = "127.0.0.1" ] && echo "$1" || ([ -n "$2" ] && echo "$1,$2" || echo "$1"))
_chinadns_local_dns="${LOCAL_DNS}"
_direct_dns_mode=$(config_n_get @global[0] direct_dns_mode "auto")
case "${_direct_dns_mode}" in
udp)
@@ -1703,6 +1704,7 @@ start() {
sleep 2
}
mkdir -p /tmp/etc /tmp/log $TMP_PATH $TMP_BIN_PATH $TMP_SCRIPT_FUNC_PATH $TMP_ROUTE_PATH $TMP_ACL_PATH $TMP_PATH2
set_cache_var "LOCAL_DNS" "$LOCAL_DNS"
get_config
export V2RAY_LOCATION_ASSET=$(config_n_get @global_rules[0] v2ray_location_asset "/usr/share/v2ray/")
export XRAY_LOCATION_ASSET=$V2RAY_LOCATION_ASSET
@@ -1892,6 +1894,7 @@ get_config() {
SMARTDNS_LISTEN_PORT=${NEXT_DNS_LISTEN_PORT}
NEXT_DNS_LISTEN_PORT=$(expr $NEXT_DNS_LISTEN_PORT + 1)
LOCAL_DNS="127.0.0.1#${SMARTDNS_LOCAL_PORT}"
set_cache_var "LOCAL_DNS" "$LOCAL_DNS"
set_cache_var "SMARTDNS_LOCAL_PORT" "${SMARTDNS_LOCAL_PORT}"
}
}
@@ -1905,7 +1908,8 @@ get_local_dns() {
DEFAULT_DNS=$(uci show dhcp.@dnsmasq[0] | grep "\.server=" | awk -F '=' '{print $2}' | sed "s/'//g" | tr ' ' '\n' | grep -v "\/" | sed ':label;N;s/\n/,/;b label')
[ -z "${DEFAULT_DNS}" ] && [ "$(echo $ISP_DNS | tr ' ' '\n' | wc -l)" -ge 1 ] && DEFAULT_DNS=$(echo -n $ISP_DNS | tr ' ' '\n' | tr '\n' ',' | sed 's/,$//')
LOCAL_DNS="${DEFAULT_DNS:-119.29.29.29,223.5.5.5}"
LOCAL_DNS="${DEFAULT_DNS:-223.5.5.5}"
LOCAL_DNS="${LOCAL_DNS%%,*}"
}
get_local_dns
@@ -201,12 +201,6 @@ if not is_file_nonzero(file_vpslist) then
process_address(dns)
end
end)
api.uci_foreach_c("subscribe_list", function(t) --订阅链接
local url, _ = api.get_domain_port_from_url(t.url or "")
if url and url ~= "" then
process_address(url)
end
end)
f_out:close()
end
if is_file_nonzero(file_vpslist) then
@@ -334,7 +334,7 @@ function add_rule(var)
end
local function get_dns_config_key()
local address_md5 = api.md5_string(sys.exec([[uci show passwall | grep -E '\.(address|download_address|domain_resolver_dns|domain_resolver_dns_https)=|^passwall\.sub_[^.]+\.url=' | cut -d "'" -f 2 | sort -u]]))
local address_md5 = api.md5_string(sys.exec([[uci show passwall | grep -E '\.(address|download_address|domain_resolver_dns|domain_resolver_dns_https)=' | cut -d "'" -f 2 | sort -u]]))
local new_rules = sys.exec([[
for f in \
/usr/share/passwall/rules/chnlist \
@@ -467,12 +467,6 @@ function add_rule(var)
process_address(dns)
end
end)
api.uci_foreach_c("subscribe_list", function(t) --订阅链接
local url, _ = api.get_domain_port_from_url(t.url or "")
if url and url ~= "" then
process_address(url)
end
end)
log(string.format(" - 节点列表中的域名(vpslist):%s", fwd_dns or "默认"))
end
end
@@ -360,12 +360,6 @@ if not is_file_nonzero(file_vpslist) then
process_address(dns)
end
end)
api.uci_foreach_c("subscribe_list", function(t) --订阅链接
local url, _ = api.get_domain_port_from_url(t.url or "")
if url and url ~= "" then
process_address(url)
end
end)
f_out:close()
end
if is_file_nonzero(file_vpslist) then
@@ -778,12 +778,6 @@ filter_vpsip() {
echo "$ipv6_addrs" | sed "s/^/add $IPSET_VPS6 /" | awk '1; END{print "COMMIT"}' | ipset -! -R
echolog " - [$?]加入所有IPv6节点服务器IP到ipset[$IPSET_VPS6]直连完成"
}
#订阅方式为直连时
local subscribe_host=$(get_subscribe_host | grep -Ev "$EXCLUDE_VPSIP")
[ -n "$subscribe_host" ] && {
echo "$subscribe_host" | grep -Eo "$IPv4_REGEX" | sed "s/^/add $IPSET_VPS /" | awk '{print $0} END{print "COMMIT"}' | ipset -! -R
echo "$subscribe_host" | grep -Eo "$IPv6_REGEX" | sed "s/^/add $IPSET_VPS6 /" | awk '{print $0} END{print "COMMIT"}' | ipset -! -R
}
}
filter_server_port() {
@@ -1434,6 +1428,11 @@ add_firewall_rule() {
filter_direct_node_list > /dev/null 2>&1 &
local direct_ipt
for direct_ipt in "$ipt_n" "$ipt_m" "$ip6t_n" "$ip6t_m"; do
$direct_ipt -I OUTPUT $(comment "PSW_DIRECT") -m owner --gid-owner $DIRECT_GID -j RETURN
done
echolog "防火墙规则加载完成!"
}
@@ -1509,7 +1508,7 @@ gen_include() {
[ -z "${_ipt}" ] && return
echo "*$2"
${_ipt}-save -t $2 | grep "PSW" | grep -v "\-j PSW$" | grep -v "mangle\-OUTPUT\-PSW" | grep -v "\-m socket .*\-j PSW_DIVERT$" | sed -e "s/^-A \(OUTPUT\|PREROUTING\|FORWARD\)/-I \1 1/"
${_ipt}-save -t $2 | grep "PSW" | grep -v "PSW_DIRECT" | grep -v "\-j PSW$" | grep -v "mangle\-OUTPUT\-PSW" | grep -v "\-m socket .*\-j PSW_DIVERT$" | sed -e "s/^-A \(OUTPUT\|PREROUTING\|FORWARD\)/-I \1 1/"
echo 'COMMIT'
}
local __ipt=""
@@ -1529,6 +1528,8 @@ gen_include() {
echo "\${mangle_output_psw}" | while read line; do
\$(${MY_PATH} insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "\${line}")
done
$ipt_n -I OUTPUT $(comment "PSW_DIRECT") -m owner --gid-owner $DIRECT_GID -j RETURN
$ipt_m -I OUTPUT $(comment "PSW_DIRECT") -m owner --gid-owner $DIRECT_GID -j RETURN
[ "$accept_icmp" = "1" ] && \$(${MY_PATH} insert_rule_after "$ipt_n" "PREROUTING" "prerouting_rule" "-p icmp -j PSW")
[ -z "${is_tproxy}" ] && \$(${MY_PATH} insert_rule_after "$ipt_n" "PREROUTING" "prerouting_rule" "-p tcp -j PSW")
@@ -1552,6 +1553,8 @@ gen_include() {
echo "\${mangle_output_psw}" | while read line; do
\$(${MY_PATH} insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "\${line}")
done
$ip6t_n -I OUTPUT $(comment "PSW_DIRECT") -m owner --gid-owner $DIRECT_GID -j RETURN
$ip6t_m -I OUTPUT $(comment "PSW_DIRECT") -m owner --gid-owner $DIRECT_GID -j RETURN
[ "$accept_icmpv6" = "1" ] && $ip6t_n -A PREROUTING -p ipv6-icmp -j PSW
@@ -838,12 +838,6 @@ filter_vpsip() {
echo "$ipv6_addrs" | insert_nftset $NFTSET_VPS6
echolog " - [$?]加入所有IPv6节点服务器IP到nftset[$NFTSET_VPS6]直连完成"
}
#订阅方式为直连时
local subscribe_host=$(get_subscribe_host | grep -Ev "$EXCLUDE_VPSIP")
[ -n "$subscribe_host" ] && {
echo "$subscribe_host" | grep -Eo "$IPv4_REGEX" | grep -Ev "$EXCLUDE_VPSIP" | insert_nftset $NFTSET_VPS
echo "$subscribe_host" | grep -Eo "$IPv6_REGEX" | insert_nftset $NFTSET_VPS6
}
}
filter_server_port() {
@@ -1509,6 +1503,9 @@ add_firewall_rule() {
filter_direct_node_list > /dev/null 2>&1 &
nft "insert rule $NFTABLE_NAME mangle_output meta skgid $DIRECT_GID counter return comment \"PSW_DIRECT\""
nft "insert rule $NFTABLE_NAME nat_output meta skgid $DIRECT_GID counter return comment \"PSW_DIRECT\""
echolog "防火墙规则加载完成!"
}
@@ -139,7 +139,7 @@ local function curl(url, file)
if file then
args[#args + 1] = "-o " .. file
end
local return_code, result = api.curl_logic(url, nil, args)
local return_code, result = api.curl_auto(url, nil, args)
if result and result ~= "" then
local body, code = result:match("^(.-)%s*([0-9]+)$")
if code then
@@ -1814,11 +1814,11 @@ local function curl(url, file, ua, mode)
local return_code, result
if mode == "direct" then
return_code, result = api.curl_base(url, file, curl_args)
return_code, result = api.curl_direct(url, file, curl_args)
elseif mode == "proxy" then
return_code, result = api.curl_proxy(url, file, curl_args)
else
return_code, result = api.curl_logic(url, file, curl_args)
return_code, result = api.curl_auto(url, file, curl_args)
end
if result and result ~= "" then
@@ -3,6 +3,7 @@
# Copyright (C) 2026 Openwrt-Passwall Organization
CONFIG=passwall
DIRECT_GID=9911
APP_PATH=/usr/share/${CONFIG}
TMP_PATH=/tmp/etc/${CONFIG}
TMP_PATH2=${TMP_PATH}_tmp
@@ -503,17 +504,6 @@ kill_all() {
kill -9 $(pidof "$@") >/dev/null 2>&1
}
get_subscribe_host(){
local line
uci show "${CONFIG}" | grep "=subscribe_list" | while read -r line; do
local section="$(echo "$line" | cut -d '.' -sf 2 | cut -d '=' -sf 1)"
local url="$(config_n_get $section url)"
[ -n "$url" ] || continue
url="$(host_from_url "$url")"
echo "$url"
done
}
gen_lanlist() {
cat $USER_RULES_PATH/lanlist_ipv4 | tr -s '\n' | grep -v "^#"
}