diff --git a/state/endpoint_resolver.go b/state/endpoint_resolver.go index b48b7e40..e7761dbb 100644 --- a/state/endpoint_resolver.go +++ b/state/endpoint_resolver.go @@ -45,8 +45,19 @@ func newEndpointResolver(dns dnsLookup) *EndpointResolver { } } -func (r *EndpointResolver) Resolve(endpoint string, expiry time.Duration) (netip.AddrPort, error) { +// literalEndpoint parses ip:port or a bare ip on the default port +func literalEndpoint(endpoint string) (netip.AddrPort, bool) { if addr, err := netip.ParseAddrPort(endpoint); err == nil { + return addr, true + } + if addr, err := netip.ParseAddr(endpoint); err == nil { + return netip.AddrPortFrom(addr, uint16(DefaultPort)), true + } + return netip.AddrPort{}, false +} + +func (r *EndpointResolver) Resolve(endpoint string, expiry time.Duration) (netip.AddrPort, error) { + if addr, ok := literalEndpoint(endpoint); ok { return addr, nil } @@ -106,7 +117,7 @@ func (r *EndpointResolver) Resolve(endpoint string, expiry time.Duration) (netip } func (r *EndpointResolver) Get(endpoint string) (netip.AddrPort, error) { - if addr, err := netip.ParseAddrPort(endpoint); err == nil { + if addr, ok := literalEndpoint(endpoint); ok { return addr, nil } diff --git a/state/endpoint_resolver_test.go b/state/endpoint_resolver_test.go index 4a89e221..7882081e 100644 --- a/state/endpoint_resolver_test.go +++ b/state/endpoint_resolver_test.go @@ -166,3 +166,32 @@ func (r *blockingDNSResolver) ResolveName(context.Context, string) ([]netip.Addr func (*blockingDNSResolver) ResolveSRV(context.Context, string, string, string) (string, uint16, error) { return "", 0, errors.New("no SRV record") } + +// a bare ip endpoint is a literal and must not wait on dns +func TestEndpointResolverBareIPSkipsDNS(t *testing.T) { + resolver := newEndpointResolver(noDNSResolver{t}) + for endpoint, want := range map[string]netip.AddrPort{ + "192.0.2.1": netip.MustParseAddrPort("192.0.2.1:57175"), + "2001:db8::1": netip.MustParseAddrPort("[2001:db8::1]:57175"), + "192.0.2.1:1234": netip.MustParseAddrPort("192.0.2.1:1234"), + } { + got, err := resolver.Resolve(endpoint, time.Hour) + require.NoError(t, err) + assert.Equal(t, want, got) + got, err = resolver.Get(endpoint) + require.NoError(t, err) + assert.Equal(t, want, got) + } +} + +type noDNSResolver struct{ t *testing.T } + +func (r noDNSResolver) ResolveName(_ context.Context, host string) ([]netip.Addr, error) { + r.t.Errorf("unexpected name lookup for %s", host) + return nil, errors.New("no dns") +} + +func (r noDNSResolver) ResolveSRV(_ context.Context, _, _, name string) (string, uint16, error) { + r.t.Errorf("unexpected SRV lookup for %s", name) + return "", 0, errors.New("no dns") +}