mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-25 11:05:45 +00:00
net/dnscache: hard-code localhost resolution
Instead of falling back to bootstrap DNS if local DNS is broken and there's no "localhost" entry in /etc/hosts, tell dnscache to always resolve localhost to a static set of IPs. Updates #14097 Signed-off-by: Andrew Dunham <andrew@du.nham.ca> Change-Id: I21b621db74cd8e153e487a579dc121255008339c
This commit is contained in:
parent
f593d3c5c0
commit
0d4135c2f5
@ -202,6 +202,20 @@ func (r *Resolver) LookupIP(ctx context.Context, host string) (ip, v6 netip.Addr
|
|||||||
r.dlogf("returning %d static results", len(allIPs))
|
r.dlogf("returning %d static results", len(allIPs))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hard-code this to avoid extra work, DNS fallbacks, etc.
|
||||||
|
if host == "localhost" {
|
||||||
|
r.dlogf("host is localhost")
|
||||||
|
|
||||||
|
// TODO: @raggi mentioned that some distributions don't use
|
||||||
|
// 127.0.0.1 as the localhost IP; should we check the interface
|
||||||
|
// address to determine this?
|
||||||
|
ip = netip.AddrFrom4([4]byte{127, 0, 0, 1})
|
||||||
|
v6 = netip.IPv6Loopback()
|
||||||
|
allIPs = []netip.Addr{ip, v6}
|
||||||
|
err = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
if ip, err := netip.ParseAddr(host); err == nil {
|
if ip, err := netip.ParseAddr(host); err == nil {
|
||||||
ip = ip.Unmap()
|
ip = ip.Unmap()
|
||||||
r.dlogf("%q is an IP", host)
|
r.dlogf("%q is an IP", host)
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -240,3 +241,51 @@ type step struct {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLocalhost(t *testing.T) {
|
||||||
|
tstest.Replace(t, &debug, func() bool { return true })
|
||||||
|
|
||||||
|
r := &Resolver{
|
||||||
|
Logf: t.Logf,
|
||||||
|
Forward: &net.Resolver{
|
||||||
|
PreferGo: true,
|
||||||
|
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||||
|
// always return an error to force fallback
|
||||||
|
return nil, errors.New("some error")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LookupIPFallback: func(ctx context.Context, host string) ([]netip.Addr, error) {
|
||||||
|
t.Errorf("unexpected call to LookupIPFallback(%q)", host)
|
||||||
|
return nil, errors.New("unimplemented")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just overriding the 'Dial' function in the *net.Resolver isn't
|
||||||
|
// enough, because the Go resolver will read /etc/hosts and return
|
||||||
|
// localhost from that.
|
||||||
|
//
|
||||||
|
// Abuse the IP cache to insert a fake localhost entry pointing to some
|
||||||
|
// invalid IP; if we get this back, we know that we didn't hit our
|
||||||
|
// hard-coded "localhost" logic.
|
||||||
|
invalid4 := netip.MustParseAddr("169.254.169.254")
|
||||||
|
invalid6 := netip.MustParseAddr("fe80::1")
|
||||||
|
r.addIPCache("localhost", invalid4, invalid6, []netip.Addr{invalid4, invalid6}, 24*time.Hour)
|
||||||
|
|
||||||
|
ip4, ip6, allIPs, err := r.LookupIP(context.Background(), "localhost")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
localhost4 := netip.MustParseAddr("127.0.0.1")
|
||||||
|
localhost6 := netip.MustParseAddr("::1")
|
||||||
|
|
||||||
|
if ip4 != localhost4 {
|
||||||
|
t.Errorf("ip4 got %q; want %q", ip4, localhost4)
|
||||||
|
}
|
||||||
|
if ip6 != localhost6 {
|
||||||
|
t.Errorf("ip6 got %q; want %q", ip6, localhost6)
|
||||||
|
}
|
||||||
|
if !slices.Equal(allIPs, []netip.Addr{localhost4, localhost6}) {
|
||||||
|
t.Errorf("allIPs got %q; want %q", allIPs, []netip.Addr{localhost4, localhost6})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user