tor_guardmgr/bridge/
relay.rs

1//! Implementation code to make a bridge something that we can connect to and use to relay traffic.
2
3use itertools::Itertools as _;
4use tor_linkspec::{
5    ChanTarget, CircTarget, HasAddrs, HasChanMethod, HasRelayIds, RelayIdRef, RelayIdType,
6};
7
8use super::{BridgeConfig, BridgeDesc};
9
10/// The information about a Bridge that is necessary to connect to it and send
11/// it traffic.
12#[derive(Clone, Debug)]
13pub struct BridgeRelay<'a> {
14    /// The local configurations for the bridge.
15    ///
16    /// This is _always_ necessary, since it without it we can't know whether
17    /// any pluggable transports are needed.
18    bridge_line: &'a BridgeConfig,
19
20    /// A descriptor for the bridge.
21    ///
22    /// If present, it MUST have every RelayId that the `bridge_line` does.
23    ///
24    /// `BridgeDesc` is an `Arc<>` internally, so we aren't so worried about
25    /// having this be owned.
26    desc: Option<BridgeDesc>,
27
28    /// All the known addresses for the bridge.
29    ///
30    /// This includes the contact addresses in `bridge_line`, plus any addresses
31    /// listed in `desc`.
32    ///
33    /// TODO(nickm): I wish we didn't have to reallocate a for this, but the API
34    /// requires that we can return a reference to a slice of this.
35    ///
36    /// TODO(nickm): perhaps, construct this lazily?
37    addrs: Vec<std::net::SocketAddr>,
38}
39
40/// A BridgeRelay that is known to have its full information available, and
41/// which is therefore usable for multi-hop circuits.
42///
43/// (All bridges can be used for single-hop circuits, but we need to know the
44/// bridge's descriptor in order to construct proper multi-hop circuits
45/// with forward secrecy through it.)
46#[derive(Clone, Debug)]
47pub struct BridgeRelayWithDesc<'a>(
48    /// This will _always_ be a bridge relay with a non-None desc.
49    &'a BridgeRelay<'a>,
50);
51
52impl<'a> BridgeRelay<'a> {
53    /// Construct a new BridgeRelay from its parts.
54    pub(crate) fn new(bridge_line: &'a BridgeConfig, desc: Option<BridgeDesc>) -> Self {
55        let addrs = bridge_line
56            .addrs()
57            .iter()
58            .copied()
59            .chain(desc.iter().flat_map(|d| d.as_ref().or_ports()))
60            .unique()
61            .collect();
62
63        Self {
64            bridge_line,
65            desc,
66            addrs,
67        }
68    }
69
70    /// Return true if this BridgeRelay has a known descriptor and can be used for relays.
71    pub fn has_descriptor(&self) -> bool {
72        self.desc.is_some()
73    }
74
75    /// If we have enough information about this relay to build a circuit through it,
76    /// return a BridgeRelayWithDesc for it.
77    pub fn as_relay_with_desc(&self) -> Option<BridgeRelayWithDesc<'_>> {
78        self.desc.is_some().then_some(BridgeRelayWithDesc(self))
79    }
80}
81
82impl<'a> HasRelayIds for BridgeRelay<'a> {
83    fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>> {
84        self.bridge_line
85            .identity(key_type)
86            .or_else(|| self.desc.as_ref().and_then(|d| d.identity(key_type)))
87    }
88}
89
90impl<'a> HasAddrs for BridgeRelay<'a> {
91    /// Note: Remember (from the documentation at [`HasAddrs`]) that these are
92    /// not necessarily addresses _at which the Bridge can be reached_. For
93    /// those, use `chan_method`.  These addresses are used for establishing
94    /// GeoIp and family info.
95    fn addrs(&self) -> &[std::net::SocketAddr] {
96        &self.addrs[..]
97    }
98}
99
100impl<'a> HasChanMethod for BridgeRelay<'a> {
101    fn chan_method(&self) -> tor_linkspec::ChannelMethod {
102        self.bridge_line.chan_method()
103    }
104}
105
106impl<'a> ChanTarget for BridgeRelay<'a> {}
107
108impl<'a> HasRelayIds for BridgeRelayWithDesc<'a> {
109    fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>> {
110        self.0.identity(key_type)
111    }
112}
113impl<'a> HasAddrs for BridgeRelayWithDesc<'a> {
114    /// Note: Remember (from the documentation at [`HasAddrs`]) that these are
115    /// not necessarily addresses _at which the Bridge can be reached_. For
116    /// those, use `chan_method`.  These addresses are used for establishing
117    /// GeoIp and family info.
118    fn addrs(&self) -> &[std::net::SocketAddr] {
119        self.0.addrs()
120    }
121}
122impl<'a> HasChanMethod for BridgeRelayWithDesc<'a> {
123    fn chan_method(&self) -> tor_linkspec::ChannelMethod {
124        self.0.chan_method()
125    }
126}
127
128impl<'a> ChanTarget for BridgeRelayWithDesc<'a> {}
129
130impl<'a> BridgeRelayWithDesc<'a> {
131    /// Return a reference to the BridgeDesc in this reference.
132    fn desc(&self) -> &BridgeDesc {
133        self.0
134            .desc
135            .as_ref()
136            .expect("There was supposed to be a descriptor here")
137    }
138}
139
140impl<'a> CircTarget for BridgeRelayWithDesc<'a> {
141    fn ntor_onion_key(&self) -> &tor_llcrypto::pk::curve25519::PublicKey {
142        self.desc().as_ref().ntor_onion_key()
143    }
144
145    fn protovers(&self) -> &tor_protover::Protocols {
146        self.desc().as_ref().protocols()
147    }
148}