update 2026-10-15 06:56:05

This commit is contained in:
action committed 2026-10-15 06:56:05 +08:00
1 parent e75bfefc80
commit 27917e2b63
483 files changed
+128531 -374

No files matched your search

@@ -1066,22 +1066,6 @@ stop_crontab() {
#echolog "清除定时执行命令。"
}
restart_smartdns() {
rm -rf /tmp/smartdns.cache
/etc/init.d/smartdns reload >/dev/null 2>&1
}
del_smartdns_conf() {
command -v smartdns >/dev/null 2>&1 || return
rm -rf "/tmp/etc/smartdns/${CONFIG}.conf"
local custom_conf="/etc/smartdns/custom.conf"
if [ -f "$custom_conf" ] && grep -q "${CONFIG}" "$custom_conf"; then
sed -i "/${CONFIG}/d" "$custom_conf" >/dev/null 2>&1
rm -rf /tmp/smartdns.cache
/etc/init.d/smartdns reload >/dev/null 2>&1
fi
}
start_dns() {
echolog "DNS域名解析:"
@@ -1111,15 +1095,15 @@ start_dns() {
china_ng_local_dns="tcp://${DIRECT_DNS}"
v2ray_local_dns="direct_dns_tcp_server=${DIRECT_DNS}"
#当全局(包括访问控制节点)开启chinadns-ng时,不启动新进程。
[ "$DNS_SHUNT" != "chinadns-ng" ] || [ "$ACL_RULE_DNSMASQ" = "1" ] && {
# ChinaDNS-NG and SmartDNS can query TCP upstreams directly.
if { [ "$DNS_SHUNT" != "chinadns-ng" ] && [ "$DNS_SHUNT" != "smartdns" ]; } || [ "$ACL_RULE_DNSMASQ" = "1" ]; then
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 查询。"
NEXT_DNS_LISTEN_PORT=$(expr $NEXT_DNS_LISTEN_PORT + 1)
}
fi
;;
auto)
#Automatic logic is already done by default
@@ -1266,9 +1250,9 @@ start_dns() {
local china_ng_listen=0
[ "${DNS_SHUNT}" = "smartdns" ] && {
if command -v smartdns > /dev/null 2>&1; then
local smartdns_bin=$(first_type smartdns)
if [ -n "$smartdns_bin" ]; then
rm -rf $TMP_PATH2/dnsmasq_default*
local group_domestic=$(config_n_get @global[0] group_domestic)
local smartdns_remote_dns=$(config_n_get @global[0] smartdns_remote_dns)
if [ -n "${smartdns_remote_dns}" ] && [ "${smartdns_remote_dns}" != "nil" ]; then
smartdns_remote_dns=$(echo ${smartdns_remote_dns} | tr -s ' ' '|')
@@ -1276,27 +1260,34 @@ start_dns() {
smartdns_remote_dns="tcp://1.1.1.1"
fi
local smartdns_default_dns=$(config_n_get @global[0] smartdns_default_dns direct)
echolog " - 域名解析:使用SmartDNS,请确保配置正常。"
china_ng_listen="127.0.0.1#${SMARTDNS_LISTEN_PORT}"
if [ "${DNS_REDIRECT}" = "1" ]; then
echolog " - DNS 重定向 -> SmartDNS(${china_ng_listen}),直连 DNS -> 国内分组(${group_domestic:-null})"
else
echolog " - SmartDNS(127.0.0.1#${SMARTDNS_LOCAL_PORT}) -> 国内分组(${group_domestic:-null}),SmartDNS(${china_ng_listen}) -> Dnsmasq"
fi
china_ng_listen="${china_ng_listen},::1#${SMARTDNS_LISTEN_PORT}"
local smartdns_listen_port=$(get_new_port "$(expr $NEXT_DNS_LISTEN_PORT + 1)")
[ -n "$smartdns_listen_port" ] || {
echolog " * SmartDNS 无法获取可用的 DNS 监听端口!"
return 1
}
local smartdns_config="${GLOBAL_ACL_PATH}/smartdns.conf"
local subnet_ip=$(config_n_get @global[0] remote_dns_client_ip)
lua $APP_PATH/helper_smartdns_add.lua -FLAG "default" -SMARTDNS_CONF "/tmp/etc/smartdns/$CONFIG.conf" \
-LISTEN_PORT ${SMARTDNS_LISTEN_PORT} -LOCAL_PORT ${SMARTDNS_LOCAL_PORT} -DNS_REDIRECT ${DNS_REDIRECT} \
-LOCAL_GROUP ${group_domestic:-null} -REMOTE_GROUP "passwall_proxy" -REMOTE_PROXY_SERVER ${GLOBAL_SOCKS_server} -USE_DEFAULT_DNS "${smartdns_default_dns}" \
-REMOTE_DNS ${smartdns_remote_dns} -DNS_MODE ${DNS_MODE:-socks} -TUN_DNS ${TUN_DNS} \
echolog " - SmartDNS(127.0.0.1#${smartdns_listen_port}),直连 DNS:${china_ng_local_dns} -> 分组(direct)"
lua "$APP_PATH/helper_smartdns_add.lua" -FLAG "default" \
-LISTEN_PORT "$smartdns_listen_port" -LOCAL_DNS "$china_ng_local_dns" -DNS_REDIRECT "${DNS_REDIRECT}" \
-REMOTE_PROXY_SERVER "${GLOBAL_SOCKS_server}" -USE_DEFAULT_DNS "${smartdns_default_dns}" \
-REMOTE_DNS "${smartdns_remote_dns}" -DNS_MODE "${DNS_MODE:-socks}" -TUN_DNS "${TUN_DNS}" \
-USE_DIRECT_LIST "${USE_DIRECT_LIST}" -USE_PROXY_LIST "${USE_PROXY_LIST}" -USE_BLOCK_LIST "${USE_BLOCK_LIST}" -USE_GFW_LIST "${USE_GFW_LIST}" -CHN_LIST "${CHN_LIST}" \
-NODE ${NODE} -DEFAULT_PROXY_MODE "${TCP_PROXY_MODE}" -NO_PROXY_IPV6 ${FILTER_PROXY_IPV6:-0} -NFTFLAG ${nftflag:-0} \
-SUBNET ${subnet_ip:-0} -NO_LOGIC_LOG ${NO_LOGIC_LOG:-0}
restart_smartdns
-NODE "${NODE}" -DEFAULT_PROXY_MODE "${TCP_PROXY_MODE}" -NO_PROXY_IPV6 "${FILTER_PROXY_IPV6:-0}" -NFTFLAG "${nftflag:-0}" \
-SUBNET "${subnet_ip:-0}" -NO_LOGIC_LOG "${NO_LOGIC_LOG:-0}" \
-LOG "$(config_n_get @global[0] log_smartdns 0)" \
-LOG_LEVEL "$(config_n_get @global[0] smartdns_log_level error)" \
-LOG_SIZE "$(config_n_get @global[0] smartdns_log_size 1)" \
-UI "$(config_n_get @global[0] smartdns_ui 0)" \
-UI_PORT "$(config_n_get @global[0] smartdns_ui_port 9880)" \
-UI_DATA_DIR "$(config_n_get @global[0] smartdns_ui_data_dir "$TMP_PATH2/smartdns")" \
-UI_LOG_MAX_AGE "$(config_n_get @global[0] smartdns_ui_log_max_age 7)" || {
echolog " * SmartDNS 配置生成失败!"
return 1
}
ln_run "$smartdns_bin" smartdns "/dev/null" -f -c "$smartdns_config" -p "${GLOBAL_ACL_PATH}/smartdns.pid"
china_ng_listen="127.0.0.1#${smartdns_listen_port},::1#${smartdns_listen_port}"
USE_DEFAULT_DNS="chinadns_ng"
else
DNS_SHUNT="dnsmasq"
@@ -1377,7 +1368,7 @@ start_dns() {
lua $APP_PATH/helper_dnsmasq.lua logic_restart -LOG 1
elif [ "${DNS_SHUNT}" = "smartdns" ]; then
# SmartDNS reads DHCP leases itself; no forwarding dnsmasq instance is needed.
DNS_REDIRECT_PORT=${SMARTDNS_LISTEN_PORT}
DNS_REDIRECT_PORT=${smartdns_listen_port}
set_cache_var "ACL_default_dns_port" "${DNS_REDIRECT_PORT}"
else
#Run a copy dnsmasq instance, DNS hijack for that need proxy devices.
@@ -1730,7 +1721,11 @@ start() {
[ "$ENABLED_DEFAULT_ACL" = 1 ] && {
mkdir -p ${GLOBAL_ACL_PATH}
start_global
start_dns
start_dns || {
echolog "DNS 启动失败,停止服务。"
stop
return 1
}
}
[ -n "$USE_TABLES" ] && source $APP_PATH/${USE_TABLES}.sh start
set_cache_var "USE_TABLES" "$USE_TABLES"
@@ -1783,7 +1778,6 @@ stop() {
unset XRAY_LOCATION_ASSET
unset SS_SYSTEM_DNS_RESOLVER_FORCE_BUILTIN
stop_crontab $1
del_smartdns_conf
rm -rf $GLOBAL_DNSMASQ_CONF
rm -rf $GLOBAL_DNSMASQ_CONF_PATH
[ "1" = "1" ] && {
@@ -1884,19 +1878,6 @@ get_config() {
fi
set_cache_var GLOBAL_DNSMASQ_CONF ${DNSMASQ_CONF_DIR}/dnsmasq-${CONFIG}.conf
set_cache_var GLOBAL_DNSMASQ_CONF_PATH ${GLOBAL_ACL_PATH}/dnsmasq.d
SMARTDNS_LOCAL_PORT=0
SMARTDNS_LISTEN_PORT=0
[ "$ENABLED_DEFAULT_ACL" = 1 ] && [ "$DNS_SHUNT" = "smartdns" ] && {
NEXT_DNS_LISTEN_PORT=$(expr $NEXT_DNS_LISTEN_PORT + 1)
SMARTDNS_LOCAL_PORT=${NEXT_DNS_LISTEN_PORT}
NEXT_DNS_LISTEN_PORT=$(expr $NEXT_DNS_LISTEN_PORT + 1)
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}"
}
}
get_local_dns() {
@@ -2,9 +2,7 @@ local api = require "luci.passwall.api"
local var = api.get_args(arg)
local FLAG = var["-FLAG"]
local SMARTDNS_CONF = var["-SMARTDNS_CONF"]
local LOCAL_GROUP = var["-LOCAL_GROUP"]
local REMOTE_GROUP = var["-REMOTE_GROUP"]
local LOCAL_DNS = var["-LOCAL_DNS"]
local REMOTE_PROXY_SERVER = var["-REMOTE_PROXY_SERVER"]
local USE_DEFAULT_DNS = var["-USE_DEFAULT_DNS"]
local REMOTE_DNS = var["-REMOTE_DNS"]
@@ -22,8 +20,14 @@ local NO_LOGIC_LOG = var["-NO_LOGIC_LOG"]
local NFTFLAG = var["-NFTFLAG"]
local SUBNET = var["-SUBNET"]
local LISTEN_PORT = var["-LISTEN_PORT"]
local LOCAL_PORT = var["-LOCAL_PORT"]
local DNS_REDIRECT = var["-DNS_REDIRECT"] == "1"
local LOG = var["-LOG"] == "1"
local LOG_LEVEL = var["-LOG_LEVEL"] or "error"
local LOG_SIZE = tonumber(var["-LOG_SIZE"]) or 1
local UI = var["-UI"] == "1"
local UI_PORT = tonumber(var["-UI_PORT"]) or 9880
local UI_DATA_DIR = var["-UI_DATA_DIR"]
local UI_LOG_MAX_AGE = tonumber(var["-UI_LOG_MAX_AGE"]) or 7
local sys = api.sys
local fs = api.fs
@@ -35,6 +39,7 @@ local USER_RULES_PATH = "/etc/passwall/rules"
local CACHE_RULES_PATH = api.CACHE_PATH .. "/user_rules"
local FLAG_PATH = TMP_PATH .. "/acl/" .. FLAG
local TMP_CONF_FILE = FLAG_PATH .. "/smartdns.conf"
local SMARTDNS_DATA_PATH = api.CACHE_PATH .. "/smartdns"
local config_lines = {}
local tmp_lines = {}
local USE_GEOVIEW = api.uci_get_c("@global_rules[0]", "enable_geoview")
@@ -60,11 +65,6 @@ local function is_file_nonzero(path)
return nil
end
local function get_new_port(start_port, protocol)
local cmd_format = ". /usr/share/passwall/utils.sh ; echo -n $(get_new_port %s %s)"
return tonumber(sys.exec(string.format(cmd_format, api.util.shellquote(tostring(start_port or "auto")), api.util.shellquote(protocol or "tcp,udp"))))
end
local function insert_unique(dest_table, value, lookup_table)
if not lookup_table[value] then
table.insert(dest_table, value)
@@ -116,121 +116,72 @@ end
sys.call("mkdir -p %s" % FLAG_PATH)
sys.call("mkdir -p %s" % CACHE_RULES_PATH)
sys.call("mkdir -p " .. api.util.shellquote(SMARTDNS_DATA_PATH))
local LOG_LEVELS = {off = true, fatal = true, error = true, warn = true, notice = true, info = true, debug = true}
if not LOG_LEVELS[LOG_LEVEL] then LOG_LEVEL = "error" end
if LOG_SIZE < 1 or LOG_SIZE % 1 ~= 0 then LOG_SIZE = 1 end
if UI_PORT < 1 or UI_PORT > 65535 or UI_PORT % 1 ~= 0 then UI_PORT = 9880 end
if UI_LOG_MAX_AGE < 1 or UI_LOG_MAX_AGE % 1 ~= 0 then UI_LOG_MAX_AGE = 7 end
if not UI_DATA_DIR or UI_DATA_DIR == "" then UI_DATA_DIR = SMARTDNS_DATA_PATH end
local UI_PLUGIN = "/usr/lib/smartdns_ui.so"
if not fs.access(UI_PLUGIN) then UI_PLUGIN = "/usr/lib/smartdns/smartdns_ui.so" end
local ENABLE_UI = UI and fs.access(UI_PLUGIN)
local data_dir = ENABLE_UI and UI_DATA_DIR or SMARTDNS_DATA_PATH
if data_dir ~= SMARTDNS_DATA_PATH then
sys.call("mkdir -p " .. api.util.shellquote(data_dir))
end
local LOCAL_EXTEND_ARG = ""
local LOCAL_SERVERS = {}
local SERVER_TYPES = {
udp = "server", tcp = "server-tcp", tls = "server-tls",
https = "server-https", quic = "server-quic", h3 = "server-h3"
}
if not LOCAL_GROUP or LOCAL_GROUP == "null" or LOCAL_GROUP == "" then
log(" * 注意:SmartDNS 国内分组名未设置,DNS 将无法正常工作!!!")
local SERVER_TYPES = {udp = "server", tcp = "server-tcp"}
for endpoint in string.gmatch(LOCAL_DNS or "", "[^,]+") do
endpoint = api.trim(endpoint)
local protocol, address = endpoint:match("^(%w+)://(.+)$")
protocol = protocol and protocol:lower() or "udp"
address = address or endpoint
local host, port = address:match("^(.-)#(%d+)$")
if host then
if host:find(":", 1, true) and not host:find("[", 1, true) then host = "[" .. host .. "]" end
address = host .. ":" .. port
elseif datatypes.ip6addr(address) and not address:find("[", 1, true) then
address = "[" .. address .. "]"
end
if SERVER_TYPES[protocol] and address ~= "" then
table.insert(LOCAL_SERVERS, SERVER_TYPES[protocol] .. " " .. address)
end
end
if #LOCAL_SERVERS == 0 then
log(" * 注意:SmartDNS 没有可用的直连 DNS 服务器,DNS 将无法正常工作!!!")
os.exit(1)
else
api.uci:foreach("smartdns", "server", function(s)
if s.enabled ~= "0" and s.server_group == LOCAL_GROUP and s.ip and s.ip ~= "" and SERVER_TYPES[s.type or "udp"] then
table.insert(LOCAL_SERVERS, s)
end
end)
if #LOCAL_SERVERS == 0 then
log(" * 注意:SmartDNS 国内分组 " .. LOCAL_GROUP .. " 没有可用的 DNS 服务器,DNS 将无法正常工作!!!")
os.exit(1)
end
--从smartdns配置中读取参数
local custom_conf_path = "/etc/smartdns/custom.conf"
local options = {
{key = "dualstack_ip_selection", config_key = "dualstack-ip-selection", yes_no = true, arg_yes = "-d yes", arg_no = "-d no", default = "yes"},
{key = "speed_check_mode", config_key = "speed-check-mode", prefix = "-c ", default = "ping,tcp:80,tcp:443"},
{key = "serve_expired", config_key = "serve-expired", yes_no = true, arg_yes = "", arg_no = "-no-serve-expired", default = "yes"},
{key = "response_mode", config_key = "response-mode", prefix = "-r ", default = "first-ping"},
{key = "rr_ttl", config_key = "rr-ttl", prefix = "-rr-ttl "},
{key = "rr_ttl_min", config_key = "rr-ttl-min", prefix = "-rr-ttl-min "},
{key = "rr_ttl_max", config_key = "rr-ttl-max", prefix = "-rr-ttl-max "},
{key = "rr_ttl_reply_max", config_key = "rr-ttl-reply-max", prefix = "-rr-ttl-reply-max "},
{
key = "force_aaaa_soa",
config_key = "force-qtype-SOA",
prefix = "-address ",
get_value = function(custom_config)
local soa = custom_config["force-qtype-SOA"]
return ((soa and soa:match("(^|%s)28(%s|$)"))
or custom_config["force-AAAA-SOA"] == "yes"
or api.uci_get("smartdns", "@smartdns[0]", "force_aaaa_soa") == "1")
and "#6" or "-6"
end
}
}
-- 从 custom.conf 中读取值,以最后出现的值为准
local custom_config = {}
local f_in = io.open(custom_conf_path, "r")
if f_in then
for line in f_in:lines() do
line = api.trim(line)
if line ~= "" and not line:match("^#") then
local param, value = line:match("^(%S+)%s+(.+)$")
if param and value then custom_config[param] = value end
end
end
f_in:close()
end
-- 从 smartdns 配置中读取值,优先级以 custom.conf 为准
for _, opt in ipairs(options) do
local val
if opt.get_value then
val = opt.get_value(custom_config)
else
val = custom_config[opt.config_key] or api.uci_get("smartdns", "@smartdns[0]", opt.key) or opt.default
end
if val == "yes" then val = "1" elseif val == "no" then val = "0" end
local arg
if opt.yes_no then
arg = (val == "1" and opt.arg_yes or opt.arg_no)
elseif val and (not opt.value or (opt.invert and val ~= opt.value) or (not opt.invert and val == opt.value)) then
arg = (opt.prefix or "") .. (opt.arg or val)
end
if arg and arg ~= "" then
LOCAL_EXTEND_ARG = LOCAL_EXTEND_ARG .. (LOCAL_EXTEND_ARG ~= "" and " " or "") .. arg
end
end
end
if not REMOTE_GROUP or REMOTE_GROUP == "nil" then
REMOTE_GROUP = "passwall_proxy"
end
if REMOTE_DNS then
REMOTE_DNS = REMOTE_DNS:gsub("#", ":")
end
local SANDBOX_GROUP = "passwall_" .. FLAG
local AUTO_GROUP = "passwall_auto"
local AUTO_ENTRY_GROUP = AUTO_GROUP .. "_entry"
local AUTO_GROUP = "auto"
local auto_config_lines = {}
--设置默认 DNS 分组(兜底组),全局代理模式仍使用远程组。
local DEFAULT_DNS_GROUP = (USE_DEFAULT_DNS == "direct" and LOCAL_GROUP) or
(USE_DEFAULT_DNS == "remote" and REMOTE_GROUP) or
local DEFAULT_DNS_GROUP = (USE_DEFAULT_DNS == "direct" and "direct") or
(USE_DEFAULT_DNS == "remote" and "proxy") or
(USE_DEFAULT_DNS == "auto" and AUTO_GROUP)
local only_global = (DEFAULT_PROXY_MODE == "proxy" and CHN_LIST == "0" and USE_GFW_LIST == "0") and 1
if only_global == 1 then
DEFAULT_DNS_GROUP = REMOTE_GROUP
DEFAULT_DNS_GROUP = "proxy"
end
local AUTO_PORT
if DEFAULT_DNS_GROUP == AUTO_GROUP then
AUTO_PORT = get_new_port(15453, "udp")
if not AUTO_PORT then
log(" * 注意:SmartDNS 自动模式无法获取可用的 UDP 回环端口!")
os.exit(1)
end
end
sys.call('sed -i "/passwall/d" /etc/smartdns/custom.conf >/dev/null 2>&1')
local force_https_soa = api.uci_get_c("@global[0]", "force_https_soa") or 0
local force_qtype_soa = tonumber(force_https_soa) == 1 and "force-qtype-SOA 65" or "force-qtype-SOA -,65"
local proxy_server_name = "psw-proxy-server"
local listen_address = "[::]:" .. LISTEN_PORT .. (DNS_REDIRECT and "" or "@lo")
local local_domain = DNS_REDIRECT and api.uci_get("dhcp", "@dnsmasq[0]", "domain")
config_lines = {
tonumber(LISTEN_PORT) ~= 0 and ("bind " .. listen_address .. " -group " .. SANDBOX_GROUP) or "",
tonumber(LISTEN_PORT) ~= 0 and ("bind-tcp " .. listen_address .. " -group " .. SANDBOX_GROUP) or "",
(tonumber(LOCAL_PORT) ~= 0 and LOCAL_GROUP) and "bind [::]:" .. LOCAL_PORT .. "@lo -group " .. LOCAL_GROUP or "",
(tonumber(LOCAL_PORT) ~= 0 and LOCAL_GROUP) and "bind-tcp [::]:" .. LOCAL_PORT .. "@lo -group " .. LOCAL_GROUP or "",
tonumber(LISTEN_PORT) ~= 0 and ("bind " .. listen_address) or "",
tonumber(LISTEN_PORT) ~= 0 and ("bind-tcp " .. listen_address) or "",
"log-level " .. LOG_LEVEL,
"log-num " .. (LOG and "1" or "0"),
LOG and string.format("log-file %q", FLAG_PATH .. "/smartdns.log") or "",
LOG and ("log-size " .. LOG_SIZE .. "M") or "",
string.format("cache-file %q", SMARTDNS_DATA_PATH .. "/smartdns.cache"),
string.format("data-dir %q", data_dir),
"server 223.5.5.5 -bootstrap-dns",
-- Set the suffix before loading hosts/leases so initial records are expanded too.
(local_domain and local_domain ~= "") and "local-domain " .. local_domain or "",
@@ -238,6 +189,14 @@ config_lines = {
is_file_nonzero("/etc/hosts") and "hosts-file /etc/hosts" or "",
DNS_MODE == "socks" and string.format("proxy-server socks5://%s -name %s", REMOTE_PROXY_SERVER, proxy_server_name) or ""
}
if ENABLE_UI then
merge_array(config_lines, {
"plugin " .. UI_PLUGIN,
"smartdns-ui.www-root /usr/share/smartdns/wwwroot",
"smartdns-ui.ip http://[::]:" .. UI_PORT,
"smartdns-ui.max-query-log-age " .. (UI_LOG_MAX_AGE * 86400)
})
end
if DNS_REDIRECT then
local hosts = {}
api.uci:foreach("dhcp", "host", function(s)
@@ -260,48 +219,20 @@ if DNS_REDIRECT then
table.insert(config_lines, string.format("odhcpd-lease-file %q", odhcpd_lease))
end
end
if DEFAULT_DNS_GROUP == AUTO_GROUP then
-- 复制国内组中启用的 UCI DNS 服务器,原组不添加白名单过滤。
for _, s in ipairs(LOCAL_SERVERS) do
local server_type = SERVER_TYPES[s.type or "udp"]
local address = s.ip
if not address:find("://", 1, true) then
if address:find(":", 1, true) and not address:find("[", 1, true) then
address = "[" .. address .. "]"
end
if s.port and s.port ~= "" then address = address .. ":" .. s.port end
end
local args = {server_type, address}
for _, key in ipairs({"tls_host_verify", "host_name", "http_host", "spki_pin", "set_mark"}) do
if s[key] and s[key] ~= "" then
table.insert(args, "-" .. key:gsub("_", "-"))
table.insert(args, s[key])
end
end
for _, key in ipairs({"no_check_certificate", "blacklist_ip", "check_edns"}) do
if s[key] == "1" and not (key == "blacklist_ip" and NO_PROXY_IPV6 == "1") then
table.insert(args, "-" .. key:gsub("_", "-"))
end
end
if s.use_proxy == "1" then table.insert(args, "-proxy default-proxy") end
-- 国内副本作为主用服务器,不继承后备标记。
local addition_arg = api.trim((" " .. (s.addition_arg or "")):gsub("(%s)%-%-?fallback%f[%s%z]", "%1"))
if NO_PROXY_IPV6 == "1" then
-- 国内副本只使用白名单,避免远程 IPv6 黑名单同时过滤国内结果。
addition_arg = api.trim((" " .. addition_arg):gsub("(%s)%-%-?blacklist%-ip%f[%s%z]", "%1"))
end
if addition_arg ~= "" then table.insert(args, addition_arg) end
table.insert(args, "-exclude-default-group -whitelist-ip")
table.insert(auto_config_lines, table.concat(args, " "))
for _, server_param in ipairs(LOCAL_SERVERS) do
table.insert(config_lines, server_param .. " -group direct -exclude-default-group")
if DEFAULT_DNS_GROUP == AUTO_GROUP then
-- 自动组的直连副本仅接受大陆 IP,普通直连组保持默认行为。
table.insert(auto_config_lines, server_param .. " -group " .. AUTO_GROUP .. " -exclude-default-group -whitelist-ip")
end
end
-- 由下方 DNS_MODE 分支调用,服务器参数来自 PassWall 的 REMOTE_DNS 或 TUN_DNS。
local function add_remote_server(server_param)
table.insert(config_lines, server_param .. " -group " .. REMOTE_GROUP .. " -exclude-default-group")
table.insert(config_lines, server_param .. " -group proxy -exclude-default-group")
if DEFAULT_DNS_GROUP == AUTO_GROUP then
-- 远程副本作为自动组的后备服务器,保留代理、ECS 和传输协议参数。
local auto_param = server_param .. " -exclude-default-group -fallback"
local auto_param = server_param .. " -group " .. AUTO_GROUP .. " -exclude-default-group -fallback"
if NO_PROXY_IPV6 == "1" then auto_param = auto_param .. " -blacklist-ip" end
table.insert(auto_config_lines, auto_param)
end
@@ -364,11 +295,11 @@ if DNS_MODE == "socks" then
end
else
add_remote_server("server " .. TUN_DNS:gsub("#", ":"))
log(" - " .. DNS_MODE:gsub("^%l",string.upper) .. " " .. TUN_DNS .. " -> " .. REMOTE_GROUP)
log(" - " .. DNS_MODE:gsub("^%l",string.upper) .. " " .. TUN_DNS .. " -> 分组(proxy)")
end
if DEFAULT_DNS_GROUP == AUTO_GROUP then
-- IP 集合和过滤规则集中在自动规则组内。
-- 仅自动组的服务器启用 IP 过滤,普通直连和代理组保持各自行为。
if NO_PROXY_IPV6 == "1" then
table.insert(auto_config_lines, "ip-rules ::/0 -blacklist-ip")
end
@@ -384,33 +315,19 @@ if DEFAULT_DNS_GROUP == AUTO_GROUP then
end
table.insert(auto_config_lines, ip_rules)
else
log(" * 注意:SmartDNS 智能模式大陆 IP 列表不存在或为空:" .. path)
log(" * 注意:SmartDNS 自动模式大陆 IP 列表不存在或为空:" .. path)
end
end
-- 兜底通过 UDP 回环入口进入自动规则组,避免 IP 过滤影响其他查询。
table.insert(config_lines, "bind [::]:" .. AUTO_PORT .. "@lo -group " .. AUTO_GROUP)
table.insert(config_lines, "server [::1]:" .. AUTO_PORT .. " -group " .. AUTO_ENTRY_GROUP .. " -exclude-default-group")
table.insert(config_lines, "group-begin " .. AUTO_GROUP .. " -inherit none")
table.insert(config_lines, force_qtype_soa)
merge_array(config_lines, auto_config_lines)
table.insert(config_lines, "domain-rules /./ -nameserver " .. AUTO_GROUP .. (LOCAL_EXTEND_ARG ~= "" and " " .. LOCAL_EXTEND_ARG or ""))
table.insert(config_lines, "group-end")
end
-- PassWall 规则组不继承外部规则。
table.insert(config_lines, "group-begin " .. SANDBOX_GROUP .. " -inherit none")
table.insert(config_lines, force_qtype_soa)
if DEFAULT_DNS_GROUP then
local domain_rules_str = "domain-rules /./ -nameserver " .. (DEFAULT_DNS_GROUP == AUTO_GROUP and AUTO_ENTRY_GROUP or DEFAULT_DNS_GROUP)
if DEFAULT_DNS_GROUP == REMOTE_GROUP then
domain_rules_str = domain_rules_str .. " -speed-check-mode none -d no -no-serve-expired"
local domain_rules_str = "domain-rules /./ -nameserver " .. DEFAULT_DNS_GROUP
if DEFAULT_DNS_GROUP == "proxy" then
domain_rules_str = domain_rules_str .. " -no-cache -speed-check-mode none -d no -no-serve-expired"
domain_rules_str = domain_rules_str .. " -address " .. ((only_global and IS_SHUNT_NODE) and "-6" or (NO_PROXY_IPV6 == "1" and "#6" or "-6"))
elseif DEFAULT_DNS_GROUP == LOCAL_GROUP then
domain_rules_str = domain_rules_str .. (LOCAL_EXTEND_ARG ~= "" and " " .. LOCAL_EXTEND_ARG or "")
elseif DEFAULT_DNS_GROUP == AUTO_GROUP then
-- 转接层只转发请求,测速、双栈优选及缓存交给自动规则组处理。
domain_rules_str = domain_rules_str .. " -speed-check-mode none -d no -no-cache"
end
table.insert(config_lines, domain_rules_str)
end
@@ -513,12 +430,11 @@ if is_file_nonzero(file_vpslist) then
"#4:" .. setflag .. "psw_vps",
"#6:" .. setflag .. "psw_vps6"
}
local domain_rules_str = string.format('domain-rules /domain-set:%s/ %s', domain_set_name, LOCAL_GROUP and "-nameserver " .. LOCAL_GROUP or "")
local domain_rules_str = string.format('domain-rules /domain-set:%s/ -nameserver direct', domain_set_name)
domain_rules_str = domain_rules_str .. " " .. set_type .. " " .. table.concat(sets, ",")
domain_rules_str = domain_rules_str .. (LOCAL_EXTEND_ARG ~= "" and " " .. LOCAL_EXTEND_ARG or "")
table.insert(tmp_lines, domain_rules_str)
insert_array_after(config_lines, tmp_lines, "#--9")
log(string.format(" - 节点列表中的域名(vpslist)使用分组:%s", LOCAL_GROUP or "默认"))
log(" - 节点列表中的域名(vpslist)使用分组:direct")
end
--直连(白名单)列表
@@ -579,12 +495,11 @@ if USE_DIRECT_LIST == "1" and is_file_nonzero(file_direct_host) then
"#4:" .. setflag .. "psw_white",
"#6:" .. setflag .. "psw_white6"
}
local domain_rules_str = string.format('domain-rules /domain-set:%s/ %s', domain_set_name, LOCAL_GROUP and "-nameserver " .. LOCAL_GROUP or "")
local domain_rules_str = string.format('domain-rules /domain-set:%s/ -nameserver direct', domain_set_name)
domain_rules_str = domain_rules_str .. " " .. set_type .. " " .. table.concat(sets, ",")
domain_rules_str = domain_rules_str .. (LOCAL_EXTEND_ARG ~= "" and " " .. LOCAL_EXTEND_ARG or "")
table.insert(tmp_lines, domain_rules_str)
insert_array_after(config_lines, tmp_lines, "#--7")
log(string.format(" - 域名白名单(whitelist)使用分组:%s", LOCAL_GROUP or "默认"))
log(" - 域名白名单(whitelist)使用分组:direct")
end
--代理(黑名单)列表
@@ -641,8 +556,8 @@ if USE_PROXY_LIST == "1" and is_file_nonzero(file_proxy_host) then
tmp_lines = {
string.format("domain-set -name %s -file %s", domain_set_name, file_proxy_host)
}
local domain_rules_str = string.format('domain-rules /domain-set:%s/ -nameserver %s', domain_set_name, REMOTE_GROUP)
domain_rules_str = domain_rules_str .. " -speed-check-mode none"
local domain_rules_str = string.format('domain-rules /domain-set:%s/ -nameserver proxy', domain_set_name)
domain_rules_str = domain_rules_str .. " -no-cache -speed-check-mode none -d no"
domain_rules_str = domain_rules_str .. " -no-serve-expired"
local sets = {
"#4:" .. setflag .. "psw_black"
@@ -651,11 +566,11 @@ if USE_PROXY_LIST == "1" and is_file_nonzero(file_proxy_host) then
domain_rules_str = domain_rules_str .. " -address #6 " .. set_type .. " " .. table.concat(sets, ",")
else
table.insert(sets, "#6:" .. setflag .. "psw_black6")
domain_rules_str = domain_rules_str .. " -address -6 -d no " .. set_type .. " " .. table.concat(sets, ",")
domain_rules_str = domain_rules_str .. " -address -6 " .. set_type .. " " .. table.concat(sets, ",")
end
table.insert(tmp_lines, domain_rules_str)
insert_array_after(config_lines, tmp_lines, "#--6")
log(string.format(" - 代理域名表(blacklist)使用分组:%s", REMOTE_GROUP or "默认"))
log(" - 代理域名表(blacklist)使用分组:proxy")
end
--GFW列表
@@ -664,8 +579,8 @@ if USE_GFW_LIST == "1" and is_file_nonzero(RULES_PATH .. "/gfwlist") then
tmp_lines = {
string.format("domain-set -name %s -file %s", domain_set_name, RULES_PATH .. "/gfwlist")
}
local domain_rules_str = string.format('domain-rules /domain-set:%s/ -nameserver %s', domain_set_name, REMOTE_GROUP)
domain_rules_str = domain_rules_str .. " -speed-check-mode none"
local domain_rules_str = string.format('domain-rules /domain-set:%s/ -nameserver proxy', domain_set_name)
domain_rules_str = domain_rules_str .. " -no-cache -speed-check-mode none -d no"
domain_rules_str = domain_rules_str .. " -no-serve-expired"
local sets = {
"#4:" .. setflag .. "psw_gfw"
@@ -674,11 +589,11 @@ if USE_GFW_LIST == "1" and is_file_nonzero(RULES_PATH .. "/gfwlist") then
domain_rules_str = domain_rules_str .. " -address #6 " .. set_type .. " " .. table.concat(sets, ",")
else
table.insert(sets, "#6:" .. setflag .. "psw_gfw6")
domain_rules_str = domain_rules_str .. " -address -6 -d no " .. set_type .. " " .. table.concat(sets, ",")
domain_rules_str = domain_rules_str .. " -address -6 " .. set_type .. " " .. table.concat(sets, ",")
end
table.insert(tmp_lines, domain_rules_str)
insert_array_after(config_lines, tmp_lines, "#--5")
log(string.format(" - 防火墙域名表(gfwlist)使用分组:%s", REMOTE_GROUP or "默认"))
log(" - 防火墙域名表(gfwlist)使用分组:proxy")
end
--中国列表
@@ -693,18 +608,17 @@ if CHN_LIST ~= "0" and is_file_nonzero(RULES_PATH .. "/chnlist") then
"#4:" .. setflag .. "psw_chn",
"#6:" .. setflag .. "psw_chn6"
}
local domain_rules_str = string.format('domain-rules /domain-set:%s/ %s', domain_set_name, LOCAL_GROUP and "-nameserver " .. LOCAL_GROUP or "")
local domain_rules_str = string.format('domain-rules /domain-set:%s/ -nameserver direct', domain_set_name)
domain_rules_str = domain_rules_str .. " " .. set_type .. " " .. table.concat(sets, ",")
domain_rules_str = domain_rules_str .. (LOCAL_EXTEND_ARG ~= "" and " " .. LOCAL_EXTEND_ARG or "")
table.insert(tmp_lines, domain_rules_str)
insert_array_after(config_lines, tmp_lines, "#--4")
log(string.format(" - 中国域名表(chnlist)使用分组:%s", LOCAL_GROUP or "默认"))
log(" - 中国域名表(chnlist)使用分组:direct")
end
--回中国模式
if CHN_LIST == "proxy" then
local domain_rules_str = string.format('domain-rules /domain-set:%s/ -nameserver %s', domain_set_name, REMOTE_GROUP)
domain_rules_str = domain_rules_str .. " -speed-check-mode none"
local domain_rules_str = string.format('domain-rules /domain-set:%s/ -nameserver proxy', domain_set_name)
domain_rules_str = domain_rules_str .. " -no-cache -speed-check-mode none -d no"
domain_rules_str = domain_rules_str .. " -no-serve-expired"
local sets = {
"#4:" .. setflag .. "psw_chn"
@@ -713,11 +627,11 @@ if CHN_LIST ~= "0" and is_file_nonzero(RULES_PATH .. "/chnlist") then
domain_rules_str = domain_rules_str .. " -address #6 " .. set_type .. " " .. table.concat(sets, ",")
else
table.insert(sets, "#6:" .. setflag .. "psw_chn6")
domain_rules_str = domain_rules_str .. " -address -6 -d no " .. set_type .. " " .. table.concat(sets, ",")
domain_rules_str = domain_rules_str .. " -address -6 " .. set_type .. " " .. table.concat(sets, ",")
end
table.insert(tmp_lines, domain_rules_str)
insert_array_after(config_lines, tmp_lines, "#--4")
log(string.format(" - 中国域名表(chnlist)使用分组:%s", REMOTE_GROUP or "默认"))
log(" - 中国域名表(chnlist)使用分组:proxy")
end
end
@@ -775,7 +689,7 @@ if IS_SHUNT_NODE and not only_global then
SHUNT_LIST = SHUNT_LIST .. domain_list .. (_node_id:sub(1, 1) == "_" and "not-node" or "node")
if _node_id ~= "_direct" and _node_id ~= "_blackhole" then
log(string.format(" - Sing-Box/Xray分流规则(%s)使用分组:%s", s.remarks, REMOTE_GROUP or "默认"))
log(string.format(" - Sing-Box/Xray分流规则(%s)使用分组:proxy", s.remarks))
end
end
end)
@@ -853,13 +767,13 @@ if IS_SHUNT_NODE and not only_global then
tmp_lines = {
string.format("domain-set -name %s -file %s", domain_set_name, shunt_direct_host)
}
local domain_rules_str = string.format('domain-rules /domain-set:%s/ -nameserver %s', domain_set_name, REMOTE_GROUP)
domain_rules_str = domain_rules_str .. " -speed-check-mode none -no-serve-expired"
local domain_rules_str = string.format('domain-rules /domain-set:%s/ -nameserver proxy', domain_set_name)
domain_rules_str = domain_rules_str .. " -no-cache -speed-check-mode none -d no -no-serve-expired"
local sets = {
"#4:" .. setflag .. "psw_shunt",
"#6:" .. setflag .. "psw_shunt6"
}
domain_rules_str = domain_rules_str .. " -address -6 -d no " .. set_type .. " " .. table.concat(sets, ",")
domain_rules_str = domain_rules_str .. " -address -6 " .. set_type .. " " .. table.concat(sets, ",")
table.insert(tmp_lines, domain_rules_str)
insert_array_after(config_lines, tmp_lines, "#--1")
end
@@ -869,13 +783,13 @@ if IS_SHUNT_NODE and not only_global then
tmp_lines = {
string.format("domain-set -name %s -file %s", domain_set_name, shunt_proxy_host)
}
local domain_rules_str = string.format('domain-rules /domain-set:%s/ -nameserver %s', domain_set_name, REMOTE_GROUP)
domain_rules_str = domain_rules_str .. " -speed-check-mode none -no-serve-expired"
local domain_rules_str = string.format('domain-rules /domain-set:%s/ -nameserver proxy', domain_set_name)
domain_rules_str = domain_rules_str .. " -no-cache -speed-check-mode none -d no -no-serve-expired"
local sets = {
"#4:" .. setflag .. "psw_shunt",
"#6:" .. setflag .. "psw_shunt6"
}
domain_rules_str = domain_rules_str .. " -address -6 -d no " .. set_type .. " " .. table.concat(sets, ",")
domain_rules_str = domain_rules_str .. " -address -6 " .. set_type .. " " .. table.concat(sets, ",")
table.insert(tmp_lines, domain_rules_str)
insert_array_after(config_lines, tmp_lines, "#--2")
end
@@ -885,19 +799,18 @@ if IS_SHUNT_NODE and not only_global then
tmp_lines = {
string.format("domain-set -name %s -file %s", domain_set_name, shunt_black_host)
}
local domain_rules_str = string.format('domain-rules /domain-set:%s/ -nameserver %s', domain_set_name, REMOTE_GROUP)
domain_rules_str = domain_rules_str .. " -speed-check-mode none -no-serve-expired"
local domain_rules_str = string.format('domain-rules /domain-set:%s/ -nameserver proxy', domain_set_name)
domain_rules_str = domain_rules_str .. " -no-cache -speed-check-mode none -d no -no-serve-expired"
local sets = {
"#4:" .. setflag .. "psw_shunt",
"#6:" .. setflag .. "psw_shunt6"
}
domain_rules_str = domain_rules_str .. " -address -6 -d no " .. set_type .. " " .. table.concat(sets, ",")
domain_rules_str = domain_rules_str .. " -address -6 " .. set_type .. " " .. table.concat(sets, ",")
table.insert(tmp_lines, domain_rules_str)
insert_array_after(config_lines, tmp_lines, "#--3")
end
end
table.insert(config_lines, "group-end")
if #config_lines > 0 then
local f_out = io.open(TMP_CONF_FILE, "w")
@@ -914,8 +827,6 @@ if DEFAULT_DNS_GROUP then
log(string.format(" - 默认 DNS 分组:%s", DEFAULT_DNS_GROUP == AUTO_GROUP and "自动" or DEFAULT_DNS_GROUP))
end
fs.symlink(TMP_CONF_FILE, SMARTDNS_CONF)
sys.call(string.format('echo "conf-file %s" >> /etc/smartdns/custom.conf', string.gsub(SMARTDNS_CONF, "passwall", "passwall*")))
if DNS_REDIRECT then
log(" - DNS 重定向直接使用 SmartDNS,DHCP 租约由 SmartDNS 自动加载。")
else
@@ -187,38 +187,30 @@ nft_rule_dual() {
nft "add rule $NFTABLE_NAME $chain_name $match_condition @${static_set} ${final_action}"
}
# Avoid terminal stdin or open-ended pipes to prevent hanging.
insert_nftset() {
local nftset_name="${1}"; shift
local suffix=""
[ -n "$nftset_name" ] || return 0
if [ -n "$nftset_name" ] && { [ $# -gt 0 ] || [ ! -t 0 ]; }; then
{
if [ $# -gt 0 ] && [ $# -le 1000 ]; then
printf "%s\n" "$@"
elif [ $# -gt 1000 ]; then
printf "%s\n" "$*"
else
cat
fi | awk -v s="$suffix" -v n="$nftset_name" -v t="$NFTABLE_NAME" '
BEGIN {
RS = "[ \t\n\r]+"
ORS = ""
}
$0 != "" {
if (!first) {
printf "add element %s %s { \n", t, n
first = 1;
} else {
print ",\n"
}
print $0 s
}
END {
if (first) print "\n }\n"
}
'
} | nft -f -
fi
awk -v n="$nftset_name" -v t="$NFTABLE_NAME" '
BEGIN {
RS = "[ \t\n\r]+"
ORS = ""
}
$0 != "" {
if (!first) {
printf "add element %s %s { \n", t, n
first = 1
} else {
print ",\n"
}
printf " %s", $0
}
END {
if (first) {
print "\n }\n"
}
}' | nft -f -
}
gen_nftset() {
@@ -235,9 +227,6 @@ gen_nftset() {
nft "add set $NFTABLE_NAME $nftset_name { type $ip_type; flags interval, timeout; timeout $timeout_argument_set; gc-interval $gc_interval_time; auto-merge; }"
fi
fi
if [ $# -gt 0 ]; then
insert_nftset "$nftset_name" "$@"
fi
}
get_jump_nft() {
@@ -969,7 +958,8 @@ add_firewall_rule() {
gen_nftset $NFTSET_VPS ipv4_addr 0
gen_nftset $NFTSET_GFW ipv4_addr "2d"
gen_nftset $NFTSET_LOCAL ipv4_addr 0
gen_nftset $NFTSET_LAN ipv4_addr 0 $(gen_lanlist)
gen_nftset $NFTSET_LAN ipv4_addr 0
gen_lanlist | insert_nftset $NFTSET_LAN
gen_nftset $NFTSET_CHN ipv4_addr "2d"
if [ -f $RULES_PATH/chnroute.nft ] && [ -s $RULES_PATH/chnroute.nft ] && [ $(awk 'END{print NR}' $RULES_PATH/chnroute.nft) -ge 8 ]; then
nft -f $RULES_PATH/chnroute.nft
@@ -990,7 +980,8 @@ add_firewall_rule() {
gen_nftset $NFTSET_VPS6 ipv6_addr 0
gen_nftset $NFTSET_GFW6 ipv6_addr "2d"
gen_nftset $NFTSET_LOCAL6 ipv6_addr 0
gen_nftset $NFTSET_LAN6 ipv6_addr 0 $(gen_lanlist_6)
gen_nftset $NFTSET_LAN6 ipv6_addr 0
gen_lanlist_6 | insert_nftset $NFTSET_LAN6
gen_nftset $NFTSET_CHN6 ipv6_addr "2d"
if [ -f $RULES_PATH/chnroute6.nft ] && [ -s $RULES_PATH/chnroute6.nft ] && [ $(awk 'END{print NR}' $RULES_PATH/chnroute6.nft) -ge 8 ]; then
#echolog "使用缓存加载chnroute6..."
@@ -1627,9 +1618,6 @@ stop() {
arg1=$1
shift
case $arg1 in
insert_nftset)
insert_nftset "$@"
;;
filter_direct_node_list)
filter_direct_node_list
;;