mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-09-10 18:34:18 +08:00
💋 Sync 2026-08-20 03:58:15
This commit is contained in:
+2
-2
@@ -5,8 +5,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=dnsproxy
|
||||
PKG_VERSION:=0.84.0
|
||||
PKG_RELEASE:=16
|
||||
PKG_VERSION:=0.84.1
|
||||
PKG_RELEASE:=17
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/AdguardTeam/dnsproxy/tar.gz/v$(PKG_VERSION)?
|
||||
|
||||
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall
|
||||
PKG_VERSION:=26.8.19
|
||||
PKG_RELEASE:=230
|
||||
PKG_RELEASE:=231
|
||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
|
||||
@@ -320,7 +320,7 @@ o:depends({ protocol = "tuic" })
|
||||
o:depends({ protocol = "hysteria2" })
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not fs.access(value) then
|
||||
if not api.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
@@ -339,7 +339,7 @@ o:depends({ protocol = "tuic" })
|
||||
o:depends({ protocol = "hysteria2" })
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not fs.access(value) then
|
||||
if not api.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
|
||||
@@ -259,7 +259,7 @@ o:depends({ tls = true, reality = false })
|
||||
o:depends({ protocol = "hysteria2"})
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not fs.access(value) then
|
||||
if not api.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
@@ -275,7 +275,7 @@ o:depends({ tls = true, reality = false })
|
||||
o:depends({ protocol = "hysteria2"})
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not fs.access(value) then
|
||||
if not api.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
|
||||
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall2
|
||||
PKG_VERSION:=26.8.17
|
||||
PKG_RELEASE:=91
|
||||
PKG_RELEASE:=92
|
||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
|
||||
@@ -1723,6 +1723,7 @@ function apply_redirect(m)
|
||||
end
|
||||
end
|
||||
else
|
||||
uci:revert(c_config .. "_redirect")
|
||||
sys.call("/bin/rm -f " .. tmp_uci_file)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ LUCI_TITLE:=luci-app-ssr-plus
|
||||
LUCI_PKGARCH:=all
|
||||
PKG_NAME:=luci-app-ssr-plus
|
||||
PKG_VERSION:=196
|
||||
PKG_RELEASE:=59
|
||||
PKG_RELEASE:=60
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \
|
||||
|
||||
@@ -183,10 +183,10 @@ if is_finded("chinadns-ng") then
|
||||
o:depends("pdnsd_enable", "6")
|
||||
o.default = "8.8.4.4:53"
|
||||
o.description = translate(
|
||||
"<ul>" ..
|
||||
"<li>" .. translate("Custom DNS Server format as IP:PORT (default: 8.8.4.4:53)") .. "</li>" ..
|
||||
"<li>" .. translate("Muitiple DNS server can saperate with ','") .. "</li>" ..
|
||||
"</ul>"
|
||||
"<ul>" ..
|
||||
"<li>" .. translate("Custom DNS Server format as IP:PORT (default: 8.8.4.4:53)") .. "</li>" ..
|
||||
"<li>" .. translate("Muitiple DNS server can saperate with ','") .. "</li>" ..
|
||||
"</ul>"
|
||||
)
|
||||
|
||||
o = s:option(ListValue, "chinadns_ng_proto", translate("ChinaDNS-NG query protocol"))
|
||||
@@ -209,13 +209,33 @@ if is_finded("chinadns-ng") then
|
||||
o:value("1.2.4.8:53", translate("CNNIC SDNS (1.2.4.8)"))
|
||||
o:depends({pdnsd_enable = "6", run_mode = "router"})
|
||||
o.default = "wan"
|
||||
o.description = translate("Custom DNS Server format as IP:PORT (default: disabled)")
|
||||
o.description = translate(
|
||||
"<ul>" ..
|
||||
"<li>" .. translate("Custom DNS Server format as IP:PORT (default: disabled)") .. "</li>" ..
|
||||
"<li>" .. translate("Muitiple DNS server can saperate with ','") .. "</li>" ..
|
||||
"</ul>"
|
||||
)
|
||||
o.validate = function(self, value, section)
|
||||
if (section and value) then
|
||||
if value == "none" or value == "wan" or value == "wan_114" then
|
||||
return value
|
||||
end
|
||||
|
||||
if string.find(value, ",") then
|
||||
local parts = {}
|
||||
for part in string.gmatch(value, "[^,]+") do
|
||||
part = part:gsub("^%s*", ""):gsub("%s*$", "")
|
||||
if not validation.ip4addrport(part) then
|
||||
return nil, translate("Expecting: %s"):format(translate("valid address:port (comma separated)"))
|
||||
end
|
||||
table.insert(parts, part)
|
||||
end
|
||||
if #parts == 0 then
|
||||
return nil, translate("Expecting: %s"):format(translate("valid address:port"))
|
||||
end
|
||||
return table.concat(parts, ",")
|
||||
end
|
||||
|
||||
if validation.ip4addrport(value) then
|
||||
return value
|
||||
end
|
||||
|
||||
@@ -87,6 +87,7 @@ msgstr ""
|
||||
#: 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
|
||||
msgid "<ul><li>"
|
||||
msgstr ""
|
||||
|
||||
@@ -588,7 +589,7 @@ msgstr ""
|
||||
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:212
|
||||
#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:214
|
||||
msgid "Custom DNS Server format as IP:PORT (default: disabled)"
|
||||
msgstr ""
|
||||
|
||||
@@ -981,7 +982,9 @@ msgstr ""
|
||||
msgid "Example:"
|
||||
msgstr ""
|
||||
|
||||
#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:223
|
||||
#: 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
|
||||
msgid "Expecting: %s"
|
||||
msgstr ""
|
||||
|
||||
@@ -1650,6 +1653,7 @@ 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
|
||||
msgid "Muitiple DNS server can saperate with ','"
|
||||
msgstr ""
|
||||
|
||||
@@ -3339,10 +3343,15 @@ msgstr ""
|
||||
msgid "v2ray-plugin"
|
||||
msgstr ""
|
||||
|
||||
#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:223
|
||||
#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:234
|
||||
#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:243
|
||||
msgid "valid address:port"
|
||||
msgstr ""
|
||||
|
||||
#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:229
|
||||
msgid "valid address:port (comma separated)"
|
||||
msgstr ""
|
||||
|
||||
#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:82
|
||||
msgid "warning! Please do not reuse the port!"
|
||||
msgstr ""
|
||||
|
||||
@@ -91,6 +91,7 @@ msgstr ""
|
||||
#: 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
|
||||
msgid "<ul><li>"
|
||||
msgstr ""
|
||||
|
||||
@@ -592,7 +593,7 @@ msgstr "自定义客户端代理规则"
|
||||
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:212
|
||||
#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:214
|
||||
msgid "Custom DNS Server format as IP:PORT (default: disabled)"
|
||||
msgstr "格式为 IP:PORT(默认:禁用)"
|
||||
|
||||
@@ -990,7 +991,9 @@ msgstr "每周三"
|
||||
msgid "Example:"
|
||||
msgstr "示例:"
|
||||
|
||||
#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:223
|
||||
#: 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
|
||||
msgid "Expecting: %s"
|
||||
msgstr "应为:%s"
|
||||
|
||||
@@ -1664,6 +1667,7 @@ 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
|
||||
msgid "Muitiple DNS server can saperate with ','"
|
||||
msgstr "多个上游 DNS 服务器请用 ',' 分隔(注意用英文逗号)"
|
||||
|
||||
@@ -3370,10 +3374,15 @@ msgstr ""
|
||||
msgid "v2ray-plugin"
|
||||
msgstr ""
|
||||
|
||||
#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:223
|
||||
#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:234
|
||||
#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:243
|
||||
msgid "valid address:port"
|
||||
msgstr "有效的地址:端口"
|
||||
|
||||
#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:229
|
||||
msgid "valid address:port (comma separated)"
|
||||
msgstr "有效地址:端口(用逗号分隔)"
|
||||
|
||||
#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:82
|
||||
msgid "warning! Please do not reuse the port!"
|
||||
msgstr "警告!请不要重复使用端口!"
|
||||
|
||||
@@ -1257,7 +1257,7 @@ start_dns() {
|
||||
if [ "$builtin_dns_enabled" = "1" ]; then
|
||||
pdnsd_enable_flag=7
|
||||
elif [ "$ssrplus_dns" != "0" ]; then
|
||||
if [ "$HAS_IPSET" -eq 1 ]; then
|
||||
if [ "$USE_TABLES" = "iptables" ]; then
|
||||
if [ -n "$dnsserver" ]; then
|
||||
add_dns_into_ipset "$run_mode" "$dnsserver"
|
||||
fi
|
||||
@@ -1273,7 +1273,7 @@ start_dns() {
|
||||
output=$(for i in $(echo "$mosdns_dnsserver" | sed "s/,/ /g"); do
|
||||
dnsserver="${i%:*}"
|
||||
dnsserver="${i##*/}"
|
||||
if [ "$HAS_IPSET" -eq 1 ]; then
|
||||
if [ "$USE_TABLES" = "iptables" ]; then
|
||||
add_dns_into_ipset "$run_mode" "$dnsserver"
|
||||
fi
|
||||
echo " - addr: $i"
|
||||
@@ -1295,29 +1295,39 @@ start_dns() {
|
||||
# 遍历每个 DNS 服务器
|
||||
IFS=',' # 设置分隔符为逗号
|
||||
for chinadns_ng_server in $dnsserver; do
|
||||
chinadns_ng_server="$(echo "$chinadns_ng_server" | sed 's/[[:space:]]//g')"
|
||||
[ -z "$chinadns_ng_server" ] && continue
|
||||
# 处理单个服务器地址
|
||||
chinadns_ng_ip="${chinadns_ng_server%%:*}"
|
||||
chinadns_ng_port="${chinadns_ng_server##*:}"
|
||||
|
||||
# 如果没有显式指定端口,根据协议填入默认端口
|
||||
[ "$chinadns_ng_ip" = "$chinadns_ng_port" ] && chinadns_ng_port="53"
|
||||
chinadns_ng_tls_port="853"
|
||||
# TLS 协议强制使用 853 端口(DoT 标准端口),忽略用户指定的端口
|
||||
[ "$chinadns_ng_proto" = "tls" ] && chinadns_ng_port="853"
|
||||
# 根据协议类型格式化服务器地址
|
||||
case "$chinadns_ng_proto" in
|
||||
"none")
|
||||
chinadns_ng_server="${chinadns_ng_ip}#${chinadns_ng_port}"
|
||||
;;
|
||||
chinadns_ng_server="${chinadns_ng_ip}#${chinadns_ng_port}"
|
||||
;;
|
||||
"tls")
|
||||
chinadns_ng_server="${chinadns_ng_proto}://${chinadns_ng_ip}#${chinadns_ng_tls_port}"
|
||||
;;
|
||||
chinadns_ng_server="${chinadns_ng_proto}://${chinadns_ng_ip}#${chinadns_ng_port}"
|
||||
;;
|
||||
*)
|
||||
chinadns_ng_server="${chinadns_ng_proto}://${chinadns_ng_ip}#${chinadns_ng_port}"
|
||||
;;
|
||||
chinadns_ng_server="${chinadns_ng_proto}://${chinadns_ng_ip}#${chinadns_ng_port}"
|
||||
;;
|
||||
esac
|
||||
# 添加到参数列表
|
||||
chinadns_ng_dns="${chinadns_ng_dns} -t ${chinadns_ng_server}"
|
||||
done
|
||||
unset IFS # 恢复默认分隔符
|
||||
|
||||
dnsserver="$chinadns_ng_dns"
|
||||
ln_start_bin "$(first_type chinadns-ng)" chinadns-ng -b 127.0.0.1 -l "$tmp_dns_port" -l "$dns_port" -p 3 -d gfw "$dnsserver" -N --filter-qtype 64,65 -f -r --cache 4096 --cache-stale 86400 --cache-refresh 20
|
||||
# $dnsserver holds a list of "-t <server>" arguments built above, so it
|
||||
# has to stay unquoted and word-split into separate arguments
|
||||
# shellcheck disable=SC2086
|
||||
ln_start_bin "$(first_type chinadns-ng)" chinadns-ng -b 127.0.0.1 -l "$dns_port" -p 3 -d gfw $dnsserver -N --filter-qtype 64,65 -f -r --cache 4096 --cache-stale 86400 --cache-refresh 20 --verdict-cache 4096
|
||||
ln_start_bin "$(first_type chinadns-ng)" chinadns-ng -b 127.0.0.1 -l "$tmp_dns_port" -p 3 -d gfw $dnsserver -N --filter-qtype 64,65 -f -r --cache 4096 --cache-stale 86400 --cache-refresh 20 --verdict-cache 4096
|
||||
echolog "ChinaDNS-NG query and cache Started!"
|
||||
pdnsd_enable_flag=6
|
||||
;;
|
||||
@@ -1332,8 +1342,30 @@ start_dns() {
|
||||
"wan_114") chinadns="$wandns,114.114.114.114" ;;
|
||||
esac
|
||||
|
||||
filtered_chinadns=$(echo "$chinadns" | sed 's/:/#/')
|
||||
ln_start_bin "$(first_type chinadns-ng)" chinadns-ng -l "$china_dns_port" -4 china -p 3 -c "$filtered_chinadns" -t "127.0.0.1#$dns_port" -N -f -r
|
||||
filtered_chinadns=""
|
||||
IFS=','
|
||||
for chinadns_ip in $chinadns; do
|
||||
# 过滤可能的前后空白字符
|
||||
chinadns_ip="$(echo "$chinadns_ip" | sed 's/[[:space:]]//g')"
|
||||
[ -z "$chinadns_ip" ] && continue
|
||||
|
||||
# 将 IP:PORT 格式转换为 IP#PORT(若无端口默认使用 53)
|
||||
if echo "$chinadns_ip" | grep -q "#"; then
|
||||
: # 已是 IP#PORT 格式,无需更改
|
||||
elif echo "$chinadns_ip" | grep -qE ':[0-9]+$'; then
|
||||
chinadns_ip="$(echo "$chinadns_ip" | sed -E 's/:([0-9]+)$/#\1/')"
|
||||
else
|
||||
chinadns_ip="${chinadns_ip}#53"
|
||||
fi
|
||||
filtered_chinadns="${filtered_chinadns} -c ${chinadns_ip}"
|
||||
done
|
||||
unset IFS
|
||||
|
||||
if [ "$USE_TABLES" = "iptables" ]; then
|
||||
ln_start_bin "$(first_type chinadns-ng)" chinadns-ng -l "$china_dns_port" -4 china -p 3 $filtered_chinadns -t "127.0.0.1#$dns_port" -N -f -r --cache 4096 --cache-stale 86400 --cache-refresh 20 --verdict-cache 4096
|
||||
elif [ "$USE_TABLES" = "nftables" ]; then
|
||||
ln_start_bin "$(first_type chinadns-ng)" chinadns-ng -l "$china_dns_port" -4 inet@ss_spec@china -p 3 $filtered_chinadns -t "127.0.0.1#$dns_port" -N -f -r --cache 4096 --cache-stale 86400 --cache-refresh 20 --verdict-cache 4096
|
||||
fi
|
||||
|
||||
cat <<-EOF >> "$TMP_DNSMASQ_PATH/chinadns_fixed_server.conf"
|
||||
no-poll
|
||||
@@ -1466,21 +1498,21 @@ generate_xray_config() {
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
cat > "$config_file" << EOF
|
||||
{
|
||||
"log": {
|
||||
"loglevel": "warning"
|
||||
},
|
||||
"inbounds": [$inbound_json],
|
||||
"outbounds": [
|
||||
|
||||
cat <<-EOF >"$config_file"
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"settings": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
"log": {
|
||||
"loglevel": "warning"
|
||||
},
|
||||
"inbounds": [$inbound_json],
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"settings": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -2944,7 +2976,7 @@ start() {
|
||||
start_rules
|
||||
start_dns
|
||||
# Restore ipsets after rules creation
|
||||
if [ "$HAS_IPSET" -eq 1 ]; then
|
||||
if [ "$USE_TABLES" = "iptables" ]; then
|
||||
for setname in gfwlist china blacklist whitelist; do
|
||||
[ "$setname" = "gfwlist" ] && [ "$run_mode" != "gfw" ] && continue
|
||||
if [ -f "/tmp/ssrplus_save/${setname}.save" ]; then
|
||||
@@ -3037,7 +3069,7 @@ stop() {
|
||||
set_lock
|
||||
check_run_environment
|
||||
# Save ipsets before stopping to persist transparent proxy state
|
||||
if [ "$HAS_IPSET" -eq 1 ]; then
|
||||
if [ "$USE_TABLES" = "iptables" ]; then
|
||||
mkdir -p /tmp/ssrplus_save
|
||||
run_mode="$(uci_get_by_type global run_mode)"
|
||||
if [ "$run_mode" = "gfw" ]; then
|
||||
|
||||
@@ -4,12 +4,23 @@ require "luci.sys"
|
||||
local ucursor = require "luci.model.uci".cursor()
|
||||
local json = require "luci.jsonc"
|
||||
|
||||
local server_section = arg[1]
|
||||
local proto = arg[2] or "tcp"
|
||||
local local_port = arg[3] or "0"
|
||||
local socks_port = arg[4] or "0"
|
||||
-- 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
|
||||
-- are truthy in Lua, so "arg[n] or default" alone does not cover both.
|
||||
local function argv(n, default)
|
||||
local value = arg[n]
|
||||
if value == nil or value == "" then
|
||||
return default
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
local chain = arg[5] or "0"
|
||||
local server_section = arg[1]
|
||||
local proto = argv(2, "tcp")
|
||||
local local_port = argv(3, "0")
|
||||
local socks_port = argv(4, "0")
|
||||
|
||||
local chain = argv(5, "0")
|
||||
|
||||
-- trim
|
||||
local function trim(text)
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=mosdns
|
||||
PKG_VERSION:=5.3.4
|
||||
PKG_RELEASE:=14
|
||||
PKG_RELEASE:=15
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/IrineSistiana/mosdns/tar.gz/v$(PKG_VERSION)?
|
||||
|
||||
@@ -0,0 +1,661 @@
|
||||
From ebf6a87a410d60785894f9c2c7693de5921591bf Mon Sep 17 00:00:00 2001
|
||||
From: sbwml <admin@cooluc.com>
|
||||
Date: Wed, 19 Aug 2026 12:44:54 +0800
|
||||
Subject: [PATCH 1/2] feat: add query log support
|
||||
|
||||
Signed-off-by: sbwml <admin@cooluc.com>
|
||||
---
|
||||
mlog/logger.go | 11 ++
|
||||
pkg/query_context/context.go | 146 ++++++++++++++++++++++++-
|
||||
pkg/server/doq.go | 1 +
|
||||
pkg/server/http_handler.go | 1 +
|
||||
pkg/server/iface.go | 1 +
|
||||
pkg/server/tcp.go | 6 +-
|
||||
pkg/server/udp.go | 2 +-
|
||||
pkg/server_handler/entry_handler.go | 5 +
|
||||
plugin/executable/cache/cache.go | 12 ++
|
||||
plugin/executable/forward/forward.go | 34 +++++-
|
||||
plugin/executable/sequence/built_in.go | 12 +-
|
||||
plugin/executable/sequence/chain.go | 98 ++++++++++++++++-
|
||||
plugin/executable/sequence/sequence.go | 8 +-
|
||||
13 files changed, 316 insertions(+), 21 deletions(-)
|
||||
|
||||
--- a/mlog/logger.go
|
||||
+++ b/mlog/logger.go
|
||||
@@ -55,13 +55,24 @@ var (
|
||||
s = l.Sugar()
|
||||
|
||||
nop = zap.NewNop()
|
||||
+
|
||||
+ isDebug bool
|
||||
)
|
||||
|
||||
+func IsDebug() bool {
|
||||
+ return isDebug
|
||||
+}
|
||||
+
|
||||
func NewLogger(lc LogConfig) (*zap.Logger, error) {
|
||||
lvl, err := zapcore.ParseLevel(lc.Level)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid log level: %w", err)
|
||||
}
|
||||
+ if lvl <= zapcore.DebugLevel {
|
||||
+ isDebug = true
|
||||
+ } else {
|
||||
+ isDebug = false
|
||||
+ }
|
||||
|
||||
var out zapcore.WriteSyncer
|
||||
if lf := lc.File; len(lf) > 0 {
|
||||
--- a/pkg/query_context/context.go
|
||||
+++ b/pkg/query_context/context.go
|
||||
@@ -20,9 +20,11 @@
|
||||
package query_context
|
||||
|
||||
import (
|
||||
+ "fmt"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
+ "github.com/IrineSistiana/mosdns/v5/mlog"
|
||||
"github.com/IrineSistiana/mosdns/v5/pkg/server"
|
||||
"github.com/miekg/dns"
|
||||
"go.uber.org/zap"
|
||||
@@ -33,6 +35,26 @@ const (
|
||||
edns0Size = 1200
|
||||
)
|
||||
|
||||
+type UpstreamLog struct {
|
||||
+ Addr string
|
||||
+ Protocol string
|
||||
+ Tag string
|
||||
+ Plugin string
|
||||
+}
|
||||
+
|
||||
+type RuleHit struct {
|
||||
+ Sequence string
|
||||
+ Matches []string
|
||||
+ Exec string
|
||||
+}
|
||||
+
|
||||
+type CacheLog struct {
|
||||
+ Hit bool
|
||||
+ LazyHit bool
|
||||
+ TTL int
|
||||
+ RemainingTTL int
|
||||
+}
|
||||
+
|
||||
// Context is a query context that pass through plugins.
|
||||
// All Context funcs are not safe for concurrent use.
|
||||
type Context struct {
|
||||
@@ -49,11 +71,42 @@ type Context struct {
|
||||
respOpt *dns.OPT // nil if clientOpt == nil
|
||||
upstreamOpt *dns.OPT // may be nil
|
||||
|
||||
+ // Log details
|
||||
+ UpstreamSelected *UpstreamLog
|
||||
+ RuleHits []RuleHit
|
||||
+ CacheState CacheLog
|
||||
+
|
||||
// lazy init.
|
||||
kv map[uint32]any
|
||||
marks map[uint32]struct{}
|
||||
}
|
||||
|
||||
+func (ctx *Context) AddRuleHit(seq string, matches []string, exec string) {
|
||||
+ ctx.RuleHits = append(ctx.RuleHits, RuleHit{
|
||||
+ Sequence: seq,
|
||||
+ Matches: matches,
|
||||
+ Exec: exec,
|
||||
+ })
|
||||
+}
|
||||
+
|
||||
+func (ctx *Context) SetUpstreamSelected(addr, protocol, tag, plugin string) {
|
||||
+ ctx.UpstreamSelected = &UpstreamLog{
|
||||
+ Addr: addr,
|
||||
+ Protocol: protocol,
|
||||
+ Tag: tag,
|
||||
+ Plugin: plugin,
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+func (ctx *Context) SetCacheState(hit, lazyHit bool, ttl, remainingTTL int) {
|
||||
+ ctx.CacheState = CacheLog{
|
||||
+ Hit: hit,
|
||||
+ LazyHit: lazyHit,
|
||||
+ TTL: ttl,
|
||||
+ RemainingTTL: remainingTTL,
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
var contextUid atomic.Uint32
|
||||
|
||||
type ServerMeta = server.QueryMeta
|
||||
@@ -237,17 +290,106 @@ func (ctx *Context) MarshalLogObject(enc
|
||||
encoder.AddUint32("uqid", ctx.id)
|
||||
|
||||
if clientAddr := ctx.ServerMeta.ClientAddr; clientAddr.IsValid() {
|
||||
- zap.Stringer("client", clientAddr).AddTo(encoder)
|
||||
+ encoder.AddString("client", clientAddr.String())
|
||||
}
|
||||
|
||||
question := ctx.query.Question[0]
|
||||
encoder.AddString("qname", question.Name)
|
||||
- encoder.AddUint16("qtype", question.Qtype)
|
||||
+
|
||||
+ qTypeStr := dns.TypeToString[question.Qtype]
|
||||
+ if qTypeStr == "" {
|
||||
+ qTypeStr = fmt.Sprintf("TYPE%d", question.Qtype)
|
||||
+ }
|
||||
+ encoder.AddString("qtype", qTypeStr)
|
||||
encoder.AddUint16("qclass", question.Qclass)
|
||||
|
||||
+ proto := ctx.ServerMeta.Protocol
|
||||
+ if proto == "" {
|
||||
+ if ctx.ServerMeta.FromUDP {
|
||||
+ proto = "UDP"
|
||||
+ } else {
|
||||
+ proto = "TCP"
|
||||
+ }
|
||||
+ }
|
||||
+ encoder.AddString("protocol", proto)
|
||||
+
|
||||
+ if mlog.IsDebug() && len(ctx.RuleHits) > 0 {
|
||||
+ encoder.AddArray("rule_hits", zapcore.ArrayMarshalerFunc(func(arr zapcore.ArrayEncoder) error {
|
||||
+ for _, hit := range ctx.RuleHits {
|
||||
+ arr.AppendObject(zapcore.ObjectMarshalerFunc(func(enc zapcore.ObjectEncoder) error {
|
||||
+ enc.AddString("sequence", hit.Sequence)
|
||||
+ enc.AddArray("matches", zapcore.ArrayMarshalerFunc(func(ae zapcore.ArrayEncoder) error {
|
||||
+ for _, m := range hit.Matches {
|
||||
+ ae.AppendString(m)
|
||||
+ }
|
||||
+ return nil
|
||||
+ }))
|
||||
+ enc.AddString("exec", hit.Exec)
|
||||
+ return nil
|
||||
+ }))
|
||||
+ }
|
||||
+ return nil
|
||||
+ }))
|
||||
+ }
|
||||
+
|
||||
+ if ctx.UpstreamSelected != nil {
|
||||
+ encoder.AddObject("upstream", zapcore.ObjectMarshalerFunc(func(enc zapcore.ObjectEncoder) error {
|
||||
+ enc.AddString("addr", ctx.UpstreamSelected.Addr)
|
||||
+ enc.AddString("protocol", ctx.UpstreamSelected.Protocol)
|
||||
+ enc.AddString("tag", ctx.UpstreamSelected.Tag)
|
||||
+ enc.AddString("plugin", ctx.UpstreamSelected.Plugin)
|
||||
+ return nil
|
||||
+ }))
|
||||
+ }
|
||||
+
|
||||
+ encoder.AddObject("cache", zapcore.ObjectMarshalerFunc(func(enc zapcore.ObjectEncoder) error {
|
||||
+ enc.AddBool("hit", ctx.CacheState.Hit)
|
||||
+ enc.AddBool("lazy_hit", ctx.CacheState.LazyHit)
|
||||
+ enc.AddInt("ttl", ctx.CacheState.TTL)
|
||||
+ enc.AddInt("remaining_ttl", ctx.CacheState.RemainingTTL)
|
||||
+ return nil
|
||||
+ }))
|
||||
+
|
||||
if r := ctx.resp; r != nil {
|
||||
encoder.AddInt("rcode", r.Rcode)
|
||||
+ encoder.AddInt("resp_size", r.Len())
|
||||
+
|
||||
+ var ips []string
|
||||
+ var cnames []string
|
||||
+ var ttl uint32
|
||||
+ for _, rr := range r.Answer {
|
||||
+ ttl = rr.Header().Ttl
|
||||
+ switch record := rr.(type) {
|
||||
+ case *dns.A:
|
||||
+ ips = append(ips, record.A.String())
|
||||
+ case *dns.AAAA:
|
||||
+ ips = append(ips, record.AAAA.String())
|
||||
+ case *dns.CNAME:
|
||||
+ cnames = append(cnames, record.Target)
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if len(ips) > 0 {
|
||||
+ encoder.AddArray("ips", zapcore.ArrayMarshalerFunc(func(ae zapcore.ArrayEncoder) error {
|
||||
+ for _, ip := range ips {
|
||||
+ ae.AppendString(ip)
|
||||
+ }
|
||||
+ return nil
|
||||
+ }))
|
||||
+ }
|
||||
+ if len(cnames) > 0 {
|
||||
+ encoder.AddArray("cnames", zapcore.ArrayMarshalerFunc(func(ae zapcore.ArrayEncoder) error {
|
||||
+ for _, c := range cnames {
|
||||
+ ae.AppendString(c)
|
||||
+ }
|
||||
+ return nil
|
||||
+ }))
|
||||
+ }
|
||||
+ if len(r.Answer) > 0 {
|
||||
+ encoder.AddUint32("original_ttl", ttl)
|
||||
+ }
|
||||
}
|
||||
+
|
||||
encoder.AddDuration("elapsed", time.Since(ctx.startTime))
|
||||
return nil
|
||||
}
|
||||
--- a/pkg/server/doq.go
|
||||
+++ b/pkg/server/doq.go
|
||||
@@ -107,6 +107,7 @@ func ServeDoQ(l *quic.Listener, h Handle
|
||||
queryMeta := QueryMeta{
|
||||
ClientAddr: clientAddr,
|
||||
ServerName: c.ConnectionState().TLS.ServerName,
|
||||
+ Protocol: "DoQ",
|
||||
}
|
||||
|
||||
resp := h.Handle(connCtx, req, queryMeta, pool.PackTCPBuffer)
|
||||
--- a/pkg/server/http_handler.go
|
||||
+++ b/pkg/server/http_handler.go
|
||||
@@ -97,6 +97,7 @@ func (h *HttpHandler) ServeHTTP(w http.R
|
||||
|
||||
queryMeta := QueryMeta{
|
||||
ClientAddr: clientAddr,
|
||||
+ Protocol: "DoH",
|
||||
}
|
||||
if u := req.URL; u != nil {
|
||||
queryMeta.UrlPath = u.Path
|
||||
--- a/pkg/server/iface.go
|
||||
+++ b/pkg/server/iface.go
|
||||
@@ -26,4 +26,5 @@ type QueryMeta struct {
|
||||
ClientAddr netip.Addr
|
||||
ServerName string
|
||||
UrlPath string
|
||||
+ Protocol string
|
||||
}
|
||||
--- a/pkg/server/tcp.go
|
||||
+++ b/pkg/server/tcp.go
|
||||
@@ -101,7 +101,11 @@ func ServeTCP(l net.Listener, h Handler,
|
||||
if ok {
|
||||
clientAddr = ta.AddrPort().Addr()
|
||||
}
|
||||
- r := h.Handle(tcpConnCtx, req, QueryMeta{ClientAddr: clientAddr, ServerName: serverName}, pool.PackTCPBuffer)
|
||||
+ proto := "TCP"
|
||||
+ if serverName != "" {
|
||||
+ proto = "DoT"
|
||||
+ }
|
||||
+ r := h.Handle(tcpConnCtx, req, QueryMeta{ClientAddr: clientAddr, ServerName: serverName, Protocol: proto}, pool.PackTCPBuffer)
|
||||
if r == nil {
|
||||
c.Close() // abort the connection
|
||||
return
|
||||
--- a/pkg/server/udp.go
|
||||
+++ b/pkg/server/udp.go
|
||||
@@ -88,7 +88,7 @@ func ServeUDP(c *net.UDPConn, h Handler,
|
||||
|
||||
// handle query
|
||||
go func() {
|
||||
- payload := h.Handle(listenerCtx, q, QueryMeta{ClientAddr: remoteAddr.Addr(), FromUDP: true}, pool.PackBuffer)
|
||||
+ payload := h.Handle(listenerCtx, q, QueryMeta{ClientAddr: remoteAddr.Addr(), FromUDP: true, Protocol: "UDP"}, pool.PackBuffer)
|
||||
if payload == nil {
|
||||
return
|
||||
}
|
||||
--- a/pkg/server_handler/entry_handler.go
|
||||
+++ b/pkg/server_handler/entry_handler.go
|
||||
@@ -131,6 +131,11 @@ func (h *EntryHandler) Handle(ctx contex
|
||||
h.opts.Logger.Error("internal err: failed to pack resp msg", qCtx.InfoField(), zap.Error(err))
|
||||
return nil
|
||||
}
|
||||
+ if mlog.IsDebug() {
|
||||
+ h.opts.Logger.Debug("query log", zap.Inline(qCtx))
|
||||
+ } else {
|
||||
+ h.opts.Logger.Info("query log", zap.Inline(qCtx))
|
||||
+ }
|
||||
return payload
|
||||
}
|
||||
|
||||
--- a/plugin/executable/cache/cache.go
|
||||
+++ b/plugin/executable/cache/cache.go
|
||||
@@ -204,6 +204,18 @@ func (c *Cache) Exec(ctx context.Context
|
||||
c.hitTotal.Inc()
|
||||
cachedResp.Id = q.Id // change msg id
|
||||
qCtx.SetResponse(cachedResp)
|
||||
+ if v, _, ok := c.backend.Get(key(msgKey)); ok && v != nil {
|
||||
+ ttl := int(v.expirationTime.Sub(v.storedTime).Seconds())
|
||||
+ remainingTtl := int(v.expirationTime.Sub(time.Now()).Seconds())
|
||||
+ if remainingTtl < 0 {
|
||||
+ remainingTtl = 0
|
||||
+ }
|
||||
+ qCtx.SetCacheState(true, lazyHit, ttl, remainingTtl)
|
||||
+ } else {
|
||||
+ qCtx.SetCacheState(true, lazyHit, 0, 0)
|
||||
+ }
|
||||
+ } else {
|
||||
+ qCtx.SetCacheState(false, false, 0, 0)
|
||||
}
|
||||
|
||||
err := next.ExecNext(ctx, qCtx)
|
||||
--- a/plugin/executable/forward/forward.go
|
||||
+++ b/plugin/executable/forward/forward.go
|
||||
@@ -104,6 +104,7 @@ type Forward struct {
|
||||
logger *zap.Logger
|
||||
us []*upstreamWrapper
|
||||
tag2Upstream map[string]*upstreamWrapper // for fast tag lookup only.
|
||||
+ pluginTag string
|
||||
}
|
||||
|
||||
type Opts struct {
|
||||
@@ -125,6 +126,7 @@ func NewForward(args *Args, opt Opts) (*
|
||||
args: args,
|
||||
logger: opt.Logger,
|
||||
tag2Upstream: make(map[string]*upstreamWrapper),
|
||||
+ pluginTag: opt.MetricsTag,
|
||||
}
|
||||
|
||||
applyGlobal := func(c *UpstreamConfig) {
|
||||
@@ -256,6 +258,7 @@ func (f *Forward) exchange(ctx context.C
|
||||
type res struct {
|
||||
r *dns.Msg
|
||||
err error
|
||||
+ u *upstreamWrapper
|
||||
}
|
||||
|
||||
resChan := make(chan res)
|
||||
@@ -266,14 +269,14 @@ func (f *Forward) exchange(ctx context.C
|
||||
for i := 0; i < concurrent; i++ {
|
||||
u := us[(r+i)%len(us)]
|
||||
qc := copyPayload(queryPayload)
|
||||
- go func(uqid uint32, question dns.Question) {
|
||||
+ go func(uqid uint32, question dns.Question, chosenUpstream *upstreamWrapper) {
|
||||
defer pool.ReleaseBuf(qc)
|
||||
// Give each upstream a fixed timeout to finish the query.
|
||||
upstreamCtx, cancel := context.WithTimeout(context.Background(), queryTimeout)
|
||||
defer cancel()
|
||||
|
||||
var r *dns.Msg
|
||||
- respPayload, err := u.ExchangeContext(upstreamCtx, *qc)
|
||||
+ respPayload, err := chosenUpstream.ExchangeContext(upstreamCtx, *qc)
|
||||
if err != nil {
|
||||
f.logger.Warn(
|
||||
"upstream error",
|
||||
@@ -281,7 +284,7 @@ func (f *Forward) exchange(ctx context.C
|
||||
zap.String("qname", question.Name),
|
||||
zap.Uint16("qclass", question.Qclass),
|
||||
zap.Uint16("qtype", question.Qtype),
|
||||
- zap.String("upstream", u.name()),
|
||||
+ zap.String("upstream", chosenUpstream.name()),
|
||||
zap.Error(err),
|
||||
)
|
||||
} else {
|
||||
@@ -293,16 +296,16 @@ func (f *Forward) exchange(ctx context.C
|
||||
}
|
||||
}
|
||||
select {
|
||||
- case resChan <- res{r: r, err: err}:
|
||||
+ case resChan <- res{r: r, err: err, u: chosenUpstream}:
|
||||
case <-done:
|
||||
}
|
||||
- }(qCtx.Id(), qCtx.QQuestion())
|
||||
+ }(qCtx.Id(), qCtx.QQuestion(), u)
|
||||
}
|
||||
|
||||
for i := 0; i < concurrent; i++ {
|
||||
select {
|
||||
case res := <-resChan:
|
||||
- r, err := res.r, res.err
|
||||
+ r, err, chosenUpstream := res.r, res.err, res.u
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@@ -311,6 +314,25 @@ func (f *Forward) exchange(ctx context.C
|
||||
if i < concurrent-1 && r.Rcode != dns.RcodeSuccess && r.Rcode != dns.RcodeNameError {
|
||||
continue
|
||||
}
|
||||
+
|
||||
+ if chosenUpstream != nil {
|
||||
+ addr := chosenUpstream.cfg.Addr
|
||||
+ proto := "UDP"
|
||||
+ if strings.Contains(addr, "://") {
|
||||
+ parts := strings.SplitN(addr, "://", 2)
|
||||
+ proto = strings.ToUpper(parts[0])
|
||||
+ addr = parts[1]
|
||||
+ }
|
||||
+ if proto == "TLS" {
|
||||
+ proto = "DoT"
|
||||
+ } else if proto == "HTTPS" {
|
||||
+ proto = "DoH"
|
||||
+ } else if proto == "QUIC" || proto == "DOQ" {
|
||||
+ proto = "DoQ"
|
||||
+ }
|
||||
+ qCtx.SetUpstreamSelected(addr, proto, chosenUpstream.cfg.Tag, f.pluginTag)
|
||||
+ }
|
||||
+
|
||||
return r, nil
|
||||
case <-ctx.Done():
|
||||
return nil, context.Cause(ctx)
|
||||
--- a/plugin/executable/sequence/built_in.go
|
||||
+++ b/plugin/executable/sequence/built_in.go
|
||||
@@ -83,11 +83,13 @@ func setupReturn(_ BQ, _ string) (any, e
|
||||
var _ RecursiveExecutable = (*ActionJump)(nil)
|
||||
|
||||
type ActionJump struct {
|
||||
- To []*ChainNode
|
||||
+ To []*ChainNode
|
||||
+ tag string
|
||||
}
|
||||
|
||||
func (a *ActionJump) Exec(ctx context.Context, qCtx *query_context.Context, next ChainWalker) error {
|
||||
w := NewChainWalker(a.To, &next)
|
||||
+ w.sequenceTag = a.tag
|
||||
return w.ExecNext(ctx, qCtx)
|
||||
}
|
||||
|
||||
@@ -96,17 +98,19 @@ func setupJump(bq BQ, s string) (any, er
|
||||
if target == nil {
|
||||
return nil, fmt.Errorf("can not find jump target %s", s)
|
||||
}
|
||||
- return &ActionJump{To: target.chain}, nil
|
||||
+ return &ActionJump{To: target.chain, tag: s}, nil
|
||||
}
|
||||
|
||||
var _ RecursiveExecutable = (*ActionGoto)(nil)
|
||||
|
||||
type ActionGoto struct {
|
||||
- To []*ChainNode
|
||||
+ To []*ChainNode
|
||||
+ tag string
|
||||
}
|
||||
|
||||
func (a ActionGoto) Exec(ctx context.Context, qCtx *query_context.Context, _ ChainWalker) error {
|
||||
w := NewChainWalker(a.To, nil)
|
||||
+ w.sequenceTag = a.tag
|
||||
return w.ExecNext(ctx, qCtx)
|
||||
}
|
||||
|
||||
@@ -115,7 +119,7 @@ func setupGoto(bq BQ, s string) (any, er
|
||||
if gt == nil {
|
||||
return nil, fmt.Errorf("can not find goto target %s", s)
|
||||
}
|
||||
- return &ActionGoto{To: gt.chain}, nil
|
||||
+ return &ActionGoto{To: gt.chain, tag: s}, nil
|
||||
}
|
||||
|
||||
var _ Matcher = (*MatchAlwaysTrue)(nil)
|
||||
--- a/plugin/executable/sequence/chain.go
|
||||
+++ b/plugin/executable/sequence/chain.go
|
||||
@@ -25,6 +25,8 @@ import (
|
||||
"fmt"
|
||||
"github.com/IrineSistiana/mosdns/v5/pkg/query_context"
|
||||
"io"
|
||||
+ "reflect"
|
||||
+ "strings"
|
||||
)
|
||||
|
||||
type ChainNode struct {
|
||||
@@ -34,12 +36,17 @@ type ChainNode struct {
|
||||
// In case both are set. E is preferred.
|
||||
E Executable
|
||||
RE RecursiveExecutable
|
||||
+
|
||||
+ RuleMatches []string
|
||||
+ RuleExec string
|
||||
+ IsControlOrSequence bool
|
||||
}
|
||||
|
||||
type ChainWalker struct {
|
||||
- p int
|
||||
- chain []*ChainNode
|
||||
- jumpBack *ChainWalker
|
||||
+ p int
|
||||
+ chain []*ChainNode
|
||||
+ jumpBack *ChainWalker
|
||||
+ sequenceTag string
|
||||
}
|
||||
|
||||
func NewChainWalker(chain []*ChainNode, jumpBack *ChainWalker) ChainWalker {
|
||||
@@ -49,6 +56,49 @@ func NewChainWalker(chain []*ChainNode,
|
||||
}
|
||||
}
|
||||
|
||||
+func formatMatchConfig(mc MatchConfig) string {
|
||||
+ var s string
|
||||
+ if mc.Tag != "" {
|
||||
+ s = "$" + mc.Tag
|
||||
+ } else {
|
||||
+ s = mc.Type
|
||||
+ if mc.Args != "" {
|
||||
+ s += " " + mc.Args
|
||||
+ }
|
||||
+ }
|
||||
+ if mc.Reverse {
|
||||
+ s = "!" + s
|
||||
+ }
|
||||
+ return s
|
||||
+}
|
||||
+
|
||||
+func formatRuleExec(rc RuleConfig) string {
|
||||
+ if rc.Tag != "" {
|
||||
+ return "$" + rc.Tag
|
||||
+ }
|
||||
+ s := rc.Type
|
||||
+ if rc.Args != "" {
|
||||
+ s += " " + rc.Args
|
||||
+ }
|
||||
+ return s
|
||||
+}
|
||||
+
|
||||
+func shouldLogRule(n *ChainNode, hasRespBefore, hasRespAfter bool) bool {
|
||||
+ for _, m := range n.RuleMatches {
|
||||
+ if !strings.HasPrefix(m, "!") {
|
||||
+ return true
|
||||
+ }
|
||||
+ }
|
||||
+ if !hasRespBefore && hasRespAfter {
|
||||
+ return true
|
||||
+ }
|
||||
+ exec := n.RuleExec
|
||||
+ if exec == "accept" || exec == "reject" || strings.HasPrefix(exec, "reject ") || exec == "drop_resp" || exec == "black_hole" {
|
||||
+ return true
|
||||
+ }
|
||||
+ return false
|
||||
+}
|
||||
+
|
||||
func (w *ChainWalker) ExecNext(ctx context.Context, qCtx *query_context.Context) error {
|
||||
p := w.p
|
||||
// Evaluate rules' matchers in loop.
|
||||
@@ -71,16 +121,26 @@ checkMatchesLoop:
|
||||
// Exec rules' executables in loop, or in stack if it is a recursive executable.
|
||||
switch {
|
||||
case n.E != nil:
|
||||
+ hasRespBefore := qCtx.R() != nil
|
||||
if err := n.E.Exec(ctx, qCtx); err != nil {
|
||||
return err
|
||||
}
|
||||
+ hasRespAfter := qCtx.R() != nil
|
||||
+ if shouldLogRule(n, hasRespBefore, hasRespAfter) {
|
||||
+ qCtx.AddRuleHit(w.sequenceTag, n.RuleMatches, n.RuleExec)
|
||||
+ }
|
||||
p++
|
||||
continue
|
||||
case n.RE != nil:
|
||||
+ hasRespBefore := qCtx.R() != nil
|
||||
+ if shouldLogRule(n, hasRespBefore, false) {
|
||||
+ qCtx.AddRuleHit(w.sequenceTag, n.RuleMatches, n.RuleExec)
|
||||
+ }
|
||||
next := ChainWalker{
|
||||
- p: p + 1,
|
||||
- chain: w.chain,
|
||||
- jumpBack: w.jumpBack,
|
||||
+ p: p + 1,
|
||||
+ chain: w.chain,
|
||||
+ jumpBack: w.jumpBack,
|
||||
+ sequenceTag: w.sequenceTag,
|
||||
}
|
||||
return n.RE.Exec(ctx, qCtx, next)
|
||||
default:
|
||||
@@ -113,8 +173,33 @@ func (s *Sequence) buildChain(bq BQ, rs
|
||||
return nil
|
||||
}
|
||||
|
||||
+func isControlOrSequence(bq BQ, rc RuleConfig) bool {
|
||||
+ exec := formatRuleExec(rc)
|
||||
+ if exec == "accept" || exec == "reject" || exec == "return" {
|
||||
+ return false
|
||||
+ }
|
||||
+ if strings.HasPrefix(exec, "jump") || strings.HasPrefix(exec, "goto") || strings.HasPrefix(exec, "return") {
|
||||
+ return true
|
||||
+ }
|
||||
+ if rc.Tag != "" {
|
||||
+ p := bq.M().GetPlugin(rc.Tag)
|
||||
+ if p != nil {
|
||||
+ t := reflect.TypeOf(p)
|
||||
+ if t != nil {
|
||||
+ name := t.String()
|
||||
+ if strings.Contains(name, "Sequence") || strings.Contains(name, "Fallback") {
|
||||
+ return true
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return false
|
||||
+}
|
||||
+
|
||||
func (s *Sequence) newNode(bq BQ, r RuleConfig, ri int) (*ChainNode, error) {
|
||||
n := new(ChainNode)
|
||||
+ n.RuleExec = formatRuleExec(r)
|
||||
+ n.IsControlOrSequence = (len(r.Matches) == 0) && isControlOrSequence(bq, r)
|
||||
|
||||
// init matches
|
||||
for mi, mc := range r.Matches {
|
||||
@@ -123,6 +208,7 @@ func (s *Sequence) newNode(bq BQ, r Rule
|
||||
return nil, fmt.Errorf("failed to init matcher #%d, %w", mi, err)
|
||||
}
|
||||
n.Matches = append(n.Matches, m)
|
||||
+ n.RuleMatches = append(n.RuleMatches, formatMatchConfig(mc))
|
||||
}
|
||||
|
||||
// init exec
|
||||
--- a/plugin/executable/sequence/sequence.go
|
||||
+++ b/plugin/executable/sequence/sequence.go
|
||||
@@ -40,6 +40,7 @@ func init() {
|
||||
}
|
||||
|
||||
type Sequence struct {
|
||||
+ tag string
|
||||
chain []*ChainNode
|
||||
anonymousPlugins []any
|
||||
}
|
||||
@@ -58,7 +59,11 @@ func Init(bp *coremain.BP, args any) (an
|
||||
}
|
||||
|
||||
func NewSequence(bq BQ, ra []RuleArgs) (*Sequence, error) {
|
||||
- s := &Sequence{}
|
||||
+ var tag string
|
||||
+ if t, ok := bq.(interface{ Tag() string }); ok {
|
||||
+ tag = t.Tag()
|
||||
+ }
|
||||
+ s := &Sequence{tag: tag}
|
||||
|
||||
var rc []RuleConfig
|
||||
for _, ra := range ra {
|
||||
@@ -73,5 +78,6 @@ func NewSequence(bq BQ, ra []RuleArgs) (
|
||||
|
||||
func (s *Sequence) Exec(ctx context.Context, qCtx *query_context.Context) error {
|
||||
walker := NewChainWalker(s.chain, nil)
|
||||
+ walker.sequenceTag = s.tag
|
||||
return walker.ExecNext(ctx, qCtx)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
From 0e78ad1d047043f9f3b4f47dea7cf9905ad09a7c Mon Sep 17 00:00:00 2001
|
||||
From: sbwml <admin@cooluc.com>
|
||||
Date: Wed, 19 Aug 2026 12:32:48 +0800
|
||||
Subject: [PATCH 2/2] fix(mlog): fix log file padded with null bytes after
|
||||
external truncation
|
||||
|
||||
Signed-off-by: sbwml <admin@cooluc.com>
|
||||
---
|
||||
mlog/rotator.go | 11 ++++++++---
|
||||
1 file changed, 8 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/mlog/rotator.go
|
||||
+++ b/mlog/rotator.go
|
||||
@@ -52,8 +52,13 @@ func (r *Rotator) Write(p []byte) (n int
|
||||
|
||||
writeLen := int64(len(p))
|
||||
if r.MaxSize > 0 && r.size+writeLen > r.MaxSize {
|
||||
- if err := r.rotate(); err != nil {
|
||||
- return 0, err
|
||||
+ if info, err := r.f.Stat(); err == nil {
|
||||
+ r.size = info.Size()
|
||||
+ }
|
||||
+ if r.size+writeLen > r.MaxSize {
|
||||
+ if err := r.rotate(); err != nil {
|
||||
+ return 0, err
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +89,7 @@ func (r *Rotator) openNew() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
- f, err := os.OpenFile(r.Filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
|
||||
+ f, err := os.OpenFile(r.Filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user