dig_nat/config.rs
1//! Connection configuration — the enabled methods, per-method timeout, relay/STUN endpoints, and the
2//! cert-binding policy that shape a [`crate::connect`] call. Built with a fluent builder; the caller
3//! never selects the traversal method (only which ones are *enabled*).
4//!
5//! The local mTLS identity is NOT here: it is a [`dig_tls::NodeCert`] the caller passes to
6//! [`crate::connect`] directly (dig-tls owns the cert model — CA, leaf, peer_id, binding).
7
8use std::time::Duration;
9
10use crate::method::TraversalKind;
11use dig_tls::BindingPolicy;
12
13/// Which traversal methods are enabled + the per-method deadline, relay settings, and cert-binding
14/// policy for a connect.
15///
16/// The DEFAULT enables every method in the canonical order with sane timeouts and the canonical
17/// [`dig_constants::DIG_RELAY_URL`] relay. The caller tweaks via the builder but never picks *which*
18/// method wins — the strategy does, first-success-wins, relay-last.
19#[derive(Debug, Clone)]
20pub struct NatConfig {
21 /// The traversal techniques permitted, by kind. The strategy always tries them in
22 /// [`TraversalKind::rank`] order regardless of the order here.
23 pub enabled_methods: Vec<TraversalKind>,
24 /// Per-method hard timeout — a method that does not complete in this window is abandoned and the
25 /// strategy moves on (this is the guarantee that a hung method can never block `connect`).
26 pub per_method_timeout: Duration,
27 /// The relay WebSocket endpoint for the relay-coordinated + relayed methods. Defaults to the
28 /// canonical relay; honour the `DIG_RELAY_URL` env override / `=off` opt-out via
29 /// [`crate::relay::relay_url_from_env`] / [`crate::relay::relay_enabled`].
30 pub relay_endpoint: String,
31 /// A STUN server used to discover this node's reflexive address for candidate advertisement +
32 /// hole-punch. `None` = derive from the relay host on the standard STUN port
33 /// [`STUN_PORT`](crate::config::STUN_PORT) (the relay co-locates a STUN server, L7 spec §3):
34 /// point a node at a private relay and its STUN follows.
35 pub stun_server: Option<std::net::SocketAddr>,
36 /// The #1204 BLS cert-binding verification stance applied to the PEER's certificate during the
37 /// mTLS handshake. Defaults to [`BindingPolicy::Opportunistic`] (the rollout default: verify a
38 /// binding when present, reject a present-but-invalid one, tolerate a legacy peer that has none).
39 /// A node that requires payload sealing sets [`BindingPolicy::Required`] (fail-closed,
40 /// anti-downgrade). Verified via `dig-tls`; the verified peer BLS pubkey lands on
41 /// [`crate::PeerConnection::peer_bls_pub`].
42 pub binding_policy: BindingPolicy,
43}
44
45/// The standard STUN port (RFC 5389). The DIG relay serves STUN here, co-located with the relay host
46/// (`relay.dig.net:3478`); a node derives its STUN host from `DIG_RELAY_URL` (L7 spec §3).
47pub const STUN_PORT: u16 = 3478;
48
49impl Default for NatConfig {
50 fn default() -> Self {
51 NatConfig {
52 enabled_methods: vec![
53 TraversalKind::Direct,
54 TraversalKind::Upnp,
55 TraversalKind::NatPmp,
56 TraversalKind::Pcp,
57 TraversalKind::HolePunch,
58 TraversalKind::Relayed,
59 ],
60 per_method_timeout: Duration::from_secs(5),
61 relay_endpoint: dig_constants::DIG_RELAY_URL.to_string(),
62 stun_server: None,
63 binding_policy: BindingPolicy::Opportunistic,
64 }
65 }
66}
67
68impl NatConfig {
69 /// Start from the default config.
70 pub fn builder() -> NatConfigBuilder {
71 NatConfigBuilder {
72 cfg: NatConfig::default(),
73 }
74 }
75
76 /// Whether `kind` is enabled in this config.
77 pub fn is_enabled(&self, kind: TraversalKind) -> bool {
78 self.enabled_methods.contains(&kind)
79 }
80}
81
82/// Fluent builder for [`NatConfig`].
83#[derive(Debug, Clone)]
84pub struct NatConfigBuilder {
85 cfg: NatConfig,
86}
87
88impl NatConfigBuilder {
89 /// Restrict the enabled methods (they are still tried in canonical rank order).
90 pub fn enabled_methods(mut self, methods: Vec<TraversalKind>) -> Self {
91 self.cfg.enabled_methods = methods;
92 self
93 }
94
95 /// Disable a single method (e.g. turn off the relay fallback for an air-gapped node).
96 pub fn disable(mut self, kind: TraversalKind) -> Self {
97 self.cfg.enabled_methods.retain(|k| *k != kind);
98 self
99 }
100
101 /// Set the per-method timeout.
102 pub fn per_method_timeout(mut self, timeout: Duration) -> Self {
103 self.cfg.per_method_timeout = timeout;
104 self
105 }
106
107 /// Override the relay endpoint (defaults to the canonical relay).
108 pub fn relay_endpoint(mut self, endpoint: impl Into<String>) -> Self {
109 self.cfg.relay_endpoint = endpoint.into();
110 self
111 }
112
113 /// Set the STUN server used for reflexive-address discovery.
114 pub fn stun_server(mut self, addr: std::net::SocketAddr) -> Self {
115 self.cfg.stun_server = Some(addr);
116 self
117 }
118
119 /// Set the #1204 cert-binding verification stance for the peer's certificate (default
120 /// [`BindingPolicy::Opportunistic`]). Use [`BindingPolicy::Required`] on a node that seals
121 /// payloads to peers (fail-closed, anti-downgrade).
122 pub fn binding_policy(mut self, policy: BindingPolicy) -> Self {
123 self.cfg.binding_policy = policy;
124 self
125 }
126
127 /// Finalize the config.
128 pub fn build(self) -> NatConfig {
129 self.cfg
130 }
131}