Skip to content
Merged
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
21 changes: 18 additions & 3 deletions luci-app-openclash/root/etc/init.d/openclash
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,21 @@ ipv6_suffix_to_nft_format()
echo "& ${suffix} == ${addr}"
} 2>/dev/null

fw4_has_dns_hijack_rule()
{
local chain="$1"
local family="$2"

case "$family" in
ipv6)
nft list chain inet fw4 "$chain" 2>/dev/null |grep 'OpenClash DNS Hijack' |grep -Eq 'meta nfproto[[:space:]]+\{?ipv6\}?|meta nfproto[[:space:]]+ipv6|ip6 nexthdr'
;;
*)
nft list chain inet fw4 "$chain" 2>/dev/null |grep 'OpenClash DNS Hijack' |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 @@ -1319,7 +1334,7 @@ if [ -n "$FW4" ]; then
fi

if [ "$enable_redirect_dns" -eq 1 ]; then
if [ -z "$(nft list chain inet fw4 dstnat |grep 'OpenClash DNS Hijack')" ]; then
if ! fw4_has_dns_hijack_rule dstnat ipv4; then
if [ "$lan_ac_mode" != "1" ]; then
ACBLACKDNSFILTER=""
if [ "$lan_ac_mode" = "0" ]; then
Expand Down Expand Up @@ -1681,7 +1696,7 @@ if [ -n "$FW4" ]; then
fi
fi

if [ -z "$(nft list chain inet fw4 dstnat |grep 'OpenClash DNS Hijack')" ]; then
if ! fw4_has_dns_hijack_rule dstnat ipv6; then
if [ "$enable_redirect_dns" -eq 1 ]; then
if [ "$lan_ac_mode" != "1" ]; then
ACBLACKDNSFILTER=""
Expand Down Expand Up @@ -3832,4 +3847,4 @@ boot()
sleep "$delay_start"
fi
restart
}
}
67 changes: 67 additions & 0 deletions tests/fw4_dns_hijack_guard_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env bash
set -euo pipefail

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
INIT_SCRIPT="$REPO_ROOT/luci-app-openclash/root/etc/init.d/openclash"
WORKDIR="$(mktemp -d "${TMPDIR:-/tmp}/openclash-fw4-dns-test.XXXXXX")"
trap 'rm -rf "$WORKDIR"' EXIT

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

cat >"$WORKDIR/nft" <<'STUB'
#!/usr/bin/env sh
if [ "$*" = "list chain inet fw4 dstnat" ]; then
cat "${TEST_NFT_DSTNAT:?}"
elif [ "$*" = "list chain inet fw4 nat_output" ]; then
cat "${TEST_NFT_NAT_OUTPUT:?}"
fi
STUB
chmod +x "$WORKDIR/nft"

assert_status() {
expected="$1"
shift
set +e
PATH="$WORKDIR:$PATH" "$@"
actual=$?
set -e
if [ "$actual" -ne "$expected" ]; then
echo "expected status $expected, got $actual: $*" >&2
exit 1
fi
}

TEST_NFT_DSTNAT="$WORKDIR/dstnat.txt"
TEST_NFT_NAT_OUTPUT="$WORKDIR/nat_output.txt"
export TEST_NFT_DSTNAT TEST_NFT_NAT_OUTPUT

cat >"$TEST_NFT_DSTNAT" <<'EOF'
meta l4proto { tcp, udp } th dport 53 counter redirect to :53 comment "OpenClash DNS Hijack"
EOF
cat >"$TEST_NFT_NAT_OUTPUT" <<'EOF'
meta l4proto { tcp, udp } th dport 53 ip daddr 127.0.0.1 counter redirect to :53 comment "OpenClash DNS Hijack"
EOF

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

cat >"$TEST_NFT_DSTNAT" <<'EOF'
meta nfproto ipv6 ip6 nexthdr { tcp, udp } th dport 53 counter redirect to :53 comment "OpenClash DNS Hijack"
EOF
cat >"$TEST_NFT_NAT_OUTPUT" <<'EOF'
skgid != 65534 meta nfproto ipv6 ip6 nexthdr { tcp, udp } th dport 53 ip6 daddr ::/0 counter redirect to :53 comment "OpenClash DNS Hijack"
EOF

assert_status 1 fw4_has_dns_hijack_rule dstnat ipv4
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

echo "fw4_dns_hijack_guard_test.sh: PASS"