mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-11-01 10:23:56 +08:00
1 parent
ccd677de3a
commit
825070ba95
2037 files changed
+1694705
-12285
No files matched your search
+42
-30
@@ -5,51 +5,60 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=dae
|
||||
PKG_VERSION:=2026.09.02
|
||||
PKG_RELEASE:=1
|
||||
PKG_VERSION:=2026.08.28
|
||||
PKG_RELEASE:=3
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_VERSION:=ebbec6b5624d7790c58a11e081604e30b6c947b3
|
||||
PKG_SOURCE_URL:=https://github.com/olicesx/dae.git
|
||||
PKG_MIRROR_HASH:=skip
|
||||
PKG_SOURCE:=dae-src-2026.08.28-d6aca8a10b35.tar.gz
|
||||
PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/dae-src
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_HASH:=d6aca8a10b3549d28ff29979793fc0e074f183957f516a17b50d6f3961730c30
|
||||
|
||||
PKG_LICENSE:=AGPL-3.0-only
|
||||
PKG_LICENSE_FILE:=LICENSE
|
||||
PKG_MAINTAINER:=Tianling Shen <cnsztl@immortalwrt.org>
|
||||
PKG_MAINTAINER:=kenzok8
|
||||
|
||||
DAE_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_BUILD_DIR:=$(DAE_BUILD_DIR)/core
|
||||
|
||||
PKG_BUILD_DEPENDS:=golang/host bpf-headers
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_BUILD_FLAGS:=no-mips16
|
||||
|
||||
# armv7 lacks a CO-RE vmlinux.h for the trace eBPF, so trace's bpf2go fails to
|
||||
# build there. Apply sbwml/openwrt_helloworld's arm patches (add vmlinux-arm.h
|
||||
# + drop the kprobe that doesn't work) to let dae build on arm targets.
|
||||
ifeq ($(ARCH),arm)
|
||||
PATCH_DIR:=$(CURDIR)/patches_arm
|
||||
endif
|
||||
|
||||
GO_PKG:=github.com/daeuniverse/dae
|
||||
GO_PKG_EXCLUDES:=control/kern/tests
|
||||
|
||||
GO_PKG_LDFLAGS:= \
|
||||
-s -w -buildid= \
|
||||
-linkmode external -extldflags '-static -Wl,-s'
|
||||
GO_PKG_LDFLAGS_X:= \
|
||||
$(GO_PKG)/cmd.Version=$(PKG_VERSION) \
|
||||
$(GO_PKG)/common/consts.MaxMatchSetLen_=1024
|
||||
GO_PKG_TAGS:=trace
|
||||
|
||||
PGO_PROFILE:=$(CURDIR)/pprof/default.pgo
|
||||
GO_PKG_TAGS:=trace,timetzdata
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(INCLUDE_DIR)/bpf.mk
|
||||
include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk
|
||||
|
||||
GO_PKG_BUILD_VARS+= \
|
||||
GOFLAGS="-trimpath -buildvcs=false -pgo=auto"
|
||||
|
||||
GO_PKG_BUILD_VARS+= GOFLAGS="-trimpath -buildvcs=false -pgo=auto"
|
||||
GO_PKG_TARGET_VARS+= \
|
||||
CGO_LDFLAGS="$(TARGET_LDFLAGS) -static -Wl,-s" \
|
||||
GOEXPERIMENT=newinliner,simd
|
||||
|
||||
define Package/dae
|
||||
define Package/dae/Default
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
SUBMENU:=Web Servers/Proxies
|
||||
URL:=https://github.com/daeuniverse/dae
|
||||
endef
|
||||
|
||||
define Package/dae
|
||||
$(call Package/dae/Default)
|
||||
TITLE:=A lightweight and high-performance transparent proxy solution
|
||||
DEPENDS:=$(GO_ARCH_DEPENDS) \
|
||||
+ca-bundle +kmod-sched-core +kmod-sched-bpf \
|
||||
@@ -73,8 +82,13 @@ define Package/dae/config
|
||||
endchoice
|
||||
endef
|
||||
|
||||
define Package/dae/description
|
||||
dae, means goose, is a lightweight and high-performance transparent
|
||||
proxy solution.
|
||||
endef
|
||||
|
||||
define Package/dae/conffiles
|
||||
/etc/dae/
|
||||
/etc/dae/config.dae
|
||||
/etc/config/dae
|
||||
endef
|
||||
|
||||
@@ -83,17 +97,16 @@ DAE_CFLAGS:= \
|
||||
-DMAX_MATCH_SET_LEN=1024 \
|
||||
-I$(BPF_HEADERS_DIR)/tools/lib \
|
||||
-I$(BPF_HEADERS_DIR)/arch/$(BPF_KARCH)/include/asm/mach-generic
|
||||
|
||||
|
||||
define Build/Prepare
|
||||
$(call Build/Prepare/Default)
|
||||
[ -f "$(PGO_PROFILE)" ] && $(CP) "$(PGO_PROFILE)" "$(PKG_BUILD_DIR)/default.pgo" || true
|
||||
mkdir -p $(DAE_BUILD_DIR)
|
||||
$(TAR) --strip-components=1 -C $(DAE_BUILD_DIR) -xzf $(DL_DIR)/$(PKG_SOURCE)
|
||||
$(if $(wildcard $(PATCH_DIR)/*.patch),$(call PatchDir,$(PKG_BUILD_DIR),$(PATCH_DIR),))
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
( \
|
||||
pushd $(PKG_BUILD_DIR) ; \
|
||||
go get -u=patch ; \
|
||||
go mod tidy ; \
|
||||
export \
|
||||
$(GO_GENERAL_BUILD_CONFIG_VARS) \
|
||||
$(GO_PKG_BUILD_CONFIG_VARS) \
|
||||
@@ -112,17 +125,16 @@ endef
|
||||
|
||||
define Package/dae/install
|
||||
$(call GoPackage/Package/Install/Bin,$(PKG_INSTALL_DIR))
|
||||
$(INSTALL_DIR) $(1)/usr/bin/
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/dae $(1)/usr/bin/dae
|
||||
$(INSTALL_DIR) $(1)/etc/dae/
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/example.dae $(1)/etc/dae/
|
||||
$(INSTALL_CONF) $(CURDIR)/files/config.dae $(1)/etc/dae/config.dae
|
||||
$(INSTALL_DIR) $(1)/etc/dae/config.d/
|
||||
$(INSTALL_CONF) $(CURDIR)/files/config.d/dns.dae $(1)/etc/dae/config.d/dns.dae
|
||||
$(INSTALL_CONF) $(CURDIR)/files/config.d/node.dae $(1)/etc/dae/config.d/node.dae
|
||||
$(INSTALL_CONF) $(CURDIR)/files/config.d/route.dae $(1)/etc/dae/config.d/route.dae
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/dae
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/example.dae $(1)/etc/dae/example.dae
|
||||
$(SED) 's|^[[:space:]]*#lan_interface: docker0| lan_interface: br-lan|' $(1)/etc/dae/example.dae
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(INSTALL_CONF) $(CURDIR)/files/dae.config $(1)/etc/config/dae
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_BIN) $(CURDIR)/files/dae.init $(1)/etc/init.d/dae
|
||||
endef
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
# dns.dae
|
||||
dns {
|
||||
optimistic_cache_ttl: 86400
|
||||
max_cache_size: 4096
|
||||
upstream {
|
||||
localdns: 'udp://127.0.0.1:53'
|
||||
overseadns: 'tcp+udp://1.0.0.1:53'
|
||||
nodedns: 'udp://111.222.333.444:53'
|
||||
}
|
||||
routing {
|
||||
request {
|
||||
sub(sub_name) -> overseadns
|
||||
subnode(sub_name) && subnode(name_keyword: 114514) -> nodedns
|
||||
qtype(https) -> reject
|
||||
qname(geosite:gfw) -> overseadns
|
||||
fallback: localdns
|
||||
}
|
||||
response {
|
||||
upstream(overseadns) -> accept
|
||||
qname(geosite:private) -> accept
|
||||
ip(geoip:cn) -> accept
|
||||
fallback: overseadns
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
# node.dae
|
||||
node {
|
||||
node1: 'xxx'
|
||||
node2: 'xxx'
|
||||
}
|
||||
subscription {
|
||||
my_sub: 'https://www.example.com/subscription/link'
|
||||
}
|
||||
group {
|
||||
my_group {
|
||||
filter: subtag(my_sub) && !name(keyword: 'ExpireAt:')
|
||||
filter: subtag(my_sub2)
|
||||
policy: min_moving_avg
|
||||
}
|
||||
local_group {
|
||||
filter: name(node1, node2)
|
||||
policy: fixed(0)
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
# route.dae
|
||||
routing {
|
||||
pname(dnsmasq, zerotier-one) -> must_direct
|
||||
dip(224.0.0.0/3, 'ff00::/8', geoip:private) -> direct
|
||||
|
||||
domain(geosite:category-bank-cn, geosite:boc@!cn, geosite:synology) -> direct
|
||||
|
||||
domain(geosite:category-ai-!cn, geosite:google, geosite:category-entertainment, geosite:gfw, geosite:github, geosite:spotify) && l4proto(udp) && dport(443) -> block
|
||||
|
||||
domain(geosite:spotify) -> proxy
|
||||
domain(geosite:category-entertainment) -> proxy
|
||||
domain(geosite:category-ai-!cn, geosite:google, geosite:github) -> proxy
|
||||
domain(geosite:gfw) -> proxy
|
||||
|
||||
dip(geoip:telegram) -> proxy
|
||||
|
||||
dip(geoip:cn) -> direct
|
||||
|
||||
l4proto(udp) && dport(443) -> block
|
||||
|
||||
fallback: proxy
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
# config.dae
|
||||
# load all dae files placed in ./config.d/
|
||||
include {
|
||||
config.d/*.dae
|
||||
}
|
||||
global {
|
||||
log_level:warn
|
||||
check_interval:600s
|
||||
check_tolerance:20ms
|
||||
lan_interface:"br-lan"
|
||||
wan_interface:auto
|
||||
auto_config_kernel_parameter:true
|
||||
sniffing_timeout:300ms
|
||||
udp_check_dns: "dns.google:53,8.8.8.8,2001:4860:4860::8888"
|
||||
tcp_check_url: "http://cp.cloudflare.com,1.1.1.1,2606:4700:4700::1111"
|
||||
dial_mode: domain
|
||||
allow_insecure: true
|
||||
}
|
||||
@@ -2,5 +2,6 @@
|
||||
config dae 'config'
|
||||
option enabled '0'
|
||||
option config_file '/etc/dae/config.dae'
|
||||
option lan_interface 'br-lan'
|
||||
option log_maxbackups '1'
|
||||
option log_maxsize '1'
|
||||
Executable → Regular
+46
-117
@@ -1,141 +1,70 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# Copyright (C) 2023 Tianling Shen <cnsztl@immortalwrt.org>
|
||||
|
||||
USE_PROCD=1
|
||||
START=96
|
||||
STOP=10
|
||||
START=99
|
||||
|
||||
extra_command "hot_reload" "Hot-reload service"
|
||||
|
||||
CONF="dae"
|
||||
PROG="/usr/bin/dae"
|
||||
LOG="/var/log/dae/dae.log"
|
||||
DAE_HOST_IFACE="dae0"
|
||||
DAE_PEER_IFACE="dae0peer"
|
||||
DAE_NETNS_NAME="daens"
|
||||
DAENETNS="/run/netns/$DAE_NETNS_NAME"
|
||||
RESOLV_DAE="/tmp/resolv.conf.dae"
|
||||
|
||||
set_chmod_640() {
|
||||
mkdir -p /etc/dae/config.d
|
||||
mkdir -p /var/log/dae
|
||||
chmod -R 640 /etc/dae/ 2>/dev/null || true
|
||||
}
|
||||
|
||||
update_cron() {
|
||||
local temp_cron="/tmp/root.cron"
|
||||
|
||||
if [ -f /etc/crontabs/root ]; then
|
||||
grep -v '/etc/init.d/dae hot_reload' /etc/crontabs/root > "$temp_cron" 2>/dev/null
|
||||
fi
|
||||
: >> "$temp_cron"
|
||||
|
||||
local auto_update
|
||||
auto_update=$(uci -q get dae.config.subscribe_auto_update)
|
||||
if [ "$1" = "add" ] && [ "${auto_update:-0}" -eq 1 ]; then
|
||||
local min=$((RANDOM % 60))
|
||||
local hr=$(uci -q get dae.config.subscribe_update_day_time)
|
||||
local wk=$(uci -q get dae.config.subscribe_update_week_time)
|
||||
echo "$min ${hr:-*} * * ${wk:-*} /etc/init.d/dae hot_reload >/dev/null 2>&1" >> "$temp_cron"
|
||||
fi
|
||||
|
||||
crontab "$temp_cron" 2>/dev/null
|
||||
rm -f "$temp_cron"
|
||||
}
|
||||
|
||||
cleanup_netns() {
|
||||
tc qdisc del dev "$DAE_HOST_IFACE" clsact 2>/dev/null || true
|
||||
ip link del "$DAE_HOST_IFACE" 2>/dev/null || true
|
||||
ip link del "$DAE_PEER_IFACE" 2>/dev/null || true
|
||||
ip netns del "$DAE_NETNS_NAME" 2>/dev/null || true
|
||||
umount "$DAENETNS" 2>/dev/null || true
|
||||
rm -f "$DAENETNS" 2>/dev/null || true
|
||||
}
|
||||
|
||||
hijack_resolv_conf() {
|
||||
grep -q ' /tmp/resolv\.conf ' /proc/mounts && return 0
|
||||
|
||||
grep -E '^(search|domain) ' /tmp/resolv.conf > "$RESOLV_DAE" 2>/dev/null
|
||||
|
||||
local dns_list LOGICAL_WAN
|
||||
. /lib/functions/network.sh
|
||||
network_find_wan LOGICAL_WAN 2>/dev/null
|
||||
if [ -n "$LOGICAL_WAN" ]; then
|
||||
dns_list=$(ubus call "network.interface.$LOGICAL_WAN" status 2>/dev/null | \
|
||||
jsonfilter -e '@["dns-server"][*]' 2>/dev/null)
|
||||
fi
|
||||
|
||||
if [ -z "$dns_list" ] && [ -f "/tmp/resolv.conf.d/resolv.conf.auto" ]; then
|
||||
dns_list=$(awk '/^nameserver/{print $2}' "/tmp/resolv.conf.d/resolv.conf.auto")
|
||||
fi
|
||||
|
||||
[ -z "$dns_list" ] && dns_list="119.29.29.29 223.5.5.5"
|
||||
|
||||
for dns in $dns_list; do
|
||||
echo "nameserver $dns" >> "$RESOLV_DAE"
|
||||
done
|
||||
|
||||
mount --bind "$RESOLV_DAE" /tmp/resolv.conf
|
||||
mount -o remount,ro,bind /tmp/resolv.conf
|
||||
}
|
||||
|
||||
restore_resolv_conf() {
|
||||
grep -q ' /tmp/resolv\.conf ' /proc/mounts || return 0
|
||||
mount -o remount,rw,bind /tmp/resolv.conf 2>/dev/null
|
||||
umount /tmp/resolv.conf 2>/dev/null
|
||||
rm -f "$RESOLV_DAE"
|
||||
}
|
||||
LOG_DIR="/var/log/dae"
|
||||
|
||||
start_service() {
|
||||
local enabled config_file log_maxbackups log_maxsize
|
||||
config_load "$CONF"
|
||||
|
||||
uci commit "$CONF" 2>/dev/null
|
||||
config_load "$CONF"
|
||||
config_get_bool enabled "config" "enabled" "0"
|
||||
[ "$enabled" -eq "1" ] || return 1
|
||||
local enabled
|
||||
config_get_bool enabled "config" "enabled" "0"
|
||||
[ "$enabled" -eq "1" ] || return 1
|
||||
|
||||
config_get config_file "config" "config_file" "/etc/dae/config.dae"
|
||||
local config_file
|
||||
config_get config_file "config" "config_file" "/etc/dae/config.dae"
|
||||
|
||||
set_chmod_640
|
||||
"$PROG" validate -c "$config_file" || return 1
|
||||
update_cron "add"
|
||||
hijack_resolv_conf
|
||||
cleanup_netns
|
||||
"$PROG" validate -c "$config_file" || return 1
|
||||
|
||||
config_get log_maxbackups "config" "log_maxbackups" "1"
|
||||
config_get log_maxsize "config" "log_maxsize" "1"
|
||||
local log_maxbackups log_maxsize
|
||||
config_get log_maxbackups "config" "log_maxbackups" "1"
|
||||
config_get log_maxsize "config" "log_maxsize" "1"
|
||||
|
||||
procd_open_instance "$CONF"
|
||||
uname -r | grep -Eq "^6\.6" && procd_set_param env "QUIC_GO_DISABLE_GSO"="true"
|
||||
procd_set_param env DAE_LOCATION_ASSET="/usr/share/v2ray"
|
||||
procd_set_param command "$PROG" run
|
||||
procd_append_param command --config "$config_file"
|
||||
procd_append_param command --disable-timestamp
|
||||
procd_append_param command --logfile "$LOG"
|
||||
procd_append_param command --logfile-maxbackups "$log_maxbackups"
|
||||
procd_append_param command --logfile-maxsize "$log_maxsize"
|
||||
procd_set_param limits core="unlimited"
|
||||
procd_set_param limits nofile="1000000 1000000"
|
||||
procd_set_param respawn
|
||||
procd_set_param stderr 1
|
||||
procd_close_instance
|
||||
procd_open_instance "$CONF"
|
||||
procd_set_param env DAE_LOCATION_ASSET="/usr/share/v2ray" TZ="$(uci -q get system.@system[0].zonename)"
|
||||
procd_set_param command "$PROG" run
|
||||
procd_append_param command --config "$config_file"
|
||||
procd_append_param command --disable-timestamp
|
||||
procd_append_param command --logfile "$LOG_DIR/dae.log"
|
||||
procd_append_param command --logfile-maxbackups "$log_maxbackups"
|
||||
procd_append_param command --logfile-maxsize "$log_maxsize"
|
||||
|
||||
procd_set_param limits core="unlimited"
|
||||
procd_set_param limits nofile="1000000 1000000"
|
||||
procd_set_param respawn
|
||||
# procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
service_stopped() {
|
||||
update_cron "remove"
|
||||
restore_resolv_conf
|
||||
cleanup_netns
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
stop
|
||||
start
|
||||
stop_service() {
|
||||
rm -rf "$LOG_DIR"
|
||||
# kill lingering procs in daens: TERM first, then KILL for stubborn ones
|
||||
for pid in $(ip netns pids daens 2>/dev/null); do kill "$pid" 2>/dev/null; done
|
||||
if [ -n "$(ip netns pids daens 2>/dev/null)" ]; then
|
||||
sleep 1
|
||||
for pid in $(ip netns pids daens 2>/dev/null); do kill -9 "$pid" 2>/dev/null; done
|
||||
fi
|
||||
# cleanup daens netns; ip-full needed for netns, busybox fallback via umount
|
||||
if ! ip netns del daens 2>/dev/null; then
|
||||
umount /run/netns/daens 2>/dev/null
|
||||
rm -f /run/netns/daens
|
||||
fi
|
||||
# clean orphaned dae0
|
||||
ip link del dae0 2>/dev/null || true
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "$CONF"
|
||||
procd_add_reload_trigger "$CONF"
|
||||
}
|
||||
|
||||
hot_reload() {
|
||||
set_chmod_640
|
||||
/etc/init.d/dae running && "$PROG" reload
|
||||
/etc/init.d/dae running && "$PROG" reload "$(cat /var/run/dae.pid)"
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
diff --git a/cmd/reload_manager.go b/cmd/reload_manager.go
|
||||
index c78910c..bcc1a37 100644
|
||||
--- a/cmd/reload_manager.go
|
||||
+++ b/cmd/reload_manager.go
|
||||
@@ -423,5 +423,8 @@ func dnsConfigFingerprint(dns config.Dns) string {
|
||||
b.WriteString("max_cache_size=")
|
||||
b.WriteString(strconv.Itoa(dns.MaxCacheSize))
|
||||
b.WriteByte(';')
|
||||
+ b.WriteString("response_ttl=")
|
||||
+ b.WriteString(strconv.Itoa(dns.ResponseTtl))
|
||||
+ b.WriteByte(';')
|
||||
return b.String()
|
||||
}
|
||||
diff --git a/cmd/run_shutdown_test.go b/cmd/run_shutdown_test.go
|
||||
index f8f731f..4dcdcff 100644
|
||||
--- a/cmd/run_shutdown_test.go
|
||||
+++ b/cmd/run_shutdown_test.go
|
||||
@@ -609,6 +609,7 @@ func TestDNSConfigFingerprintCoversAllDnsFields(t *testing.T) {
|
||||
"OptimisticCache": {},
|
||||
"OptimisticCacheTtl": {},
|
||||
"MaxCacheSize": {},
|
||||
+ "ResponseTtl": {},
|
||||
}
|
||||
|
||||
dnsType := reflect.TypeOf(config.Dns{})
|
||||
diff --git a/config/config.go b/config/config.go
|
||||
index e688e88..af28da5 100644
|
||||
--- a/config/config.go
|
||||
+++ b/config/config.go
|
||||
@@ -160,6 +160,7 @@ type Dns struct {
|
||||
OptimisticCache bool `mapstructure:"optimistic_cache" default:"true"`
|
||||
OptimisticCacheTtl int `mapstructure:"optimistic_cache_ttl" default:"60"`
|
||||
MaxCacheSize int `mapstructure:"max_cache_size" default:"0"`
|
||||
+ ResponseTtl int `mapstructure:"response_ttl" default:"0"`
|
||||
}
|
||||
|
||||
type Routing struct {
|
||||
diff --git a/config/desc.go b/config/desc.go
|
||||
index 513cf7e..9b3c1a2 100644
|
||||
--- a/config/desc.go
|
||||
+++ b/config/desc.go
|
||||
@@ -66,6 +66,7 @@ var GlobalDesc = Desc{
|
||||
var DnsDesc = Desc{
|
||||
"ipversion_prefer": "For example, if ipversion_prefer is 4 and the domain name has both type A and type AAAA records, the dae will only respond to type A queries and response empty answer to type AAAA queries.",
|
||||
"fixed_domain_ttl": "Give a fixed ttl for domains. Zero means that dae will request to upstream every time and not cache DNS results for these domains.",
|
||||
+ "response_ttl": "Override the TTL returned to downstream DNS clients. Zero keeps dae's default behavior.",
|
||||
"upstream": "Value can be scheme://host:port, where the scheme can be tcp/udp/tcp+udp.\nIf host is a domain and has both IPv4 and IPv6 record, dae will automatically choose IPv4 or IPv6 to use according to group policy (such as min latency policy).\nPlease make sure DNS traffic will go through and be forwarded by dae, which is REQUIRED for domain routing.\nIf dial_mode is \"ip\", the upstream DNS answer SHOULD NOT be polluted, so domestic public DNS is not recommended.",
|
||||
"request": `DNS request routing for ordinary client traffic uses qname and qtype.
|
||||
Built-in outbounds for ordinary DNS requests: asis, reject.
|
||||
diff --git a/control/control_plane.go b/control/control_plane.go
|
||||
index 5df98db..a543f3b 100644
|
||||
--- a/control/control_plane.go
|
||||
+++ b/control/control_plane.go
|
||||
@@ -771,6 +771,7 @@ func newControlPlaneWithContextOptions(
|
||||
}
|
||||
plane.dnsRouting = dnsUpstream
|
||||
plane.dnsFixedDomainTtl = fixedDomainTtl
|
||||
+ plane.dnsResponseTtl = dnsConfig.ResponseTtl
|
||||
dnsControllerOption := plane.dnsControllerOption()
|
||||
dnsControllerOption.OptimisticCache = dnsConfig.OptimisticCache
|
||||
dnsControllerOption.OptimisticCacheTtl = dnsConfig.OptimisticCacheTtl
|
||||
@@ -1256,6 +1257,7 @@ func (c *ControlPlane) dnsControllerOption() *DnsControllerOption {
|
||||
Log: c.log,
|
||||
LifecycleContext: c.ctx,
|
||||
ConcurrencyLimit: 0,
|
||||
+ ResponseTtl: c.dnsResponseTtl,
|
||||
CacheAccessCallback: func(cache *DnsCache) (err error) {
|
||||
if err = c.core.BatchUpdateDomainRouting(cache); err != nil {
|
||||
return fmt.Errorf("BatchUpdateDomainRouting: %w", err)
|
||||
diff --git a/control/dns_control.go b/control/dns_control.go
|
||||
index d5bf872..b52132d 100644
|
||||
--- a/control/dns_control.go
|
||||
+++ b/control/dns_control.go
|
||||
@@ -82,6 +82,7 @@ type DnsControllerOption struct {
|
||||
OptimisticCache bool
|
||||
OptimisticCacheTtl int // 0 means never expire (rely on LRU eviction)
|
||||
MaxCacheSize int // maximum number of cache entries (0 = unlimited)
|
||||
+ ResponseTtl int
|
||||
}
|
||||
|
||||
type dnsControllerRuntimeState struct {
|
||||
@@ -94,6 +95,7 @@ type dnsControllerRuntimeState struct {
|
||||
bestDialerChooser func(ctx context.Context, req *udpRequest, upstream *dns.Upstream) (*dialArgument, error)
|
||||
timeoutExceedCallback func(dialArgument *dialArgument, err error)
|
||||
fixedDomainTtl map[string]int
|
||||
+ responseTtl int
|
||||
}
|
||||
|
||||
type dnsControllerStore struct {
|
||||
@@ -170,6 +172,9 @@ func normalizeDnsRuntimeBehavior(option *DnsControllerOption) (qtypePrefer uint1
|
||||
if err != nil {
|
||||
return 0, false, 0, 0, err
|
||||
}
|
||||
+ if option.ResponseTtl < 0 {
|
||||
+ return 0, false, 0, 0, fmt.Errorf("response_ttl must be greater than or equal to 0")
|
||||
+ }
|
||||
optimisticCacheTtl = option.OptimisticCacheTtl
|
||||
maxCacheSize = option.MaxCacheSize
|
||||
if optimisticCacheTtl == 0 && maxCacheSize == 0 {
|
||||
@@ -422,6 +427,7 @@ func (c *DnsController) updateRuntime(option *DnsControllerOption, routing *dns.
|
||||
bestDialerChooser: option.BestDialerChooser,
|
||||
timeoutExceedCallback: option.TimeoutExceedCallback,
|
||||
fixedDomainTtl: option.FixedDomainTtl,
|
||||
+ responseTtl: option.ResponseTtl,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
@@ -1547,10 +1553,16 @@ func (c *DnsController) NormalizeAndCacheDnsResp_(msg *dnsmessage.Msg, responseC
|
||||
ttl = 31536000
|
||||
}
|
||||
|
||||
- // For A/AAAA records, we set TTL to 0 to prevent downstream caching while we manage it.
|
||||
+ responseTtl := 0
|
||||
+ if rt := c.runtime(); rt != nil {
|
||||
+ responseTtl = rt.responseTtl
|
||||
+ }
|
||||
+
|
||||
+ // For A/AAAA records, we set TTL to 0 by default to prevent downstream caching while we manage it.
|
||||
+ // When response_ttl is set, use it as the downstream-visible TTL.
|
||||
if q.Qtype == dnsmessage.TypeA || q.Qtype == dnsmessage.TypeAAAA {
|
||||
for i := range msg.Answer {
|
||||
- msg.Answer[i].Header().Ttl = 0
|
||||
+ msg.Answer[i].Header().Ttl = uint32(responseTtl)
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/control/dns_response_ttl_test.go b/control/dns_response_ttl_test.go
|
||||
new file mode 100644
|
||||
index 0000000..0e5406e
|
||||
--- /dev/null
|
||||
+++ b/control/dns_response_ttl_test.go
|
||||
@@ -0,0 +1,64 @@
|
||||
+/*
|
||||
+ * SPDX-License-Identifier: AGPL-3.0-only
|
||||
+ * Copyright (c) 2022-2026, daeuniverse Organization <dae@v2raya.org>
|
||||
+ */
|
||||
+
|
||||
+package control
|
||||
+
|
||||
+import (
|
||||
+ "net"
|
||||
+ "testing"
|
||||
+ "time"
|
||||
+
|
||||
+ dnsmessage "github.com/miekg/dns"
|
||||
+ "github.com/stretchr/testify/require"
|
||||
+)
|
||||
+
|
||||
+func TestDnsController_ResponseTtlOverride(t *testing.T) {
|
||||
+ for _, tt := range []struct {
|
||||
+ name string
|
||||
+ responseTtl int
|
||||
+ wantTtl uint32
|
||||
+ }{
|
||||
+ {name: "default_zero", responseTtl: 0, wantTtl: 0},
|
||||
+ {name: "override", responseTtl: 60, wantTtl: 60},
|
||||
+ } {
|
||||
+ t.Run(tt.name, func(t *testing.T) {
|
||||
+ ctrl := setTestDnsControllerRuntime(newTestDnsController(), func(rt *dnsControllerRuntimeState) {
|
||||
+ rt.responseTtl = tt.responseTtl
|
||||
+ rt.newCache = func(fqdn string, answers, ns, extra []dnsmessage.RR, deadline time.Time, originalDeadline time.Time) (*DnsCache, error) {
|
||||
+ return &DnsCache{
|
||||
+ Answer: answers,
|
||||
+ NS: ns,
|
||||
+ Extra: extra,
|
||||
+ Deadline: deadline,
|
||||
+ OriginalDeadline: originalDeadline,
|
||||
+ }, nil
|
||||
+ }
|
||||
+ })
|
||||
+
|
||||
+ msg := new(dnsmessage.Msg)
|
||||
+ msg.SetReply(&dnsmessage.Msg{
|
||||
+ Question: []dnsmessage.Question{{
|
||||
+ Name: "example.com.",
|
||||
+ Qtype: dnsmessage.TypeA,
|
||||
+ Qclass: dnsmessage.ClassINET,
|
||||
+ }},
|
||||
+ })
|
||||
+ msg.Answer = []dnsmessage.RR{
|
||||
+ &dnsmessage.A{
|
||||
+ Hdr: dnsmessage.RR_Header{
|
||||
+ Name: "example.com.",
|
||||
+ Rrtype: dnsmessage.TypeA,
|
||||
+ Class: dnsmessage.ClassINET,
|
||||
+ Ttl: 300,
|
||||
+ },
|
||||
+ A: net.IPv4(93, 184, 216, 34),
|
||||
+ },
|
||||
+ }
|
||||
+
|
||||
+ require.NoError(t, ctrl.NormalizeAndCacheDnsResp_(msg, "example.com.:1"))
|
||||
+ require.Equal(t, tt.wantTtl, msg.Answer[0].Header().Ttl)
|
||||
+ })
|
||||
+ }
|
||||
+}
|
||||
diff --git a/control/dns_runtime.go b/control/dns_runtime.go
|
||||
index b871cc3..0c1d9c6 100644
|
||||
--- a/control/dns_runtime.go
|
||||
+++ b/control/dns_runtime.go
|
||||
@@ -20,6 +20,7 @@ type controlPlaneDNSRuntime struct {
|
||||
dnsController *DnsController
|
||||
dnsRouting *dns.Dns
|
||||
dnsFixedDomainTtl map[string]int
|
||||
+ dnsResponseTtl int
|
||||
dnsListener *DNSListener
|
||||
dnsListenerStopRegistered bool
|
||||
delayDNSListenerStart bool
|
||||
@@ -262,6 +263,7 @@ func (r *controlPlaneDNSRuntime) releaseRetainedState() {
|
||||
r.dnsController = nil
|
||||
r.dnsRouting = nil
|
||||
r.dnsFixedDomainTtl = nil
|
||||
+ r.dnsResponseTtl = 0
|
||||
r.dnsListener = nil
|
||||
r.dnsListenerStopRegistered = false
|
||||
r.delayDNSListenerStart = false
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,24 @@
|
||||
--- a/trace/kern/trace.c
|
||||
+++ b/trace/kern/trace.c
|
||||
@@ -228,7 +228,7 @@ KPROBE_SKB_AT(1)
|
||||
KPROBE_SKB_AT(2)
|
||||
KPROBE_SKB_AT(3)
|
||||
KPROBE_SKB_AT(4)
|
||||
-KPROBE_SKB_AT(5)
|
||||
+//KPROBE_SKB_AT(5)
|
||||
|
||||
SEC("kprobe/skb_lifetime_termination")
|
||||
int kprobe_skb_lifetime_termination(struct pt_regs *ctx)
|
||||
--- a/trace/trace.go
|
||||
+++ b/trace/trace.go
|
||||
@@ -212,8 +212,8 @@ func attachBpfToTargets(objs *bpfObjects
|
||||
kp, err = link.Kprobe(fn, objs.KprobeSkb3, nil)
|
||||
case 4:
|
||||
kp, err = link.Kprobe(fn, objs.KprobeSkb4, nil)
|
||||
- case 5:
|
||||
- kp, err = link.Kprobe(fn, objs.KprobeSkb5, nil)
|
||||
+ //case 5:
|
||||
+ // kp, err = link.Kprobe(fn, objs.KprobeSkb5, nil)
|
||||
}
|
||||
if err != nil {
|
||||
logrus.Debugf("failed to attach kprobe to %s: %+v\n", fn, err)
|
||||
Binary file not shown.
Reference in new issue
Block a user