diff --git a/CHANGELOG.md b/CHANGELOG.md index 827f4bf2..a8e5888a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,11 +27,16 @@ and this project adheres to --> - Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. +### Fixed + +- Panic on port availability check during installation ([#3987]). + ### Removed - Go 1.16 support. [#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 +[#3987]: https://github.com/AdguardTeam/AdGuardHome/issues/3987 diff --git a/internal/aghnet/net.go b/internal/aghnet/net.go index f8e36406..77bdcc63 100644 --- a/internal/aghnet/net.go +++ b/internal/aghnet/net.go @@ -187,7 +187,8 @@ func GetSubnet(ifaceName string) *net.IPNet { return nil } -// CheckPort checks if the port is available for binding. +// CheckPort checks if the port is available for binding. network is expected +// to be one of "udp" and "tcp". func CheckPort(network string, ip net.IP, port int) (err error) { var c io.Closer addr := netutil.IPPort{IP: ip, Port: port}.String() @@ -200,7 +201,11 @@ func CheckPort(network string, ip net.IP, port int) (err error) { return nil } - return errors.WithDeferred(err, closePortChecker(c)) + if err != nil { + return err + } + + return closePortChecker(c) } // IsAddrInUse checks if err is about unsuccessful address binding. diff --git a/internal/aghnet/net_test.go b/internal/aghnet/net_test.go index 38fdf9cc..2e3f54be 100644 --- a/internal/aghnet/net_test.go +++ b/internal/aghnet/net_test.go @@ -5,6 +5,8 @@ import ( "testing" "github.com/AdguardTeam/AdGuardHome/internal/aghtest" + "github.com/AdguardTeam/golibs/netutil" + "github.com/AdguardTeam/golibs/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -69,3 +71,20 @@ func TestBroadcastFromIPNet(t *testing.T) { }) } } + +func TestCheckPort(t *testing.T) { + l, err := net.Listen("tcp", "127.0.0.1:") + require.NoError(t, err) + testutil.CleanupAndRequireSuccess(t, l.Close) + + ipp := netutil.IPPortFromAddr(l.Addr()) + require.NotNil(t, ipp) + require.NotNil(t, ipp.IP) + require.NotZero(t, ipp.Port) + + err = CheckPort("tcp", ipp.IP, ipp.Port) + target := &net.OpError{} + require.ErrorAs(t, err, &target) + + assert.Equal(t, "listen", target.Op) +} diff --git a/internal/aghnet/net_unix.go b/internal/aghnet/net_unix.go index 9f0f5011..27b79579 100644 --- a/internal/aghnet/net_unix.go +++ b/internal/aghnet/net_unix.go @@ -10,6 +10,7 @@ import ( "github.com/AdguardTeam/golibs/errors" ) +// closePortChecker closes c. c must be non-nil. func closePortChecker(c io.Closer) (err error) { return c.Close() } diff --git a/internal/aghnet/net_windows.go b/internal/aghnet/net_windows.go index bbbb81d7..128f5716 100644 --- a/internal/aghnet/net_windows.go +++ b/internal/aghnet/net_windows.go @@ -25,6 +25,7 @@ func ifaceSetStaticIP(string) (err error) { return aghos.Unsupported("setting static ip") } +// closePortChecker closes c. c must be non-nil. func closePortChecker(c io.Closer) (err error) { if err = c.Close(); err != nil { return err