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.
This commit is contained in:
Cuong Manh Le
2023-11-08 01:11:49 +07:00
committed by Cuong Manh Le
parent 8e0a96a44c
commit efb5a92571
2 changed files with 20 additions and 22 deletions
+1 -6
View File
@@ -10,13 +10,10 @@ import (
"net/http" "net/http"
"runtime" "runtime"
"sync" "sync"
"time"
"github.com/miekg/dns" "github.com/miekg/dns"
"github.com/quic-go/quic-go" "github.com/quic-go/quic-go"
"github.com/quic-go/quic-go/http3" "github.com/quic-go/quic-go/http3"
ctrldnet "github.com/Control-D-Inc/ctrld/internal/net"
) )
func (uc *UpstreamConfig) setupDOH3Transport() { func (uc *UpstreamConfig) setupDOH3Transport() {
@@ -29,9 +26,7 @@ func (uc *UpstreamConfig) setupDOH3Transport() {
uc.http3RoundTripper = uc.newDOH3Transport(uc.bootstrapIPs6) uc.http3RoundTripper = uc.newDOH3Transport(uc.bootstrapIPs6)
case IpStackSplit: case IpStackSplit:
uc.http3RoundTripper4 = uc.newDOH3Transport(uc.bootstrapIPs4) uc.http3RoundTripper4 = uc.newDOH3Transport(uc.bootstrapIPs4)
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) if hasIPv6() {
defer cancel()
if ctrldnet.IPv6Available(ctx) {
uc.http3RoundTripper6 = uc.newDOH3Transport(uc.bootstrapIPs6) uc.http3RoundTripper6 = uc.newDOH3Transport(uc.bootstrapIPs6)
} else { } else {
uc.http3RoundTripper6 = uc.http3RoundTripper4 uc.http3RoundTripper6 = uc.http3RoundTripper4
+19 -16
View File
@@ -2,13 +2,10 @@ package ctrld
import ( import (
"context" "context"
"errors"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
"tailscale.com/logtail/backoff"
ctrldnet "github.com/Control-D-Inc/ctrld/internal/net" ctrldnet "github.com/Control-D-Inc/ctrld/internal/net"
) )
@@ -17,30 +14,36 @@ var (
ipv6Available atomic.Bool ipv6Available atomic.Bool
) )
const ipv6ProbingInterval = 10 * time.Second
func hasIPv6() bool { func hasIPv6() bool {
hasIPv6Once.Do(func() { hasIPv6Once.Do(func() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel() defer cancel()
val := ctrldnet.IPv6Available(ctx) val := ctrldnet.IPv6Available(ctx)
ipv6Available.Store(val) ipv6Available.Store(val)
go probingIPv6(val) go probingIPv6(context.TODO(), val)
}) })
return ipv6Available.Load() return ipv6Available.Load()
} }
// TODO(cuonglm): doing poll check natively for supported platforms. // TODO(cuonglm): doing poll check natively for supported platforms.
func probingIPv6(old bool) { func probingIPv6(ctx context.Context, old bool) {
b := backoff.NewBackoff("probingIPv6", func(format string, args ...any) {}, 30*time.Second) ticker := time.NewTicker(ipv6ProbingInterval)
bCtx := context.Background() defer ticker.Stop()
for { for {
func() { select {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) case <-ctx.Done():
defer cancel() return
cur := ctrldnet.IPv6Available(ctx) case <-ticker.C:
if ipv6Available.CompareAndSwap(old, cur) { func() {
old = cur ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
} defer cancel()
}() cur := ctrldnet.IPv6Available(ctx)
b.BackOff(bCtx, errors.New("no change")) if ipv6Available.CompareAndSwap(old, cur) {
old = cur
}
}()
}
} }
} }