From 096e7ea429daf4041d939605ed095f2d78dd4cfd Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Wed, 15 Mar 2023 10:33:37 +0700 Subject: [PATCH] internal/net: enforce timeout for probing stack On Windows host with StarLink network, ctrld hangs on startup for ~30s before continue running. This dues to IPv6 is configured but no external IPv6 can be reached. When probing stack, ctrld is dialing using ipv6 without any timeout set, so the dialing timeout is enforced by OS. This commit adds a timeout for probing dialer, so we ensure the probing process will fail fast. --- internal/net/net.go | 13 ++++++++++--- internal/net/net_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 internal/net/net_test.go diff --git a/internal/net/net.go b/internal/net/net.go index a155f2c..888a2d6 100644 --- a/internal/net/net.go +++ b/internal/net/net.go @@ -28,6 +28,13 @@ var Dialer = &net.Dialer{ }, } +const probeStackTimeout = 2 * time.Second + +var probeStackDialer = &net.Dialer{ + Resolver: Dialer.Resolver, + Timeout: probeStackTimeout, +} + var ( stackOnce atomic.Pointer[sync.Once] ipv4Enabled bool @@ -41,12 +48,12 @@ func init() { } func supportIPv4() bool { - _, err := Dialer.Dial("tcp4", net.JoinHostPort(controldIPv4Test, "80")) + _, err := probeStackDialer.Dial("tcp4", net.JoinHostPort(controldIPv4Test, "80")) return err == nil } func supportIPv6(ctx context.Context) bool { - _, err := Dialer.DialContext(ctx, "tcp6", net.JoinHostPort(controldIPv6Test, "80")) + _, err := probeStackDialer.DialContext(ctx, "tcp6", net.JoinHostPort(controldIPv6Test, "80")) return err == nil } @@ -61,7 +68,7 @@ func supportListenIPv6Local() bool { func probeStack() { b := backoff.NewBackoff("probeStack", func(format string, args ...any) {}, time.Minute) for { - if _, err := Dialer.Dial("udp", bootstrapDNS); err == nil { + if _, err := probeStackDialer.Dial("udp", bootstrapDNS); err == nil { hasNetworkUp = true break } else { diff --git a/internal/net/net_test.go b/internal/net/net_test.go new file mode 100644 index 0000000..d28dbed --- /dev/null +++ b/internal/net/net_test.go @@ -0,0 +1,24 @@ +package net + +import ( + "context" + "testing" + "time" +) + +func TestProbeStackTimeout(t *testing.T) { + done := make(chan struct{}) + started := make(chan struct{}) + go func() { + defer close(done) + close(started) + supportIPv6(context.Background()) + }() + + <-started + select { + case <-time.After(probeStackTimeout + time.Second): + t.Error("probeStack timeout is not enforce") + case <-done: + } +}