Skip to content

Commit 5df6534

Browse files
committed
basichost: don't advertise unreachable addrs.
1 parent a29a664 commit 5df6534

File tree

2 files changed

+63
-24
lines changed

2 files changed

+63
-24
lines changed

p2p/host/basic/addrs_manager.go

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -317,13 +317,13 @@ func (a *addrsManager) updateAddrs(prevHostAddrs hostAddrs, relayAddrs []ma.Mult
317317
currReachableAddrs, currUnreachableAddrs, currUnknownAddrs = a.getConfirmedAddrs(localAddrs)
318318
}
319319
relayAddrs = slices.Clone(relayAddrs)
320-
currAddrs := a.getAddrs(slices.Clone(localAddrs), relayAddrs)
320+
currAddrs := a.getDialableAddrs(localAddrs, currReachableAddrs, currUnreachableAddrs, relayAddrs)
321+
currAddrs = a.applyAddrsFactory(currAddrs)
321322

322323
if areAddrsDifferent(prevHostAddrs.addrs, currAddrs) {
323324
_, _, removed := diffAddrs(prevHostAddrs.addrs, currAddrs)
324325
a.updatePeerStore(currAddrs, removed)
325326
}
326-
327327
a.addrsMx.Lock()
328328
a.currentAddrs = hostAddrs{
329329
addrs: append(a.currentAddrs.addrs[:0], currAddrs...),
@@ -410,25 +410,35 @@ func (a *addrsManager) notifyAddrsUpdated(emitter event.Emitter, localAddrsEmitt
410410
// the node's relay addresses and private network addresses.
411411
func (a *addrsManager) Addrs() []ma.Multiaddr {
412412
a.addrsMx.RLock()
413-
directAddrs := slices.Clone(a.currentAddrs.localAddrs)
414-
relayAddrs := slices.Clone(a.currentAddrs.relayAddrs)
413+
addrs := a.getDialableAddrs(a.currentAddrs.localAddrs, a.currentAddrs.reachableAddrs, a.currentAddrs.unreachableAddrs, a.currentAddrs.relayAddrs)
415414
a.addrsMx.RUnlock()
416-
return a.getAddrs(directAddrs, relayAddrs)
415+
// don't hold the lock while applying addrs factory
416+
return a.applyAddrsFactory(addrs)
417417
}
418418

419-
// getAddrs returns the node's dialable addresses. Mutates localAddrs
420-
func (a *addrsManager) getAddrs(localAddrs []ma.Multiaddr, relayAddrs []ma.Multiaddr) []ma.Multiaddr {
421-
addrs := localAddrs
422-
rch := a.hostReachability.Load()
423-
if rch != nil && *rch == network.ReachabilityPrivate {
424-
// Delete public addresses if the node's reachability is private, and we have relay addresses
425-
if len(relayAddrs) > 0 {
419+
// getDialableAddrs returns the node's dialable addrs. Doesn't mutate any argument.
420+
func (a *addrsManager) getDialableAddrs(localAddrs, reachableAddrs, unreachableAddrs, relayAddrs []ma.Multiaddr) []ma.Multiaddr {
421+
// remove known unreachable addrs
422+
addrs := removeInSource(slices.Clone(localAddrs), unreachableAddrs)
423+
// If we have no confirmed reachable addresses, add the relay addresses
424+
if a.addrsReachabilityTracker != nil {
425+
if len(reachableAddrs) == 0 {
426+
addrs = append(addrs, relayAddrs...)
427+
}
428+
} else {
429+
// If we're only using autonatv1, remove public addrs and add relay addrs
430+
if len(relayAddrs) > 0 && *a.hostReachability.Load() == network.ReachabilityPrivate {
426431
addrs = slices.DeleteFunc(addrs, manet.IsPublicAddr)
427432
addrs = append(addrs, relayAddrs...)
428433
}
429434
}
430-
// Make a copy. Consumers can modify the slice elements
431-
addrs = slices.Clone(a.addrsFactory(addrs))
435+
return addrs
436+
}
437+
438+
func (a *addrsManager) applyAddrsFactory(addrs []ma.Multiaddr) []ma.Multiaddr {
439+
af := a.addrsFactory(addrs)
440+
// Copy to our slice in case addrsFactory returns its own same slice always.
441+
addrs = append(addrs[:0], af...)
432442
// Add certhashes for the addresses provided by the user via address factory.
433443
addrs = a.addCertHashes(ma.Unique(addrs))
434444
slices.SortFunc(addrs, func(a, b ma.Multiaddr) int { return a.Compare(b) })
@@ -880,6 +890,33 @@ func removeNotInSource(addrs, source []ma.Multiaddr) []ma.Multiaddr {
880890
return addrs[:i]
881891
}
882892

893+
// removeInSource removes items from addrs that are present in source.
894+
// Modifies the addrs slice in place
895+
// addrs and source must be sorted using multiaddr.Compare.
896+
func removeInSource(addrs, source []ma.Multiaddr) []ma.Multiaddr {
897+
j := 0
898+
// mark entries in source as nil
899+
for i, a := range addrs {
900+
// move right in source as long as a > source[j]
901+
for j < len(source) && a.Compare(source[j]) > 0 {
902+
j++
903+
}
904+
// a is in source, mark nil
905+
if j < len(source) && a.Compare(source[j]) == 0 {
906+
addrs[i] = nil
907+
}
908+
}
909+
// j is the current element, i is the lowest index nil element
910+
i := 0
911+
for j := range len(addrs) {
912+
if addrs[j] != nil {
913+
addrs[i], addrs[j] = addrs[j], addrs[i]
914+
i++
915+
}
916+
}
917+
return addrs[:i]
918+
}
919+
883920
type multiCloser []io.Closer
884921

885922
func (mc *multiCloser) Close() error {

p2p/host/basic/addrs_manager_test.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package basichost
33
import (
44
"context"
55
"crypto/rand"
6-
"errors"
76
"fmt"
87
"slices"
98
"sync/atomic"
@@ -406,10 +405,10 @@ func TestAddrsManagerReachabilityEvent(t *testing.T) {
406405
F: func(_ context.Context, reqs []autonatv2.Request) (autonatv2.Result, error) {
407406
if reqs[0].Addr.Equal(publicQUIC) {
408407
return autonatv2.Result{Addr: reqs[0].Addr, Idx: 0, Reachability: network.ReachabilityPublic}, nil
409-
} else if reqs[0].Addr.Equal(publicTCP) || reqs[0].Addr.Equal(publicQUIC2) {
408+
} else if reqs[0].Addr.Equal(publicQUIC2) {
410409
return autonatv2.Result{Addr: reqs[0].Addr, Idx: 0, Reachability: network.ReachabilityPrivate}, nil
411410
}
412-
return autonatv2.Result{}, errors.New("invalid")
411+
return autonatv2.Result{Addr: reqs[0].Addr, Idx: 0, Reachability: network.ReachabilityUnknown, AllAddrsRefused: true}, nil
413412
},
414413
},
415414
})
@@ -429,17 +428,20 @@ func TestAddrsManagerReachabilityEvent(t *testing.T) {
429428

430429
// Wait for probes to complete and addresses to be classified
431430
reachableAddrs := []ma.Multiaddr{publicQUIC}
432-
unreachableAddrs := []ma.Multiaddr{publicTCP, publicQUIC2}
431+
unreachableAddrs := []ma.Multiaddr{publicQUIC2}
432+
unknownAddrs := []ma.Multiaddr{publicTCP}
433433
select {
434434
case e := <-sub.Out():
435435
evt := e.(event.EvtHostReachableAddrsChanged)
436-
require.ElementsMatch(t, reachableAddrs, evt.Reachable)
437-
require.ElementsMatch(t, unreachableAddrs, evt.Unreachable)
438-
require.Empty(t, evt.Unknown)
436+
matest.AssertMultiaddrsMatch(t, reachableAddrs, evt.Reachable)
437+
matest.AssertMultiaddrsMatch(t, unreachableAddrs, evt.Unreachable)
438+
matest.AssertMultiaddrsMatch(t, unknownAddrs, evt.Unknown)
439439
reachable, unreachable, unknown := am.ConfirmedAddrs()
440-
require.ElementsMatch(t, reachable, reachableAddrs)
441-
require.ElementsMatch(t, unreachable, unreachableAddrs)
442-
require.Empty(t, unknown)
440+
matest.AssertMultiaddrsMatch(t, reachableAddrs, reachable)
441+
matest.AssertMultiaddrsMatch(t, unreachableAddrs, unreachable)
442+
matest.AssertMultiaddrsMatch(t, unknownAddrs, unknown)
443+
// unreachable addrs should be removed
444+
matest.AssertMultiaddrsMatch(t, []ma.Multiaddr{publicQUIC, publicTCP}, am.Addrs())
443445
case <-time.After(5 * time.Second):
444446
t.Fatal("expected final event for reachability change after probing")
445447
}

0 commit comments

Comments
 (0)