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 <noreply@anthropic.com>
This commit is contained in:
patterniha
2026-11-02 12:27:26 +03:30
co-authored by Claude Opus 5.5
parent bb4cd4b6d3
commit 2933b0c8d5
3 changed files with 10 additions and 4 deletions
+1 -1
View File
@@ -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.
+5 -3
View File
@@ -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)
}
}
+4
View File
@@ -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) {