1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//! Implementation code to make a bridge something that we can connect to and use to relay traffic.

use itertools::Itertools as _;
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<BridgeDesc>,

    /// 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<std::net::SocketAddr>,
}

/// 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<BridgeDesc>) -> Self {
        let addrs = bridge_line
            .addrs()
            .iter()
            .copied()
            .chain(desc.iter().flat_map(|d| d.as_ref().or_ports()))
            .unique()
            .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<BridgeRelayWithDesc<'_>> {
        self.desc.is_some().then_some(BridgeRelayWithDesc(self))
    }
}

impl<'a> HasRelayIds for BridgeRelay<'a> {
    fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>> {
        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<RelayIdRef<'_>> {
        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()
    }
}