From 9815dac48faa1070f2b21661ddf241f328a3fbde Mon Sep 17 00:00:00 2001 From: Allan Roger Reid Date: Tue, 10 Jan 2023 19:17:39 -0800 Subject: [PATCH] fix: allow bind on ipv6 loopback failures (#16388) --- internal/http/listener.go | 32 +++++++++++++++++++++++++++++++- internal/http/listener_test.go | 3 ++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/internal/http/listener.go b/internal/http/listener.go index 76c297862..c9dba678b 100644 --- a/internal/http/listener.go +++ b/internal/http/listener.go @@ -21,6 +21,7 @@ import ( "context" "fmt" "net" + "strings" "syscall" ) @@ -136,20 +137,49 @@ func newHTTPListener(ctx context.Context, serverAddrs []string) (listener *httpL } }() + isLocalhost := false + for _, serverAddr := range serverAddrs { + host, _, err := net.SplitHostPort(serverAddr) + if err == nil { + if strings.EqualFold(host, "localhost") { + isLocalhost = true + } + } + } + + // Silently ignore failure to bind on DNS cached ipv6 loopback iff user specifies "localhost" for _, serverAddr := range serverAddrs { var l net.Listener if l, err = listenCfg.Listen(ctx, "tcp", serverAddr); err != nil { + if isLocalhost && strings.HasPrefix(serverAddr, "[::1]") { + continue + } return nil, err } tcpListener, ok := l.(*net.TCPListener) if !ok { - return nil, fmt.Errorf("unexpected listener type found %v, expected net.TCPListener", l) + err = fmt.Errorf("unexpected listener type found %v, expected net.TCPListener", l) + if isLocalhost && strings.HasPrefix(serverAddr, "[::1]") { + continue + } + return nil, err } tcpListeners = append(tcpListeners, tcpListener) } + // Fail if no listeners found + if len(tcpListeners) == 0 { + // Report specific issue + if err != nil { + return nil, err + } + // Report general issue + err = fmt.Errorf("%v listeners found, expected at least 1", 0) + return nil, err + } + listener = &httpListener{ tcpListeners: tcpListeners, acceptCh: make(chan acceptResult, len(tcpListeners)), diff --git a/internal/http/listener_test.go b/internal/http/listener_test.go index df9790861..50d327a68 100644 --- a/internal/http/listener_test.go +++ b/internal/http/listener_test.go @@ -142,17 +142,18 @@ func TestNewHTTPListener(t *testing.T) { {[]string{"example.org:65432"}, time.Duration(0), time.Duration(0), time.Duration(0), true}, {[]string{"unknown-host"}, time.Duration(0), time.Duration(0), time.Duration(0), true}, {[]string{"unknown-host:65432"}, time.Duration(0), time.Duration(0), time.Duration(0), true}, + {[]string{"localhost:65432"}, time.Duration(0), time.Duration(0), time.Duration(0), false}, {[]string{"localhost:65432", "93.184.216.34:65432"}, time.Duration(0), time.Duration(0), time.Duration(0), true}, {[]string{"localhost:65432", "unknown-host:65432"}, time.Duration(0), time.Duration(0), time.Duration(0), true}, {[]string{"localhost:0"}, time.Duration(0), time.Duration(0), time.Duration(0), false}, {[]string{"localhost:0"}, time.Duration(0), time.Duration(0), time.Duration(0), false}, + {[]string{"[::1]:9090", "localhost:0"}, time.Duration(0), time.Duration(0), time.Duration(0), false}, } for _, testCase := range testCases { listener, err := newHTTPListener(context.Background(), testCase.serverAddrs, ) - if !testCase.expectedErr { if err != nil { t.Fatalf("error: expected = , got = %v", err)