From 75e2137e6beb97a8bc089e71e69edac6686daace Mon Sep 17 00:00:00 2001 From: Nathaniel Cook Date: Mon, 13 Nov 2023 14:58:02 -0700 Subject: [PATCH] feat: add control over autonat (#176) Prior to this change autonat would always be enabled. Now it can be disabled in cases where NAT is not being used. Additionally previously an unbounded number of probes would be running concurrently for all observed addresses. When an dynamic outbound NAT is used this results in many probes. Now we limit to one active probe at a time and also track failed external address so we do not repeatedly attempt to probe them. --- one/src/lib.rs | 13 +++++++++---- p2p/src/node.rs | 38 ++++++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/one/src/lib.rs b/one/src/lib.rs index c788cd238..c01dc479f 100644 --- a/one/src/lib.rs +++ b/one/src/lib.rs @@ -78,7 +78,7 @@ struct DaemonOpts { #[arg( short, long, - default_value = "127.0.0.1:9090", + default_value = "127.0.0.1:9464", env = "CERAMIC_ONE_METRICS_BIND_ADDRESS" )] metrics_bind_address: String, @@ -99,14 +99,19 @@ struct DaemonOpts { #[arg(long, env = "CERAMIC_ONE_LOCAL_NETWORK_ID")] local_network_id: Option, - /// When true mdns will be used to discover peers. + /// When set mdns will be used to discover peers. #[arg(long, default_value_t = false, env = "CERAMIC_ONE_MDNS")] mdns: bool, - /// When true Recon will be used to synchronized events with peers. + /// When set Recon will be used to synchronized events with peers. #[arg(long, default_value_t = false, env = "CERAMIC_ONE_RECON")] recon: bool, + /// When set autonat will not be used to discover external address or allow other peers + /// to directly dial the local peer. + #[arg(long, default_value_t = false, env = "CERAMIC_ONE_DISABLE_AUTONAT")] + disable_autonat: bool, + /// Specify the format of log events. #[arg(long, default_value = "multi-line", env = "CERAMIC_ONE_LOG_FORMAT")] log_format: LogFormat, @@ -348,7 +353,7 @@ impl Daemon { bitswap_server: true, bitswap_client: true, kademlia: true, - autonat: true, + autonat: !opts.disable_autonat, relay_server: true, relay_client: true, gossipsub: true, diff --git a/p2p/src/node.rs b/p2p/src/node.rs index a2d697228..822a23f5d 100644 --- a/p2p/src/node.rs +++ b/p2p/src/node.rs @@ -84,6 +84,8 @@ where listen_addrs: Vec, trust_observed_addrs: bool, + failed_external_addresses: HashSet, + active_address_probe: Option, } impl fmt::Debug for Node @@ -194,6 +196,8 @@ where providers: Providers::new(4), listen_addrs, trust_observed_addrs: libp2p_config.trust_observed_addrs, + failed_external_addresses: Default::default(), + active_address_probe: Default::default(), }) } @@ -629,6 +633,7 @@ where .swarm .external_addresses() .any(|addr| addr == &info.observed_addr) + && !self.failed_external_addresses.contains(&info.observed_addr) { if self.trust_observed_addrs { debug!( @@ -640,14 +645,26 @@ where self.swarm.add_external_address(info.observed_addr.clone()); } else if let Some(autonat) = self.swarm.behaviour_mut().autonat.as_mut() { // Probe the observed addr for external connectivity. - // See OutboundProbeEvent case for - - debug!( - address=%info.observed_addr, - %peer_id, - "probing observed address from peer for external connectivity", - ); - autonat.probe_address(info.observed_addr.clone()); + // Only probe one address at a time. + // + // This logic is run very frequently because any new peer connection + // for a new observed address triggers this path. Its typical to have + // only a few external addresses, in which cases its likely that the + // in-progress address probe is one that will succeed. + // + // In cases where there are lots of different observed addresses its + // likely that NAT hasn't been setup and so the peer doesn't have an + // external address. Therefore we do not want to waste resources on + // probing many different addresses that are likely to fail. + if self.active_address_probe.is_none() { + self.active_address_probe = Some(info.observed_addr.clone()); + debug!( + address=%info.observed_addr, + %peer_id, + "probing observed address from peer for external connectivity", + ); + autonat.probe_address(info.observed_addr.clone()); + } }; }; @@ -765,6 +782,11 @@ where self.swarm.add_external_address(address); } } + Event::Autonat(autonat::Event::OutboundProbe(OutboundProbeEvent::Error { .. })) => { + if let Some(addr) = self.active_address_probe.take() { + self.failed_external_addresses.insert(addr); + } + } _ => { // TODO: check all important events are handled }