Skip to content

Commit d2e6f83

Browse files
committed
basichost: improve autonatv2 reachability logic
This improves the reachability detection logic by introducing the concept of primary and secondary addresses. If we have a webtransport address which shares the IP and Port with a QUIC address, the WebTransport address will be considered secondary and the QUIC address will be considered primary. If the Primary is reachable or unreachable, we require only one confirmation for the Secondary address. This speeds up address verification considerably.
1 parent 8be2504 commit d2e6f83

File tree

1 file changed

+109
-4
lines changed

1 file changed

+109
-4
lines changed

p2p/host/basic/addrs_reachability_tracker.go

Lines changed: 109 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,15 @@ func (m *probeManager) AppendConfirmedAddrs(reachable, unreachable, unknown []ma
412412
return reachable, unreachable, unknown
413413
}
414414

415+
func hasProto(a ma.Multiaddr, code int) bool {
416+
for _, c := range a {
417+
if c.Code() == code {
418+
return true
419+
}
420+
}
421+
return false
422+
}
423+
415424
// UpdateAddrs updates the tracked addrs
416425
func (m *probeManager) UpdateAddrs(addrs []ma.Multiaddr) {
417426
m.mx.Lock()
@@ -427,6 +436,40 @@ func (m *probeManager) UpdateAddrs(addrs []ma.Multiaddr) {
427436
statuses[k] = m.statuses[k]
428437
}
429438
}
439+
/*
440+
- First check if it's a TCP address. Then handle that case
441+
- Handle the same case for UDP
442+
*/
443+
for _, s := range statuses {
444+
if hasProto(s.Addr, ma.P_TCP) {
445+
n := len(s.Addr) - 1
446+
if s.Addr[n].Code() == ma.P_TCP {
447+
continue
448+
}
449+
for i, v := range s.Addr {
450+
if v.Code() == ma.P_TCP {
451+
if a, ok := statuses[string(s.Addr[:i].Bytes())]; ok {
452+
s.primaryAddr = a
453+
}
454+
break
455+
}
456+
}
457+
} else if hasProto(s.Addr, ma.P_UDP) {
458+
n := len(s.Addr) - 1
459+
if s.Addr[n].Code() == ma.P_QUIC_V1 {
460+
continue
461+
}
462+
for i, v := range s.Addr {
463+
if v.Code() == ma.P_UDP {
464+
qAddr := s.Addr[:i].Encapsulate(ma.StringCast("/quic-v1"))
465+
if a, ok := statuses[string(qAddr.Bytes())]; ok {
466+
s.primaryAddr = a
467+
}
468+
break
469+
}
470+
}
471+
}
472+
}
430473
m.addrs = addrs
431474
m.statuses = statuses
432475
}
@@ -439,21 +482,29 @@ func (m *probeManager) GetProbe() probe {
439482
defer m.mx.Unlock()
440483

441484
now := m.now()
485+
reqs := make(probe, 0, maxAddrsPerRequest)
442486
for i, a := range m.addrs {
443487
ab := a.Bytes()
444-
pc := m.statuses[string(ab)].RequiredProbeCount(now)
488+
s := m.statuses[string(ab)]
489+
if s.primaryAddr != nil {
490+
continue
491+
}
492+
pc := s.RequiredProbeCount(now)
445493
if m.inProgressProbes[string(ab)] >= pc {
446494
continue
447495
}
448-
reqs := make(probe, 0, maxAddrsPerRequest)
449496
reqs = append(reqs, autonatv2.Request{Addr: a, SendDialData: true})
450497
// We have the first(primary) address. Append other addresses, ignoring inprogress probes
451498
// on secondary addresses. The expectation is that the primary address will
452499
// be dialed.
453500
for j := 1; j < len(m.addrs); j++ {
454501
k := (i + j) % len(m.addrs)
455502
ab := m.addrs[k].Bytes()
456-
pc := m.statuses[string(ab)].RequiredProbeCount(now)
503+
s := m.statuses[string(ab)]
504+
if s.primaryAddr != nil {
505+
continue
506+
}
507+
pc := s.RequiredProbeCount(now)
457508
if pc == 0 {
458509
continue
459510
}
@@ -462,9 +513,49 @@ func (m *probeManager) GetProbe() probe {
462513
break
463514
}
464515
}
516+
break
517+
}
518+
if len(reqs) >= maxAddrsPerRequest {
519+
reqs = reqs[:maxAddrsPerRequest]
465520
return reqs
466521
}
467-
return nil
522+
for i, a := range m.addrs {
523+
ab := a.Bytes()
524+
s := m.statuses[string(ab)]
525+
pc := s.RequiredProbeCount(now)
526+
if s.primaryAddr == nil {
527+
continue
528+
}
529+
if m.inProgressProbes[string(ab)] >= pc {
530+
continue
531+
}
532+
reqs := make(probe, 0, maxAddrsPerRequest)
533+
reqs = append(reqs, autonatv2.Request{Addr: a, SendDialData: true})
534+
// We have the first(primary) address. Append other addresses, ignoring inprogress probes
535+
// on secondary addresses. The expectation is that the primary address will
536+
// be dialed.
537+
for j := 1; j < len(m.addrs); j++ {
538+
k := (i + j) % len(m.addrs)
539+
ab := m.addrs[k].Bytes()
540+
s := m.statuses[string(ab)]
541+
if s.primaryAddr == nil {
542+
continue
543+
}
544+
pc := s.RequiredProbeCount(now)
545+
if pc == 0 {
546+
continue
547+
}
548+
reqs = append(reqs, autonatv2.Request{Addr: m.addrs[k], SendDialData: true})
549+
if len(reqs) >= maxAddrsPerRequest {
550+
break
551+
}
552+
}
553+
break
554+
}
555+
if len(reqs) >= maxAddrsPerRequest {
556+
reqs = reqs[:maxAddrsPerRequest]
557+
}
558+
return reqs
468559
}
469560

470561
// MarkProbeInProgress should be called when a probe is started.
@@ -530,6 +621,10 @@ func (m *probeManager) CompleteProbe(reqs probe, res autonatv2.Result, err error
530621
if s, ok := m.statuses[dialAddrKey]; ok {
531622
s.AddOutcome(now, res.Reachability, maxRecentDialsWindow)
532623
}
624+
fmt.Println("processed:", reqs[0].Addr, res.Addr, res.Reachability)
625+
for _, s := range m.statuses {
626+
fmt.Println("required", s.Addr, s.Reachability(), s.RequiredProbeCount(now), s.requiredProbeCountForConfirmation(now))
627+
}
533628
}
534629

535630
type dialOutcome struct {
@@ -539,6 +634,7 @@ type dialOutcome struct {
539634

540635
type addrStatus struct {
541636
Addr ma.Multiaddr
637+
primaryAddr *addrStatus
542638
lastRefusalTime time.Time
543639
consecutiveRefusals int
544640
dialTimes []time.Time
@@ -670,6 +766,15 @@ func (s *addrStatus) reachabilityAndCounts() (rch network.Reachability, successe
670766
failures++
671767
}
672768
}
769+
if s.primaryAddr != nil {
770+
prch, _, _ := s.primaryAddr.reachabilityAndCounts()
771+
switch prch {
772+
case network.ReachabilityPublic:
773+
successes *= 3
774+
case network.ReachabilityPrivate:
775+
failures *= 3
776+
}
777+
}
673778
if successes-failures >= minConfidence {
674779
return network.ReachabilityPublic, successes, failures
675780
}

0 commit comments

Comments
 (0)