diff --git a/dns/dns_proxy.go b/dns/dns_proxy.go index 3c8ee9a..8cebb23 100644 --- a/dns/dns_proxy.go +++ b/dns/dns_proxy.go @@ -713,6 +713,14 @@ func (p *DNSProxy) dialTunnel(network, addr string) (net.Conn, uint16, error) { return nil, 0, err } + // The tunnel netstack only has an IPv4 address and route (the WireGuard + // interface IP), so an IPv6 upstream server can't be reached through it. + // To4() is nil for those, and converting that to a [4]byte below would panic. + raddrIP := raddr.IP.To4() + if raddrIP == nil { + return nil, 0, fmt.Errorf("upstream DNS server %s is not an IPv4 address, only IPv4 is supported over the tunnel", addr) + } + // Use tunnel IP as source ipBytes := p.tunnelIP.As4() @@ -725,7 +733,7 @@ func (p *DNSProxy) dialTunnel(network, addr string) (net.Conn, uint16, error) { raddrTcpip := &tcpip.FullAddress{ NIC: 1, - Addr: tcpip.AddrFrom4([4]byte(raddr.IP.To4())), + Addr: tcpip.AddrFrom4([4]byte(raddrIP)), Port: uint16(raddr.Port), } diff --git a/dns/dns_proxy_test.go b/dns/dns_proxy_test.go index 9eecad7..98209a2 100644 --- a/dns/dns_proxy_test.go +++ b/dns/dns_proxy_test.go @@ -2,9 +2,11 @@ package dns import ( "net" + "net/netip" "testing" "github.com/miekg/dns" + "gvisor.dev/gvisor/pkg/tcpip/stack" ) func TestCheckLocalRecordsNODATAForAAAA(t *testing.T) { @@ -176,3 +178,17 @@ func TestCheckLocalRecordsNODATAWildcard(t *testing.T) { t.Fatalf("Expected 1 answer, got %d", len(response.Answer)) } } + +func TestDialTunnelRejectsIPv6Upstream(t *testing.T) { + proxy := &DNSProxy{ + tunnelStack: stack.New(stack.Options{}), + tunnelIP: netip.MustParseAddr("100.90.128.1"), + tunnelActivePorts: make(map[uint16]bool), + } + defer proxy.tunnelStack.Close() + + // Must return an error rather than panic: the tunnel netstack is IPv4-only + if _, _, err := proxy.dialTunnel("udp", "[2606:4700:4700::1111]:53"); err == nil { + t.Fatal("Expected error dialing an IPv6 upstream through the tunnel, got nil") + } +} diff --git a/olm/olm.go b/olm/olm.go index 7e7be9a..f1a79b5 100644 --- a/olm/olm.go +++ b/olm/olm.go @@ -554,7 +554,7 @@ func (o *Olm) StartTunnel(config TunnelConfig) { // Fall back to hardcoded DNS if the system monitor could not detect any. if len(o.tunnelConfig.PublicDNS) == 0 { if o.tunnelConfig.DNS != "" { - o.tunnelConfig.PublicDNS = []string{o.tunnelConfig.DNS + ":53"} + o.tunnelConfig.PublicDNS = []string{net.JoinHostPort(o.tunnelConfig.DNS, "53")} } else { o.tunnelConfig.PublicDNS = []string{"8.8.8.8:53"} }