Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions luci-app-openclash/root/etc/init.d/openclash
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,20 @@ fw4_has_dns_hijack_rule()
esac
}

fw4_has_dns_redirect_jump()
{
local family="$1"

case "$family" in
ipv6)
nft list chain inet fw4 dstnat 2>/dev/null |grep 'jump openclash_dns_redirect' |grep -Eq 'meta nfproto[[:space:]]+\{?ipv6\}?|meta nfproto[[:space:]]+ipv6|ip6 nexthdr'
;;
*)
nft list chain inet fw4 dstnat 2>/dev/null |grep 'jump openclash_dns_redirect' |grep -Evq 'meta nfproto[[:space:]]+\{?ipv6\}?|meta nfproto[[:space:]]+ipv6|ip6 nexthdr'
;;
esac
}

firewall_lan_ac_traffic()
{
local src_port sport_rule dscp_rule sport_ipt dscp_ipt src_ip src_ip_v6 proto target target_ enabled family dscp rule output_rule comment
Expand Down Expand Up @@ -1357,6 +1371,7 @@ if [ -n "$FW4" ]; then
fi
elif [ "$enable_redirect_dns" -eq 2 ]; then
nft 'add chain inet fw4 openclash_dns_redirect'
nft 'flush chain inet fw4 openclash_dns_redirect'
if [ "$lan_ac_mode" != "1" ]; then
ACBLACKDNSFILTER=""
if [ "$lan_ac_mode" = "0" ]; then
Expand All @@ -1372,7 +1387,9 @@ if [ -n "$FW4" ]; then
nft add rule inet fw4 openclash_dns_redirect meta l4proto {tcp,udp} th dport 53 ip saddr @lan_ac_white_ips counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\"
nft add rule inet fw4 openclash_dns_redirect meta l4proto {tcp,udp} th dport 53 ether saddr @lan_ac_white_macs counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\"
fi
nft 'insert rule inet fw4 dstnat position 0 meta l4proto {tcp,udp} th dport 53 counter jump openclash_dns_redirect'
if ! fw4_has_dns_redirect_jump ipv4; then
nft 'insert rule inet fw4 dstnat position 0 meta l4proto {tcp,udp} th dport 53 counter jump openclash_dns_redirect'
fi
if [ "$router_self_proxy" = 1 ]; then
nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }'
nft insert rule inet fw4 nat_output position 0 meta l4proto {tcp,udp} th dport 53 ip daddr {127.0.0.1} meta skgid != 65534 counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\"
Expand Down Expand Up @@ -1733,7 +1750,9 @@ if [ -n "$FW4" ]; then
nft add rule inet fw4 openclash_dns_redirect meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ip6 saddr @lan_ac_white_ipv6s counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\"
nft add rule inet fw4 openclash_dns_redirect meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ether saddr @lan_ac_white_macs counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\"
fi
nft 'insert rule inet fw4 dstnat position 0 meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 counter jump openclash_dns_redirect'
if ! fw4_has_dns_redirect_jump ipv6; then
nft 'insert rule inet fw4 dstnat position 0 meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 counter jump openclash_dns_redirect'
fi
if [ "$router_self_proxy" = 1 ]; then
nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }'
nft insert rule inet fw4 nat_output position 0 meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ip6 daddr {::/0} meta skgid != 65534 counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\"
Expand Down
59 changes: 59 additions & 0 deletions tests/fw4_dns_hijack_guard_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ if [ -z "$fn" ]; then
fi
eval "$fn"

redirect_fn=$(awk '/^fw4_has_dns_redirect_jump\(\)/,/^}/' "$INIT_SCRIPT")
if [ -z "$redirect_fn" ]; then
echo "fw4_has_dns_redirect_jump not found" >&2
exit 1
fi
eval "$redirect_fn"

cat >"$WORKDIR/nft" <<'STUB'
#!/usr/bin/env sh
if [ "$*" = "list chain inet fw4 dstnat" ]; then
Expand Down Expand Up @@ -51,6 +58,18 @@ assert_status 0 fw4_has_dns_hijack_rule dstnat ipv4
assert_status 1 fw4_has_dns_hijack_rule dstnat ipv6
assert_status 0 fw4_has_dns_hijack_rule nat_output ipv4
assert_status 1 fw4_has_dns_hijack_rule nat_output ipv6
assert_status 1 fw4_has_dns_redirect_jump ipv4
assert_status 1 fw4_has_dns_redirect_jump ipv6

cat >"$TEST_NFT_DSTNAT" <<'EOF'
meta l4proto { tcp, udp } th dport 53 counter jump openclash_dns_redirect
meta nfproto ipv6 ip6 nexthdr { tcp, udp } th dport 53 counter jump openclash_dns_redirect
EOF
cat >"$TEST_NFT_NAT_OUTPUT" <<'EOF'
EOF

assert_status 0 fw4_has_dns_redirect_jump ipv4
assert_status 0 fw4_has_dns_redirect_jump ipv6

cat >"$TEST_NFT_DSTNAT" <<'EOF'
meta nfproto ipv6 ip6 nexthdr { tcp, udp } th dport 53 counter redirect to :53 comment "OpenClash DNS Hijack"
Expand All @@ -64,4 +83,44 @@ assert_status 0 fw4_has_dns_hijack_rule dstnat ipv6
assert_status 1 fw4_has_dns_hijack_rule nat_output ipv4
assert_status 0 fw4_has_dns_hijack_rule nat_output ipv6

if ! grep -F "flush chain inet fw4 openclash_dns_redirect" "$INIT_SCRIPT" >/dev/null 2>&1; then
echo "openclash_dns_redirect chain should be flushed before rebuilding redirect rules" >&2
exit 1
fi

assert_redirect_jump_guarded() {
family="$1"
jump_text="$2"

awk -v family="$family" -v jump_text="$jump_text" '
$0 ~ "fw4_has_dns_redirect_jump " family {
guard_window = 4
}
index($0, jump_text) {
seen++
if (guard_window <= 0) {
print "redirect jump is not guarded for " family ": " $0 > "/dev/stderr"
bad = 1
}
}
{
if (guard_window > 0) {
guard_window--
}
}
END {
if (seen != 1) {
print "expected one guarded redirect jump for " family ", got " seen > "/dev/stderr"
exit 1
}
if (bad) {
exit 1
}
}
' "$INIT_SCRIPT"
}

assert_redirect_jump_guarded ipv4 'nft '\''insert rule inet fw4 dstnat position 0 meta l4proto {tcp,udp} th dport 53 counter jump openclash_dns_redirect'\'''
assert_redirect_jump_guarded ipv6 'nft '\''insert rule inet fw4 dstnat position 0 meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 counter jump openclash_dns_redirect'\'''

echo "fw4_dns_hijack_guard_test.sh: PASS"