Skip to content
14 changes: 13 additions & 1 deletion iroh/src/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,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::Config as NetReportConfig, portmapper::PortmapperConfig};
Comment thread
rklaehn marked this conversation as resolved.
Outdated

/// Builder for [`Endpoint`].
///
Expand Down Expand Up @@ -129,6 +129,7 @@ pub struct Builder {
hooks: EndpointHooksList,
transport_bias: socket::transports::TransportBiasMap,
portmapper_config: PortmapperConfig,
net_report_config: NetReportConfig,
}

impl From<RelayMode> for Option<TransportConfig> {
Expand Down Expand Up @@ -194,6 +195,7 @@ impl Builder {
hooks: Default::default(),
transport_bias: Default::default(),
portmapper_config: Default::default(),
net_report_config: Default::default(),
}
}

Expand Down Expand Up @@ -240,6 +242,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,
};

Expand Down Expand Up @@ -703,6 +706,15 @@ impl Builder {
self
}

/// Configures the net report service.
///
/// Controls which probes (HTTPS latency, captive portal detection) are run.
/// Defaults to all probes enabled.
pub fn net_report_config(mut self, config: NetReportConfig) -> Self {
Comment thread
rklaehn marked this conversation as resolved.
Outdated
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
4 changes: 3 additions & 1 deletion iroh/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,9 @@ pub use iroh_base::{
pub use iroh_relay::dns;
pub use iroh_relay::{RelayConfig, RelayMap, endpoint_info};
pub use n0_watcher::Watcher;
pub use net_report::{Report as NetReport, TIMEOUT as NET_REPORT_TIMEOUT};
pub use net_report::{
Config as NetReportConfig, Report as NetReport, TIMEOUT as NET_REPORT_TIMEOUT,
};

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

/// Configuration for the net report service.
///
/// 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 Config {
/// Run HTTPS latency probes against relay servers.
///
/// Disable this on constrained devices where the extra TCP connections are
/// too expensive — QAD (UDP) probes already measure relay latency.
Comment thread
rklaehn marked this conversation as resolved.
Outdated
pub https_probes: bool,
/// Check for captive portals when generating the first report.
///
/// Disable this on embedded devices or environments where captive portal
/// detection is not meaningful.
Comment thread
rklaehn marked this conversation as resolved.
Outdated
pub captive_portal_check: bool,
}

impl Config {
/// 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 Config {
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 @@ -100,6 +138,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 @@ -239,6 +279,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 @@ -294,6 +335,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::{Config, 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: Config,
}

impl Options {
pub(crate) fn new(tls_config: rustls::ClientConfig) -> Self {
Self {
quic_config: None,
tls_config,
user_config: Config::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: Config) -> 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::{Config, 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: Config,
}

impl Default for Options {
fn default() -> Self {
Self { https: true }
Self {
user_config: Config::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: Config) -> 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 @@ -115,10 +115,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 @@ -130,6 +132,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 @@ -168,6 +171,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 @@ -276,7 +282,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 @@ -150,6 +150,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::Config,

/// Static configuration for the endpoint.
pub(crate) static_config: StaticConfig,
Expand Down Expand Up @@ -778,6 +779,7 @@ impl EndpointInner {
hooks,
transport_bias,
portmapper_config,
net_report_config,
static_config,
} = opts;

Expand Down Expand Up @@ -932,11 +934,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 @@ -1780,6 +1784,7 @@ mod tests {
hooks: Default::default(),
transport_bias: Default::default(),
portmapper_config: Default::default(),
net_report_config: Default::default(),
static_config,
}
}
Expand Down Expand Up @@ -2179,6 +2184,7 @@ mod tests {
hooks: Default::default(),
transport_bias: Default::default(),
portmapper_config: Default::default(),
net_report_config: Default::default(),
static_config,
};
let sock = EndpointInner::bind(opts).await?;
Expand Down
Loading