basichost: use autonatv2 to verify reachability (#3231)

This introduces addrsReachabilityTracker that tracks reachability on
a set of addresses. It probes reachability for addresses periodically
and has an exponential backoff in case there are too many errors
or we don't have any valid autonatv2 peer.

There's no smartness in the address selection logic currently. We just
test all provided addresses. It also doesn't use the addresses provided
by `AddrsFactory`, so currently there's no way to get a user provided
address tested for reachability, something that would be a problem for
dns addresses. I intend to introduce an alternative to
`AddrsFactory`, something like, `AnnounceAddrs(addrs []ma.Multiaddr)`
that's just appended to the set of addresses that we have, and check
reachability for those addresses.

There's only one method exposed in the BasicHost right now that's
`ReachableAddrs() []ma.Multiadd`r that returns the host's reachable
addrs. Users can also use the event `EvtHostReachableAddrsChanged`
to be notified when any addrs reachability changes.
This commit is contained in:
sukun
2025-06-03 17:13:56 +05:30
committed by GitHub
parent 31c8c83308
commit fb1d9512e8
15 changed files with 2420 additions and 321 deletions
+23 -16
View File
@@ -156,8 +156,8 @@ type HostOpts struct {
// DisableIdentifyAddressDiscovery disables address discovery using peer provided observed addresses in identify
DisableIdentifyAddressDiscovery bool
EnableAutoNATv2 bool
AutoNATv2Dialer host.Host
AutoNATv2 *autonatv2.AutoNAT
}
// NewHost constructs a new *BasicHost and activates it by attaching its stream and connection handlers to the given inet.Network.
@@ -236,7 +236,16 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) {
}); ok {
tfl = s.TransportForListening
}
h.addressManager, err = newAddrsManager(h.eventbus, natmgr, addrFactory, h.Network().ListenAddresses, tfl, h.ids, h.addrsUpdatedChan)
if opts.AutoNATv2 != nil {
h.autonatv2 = opts.AutoNATv2
}
var autonatv2Client autonatv2Client // avoid typed nil errors
if h.autonatv2 != nil {
autonatv2Client = h.autonatv2
}
h.addressManager, err = newAddrsManager(h.eventbus, natmgr, addrFactory, h.Network().ListenAddresses, tfl, h.ids, h.addrsUpdatedChan, autonatv2Client)
if err != nil {
return nil, fmt.Errorf("failed to create address service: %w", err)
}
@@ -283,17 +292,6 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) {
h.pings = ping.NewPingService(h)
}
if opts.EnableAutoNATv2 {
var mt autonatv2.MetricsTracer
if opts.EnableMetrics {
mt = autonatv2.NewMetricsTracer(opts.PrometheusRegisterer)
}
h.autonatv2, err = autonatv2.New(h, opts.AutoNATv2Dialer, autonatv2.WithMetricsTracer(mt))
if err != nil {
return nil, fmt.Errorf("failed to create autonatv2: %w", err)
}
}
if !h.disableSignedPeerRecord {
h.signKey = h.Peerstore().PrivKey(h.ID())
cab, ok := peerstore.GetCertifiedAddrBook(h.Peerstore())
@@ -320,7 +318,7 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) {
func (h *BasicHost) Start() {
h.psManager.Start()
if h.autonatv2 != nil {
err := h.autonatv2.Start()
err := h.autonatv2.Start(h)
if err != nil {
log.Errorf("autonat v2 failed to start: %s", err)
}
@@ -754,6 +752,16 @@ func (h *BasicHost) AllAddrs() []ma.Multiaddr {
return h.addressManager.DirectAddrs()
}
// ReachableAddrs returns all addresses of the host that are reachable from the internet
// as verified by autonatv2.
//
// Experimental: This API may change in the future without deprecation.
//
// Requires AutoNATv2 to be enabled.
func (h *BasicHost) ReachableAddrs() []ma.Multiaddr {
return h.addressManager.ReachableAddrs()
}
func trimHostAddrList(addrs []ma.Multiaddr, maxSize int) []ma.Multiaddr {
totalSize := 0
for _, a := range addrs {
@@ -836,7 +844,6 @@ func (h *BasicHost) Close() error {
if h.cmgr != nil {
h.cmgr.Close()
}
h.addressManager.Close()
if h.ids != nil {