From efb5a92571c956d53793665c9b8f1fd4e72c19cb Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Wed, 8 Nov 2023 01:11:49 +0700 Subject: [PATCH] Using time interval for probing ipv6 A backoff with small max time will flood requests to Control D server, causing false positive for abuse mitiation system. While a big max time will cause ctrld not realize network change as fast as possible. While at it, also sync DoH3 code with DoH code, ensuring no others place can trigger requests flooding for ipv6 probing. --- config_quic.go | 7 +------ net.go | 35 +++++++++++++++++++---------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/config_quic.go b/config_quic.go index 3f397cb..5103231 100644 --- a/config_quic.go +++ b/config_quic.go @@ -10,13 +10,10 @@ import ( "net/http" "runtime" "sync" - "time" "github.com/miekg/dns" "github.com/quic-go/quic-go" "github.com/quic-go/quic-go/http3" - - ctrldnet "github.com/Control-D-Inc/ctrld/internal/net" ) func (uc *UpstreamConfig) setupDOH3Transport() { @@ -29,9 +26,7 @@ func (uc *UpstreamConfig) setupDOH3Transport() { uc.http3RoundTripper = uc.newDOH3Transport(uc.bootstrapIPs6) case IpStackSplit: uc.http3RoundTripper4 = uc.newDOH3Transport(uc.bootstrapIPs4) - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) - defer cancel() - if ctrldnet.IPv6Available(ctx) { + if hasIPv6() { uc.http3RoundTripper6 = uc.newDOH3Transport(uc.bootstrapIPs6) } else { uc.http3RoundTripper6 = uc.http3RoundTripper4 diff --git a/net.go b/net.go index 110d67e..3ae3bb5 100644 --- a/net.go +++ b/net.go @@ -2,13 +2,10 @@ package ctrld import ( "context" - "errors" "sync" "sync/atomic" "time" - "tailscale.com/logtail/backoff" - ctrldnet "github.com/Control-D-Inc/ctrld/internal/net" ) @@ -17,30 +14,36 @@ var ( ipv6Available atomic.Bool ) +const ipv6ProbingInterval = 10 * time.Second + func hasIPv6() bool { hasIPv6Once.Do(func() { ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() val := ctrldnet.IPv6Available(ctx) ipv6Available.Store(val) - go probingIPv6(val) + go probingIPv6(context.TODO(), val) }) return ipv6Available.Load() } // TODO(cuonglm): doing poll check natively for supported platforms. -func probingIPv6(old bool) { - b := backoff.NewBackoff("probingIPv6", func(format string, args ...any) {}, 30*time.Second) - bCtx := context.Background() +func probingIPv6(ctx context.Context, old bool) { + ticker := time.NewTicker(ipv6ProbingInterval) + defer ticker.Stop() for { - func() { - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) - defer cancel() - cur := ctrldnet.IPv6Available(ctx) - if ipv6Available.CompareAndSwap(old, cur) { - old = cur - } - }() - b.BackOff(bCtx, errors.New("no change")) + select { + case <-ctx.Done(): + return + case <-ticker.C: + func() { + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + cur := ctrldnet.IPv6Available(ctx) + if ipv6Available.CompareAndSwap(old, cur) { + old = cur + } + }() + } } }