net/dnscache: fix case where Resolver could return zero IP with single IPv6 address

The controlhttp dialer with a ControlDialPlan IPv6 entry was hitting a
case where the dnscache Resolver was returning an netip.Addr zero
value, where it should've been returning the IPv6 address.

We then tried to dial "invalid IP:80", which would immediately fail,
at least locally.

Mostly this was causing spammy logs when debugging other stuff.

Updates tailscale/corp#32534

Change-Id: If8b9a20f10c1a6aa8a662c324151d987fe9bd2f8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2025-09-20 16:14:44 -07:00 committed by Brad Fitzpatrick
parent d7ec043306
commit 1b6bc37f28
2 changed files with 61 additions and 0 deletions

View File

@ -205,6 +205,9 @@ func (r *Resolver) LookupIP(ctx context.Context, host string) (ip, v6 netip.Addr
}
allIPs = append(allIPs, naIP)
}
if !ip.IsValid() && v6.IsValid() {
ip = v6
}
r.dlogf("returning %d static results", len(allIPs))
return
}

View File

@ -11,6 +11,7 @@ import (
"net"
"net/netip"
"reflect"
"slices"
"testing"
"time"
@ -240,3 +241,60 @@ func TestShouldTryBootstrap(t *testing.T) {
})
}
}
func TestSingleHostStaticResult(t *testing.T) {
v4 := netip.MustParseAddr("0.0.0.1")
v6 := netip.MustParseAddr("2001::a")
tests := []struct {
name string
static []netip.Addr
wantIP netip.Addr
wantIP6 netip.Addr
wantAll []netip.Addr
}{
{
name: "just-v6",
static: []netip.Addr{v6},
wantIP: v6,
wantIP6: v6,
wantAll: []netip.Addr{v6},
},
{
name: "just-v4",
static: []netip.Addr{v4},
wantIP: v4,
wantIP6: netip.Addr{},
wantAll: []netip.Addr{v4},
},
{
name: "v6-then-v4",
static: []netip.Addr{v6, v4},
wantIP: v4,
wantIP6: v6,
wantAll: []netip.Addr{v6, v4},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Resolver{
SingleHost: "example.com",
SingleHostStaticResult: tt.static,
}
ip, ip6, all, err := r.LookupIP(context.Background(), "example.com")
if err != nil {
t.Fatal(err)
}
if ip != tt.wantIP {
t.Errorf("got ip %v; want %v", ip, tt.wantIP)
}
if ip6 != tt.wantIP6 {
t.Errorf("got ip6 %v; want %v", ip6, tt.wantIP6)
}
if !slices.Equal(all, tt.wantAll) {
t.Errorf("got all %v; want %v", all, tt.wantAll)
}
})
}
}