iroh_net/relay/
map.rs

1//! based on tailscale/tailcfg/derpmap.go
2
3use std::{collections::BTreeMap, fmt, sync::Arc};
4
5use anyhow::{ensure, Result};
6use serde::{Deserialize, Serialize};
7
8use super::RelayUrl;
9use crate::defaults::DEFAULT_STUN_PORT;
10
11/// Configuration of the relay servers for an [`Endpoint`].
12///
13/// [`Endpoint`]: crate::endpoint::Endpoint
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum RelayMode {
16    /// Disable relay servers completely.
17    Disabled,
18    /// Use the default relay map, with production relay servers from n0.
19    ///
20    /// See [`crate::defaults::prod`] for the severs used.
21    Default,
22    /// Use the staging relay servers from n0.
23    Staging,
24    /// Use a custom relay map.
25    Custom(RelayMap),
26}
27
28impl RelayMode {
29    /// Returns the relay map for this mode.
30    pub fn relay_map(&self) -> RelayMap {
31        match self {
32            RelayMode::Disabled => RelayMap::empty(),
33            RelayMode::Default => crate::defaults::prod::default_relay_map(),
34            RelayMode::Staging => crate::defaults::staging::default_relay_map(),
35            RelayMode::Custom(relay_map) => relay_map.clone(),
36        }
37    }
38}
39
40/// Configuration of all the relay servers that can be used.
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub struct RelayMap {
43    /// A map of the different relay IDs to the [`RelayNode`] information
44    nodes: Arc<BTreeMap<RelayUrl, Arc<RelayNode>>>,
45}
46
47impl RelayMap {
48    /// Returns the sorted relay URLs.
49    pub fn urls(&self) -> impl Iterator<Item = &RelayUrl> {
50        self.nodes.keys()
51    }
52
53    /// Create an empty relay map.
54    pub fn empty() -> Self {
55        Self {
56            nodes: Default::default(),
57        }
58    }
59
60    /// Returns an `Iterator` over all known nodes.
61    pub fn nodes(&self) -> impl Iterator<Item = &Arc<RelayNode>> {
62        self.nodes.values()
63    }
64
65    /// Is this a known node?
66    pub fn contains_node(&self, url: &RelayUrl) -> bool {
67        self.nodes.contains_key(url)
68    }
69
70    /// Get the given node.
71    pub fn get_node(&self, url: &RelayUrl) -> Option<&Arc<RelayNode>> {
72        self.nodes.get(url)
73    }
74
75    /// How many nodes are known?
76    pub fn len(&self) -> usize {
77        self.nodes.len()
78    }
79
80    /// Are there any nodes in this map?
81    pub fn is_empty(&self) -> bool {
82        self.nodes.is_empty()
83    }
84
85    /// Creates a new [`RelayMap`] with a single relay server configured.
86    ///
87    /// Allows to set a custom STUN port and different IP addresses for IPv4 and IPv6.
88    /// If IP addresses are provided, no DNS lookup will be performed.
89    pub fn default_from_node(url: RelayUrl, stun_port: u16) -> Self {
90        let mut nodes = BTreeMap::new();
91        nodes.insert(
92            url.clone(),
93            RelayNode {
94                url,
95                stun_only: false,
96                stun_port,
97            }
98            .into(),
99        );
100
101        RelayMap {
102            nodes: Arc::new(nodes),
103        }
104    }
105
106    /// Returns a [`RelayMap`] from a [`RelayUrl`].
107    ///
108    /// This will use the default STUN port and IP addresses resolved from the URL's host name via DNS.
109    /// relay nodes are specified at <../../docs/relay_nodes.md>
110    pub fn from_url(url: RelayUrl) -> Self {
111        Self::default_from_node(url, DEFAULT_STUN_PORT)
112    }
113
114    /// Constructs the [`RelayMap`] from an iterator of [`RelayNode`]s.
115    pub fn from_nodes(value: impl IntoIterator<Item = RelayNode>) -> Result<Self> {
116        let mut map = BTreeMap::new();
117        for node in value.into_iter() {
118            ensure!(!map.contains_key(&node.url), "Duplicate node url");
119            map.insert(node.url.clone(), node.into());
120        }
121        Ok(RelayMap { nodes: map.into() })
122    }
123}
124
125impl fmt::Display for RelayMap {
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        fmt::Debug::fmt(&self, f)
128    }
129}
130
131/// Information on a specific relay server.
132///
133/// Includes the Url where it can be dialed.
134// Please note that this is documented in the `iroh.computer` repository under
135// `src/app/docs/reference/config/page.mdx`.  Any changes to this need to be updated there.
136#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)]
137pub struct RelayNode {
138    /// The [`RelayUrl`] where this relay server can be dialed.
139    pub url: RelayUrl,
140    /// Whether this relay server should only be used for STUN requests.
141    ///
142    /// This essentially allows you to use a normal STUN server as a relay node, no relay
143    /// functionality is used.
144    pub stun_only: bool,
145    /// The stun port of the relay server.
146    ///
147    /// Setting this to `0` means the default STUN port is used.
148    pub stun_port: u16,
149}
150
151impl fmt::Display for RelayNode {
152    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
153        write!(f, "{}", self.url)
154    }
155}