diff --git a/core/dns/socket_test.go b/core/dns/socket_test.go index 6f04f48f..feb074d5 100644 --- a/core/dns/socket_test.go +++ b/core/dns/socket_test.go @@ -25,9 +25,6 @@ func TestNewMarkedDnsClient(t *testing.T) { if client.Dialer == nil { t.Fatal("Dialer is nil") } - if client.Dialer.Control == nil { - t.Error("Dialer.Control is nil — sockets would not carry SO_MARK=0x80 and queries could loop back into the DNS module") - } } func TestNewMarkedDnsClientTCP(t *testing.T) { @@ -38,7 +35,4 @@ func TestNewMarkedDnsClientTCP(t *testing.T) { if client.Dialer == nil { t.Fatal("Dialer is nil") } - if client.Dialer.Control == nil { - t.Error("Dialer.Control is nil — TCP sockets would not carry SO_MARK=0x80") - } } diff --git a/core/dns/socket_unix_test.go b/core/dns/socket_unix_test.go new file mode 100644 index 00000000..c6b4d547 --- /dev/null +++ b/core/dns/socket_unix_test.go @@ -0,0 +1,31 @@ +//go:build !windows + +package dns + +import ( + "testing" +) + +// On Unix, markedDialer() sets Dialer.Control so every socket created by the +// dialer carries SO_MARK=0x80 (the fwmark that makes iptables skip the DNS +// redirect rules). Without Control the upstream queries would be hijacked +// back into this module — an infinite loop and unbounded memory growth. +// Windows has no SO_MARK (markFd is a no-op there), so these assertions are +// platform-specific and live in a !windows file. +func TestMarkedDnsClientHasControl(t *testing.T) { + udpClient := newMarkedDnsClient("udp") + if udpClient.Dialer == nil { + t.Fatal("Dialer is nil") + } + if udpClient.Dialer.Control == nil { + t.Error("Dialer.Control is nil — UDP sockets would not carry SO_MARK=0x80 and queries could loop back into the DNS module") + } + + tcpClient := newMarkedDnsClient("tcp") + if tcpClient.Dialer == nil { + t.Fatal("Dialer is nil") + } + if tcpClient.Dialer.Control == nil { + t.Error("Dialer.Control is nil — TCP sockets would not carry SO_MARK=0x80") + } +}