//! Implementation code to make a bridge something that we can connect to and use to relay traffic. use tor_linkspec::{ ChanTarget, CircTarget, HasAddrs, HasChanMethod, HasRelayIds, RelayIdRef, RelayIdType, }; use super::{BridgeConfig, BridgeDesc}; /// The information about a Bridge that is necessary to connect to it and send /// it traffic. #[derive(Clone, Debug)] pub struct BridgeRelay<'a> { /// The local configurations for the bridge. /// /// This is _always_ necessary, since it without it we can't know whether /// any pluggable transports are needed. bridge_line: &'a BridgeConfig, /// A descriptor for the bridge. /// /// If present, it MUST have every RelayId that the `bridge_line` does. /// /// `BridgeDesc` is an `Arc<>` internally, so we aren't so worried about /// having this be owned. desc: Option, /// All the known addresses for the bridge. /// /// This includes the contact addresses in `bridge_line`, plus any addresses /// listed in `desc`. /// /// TODO(nickm): I wish we didn't have to reallocate a for this, but the API /// requires that we can return a reference to a slice of this. /// /// TODO(nickm): perhaps, construct this lazily? addrs: Vec, } /// A BridgeRelay that is known to have its full information available, and /// which is therefore usable for multi-hop circuits. /// /// (All bridges can be used for single-hop circuits, but we need to know the /// bridge's descriptor in order to construct proper multi-hop circuits /// with forward secrecy through it.) #[derive(Clone, Debug)] pub struct BridgeRelayWithDesc<'a>( /// This will _always_ be a bridge relay with a non-None desc. &'a BridgeRelay<'a>, ); impl<'a> BridgeRelay<'a> { /// Construct a new BridgeRelay from its parts. pub(crate) fn new(bridge_line: &'a BridgeConfig, desc: Option) -> Self { let addrs = bridge_line .addrs() .iter() .copied() .chain(desc.iter().flat_map(|d| d.as_ref().or_ports())) .collect(); Self { bridge_line, desc, addrs, } } /// Return true if this BridgeRelay has a known descriptor and can be used for relays. pub fn has_descriptor(&self) -> bool { self.desc.is_some() } /// If we have enough information about this relay to build a circuit through it, /// return a BridgeRelayWithDesc for it. pub fn as_relay_with_desc(&self) -> Option> { self.desc.is_some().then_some(BridgeRelayWithDesc(self)) } } impl<'a> HasRelayIds for BridgeRelay<'a> { fn identity(&self, key_type: RelayIdType) -> Option> { self.bridge_line .identity(key_type) .or_else(|| self.desc.as_ref().and_then(|d| d.identity(key_type))) } } impl<'a> HasAddrs for BridgeRelay<'a> { /// Note: Remember (from the documentation at [`HasAddrs`]) that these are /// not necessarily addresses _at which the Bridge can be reached_. For /// those, use `chan_method`. These addresses are used for establishing /// GeoIp and family info. fn addrs(&self) -> &[std::net::SocketAddr] { &self.addrs[..] } } impl<'a> HasChanMethod for BridgeRelay<'a> { fn chan_method(&self) -> tor_linkspec::ChannelMethod { self.bridge_line.chan_method() } } impl<'a> ChanTarget for BridgeRelay<'a> {} impl<'a> HasRelayIds for BridgeRelayWithDesc<'a> { fn identity(&self, key_type: RelayIdType) -> Option> { self.0.identity(key_type) } } impl<'a> HasAddrs for BridgeRelayWithDesc<'a> { /// Note: Remember (from the documentation at [`HasAddrs`]) that these are /// not necessarily addresses _at which the Bridge can be reached_. For /// those, use `chan_method`. These addresses are used for establishing /// GeoIp and family info. fn addrs(&self) -> &[std::net::SocketAddr] { self.0.addrs() } } impl<'a> HasChanMethod for BridgeRelayWithDesc<'a> { fn chan_method(&self) -> tor_linkspec::ChannelMethod { self.0.chan_method() } } impl<'a> ChanTarget for BridgeRelayWithDesc<'a> {} impl<'a> BridgeRelayWithDesc<'a> { /// Return a reference to the BridgeDesc in this reference. fn desc(&self) -> &BridgeDesc { self.0 .desc .as_ref() .expect("There was supposed to be a descriptor here") } } impl<'a> CircTarget for BridgeRelayWithDesc<'a> { fn ntor_onion_key(&self) -> &tor_llcrypto::pk::curve25519::PublicKey { self.desc().as_ref().ntor_onion_key() } fn protovers(&self) -> &tor_protover::Protocols { self.desc().as_ref().protocols() } }