Skip to content
17 changes: 16 additions & 1 deletion iroh/src/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ pub use self::{
VarIntBoundsExceeded, WriteError, Written,
},
};
pub use crate::portmapper::PortmapperConfig;
#[cfg(not(wasm_browser))]
use crate::socket::transports::IpConfig;
use crate::socket::transports::TransportConfig;
pub use crate::{net_report::NetReportConfig, portmapper::PortmapperConfig};

/// Builder for [`Endpoint`].
///
Expand Down Expand Up @@ -130,6 +130,7 @@ pub struct Builder {
hooks: EndpointHooksList,
transport_bias: socket::transports::TransportBiasMap,
portmapper_config: PortmapperConfig,
net_report_config: NetReportConfig,
crypto_provider: Option<Arc<rustls::crypto::CryptoProvider>>,
configured_addrs: BTreeSet<SocketAddr>,
}
Expand Down Expand Up @@ -197,6 +198,7 @@ impl Builder {
hooks: Default::default(),
transport_bias: Default::default(),
portmapper_config: Default::default(),
net_report_config: Default::default(),
crypto_provider: None,
configured_addrs: Default::default(),
}
Expand Down Expand Up @@ -258,6 +260,7 @@ impl Builder {
hooks: self.hooks,
transport_bias: self.transport_bias,
portmapper_config: self.portmapper_config,
net_report_config: self.net_report_config,
static_config,
configured_addrs: self.configured_addrs,
};
Expand Down Expand Up @@ -760,6 +763,18 @@ impl Builder {
self
}

/// Configures the net report.
///
/// The net report component is responsible for figuring out if and how the endpoint is connected to the internet.
/// It does this by doing various probes to the configured relay servers to get public addresses, NAT behaviour, and
/// relay latencies. In addition it tries to detect captive portals.
///
/// Some non-essential features of the net report component can be disabled via this configuration.
pub fn net_report_config(mut self, config: NetReportConfig) -> Self {
self.net_report_config = config;
self
}

/// Adds a custom transport
#[cfg(feature = "unstable-custom-transports")]
pub fn add_custom_transport(mut self, factory: Arc<dyn CustomTransport>) -> Self {
Expand Down
2 changes: 1 addition & 1 deletion iroh/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ pub use iroh_dns::dns;
pub use iroh_dns::endpoint_info;
pub use iroh_relay::{RelayConfig, RelayMap};
pub use n0_watcher::Watcher;
pub use net_report::{Report as NetReport, TIMEOUT as NET_REPORT_TIMEOUT};
pub use net_report::{NetReportConfig, Report as NetReport, TIMEOUT as NET_REPORT_TIMEOUT};

#[cfg(any(test, feature = "test-utils"))]
pub mod test_utils;
54 changes: 54 additions & 0 deletions iroh/src/net_report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,56 @@ pub(crate) use self::{
options::Options, probes::Probe, report::RelayLatencies, reportgen::QuicConfig,
};

/// Configuration for the net report component.
///
/// Controls which probes and checks are performed when generating network reports.
/// All options default to `true`.
#[derive(Debug, Clone)]
#[non_exhaustive]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

pub struct NetReportConfig {
/// Run HTTPS latency probes against relay servers.
///
/// HTTPS latency probes perform an empty HTTPS GET request to each configured
/// relay server and measure latency.
///
/// They are performed in addition to the QUIC address discovery (QAD) probes.
/// They are the only way to detect relay latencies and thus the preferred relay
/// in networks that do not allow QUIC traffic.
///
/// Disabling them is harmless on networks that do allow QUIC traffic, but will
/// completely prevent finding the home relay on networks that do block QUIC.
pub https_probes: bool,

/// Check for captive portals when generating the first report.
///
/// This is done by accessing a well-known URL that is available on each relay
/// server, `/generate_204`. If a GET request to this URL returns anything else
/// but a 204 No Content response, we assume we are behind a captive portal.
///
/// When we have detected that we are behind a captive portal, we try to contact
/// the relay servers more frequently in case the captive portal status changes.
pub captive_portal_check: bool,
}

impl NetReportConfig {
/// Creates a minimal configuration that disables all optional probes and checks.
pub fn minimal() -> Self {
Self {
https_probes: false,
captive_portal_check: false,
}
}
}

impl Default for NetReportConfig {
fn default() -> Self {
Self {
https_probes: true,
captive_portal_check: true,
}
}
}

const FULL_REPORT_INTERVAL: Duration = Duration::from_secs(5 * 60);
const ENOUGH_ENDPOINTS: usize = 3;

Expand All @@ -98,6 +148,8 @@ pub(crate) struct Client {
qad_conns: QadConns,
#[cfg(not(wasm_browser))]
tls_config: rustls::ClientConfig,
/// Whether to check for captive portals.
captive_portal_check: bool,
/// A collection of previously generated reports.
///
/// Sometimes it is useful to look at past reports to decide what to do.
Expand Down Expand Up @@ -237,6 +289,7 @@ impl Client {
qad_conns: QadConns::default(),
#[cfg(not(wasm_browser))]
tls_config: opts.tls_config,
captive_portal_check: opts.user_config.captive_portal_check,
}
}

Expand Down Expand Up @@ -292,6 +345,7 @@ impl Client {
self.reports.last.clone(),
self.relay_map.clone(),
self.probes.clone(),
self.captive_portal_check,
if_state.clone(),
shutdown_token.child_token(),
#[cfg(not(wasm_browser))]
Expand Down
40 changes: 23 additions & 17 deletions iroh/src/net_report/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub(crate) use imp::Options;
mod imp {
use std::collections::BTreeSet;

use crate::net_report::{QuicConfig, probes::Probe};
use crate::net_report::{NetReportConfig, QuicConfig, probes::Probe};

/// Options for running probes
///
Expand All @@ -21,13 +21,16 @@ mod imp {
pub(crate) quic_config: Option<QuicConfig>,
/// TLS config for HTTPS probes.
pub(crate) tls_config: rustls::ClientConfig,
/// User-facing configuration.
pub(crate) user_config: NetReportConfig,
}

impl Options {
pub(crate) fn new(tls_config: rustls::ClientConfig) -> Self {
Self {
quic_config: None,
tls_config,
user_config: NetReportConfig::default(),
}
}
/// Enable quic probes
Expand All @@ -36,6 +39,12 @@ mod imp {
self
}

/// Set the net report configuration.
pub(crate) fn net_report_config(mut self, config: NetReportConfig) -> Self {
self.user_config = config;
self
}

/// Turn the options into set of valid protocols
pub(crate) fn as_protocols(&self) -> BTreeSet<Probe> {
let mut protocols = BTreeSet::new();
Expand All @@ -47,7 +56,9 @@ mod imp {
protocols.insert(Probe::QadIpv6);
}
}
protocols.insert(Probe::Https);
if self.user_config.https_probes {
protocols.insert(Probe::Https);
}
protocols
}
}
Expand All @@ -57,42 +68,37 @@ mod imp {
mod imp {
use std::collections::BTreeSet;

use crate::net_report::Probe;
use crate::net_report::{NetReportConfig, Probe};

/// Options for running probes (in browsers).
///
/// Only HTTPS probes are supported in browsers.
/// These are run by default.
#[derive(Debug, Clone)]
pub(crate) struct Options {
/// Enable https probes
///
/// On by default
pub(crate) https: bool,
/// User-facing configuration.
pub(crate) user_config: NetReportConfig,
}

impl Default for Options {
fn default() -> Self {
Self { https: true }
Self {
user_config: NetReportConfig::default(),
}
}
}

impl Options {
/// Create an [`Options`] that disables all probes
pub(crate) fn disabled() -> Self {
Self { https: false }
}

/// Enable or disable https probe
pub(crate) fn https(mut self, enable: bool) -> Self {
self.https = enable;
/// Set the net report configuration.
pub(crate) fn net_report_config(mut self, config: NetReportConfig) -> Self {
self.user_config = config;
self
}

/// Turn the options into set of valid protocols
pub(crate) fn as_protocols(&self) -> BTreeSet<Probe> {
let mut protocols = BTreeSet::new();
if self.https {
if self.user_config.https_probes {
protocols.insert(Probe::Https);
}
protocols
Expand Down
8 changes: 7 additions & 1 deletion iroh/src/net_report/reportgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,12 @@ impl Client {
///
/// The actor starts running immediately and only generates a single report, after which
/// it shuts down. Dropping this handle will abort the actor.
#[allow(clippy::too_many_arguments)]
pub(super) fn new(
last_report: Option<Report>,
relay_map: RelayMap,
protocols: BTreeSet<Probe>,
captive_portal_check: bool,
if_state: IfStateDetails,
shutdown_token: CancellationToken,
#[cfg(not(wasm_browser))] socket_state: SocketState,
Expand All @@ -129,6 +131,7 @@ impl Client {
last_report,
relay_map,
protocols,
captive_portal_check,
#[cfg(not(wasm_browser))]
socket_state,
#[cfg(not(wasm_browser))]
Expand Down Expand Up @@ -167,6 +170,9 @@ struct Actor {
/// configuration for that protocol.
protocols: BTreeSet<Probe>,

/// Whether to check for captive portals.
captive_portal_check: bool,

/// Any socket-related state that doesn't exist/work in browsers
#[cfg(not(wasm_browser))]
socket_state: SocketState,
Expand Down Expand Up @@ -275,7 +281,7 @@ impl Actor {
// delay by a bit to wait for UDP QAD to finish, to avoid the probe if
// it's unnecessary.
#[cfg(not(wasm_browser))]
if self.last_report.is_none() {
if self.captive_portal_check && self.last_report.is_none() {
// Even if we're doing a non-incremental update, we may want to try our
// preferred relay for captive portal detection.
let preferred_relay = self
Expand Down
10 changes: 8 additions & 2 deletions iroh/src/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ pub(crate) struct Options {
pub(crate) hooks: EndpointHooksList,
pub(crate) transport_bias: TransportBiasMap,
pub(crate) portmapper_config: portmapper::PortmapperConfig,
pub(crate) net_report_config: crate::net_report::NetReportConfig,

/// Static configuration for the endpoint.
pub(crate) static_config: StaticConfig,
Expand Down Expand Up @@ -871,6 +872,7 @@ impl EndpointInner {
hooks,
transport_bias,
portmapper_config,
net_report_config,
static_config,
configured_addrs,
} = opts;
Expand Down Expand Up @@ -1030,11 +1032,13 @@ impl EndpointInner {
ipv4: true,
ipv6: has_ipv6_transport,
});
net_report::Options::new(tls_config.clone()).quic_config(qad_config)
net_report::Options::new(tls_config.clone())
.quic_config(qad_config)
.net_report_config(net_report_config)
};

#[cfg(wasm_browser)]
let net_report_config = net_report::Options::default();
let net_report_config = net_report::Options::default().net_report_config(net_report_config);

let net_reporter = net_report::Client::new(
#[cfg(not(wasm_browser))]
Expand Down Expand Up @@ -2162,6 +2166,7 @@ mod tests {
hooks: Default::default(),
transport_bias: Default::default(),
portmapper_config: Default::default(),
net_report_config: Default::default(),
static_config,
configured_addrs: Default::default(),
}
Expand Down Expand Up @@ -2571,6 +2576,7 @@ mod tests {
hooks: Default::default(),
transport_bias: Default::default(),
portmapper_config: Default::default(),
net_report_config: Default::default(),
static_config,
configured_addrs: Default::default(),
};
Expand Down
Loading