@@ -361,6 +361,10 @@ const (
361
361
// and then a success(...S S S S F S). The confidence in the targetConfidence window will be equal to
362
362
// targetConfidence, the last F and S cancel each other, and we won't probe again for maxProbeInterval.
363
363
maxRecentDialsWindow = targetConfidence + 2
364
+ // secondaryAddrsScalingFactor is the multiplier applied to secondary address dial outcomes. For secondary
365
+ // addr, if the primary addr is reachable, a single successful dial is enough to consider the secondary addr
366
+ // reachable.
367
+ secondaryAddrsScalingFactor = targetConfidence
364
368
// highConfidenceAddrProbeInterval is the maximum interval between probes for an address
365
369
highConfidenceAddrProbeInterval = 1 * time .Hour
366
370
// maxProbeResultTTL is the maximum time to keep probe results for an address
@@ -380,7 +384,8 @@ type probeManager struct {
380
384
inProgressProbes map [string ]int // addr -> count
381
385
inProgressProbesTotal int
382
386
statuses map [string ]* addrStatus
383
- addrs []ma.Multiaddr
387
+ primaryAddrs []ma.Multiaddr
388
+ secondaryAddrs []ma.Multiaddr
384
389
}
385
390
386
391
// newProbeManager creates a new probe manager.
@@ -397,7 +402,19 @@ func (m *probeManager) AppendConfirmedAddrs(reachable, unreachable, unknown []ma
397
402
m .mx .Lock ()
398
403
defer m .mx .Unlock ()
399
404
400
- for _ , a := range m .addrs {
405
+ for _ , a := range m .primaryAddrs {
406
+ s := m .statuses [string (a .Bytes ())]
407
+ s .RemoveBefore (m .now ().Add (- maxProbeResultTTL )) // cleanup stale results
408
+ switch s .Reachability () {
409
+ case network .ReachabilityPublic :
410
+ reachable = append (reachable , a )
411
+ case network .ReachabilityPrivate :
412
+ unreachable = append (unreachable , a )
413
+ case network .ReachabilityUnknown :
414
+ unknown = append (unknown , a )
415
+ }
416
+ }
417
+ for _ , a := range m .secondaryAddrs {
401
418
s := m .statuses [string (a .Bytes ())]
402
419
s .RemoveBefore (m .now ().Add (- maxProbeResultTTL )) // cleanup stale results
403
420
switch s .Reachability () {
@@ -425,9 +442,20 @@ func (m *probeManager) UpdateAddrs(addrs []ma.Multiaddr) {
425
442
statuses [k ] = & addrStatus {Addr : addr }
426
443
} else {
427
444
statuses [k ] = m .statuses [k ]
445
+ // our addresses have changed, we might have removed the primary address
446
+ statuses [k ].primary = nil
447
+ }
448
+ }
449
+ assignPrimaryAddrs (statuses )
450
+ m .primaryAddrs = m .primaryAddrs [:0 ]
451
+ m .secondaryAddrs = m .secondaryAddrs [:0 ]
452
+ for _ , a := range addrs {
453
+ if statuses [string (a .Bytes ())].primary == nil {
454
+ m .primaryAddrs = append (m .primaryAddrs , a )
455
+ } else {
456
+ m .secondaryAddrs = append (m .secondaryAddrs , a )
428
457
}
429
458
}
430
- m .addrs = addrs
431
459
m .statuses = statuses
432
460
}
433
461
@@ -439,32 +467,52 @@ func (m *probeManager) GetProbe() probe {
439
467
defer m .mx .Unlock ()
440
468
441
469
now := m .now ()
442
- for i , a := range m .addrs {
443
- ab := a .Bytes ()
444
- pc := m .statuses [string (ab )].RequiredProbeCount (now )
445
- if m .inProgressProbes [string (ab )] >= pc {
446
- continue
470
+ reqs := make (probe , 0 , maxAddrsPerRequest )
471
+ reqs = m .appendRequestsToProbe (reqs , m .primaryAddrs , now )
472
+ reqs = m .appendRequestsToProbe (reqs , m .secondaryAddrs , now )
473
+ if len (reqs ) >= maxAddrsPerRequest {
474
+ reqs = reqs [:maxAddrsPerRequest ]
475
+ }
476
+ return reqs
477
+ }
478
+
479
+ func (m * probeManager ) appendRequestsToProbe (reqs probe , addrs []ma.Multiaddr , now time.Time ) probe {
480
+ n := len (addrs )
481
+ i := n
482
+ if len (reqs ) == 0 {
483
+ for i = 0 ; i < n ; i ++ {
484
+ sab := string (addrs [i ].Bytes ())
485
+ s := m .statuses [sab ]
486
+ pc := s .RequiredProbeCount (now )
487
+ if pc == 0 || m .inProgressProbes [sab ] >= pc {
488
+ continue
489
+ }
490
+ reqs = append (reqs , autonatv2.Request {Addr : addrs [i ], SendDialData : true })
491
+ break
447
492
}
448
- reqs := make (probe , 0 , maxAddrsPerRequest )
449
- reqs = append (reqs , autonatv2.Request {Addr : a , SendDialData : true })
450
- // We have the first(primary) address. Append other addresses, ignoring inprogress probes
451
- // on secondary addresses. The expectation is that the primary address will
452
- // be dialed.
453
- for j := 1 ; j < len (m .addrs ); j ++ {
454
- k := (i + j ) % len (m .addrs )
455
- ab := m .addrs [k ].Bytes ()
456
- pc := m .statuses [string (ab )].RequiredProbeCount (now )
493
+ }
494
+
495
+ // We have the first address. Append other addresses, ignoring inprogress probes.
496
+ // The expectation is that the first address will be dialed.
497
+ if len (reqs ) > 0 {
498
+ for j := range n {
499
+ k := (j + i ) % n
500
+ if k == i {
501
+ continue
502
+ }
503
+ sab := string (addrs [k ].Bytes ())
504
+ s := m .statuses [sab ]
505
+ pc := s .RequiredProbeCount (now )
457
506
if pc == 0 {
458
507
continue
459
508
}
460
- reqs = append (reqs , autonatv2.Request {Addr : m . addrs [k ], SendDialData : true })
509
+ reqs = append (reqs , autonatv2.Request {Addr : addrs [k ], SendDialData : true })
461
510
if len (reqs ) >= maxAddrsPerRequest {
462
511
break
463
512
}
464
513
}
465
- return reqs
466
514
}
467
- return nil
515
+ return reqs
468
516
}
469
517
470
518
// MarkProbeInProgress should be called when a probe is started.
@@ -499,10 +547,10 @@ func (m *probeManager) CompleteProbe(reqs probe, res autonatv2.Result, err error
499
547
defer m .mx .Unlock ()
500
548
501
549
// decrement in-progress count for the first address
502
- primaryAddrKey := string (reqs [0 ].Addr .Bytes ())
503
- m .inProgressProbes [primaryAddrKey ]--
504
- if m .inProgressProbes [primaryAddrKey ] <= 0 {
505
- delete (m .inProgressProbes , primaryAddrKey )
550
+ firstAddrKey := string (reqs [0 ].Addr .Bytes ())
551
+ m .inProgressProbes [firstAddrKey ]--
552
+ if m .inProgressProbes [firstAddrKey ] <= 0 {
553
+ delete (m .inProgressProbes , firstAddrKey )
506
554
}
507
555
m .inProgressProbesTotal --
508
556
@@ -511,17 +559,17 @@ func (m *probeManager) CompleteProbe(reqs probe, res autonatv2.Result, err error
511
559
return
512
560
}
513
561
514
- // Consider only primary address as refused. This increases the number of
562
+ // Consider only first address as refused. This increases the number of
515
563
// refused probes, but refused probes are cheap for a server as no dials are made.
516
564
if res .AllAddrsRefused {
517
- if s , ok := m .statuses [primaryAddrKey ]; ok {
565
+ if s , ok := m .statuses [firstAddrKey ]; ok {
518
566
s .AddRefusal (now )
519
567
}
520
568
return
521
569
}
522
570
dialAddrKey := string (res .Addr .Bytes ())
523
- if dialAddrKey != primaryAddrKey {
524
- if s , ok := m .statuses [primaryAddrKey ]; ok {
571
+ if dialAddrKey != firstAddrKey {
572
+ if s , ok := m .statuses [firstAddrKey ]; ok {
525
573
s .AddRefusal (now )
526
574
}
527
575
}
@@ -539,6 +587,7 @@ type dialOutcome struct {
539
587
540
588
type addrStatus struct {
541
589
Addr ma.Multiaddr
590
+ primary * addrStatus
542
591
lastRefusalTime time.Time
543
592
consecutiveRefusals int
544
593
dialTimes []time.Time
@@ -670,6 +719,15 @@ func (s *addrStatus) reachabilityAndCounts() (rch network.Reachability, successe
670
719
failures ++
671
720
}
672
721
}
722
+ if s .primary != nil {
723
+ prch , _ , _ := s .primary .reachabilityAndCounts ()
724
+ switch prch {
725
+ case network .ReachabilityPublic :
726
+ successes *= secondaryAddrsScalingFactor
727
+ case network .ReachabilityPrivate :
728
+ failures *= secondaryAddrsScalingFactor
729
+ }
730
+ }
673
731
if successes - failures >= minConfidence {
674
732
return network .ReachabilityPublic , successes , failures
675
733
}
@@ -678,3 +736,60 @@ func (s *addrStatus) reachabilityAndCounts() (rch network.Reachability, successe
678
736
}
679
737
return network .ReachabilityUnknown , successes , failures
680
738
}
739
+
740
+ var errNotTW = errors .New ("not a thinwaist address" )
741
+
742
+ func thinWaistPart (a ma.Multiaddr ) (ma.Multiaddr , error ) {
743
+ if len (a ) < 2 {
744
+ return nil , errNotTW
745
+ }
746
+ if c0 , c1 := a [0 ].Code (), a [1 ].Code (); (c0 != ma .P_IP4 && c0 != ma .P_IP6 ) || (c1 != ma .P_TCP && c1 != ma .P_UDP ) {
747
+ return nil , errNotTW
748
+ }
749
+ return a [:2 ], nil
750
+ }
751
+
752
+ func assignPrimaryAddrs (statuses map [string ]* addrStatus ) {
753
+ twMap := make (map [string ][]ma.Multiaddr , len (statuses ))
754
+ for _ , s := range statuses {
755
+ twp , err := thinWaistPart (s .Addr )
756
+ if err != nil {
757
+ continue
758
+ }
759
+ twMap [string (twp .Bytes ())] = append (twMap [string (twp .Bytes ())], s .Addr )
760
+ }
761
+
762
+ score := func (a ma.Multiaddr ) int {
763
+ score := 0
764
+ for _ , p := range a {
765
+ switch p .Code () {
766
+ case ma .P_QUIC_V1 , ma .P_TCP :
767
+ score += 1
768
+ case ma .P_WEBTRANSPORT :
769
+ score += 1 << 1
770
+ case ma .P_WEBRTC :
771
+ score += 1 << 2
772
+ case ma .P_WS , ma .P_WSS :
773
+ score += 1 << 3
774
+ }
775
+ }
776
+ if score == 0 {
777
+ return 1 << 20
778
+ }
779
+ return score
780
+ }
781
+ for _ , addrs := range twMap {
782
+ if len (addrs ) <= 1 {
783
+ continue
784
+ }
785
+ slices .SortFunc (addrs , func (a , b ma.Multiaddr ) int {
786
+ return score (a ) - score (b )
787
+ })
788
+ primary := addrs [0 ]
789
+ ps := statuses [string (primary .Bytes ())]
790
+ for _ , a := range addrs [1 :] {
791
+ s := statuses [string (a .Bytes ())]
792
+ s .primary = ps
793
+ }
794
+ }
795
+ }
0 commit comments