From 2933b0c8d5dbc0b95752f79e73029149b57b6852 Mon Sep 17 00:00:00 2001 From: patterniha <71074308+patterniha@users.noreply.github.com> Date: Mon, 2 Nov 2026 12:27:26 +0330 Subject: [PATCH] TUN inbound: Don't warn that loopback DNS servers are blocked With autoSystemWfpBlockLeak, loopback now always stays allowed, so a DNS server in dns like 127.0.0.1, a local resolver, stays reachable although it lies in neither gateway nor autoSystemRoutingTable. Leave loopback servers out of the warning that queries to them cannot go through the TUN and are blocked, and say so in the README. Co-Authored-By: Claude Opus 5.5 --- proxy/tun/README.md | 2 +- proxy/tun/tun_windows_wfp.go | 8 +++++--- proxy/tun/tun_windows_wfp_test.go | 4 ++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/proxy/tun/README.md b/proxy/tun/README.md index 6441bddb6..0ac786dd3 100644 --- a/proxy/tun/README.md +++ b/proxy/tun/README.md @@ -236,7 +236,7 @@ With `autoSystemWfpBlockLeak`, which needs `autoSystemRoutingTable` (the config Whatever is blocked, loopback, which cannot leave the system, and what Windows itself needs on the local link stay allowed: DHCP, DHCPv6, and IPv6 neighbor and multicast listener discovery. -Keeping the system's DNS inside the TUN, with `"all"`, `"allexceptlan"`, `"dns"`, `"windnsclient"`, or anything covering TCP or UDP port 53, needs `dns` (the config is rejected otherwise). The `dns` servers then have to lie within `gateway` or `autoSystemRoutingTable` (a warning is logged otherwise), and DNS servers that should be reached directly belong in Xray's own `dns` settings. +Keeping the system's DNS inside the TUN, with `"all"`, `"allexceptlan"`, `"dns"`, `"windnsclient"`, or anything covering TCP or UDP port 53, needs `dns` (the config is rejected otherwise). The `dns` servers then have to lie within `gateway` or `autoSystemRoutingTable`, or be loopback addresses like `127.0.0.1` for a local resolver (a warning is logged otherwise), and DNS servers that should be reached directly belong in Xray's own `dns` settings. With the filters in place, Xray's own connections out also get past Windows Firewall's block rules (other firewalls may still block them), while connections to Xray's inbounds stay subject to them. diff --git a/proxy/tun/tun_windows_wfp.go b/proxy/tun/tun_windows_wfp.go index 5ad4757f9..f58c80574 100644 --- a/proxy/tun/tun_windows_wfp.go +++ b/proxy/tun/tun_windows_wfp.go @@ -618,13 +618,15 @@ func addFilter(engine windows.Handle, sublayer, layer *windows.GUID, name string return nil } -// dnsOutsideTUN returns the servers outside all of prefixes, the TUN's own -// subnets and routes: queries to them cannot go through the TUN. +// dnsOutsideTUN returns the servers whose queries the filters block: those +// outside all of prefixes, the TUN's own subnets and routes, as queries to +// them cannot go through the TUN. Loopback ones, local resolvers, are not +// among them, as loopback stays allowed. func dnsOutsideTUN(servers []netip.Addr, prefixes []netip.Prefix) []netip.Addr { var outside []netip.Addr for _, server := range servers { server = server.Unmap() - if !slices.ContainsFunc(prefixes, func(p netip.Prefix) bool { return p.Contains(server) }) { + if !server.IsLoopback() && !slices.ContainsFunc(prefixes, func(p netip.Prefix) bool { return p.Contains(server) }) { outside = append(outside, server) } } diff --git a/proxy/tun/tun_windows_wfp_test.go b/proxy/tun/tun_windows_wfp_test.go index 8ed850813..288164699 100644 --- a/proxy/tun/tun_windows_wfp_test.go +++ b/proxy/tun/tun_windows_wfp_test.go @@ -214,6 +214,10 @@ func TestDNSOutsideTUN(t *testing.T) { netip.MustParseAddr("::ffff:203.0.113.54"), netip.MustParseAddr("8.8.8.8"), netip.MustParseAddr("2001:db8::53"), + // Local resolvers, reachable over loopback whatever is blocked. + netip.MustParseAddr("127.0.0.1"), + netip.MustParseAddr("::ffff:127.0.0.53"), + netip.MustParseAddr("::1"), } want := []netip.Addr{netip.MustParseAddr("8.8.8.8"), netip.MustParseAddr("2001:db8::53")} if got := dnsOutsideTUN(servers, prefixes); !slices.Equal(got, want) {