diff --git a/stack_system.go b/stack_system.go index 62bc9a7..9f32abc 100644 --- a/stack_system.go +++ b/stack_system.go @@ -120,8 +120,15 @@ func (s *System) start() error { return nil }) } + var tcpListener net.Listener if s.inet4Address.IsValid() { - tcpListener, err := listener.Listen(s.ctx, "tcp4", net.JoinHostPort(s.inet4ServerAddress.String(), "0")) + for i := 0; i < 3; i++ { + tcpListener, err = listener.Listen(s.ctx, "tcp4", net.JoinHostPort(s.inet4ServerAddress.String(), "0")) + if !retryableListenError(err) { + break + } + time.Sleep(time.Second) + } if err != nil { return err } @@ -130,7 +137,13 @@ func (s *System) start() error { go s.acceptLoop(tcpListener) } if s.inet6Address.IsValid() { - tcpListener, err := listener.Listen(s.ctx, "tcp6", net.JoinHostPort(s.inet6ServerAddress.String(), "0")) + for i := 0; i < 3; i++ { + tcpListener, err = listener.Listen(s.ctx, "tcp6", net.JoinHostPort(s.inet6ServerAddress.String(), "0")) + if !retryableListenError(err) { + break + } + time.Sleep(time.Second) + } if err != nil { return err } diff --git a/stack_system_nonwindows.go b/stack_system_nonwindows.go index 15b8741..822e509 100644 --- a/stack_system_nonwindows.go +++ b/stack_system_nonwindows.go @@ -2,6 +2,16 @@ package tun +import ( + "errors" + + "golang.org/x/sys/unix" +) + func fixWindowsFirewall() error { return nil } + +func retryableListenError(err error) bool { + return errors.Is(err, unix.EADDRNOTAVAIL) +} diff --git a/stack_system_windows.go b/stack_system_windows.go index 39f1877..ffa2a09 100644 --- a/stack_system_windows.go +++ b/stack_system_windows.go @@ -1,10 +1,13 @@ package tun import ( + "errors" "os" "path/filepath" "github.com/sagernet/sing-tun/internal/winfw" + + "golang.org/x/sys/windows" ) func fixWindowsFirewall() error { @@ -23,3 +26,7 @@ func fixWindowsFirewall() error { _, err = winfw.FirewallRuleAddAdvanced(rule) return err } + +func retryableListenError(err error) bool { + return errors.Is(err, windows.WSAEADDRNOTAVAIL) +}