1
//! Support for identifying a particular transport.
2
//!
3
//! A "transport" is a mechanism to connect to a relay on the Tor network and
4
//! make a `Channel`. Currently, two types of transports exist: the "built-in"
5
//! transport, which uses TLS over TCP, and various anti-censorship "pluggable
6
//! transports", which use TLS over other protocols to avoid detection by
7
//! censors.
8

            
9
use std::fmt::{self, Debug, Display};
10
use std::net::SocketAddr;
11
use std::slice;
12
use std::str::FromStr;
13

            
14
use itertools::Either;
15
use safelog::Redactable;
16
use safelog::util::write_start_redacted;
17
use serde::{Deserialize, Serialize};
18
use thiserror::Error;
19

            
20
use crate::HasAddrs;
21

            
22
/// Identify a type of Transport.
23
///
24
/// If this crate is compiled with the `pt-client` feature, this type can
25
/// support pluggable transports; otherwise, only the built-in transport type is
26
/// supported.
27
///
28
/// This can be displayed as, or parsed from, a string.
29
/// `"-"` is used to indicate the builtin transport,
30
/// and `""` and `"bridge"` and `"<none>"` are also recognised for that.
31
//
32
// We recognise "bridge" as pluggable; "BRIDGE" is rejected as invalid.
33
#[derive(Debug, Clone, Default, Eq, PartialEq, Hash)]
34
pub struct TransportId(Inner);
35

            
36
/// Helper type to implement [`TransportId`].
37
///
38
/// This is a separate type so that TransportId can be opaque.
39
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
40
enum Inner {
41
    /// The built-in transport type.
42
    #[default]
43
    BuiltIn,
44

            
45
    /// A pluggable transport type, specified by its name.
46
    #[cfg(feature = "pt-client")]
47
    Pluggable(PtTransportName),
48
}
49

            
50
/// The name of a Pluggable Transport protocol.
51
///
52
/// The name has been syntax-checked.
53
///
54
/// These names are used to identify the particular transport protocol, such as
55
/// "obfs4" or "snowflake".  They match a name of a protocol that the transport
56
/// binary knows how to provide to the name of a protocol that a bridge is
57
/// configured to use.
58
#[derive(
59
    Debug,
60
    Clone,
61
    Default,
62
    Eq,
63
    PartialEq,
64
    Hash,
65
    serde_with::DeserializeFromStr,
66
    serde_with::SerializeDisplay,
67
)]
68
pub struct PtTransportName(String);
69

            
70
impl FromStr for PtTransportName {
71
    type Err = TransportIdError;
72

            
73
4749
    fn from_str(s: &str) -> Result<Self, Self::Err> {
74
4749
        s.to_string().try_into()
75
4749
    }
76
}
77

            
78
impl TryFrom<String> for PtTransportName {
79
    type Error = TransportIdError;
80

            
81
4749
    fn try_from(s: String) -> Result<PtTransportName, Self::Error> {
82
4749
        if is_well_formed_id(&s) {
83
4617
            Ok(PtTransportName(s))
84
        } else {
85
132
            Err(TransportIdError::BadId(s))
86
        }
87
4749
    }
88
}
89

            
90
impl Display for PtTransportName {
91
1201
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92
1201
        Display::fmt(&self.0, f)
93
1201
    }
94
}
95

            
96
impl AsRef<str> for PtTransportName {
97
    fn as_ref(&self) -> &str {
98
        &self.0
99
    }
100
}
101

            
102
/// These identifiers are used to indicate the built-in transport.
103
///
104
/// When outputting string representations, the first (`"-"`) is used.
105
//
106
// Actual pluggable transport names are restricted to the syntax of C identifiers.
107
// These strings are deliberately not in that syntax so as to avoid clashes.
108
// `"bridge"` is likewise prohibited by the spec.
109
const BUILT_IN_IDS: &[&str] = &["-", "", "bridge", "<none>"];
110

            
111
impl FromStr for TransportId {
112
    type Err = TransportIdError;
113

            
114
3682
    fn from_str(s: &str) -> Result<Self, Self::Err> {
115
3682
        if BUILT_IN_IDS.contains(&s) {
116
2217
            return Ok(TransportId(Inner::BuiltIn));
117
1465
        };
118

            
119
        #[cfg(feature = "pt-client")]
120
        {
121
1465
            let name: PtTransportName = s.parse()?;
122
1459
            Ok(TransportId(Inner::Pluggable(name)))
123
        }
124

            
125
        #[cfg(not(feature = "pt-client"))]
126
        Err(TransportIdError::NoSupport)
127
3682
    }
128
}
129

            
130
impl Display for TransportId {
131
6
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132
6
        match &self.0 {
133
4
            Inner::BuiltIn => write!(f, "{}", BUILT_IN_IDS[0]),
134
            #[cfg(feature = "pt-client")]
135
2
            Inner::Pluggable(name) => write!(f, "{}", name),
136
        }
137
6
    }
138
}
139

            
140
#[cfg(feature = "pt-client")]
141
impl From<PtTransportName> for TransportId {
142
6
    fn from(name: PtTransportName) -> Self {
143
6
        TransportId(Inner::Pluggable(name))
144
6
    }
145
}
146

            
147
/// Return true if `s` is a well-formed transport ID.
148
///
149
/// According to the specification, a well-formed transport ID follows the same
150
/// rules as a C99 identifier: It must follow the regular expression
151
/// `[a-zA-Z_][a-zA-Z0-9_]*`.
152
4767
fn is_well_formed_id(s: &str) -> bool {
153
    // It's okay to use a bytes iterator, since non-ascii strings are not
154
    // allowed.
155
4767
    let mut bytes = s.bytes();
156

            
157
4767
    if let Some(first) = bytes.next() {
158
4765
        (first.is_ascii_alphabetic() || first == b'_')
159
21673
            && bytes.all(|b| b.is_ascii_alphanumeric() || b == b'_')
160
4692
            && !s.eq_ignore_ascii_case("bridge")
161
    } else {
162
2
        false
163
    }
164
4767
}
165

            
166
/// An error related to parsing a TransportId.
167
#[derive(Clone, Debug, thiserror::Error)]
168
#[non_exhaustive]
169
pub enum TransportIdError {
170
    /// Arti was compiled without client-side pluggable transport support, and
171
    /// we tried to use a pluggable transport.
172
    #[error("Not compiled with pluggable transport support")]
173
    NoSupport,
174

            
175
    /// Tried to parse a pluggable transport whose name was not well-formed.
176
    #[error("{0:?} is not a valid pluggable transport ID")]
177
    BadId(String),
178
}
179

            
180
impl TransportId {
181
    /// Return a new `TransportId` referencing the builtin transport
182
    ///
183
    /// This is equivalent to the `Default` impl.
184
    pub fn new_builtin() -> Self {
185
        TransportId(Inner::BuiltIn)
186
    }
187

            
188
    /// Return a new `TransportId` referencing a pluggable transport
189
    ///
190
    /// This is equivalent to the `From<PtTransportName>` impl.
191
    #[cfg(feature = "pt-client")]
192
    pub fn new_pluggable(pt: PtTransportName) -> Self {
193
        pt.into()
194
    }
195

            
196
    /// Return true if this is the built-in transport.
197
2778
    pub fn is_builtin(&self) -> bool {
198
2778
        self.0 == Inner::BuiltIn
199
2778
    }
200

            
201
    /// Returns the pluggable transport name
202
    ///
203
    /// Or `None` if `self` doesn't specify a pluggable transport
204
    /// (e.g. if it specifies the builtin transport).
205
    #[cfg(feature = "pt-client")]
206
1071
    pub fn as_pluggable(&self) -> Option<&PtTransportName> {
207
1071
        match &self.0 {
208
            Inner::BuiltIn => None,
209
            #[cfg(feature = "pt-client")]
210
1071
            Inner::Pluggable(pt) => Some(pt),
211
        }
212
1071
    }
213

            
214
    /// Consumes this `TransportId` and returns the pluggable transport name
215
    ///
216
    /// Or `None` if `self` doesn't specify a pluggable transport
217
    /// (e.g. if it specifies the builtin transport).
218
    #[cfg(feature = "pt-client")]
219
1953
    pub fn into_pluggable(self) -> Option<PtTransportName> {
220
1953
        match self.0 {
221
504
            Inner::BuiltIn => None,
222
            #[cfg(feature = "pt-client")]
223
1449
            Inner::Pluggable(pt) => Some(pt),
224
        }
225
1953
    }
226
}
227

            
228
/// This identifier is used to indicate no transport address.
229
const NONE_ADDR: &str = "-";
230

            
231
/// An address that an be passed to a pluggable transport to tell it where to
232
/// connect (typically, to a bridge).
233
///
234
/// Not every transport accepts all kinds of addresses.
235
///
236
/// This is semantically very similar to `Option<BridgeAddr>`,
237
/// but it has some of its own conversion methods and bespoke `FromStr` and `Display`.
238
//
239
// Implementations for `PtTargetAddr` are in terms of those for `BridgeAddr`
240
// wheresoever possible, to ensure that they do not diverge in semantics.
241
#[derive(
242
    Clone, Debug, PartialEq, Eq, Hash, serde_with::DeserializeFromStr, serde_with::SerializeDisplay,
243
)]
244
#[non_exhaustive]
245
pub enum PtTargetAddr {
246
    /// An IP address and port for a Tor relay.
247
    ///
248
    /// This is the only address type supported by the BuiltIn transport.
249
    IpPort(SocketAddr),
250
    /// A hostname-and-port target address.  Some transports may support this.
251
    HostPort(String, u16),
252
    /// A completely absent target address.  Some transports support this.
253
    None,
254
}
255

            
256
/// An address of a bridge, for use in configuration.
257
///
258
/// Contains precisely, either:
259
///  * A hostname (as a string), plus a `u16` port; or
260
///  * An (IPv4 or IPv6) socket address including port - i.e., a `SocketAddr`,
261
///    or to put it another way, an IP address (v4 or v6) plus a `u16` port.
262
///
263
/// Hostnames which are not syntactically invalid Internet hostnames,
264
/// and a port value of zero,
265
/// *can* be represented within a `BridgeAddr`.
266
#[derive(
267
    Clone,
268
    Debug,
269
    PartialEq,
270
    Eq,
271
    Hash,
272
    serde_with::DeserializeFromStr,
273
    serde_with::SerializeDisplay,
274
    derive_more::Display,
275
)]
276
pub struct BridgeAddr(BridgeAddrInner<SocketAddr, String>);
277

            
278
/// `BridgeAddr` contents; type parameters allow use with references to avoid some copying
279
///
280
/// `SA` is always `SocketAddr` or `&SocketAddr`.
281
///
282
/// `HN` is always `String` or `&str`.
283
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
284
enum BridgeAddrInner<SA, HN> {
285
    /// An IP address and port for a bridge
286
    IpPort(SA),
287
    /// A hostname-and-port target address
288
    HostPort(HN, u16),
289
}
290

            
291
// These methods have long slightly awkward names because we think
292
// we may want to change their names and types later, and/or deprecate them.
293
// So let's not use up the nice names now.
294
//
295
// TODO: decide on, and implement, a nicer API, or functions with nicer names.
296
// TODO: add From/Into conversions for SocketAddr and maybe (String, u16).
297
// TODO: consider providing constructor/accessor/deconstructor to/from Either.
298
impl BridgeAddr {
299
    /// Create a new `BridgeAddr` referring to a numeric address and port
300
882
    pub fn new_addr_from_sockaddr(sa: SocketAddr) -> Self {
301
882
        BridgeAddr(BridgeAddrInner::IpPort(sa))
302
882
    }
303

            
304
    /// If this is a numeric address, return it as a `SocketAddr`
305
1449
    pub fn as_socketaddr(&self) -> Option<&SocketAddr> {
306
1449
        match &self.0 {
307
1323
            BridgeAddrInner::IpPort(sa) => Some(sa),
308
126
            BridgeAddrInner::HostPort(..) => None,
309
        }
310
1449
    }
311

            
312
    /// Create a new `BridgeAddr` referring to a numeric address and port
313
    pub fn new_named_host_port(hostname: impl Into<String>, port: u16) -> Self {
314
        BridgeAddr(BridgeAddrInner::HostPort(hostname.into(), port))
315
    }
316

            
317
    /// If this is a named host and port, return it as hostname string and port
318
126
    pub fn as_host_port(&self) -> Option<(&str, u16)> {
319
126
        match &self.0 {
320
            BridgeAddrInner::IpPort(..) => None,
321
126
            BridgeAddrInner::HostPort(hn, port) => Some((hn, *port)),
322
        }
323
126
    }
324
}
325

            
326
impl From<PtTargetAddr> for Option<BridgeAddr> {
327
669
    fn from(pt: PtTargetAddr) -> Option<BridgeAddr> {
328
669
        match pt {
329
4
            PtTargetAddr::IpPort(sa) => Some(BridgeAddrInner::IpPort(sa)),
330
665
            PtTargetAddr::HostPort(hn, p) => Some(BridgeAddrInner::HostPort(hn, p)),
331
            PtTargetAddr::None => None,
332
        }
333
669
        .map(BridgeAddr)
334
669
    }
335
}
336
impl From<Option<BridgeAddr>> for PtTargetAddr {
337
2282
    fn from(pt: Option<BridgeAddr>) -> PtTargetAddr {
338
2282
        match pt.map(|ba| ba.0) {
339
199
            Some(BridgeAddrInner::IpPort(sa)) => PtTargetAddr::IpPort(sa),
340
2083
            Some(BridgeAddrInner::HostPort(hn, p)) => PtTargetAddr::HostPort(hn, p),
341
            None => PtTargetAddr::None,
342
        }
343
2282
    }
344
}
345

            
346
/// An error from parsing a [`BridgeAddr`] or [`PtTargetAddr`].
347
#[derive(Clone, Debug, thiserror::Error)]
348
#[non_exhaustive]
349
pub enum BridgeAddrError {
350
    /// We were compiled without support for addresses of this type.
351
    #[error("Not compiled with pluggable transport support.")]
352
    NoSupport,
353
    /// We cannot parse this address.
354
    #[error("Cannot parse {0:?} as an address.")]
355
    BadAddress(String),
356
}
357

            
358
impl FromStr for BridgeAddr {
359
    type Err = BridgeAddrError;
360

            
361
2292
    fn from_str(s: &str) -> Result<Self, Self::Err> {
362
2292
        Ok(BridgeAddr(if let Ok(addr) = s.parse() {
363
703
            BridgeAddrInner::IpPort(addr)
364
1589
        } else if let Some((name, port)) = s.rsplit_once(':') {
365
1516
            let port = port
366
1516
                .parse()
367
1516
                .map_err(|_| BridgeAddrError::BadAddress(s.to_string()))?;
368

            
369
1516
            BridgeAddrInner::HostPort(name.to_string(), port)
370
        } else {
371
73
            return Err(BridgeAddrError::BadAddress(s.to_string()));
372
        }))
373
2292
    }
374
}
375

            
376
impl FromStr for PtTargetAddr {
377
    type Err = BridgeAddrError;
378

            
379
1400
    fn from_str(s: &str) -> Result<Self, Self::Err> {
380
1400
        Ok(if s == NONE_ADDR {
381
2
            PtTargetAddr::None
382
        } else {
383
1398
            Some(BridgeAddr::from_str(s)?).into()
384
        })
385
1400
    }
386
}
387

            
388
impl PtTargetAddr {
389
    /// Obtain an `Option<BridgeAddrInner>` containing references
390
    ///
391
    /// This is a useful helper for display-like implementations,
392
    /// which can then implement for `PtTargetAddr` in terms of the impls for `BridgeAddrInner`.
393
    ///
394
    /// (See the code comment for `PtTargetAddr`.)
395
388
    fn as_bridge_ref(&self) -> Option<BridgeAddrInner<&SocketAddr, &str>> {
396
388
        match self {
397
195
            PtTargetAddr::IpPort(addr) => Some(BridgeAddrInner::IpPort(addr)),
398
191
            PtTargetAddr::HostPort(host, port) => Some(BridgeAddrInner::HostPort(host, *port)),
399
2
            PtTargetAddr::None => None,
400
        }
401
388
    }
402
}
403

            
404
impl<SA: Display, HN: Display> Display for BridgeAddrInner<SA, HN> {
405
959
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406
959
        match self {
407
514
            BridgeAddrInner::IpPort(addr) => write!(f, "{}", addr),
408
445
            BridgeAddrInner::HostPort(host, port) => write!(f, "{}:{}", host, port),
409
        }
410
959
    }
411
}
412

            
413
// impl Display for BridgeAddr is done with derive_more, on the struct definition.
414

            
415
impl Display for PtTargetAddr {
416
388
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
417
388
        match self.as_bridge_ref() {
418
386
            Some(b) => write!(f, "{}", b),
419
2
            None => write!(f, "{}", NONE_ADDR),
420
        }
421
388
    }
422
}
423

            
424
impl<SA: Debug + Redactable, HN: Debug + Display + AsRef<str>> Redactable
425
    for BridgeAddrInner<SA, HN>
426
{
427
    fn display_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
428
        match self {
429
            BridgeAddrInner::IpPort(a) => a.display_redacted(f),
430
            BridgeAddrInner::HostPort(host, port) => {
431
                write_start_redacted(f, host.as_ref(), 2, "…")?;
432
                write!(f, ":{port}")
433
            }
434
        }
435
    }
436
}
437

            
438
impl Redactable for BridgeAddr {
439
    fn display_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
440
        self.0.display_redacted(f)
441
    }
442
}
443

            
444
impl Redactable for PtTargetAddr {
445
    fn display_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
446
        match self.as_bridge_ref() {
447
            Some(b) => b.display_redacted(f),
448
            None => write!(f, "{}", NONE_ADDR),
449
        }
450
    }
451
}
452

            
453
/// A set of options to be passed along to a pluggable transport along with a
454
/// single target bridge relay.
455
///
456
/// These options typically describe aspects of the targeted bridge relay that
457
/// are not included in its address and Tor keys, such as additional
458
/// transport-specific keys or parameters.
459
///
460
/// This type is _not_ for settings that apply to _all_ of the connections over
461
/// a transport.
462
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Serialize, Deserialize)]
463
#[serde(into = "Vec<(String, String)>", try_from = "Vec<(String, String)>")]
464
pub struct PtTargetSettings {
465
    /// A list of (key,value) pairs
466
    settings: Vec<(String, String)>,
467
}
468

            
469
impl PtTargetSettings {
470
    /// Return an error if `k,v` is not a valid setting.
471
2591
    fn check_setting(k: &str, v: &str) -> Result<(), PtTargetInvalidSetting> {
472
        // Unfortunately the spec is not very clear about the valid syntax.
473
        // https://gitlab.torproject.org/tpo/core/torspec/-/issues/173
474
        //
475
        // For now we reject things that cannot be represented in a bridge line
476
19408
        if k.find(|c: char| c == '=' || c.is_whitespace()).is_some() {
477
2
            return Err(PtTargetInvalidSetting::Key(k.to_string()));
478
2589
        }
479
16251
        if v.find(|c: char| c.is_whitespace()).is_some() {
480
2
            return Err(PtTargetInvalidSetting::Value(v.to_string()));
481
2587
        }
482
2587
        Ok(())
483
2591
    }
484

            
485
    /// Add `k,v` to this list of settings, if it is valid.
486
1071
    fn push_setting(
487
1071
        &mut self,
488
1071
        k: impl Into<String>,
489
1071
        v: impl Into<String>,
490
1071
    ) -> Result<(), PtTargetInvalidSetting> {
491
1071
        let k = k.into();
492
1071
        let v = v.into();
493
1071
        Self::check_setting(&k, &v)?;
494
1071
        self.settings.push((k, v));
495
1071
        Ok(())
496
1071
    }
497

            
498
    /// Return the inner list of (key, value) pairs
499
819
    pub fn into_inner(self) -> Vec<(String, String)> {
500
819
        self.settings
501
819
    }
502
}
503

            
504
impl TryFrom<Vec<(String, String)>> for PtTargetSettings {
505
    type Error = PtTargetInvalidSetting;
506

            
507
8
    fn try_from(settings: Vec<(String, String)>) -> Result<Self, Self::Error> {
508
8
        for (k, v) in settings.iter() {
509
8
            Self::check_setting(k, v)?;
510
        }
511
4
        Ok(Self { settings })
512
8
    }
513
}
514

            
515
impl From<PtTargetSettings> for Vec<(String, String)> {
516
4
    fn from(settings: PtTargetSettings) -> Self {
517
4
        settings.settings
518
4
    }
519
}
520

            
521
/// The set of information passed to the  pluggable transport subsystem in order
522
/// to establish a connection to a bridge relay.
523
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
524
pub struct PtTarget {
525
    /// The transport to be used.
526
    transport: PtTransportName,
527
    /// The address of the bridge relay, if any.
528
    addr: PtTargetAddr,
529
    /// Any additional settings used by the transport.
530
    #[serde(default)]
531
    settings: PtTargetSettings,
532
}
533

            
534
/// Invalid PT parameter setting
535
#[derive(Error, Clone, Debug, Eq, PartialEq)]
536
#[non_exhaustive]
537
pub enum PtTargetInvalidSetting {
538
    /// Currently: the key contains whitespace or `=`
539
    ///
540
    /// Will probably be generated for a greater variety of values
541
    /// when the spec is more nailed down.
542
    #[error("key {0:?} has invalid or unsupported syntax")]
543
    Key(String),
544

            
545
    /// Currently: the value contains whitespace
546
    ///
547
    /// Will probably be generated for a greater variety of values
548
    /// when the spec is more nailed down.
549
    #[error("value {0:?} has invalid or unsupported syntax")]
550
    Value(String),
551
}
552

            
553
impl PtTarget {
554
    /// Create a new `PtTarget` (with no settings)
555
2402
    pub fn new(transport: PtTransportName, addr: PtTargetAddr) -> Self {
556
2402
        PtTarget {
557
2402
            transport,
558
2402
            addr,
559
2402
            settings: Default::default(),
560
2402
        }
561
2402
    }
562

            
563
    /// Add a setting (to be passed during the SOCKS handshake)
564
1071
    pub fn push_setting(
565
1071
        &mut self,
566
1071
        k: impl Into<String>,
567
1071
        v: impl Into<String>,
568
1071
    ) -> Result<(), PtTargetInvalidSetting> {
569
1071
        self.settings.push_setting(k, v)
570
1071
    }
571

            
572
    /// Get the transport name
573
386
    pub fn transport(&self) -> &PtTransportName {
574
386
        &self.transport
575
386
    }
576

            
577
    /// Get the transport target address (or host and port)
578
380
    pub fn addr(&self) -> &PtTargetAddr {
579
380
        &self.addr
580
380
    }
581

            
582
    /// Iterate over the PT setting strings
583
378
    pub fn settings(&self) -> impl Iterator<Item = (&str, &str)> {
584
390
        self.settings.settings.iter().map(|(k, v)| (&**k, &**v))
585
378
    }
586

            
587
    /// Return all the advertized socket addresses to which this target may
588
    /// connect.
589
    ///
590
    /// Returns `Some(&[])` if there is no way to connect to this target, and
591
    /// `None` if this target does not use `SocketAddr` to connect
592
    ///
593
    /// NOTE that these are not necessarily an address to which you can open a
594
    /// TCP connection! The address will be interpreted by the implementation of
595
    /// this pluggable transport.
596
6
    pub fn socket_addrs(&self) -> Option<&[std::net::SocketAddr]> {
597
6
        match self {
598
            PtTarget {
599
2
                addr: PtTargetAddr::IpPort(addr),
600
                ..
601
2
            } => Some(std::slice::from_ref(addr)),
602

            
603
4
            _ => None,
604
        }
605
6
    }
606

            
607
    /// Consume the `PtTarget` and return the component parts
608
819
    pub fn into_parts(self) -> (PtTransportName, PtTargetAddr, PtTargetSettings) {
609
819
        (self.transport, self.addr, self.settings)
610
819
    }
611
}
612

            
613
impl Display for PtTarget {
614
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
615
        write!(
616
            f,
617
            "{} @ {} with {:?}",
618
            self.transport, self.addr, self.settings
619
        )
620
    }
621
}
622

            
623
/// The way to approach a single relay in order to open a channel.
624
///
625
/// For direct connections, this is simply an address.  For connections via a
626
/// pluggable transport, this includes information about the transport, and any
627
/// address and settings information that transport requires.
628
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
629
#[non_exhaustive]
630
pub enum ChannelMethod {
631
    /// Connect to the relay directly at one of several addresses.
632
    Direct(Vec<std::net::SocketAddr>),
633

            
634
    /// Connect to a bridge relay via a pluggable transport.
635
    #[cfg(feature = "pt-client")]
636
    Pluggable(PtTarget),
637
}
638

            
639
impl ChannelMethod {
640
    /// Return all the advertized socket addresses to which this method may connect.
641
    ///
642
    /// Returns `Some(&[])` if there is no way to connect to this target, and
643
    /// `None` if this target does not use `SocketAddr` to connect
644
    ///
645
    /// NOTE that these are not necessarily an address to which you can open a
646
    /// TCP connection! If this `ChannelMethod` is using a non-`Direct`
647
    /// transport, then this address will be interpreted by that transport's
648
    /// implementation.
649
7820
    pub fn socket_addrs(&self) -> Option<&[std::net::SocketAddr]> {
650
7820
        match self {
651
7814
            ChannelMethod::Direct(addr) => Some(addr.as_ref()),
652

            
653
            #[cfg(feature = "pt-client")]
654
6
            ChannelMethod::Pluggable(t) => t.socket_addrs(),
655
        }
656
7820
    }
657

            
658
    /// Return a BridgeAddr that this ChannelMethod uses.
659
    //
660
    // TODO this is kind of weird, what does Some(PtTargetAddr::None) mean?
661
8
    pub fn target_addr(&self) -> Option<PtTargetAddr> {
662
2
        match self {
663
2
            ChannelMethod::Direct(addr) if !addr.is_empty() => Some(PtTargetAddr::IpPort(addr[0])),
664

            
665
            #[cfg(feature = "pt-client")]
666
6
            ChannelMethod::Pluggable(PtTarget { addr, .. }) => Some(addr.clone()),
667

            
668
            _ => None,
669
        }
670
8
    }
671

            
672
    /// Return the [`SocketAddr`] if this method is [`ChannelMethod::Direct`] and there is one and
673
    /// only one available address.
674
    ///
675
    /// This is single address requirement is very important as this call is used during the
676
    /// channel handshake on which we need the actual peer address we are connected to and not all
677
    /// the possibilities.
678
    ///
679
    /// When connecting or accepting, that address is put in the OwnedChanTarget and so this
680
    /// extracts it.
681
    pub fn unique_direct_addr(&self) -> Option<SocketAddr> {
682
        match self {
683
            Self::Direct(addrs) => match addrs.as_slice() {
684
                [addr] => Some(*addr),
685
                // Remember, more than one, we don't have a single address.
686
                _ => None,
687
            },
688
            #[cfg(feature = "pt-client")]
689
            Self::Pluggable(_) => None,
690
        }
691
    }
692

            
693
    /// Return true if this is a method for a direct connection.
694
71
    pub fn is_direct(&self) -> bool {
695
71
        matches!(self, ChannelMethod::Direct(_))
696
71
    }
697

            
698
    /// Return an identifier for the Transport to be used by this `ChannelMethod`.
699
8
    pub fn transport_id(&self) -> TransportId {
700
8
        match self {
701
2
            ChannelMethod::Direct(_) => TransportId::default(),
702
            #[cfg(feature = "pt-client")]
703
6
            ChannelMethod::Pluggable(target) => target.transport().clone().into(),
704
        }
705
8
    }
706

            
707
    ///
708
    /// Change this `ChannelMethod` by removing every socket address that
709
    /// does not satisfy `pred`.
710
    ///
711
    /// `Hostname` and `None` addresses are never removed.
712
    ///
713
    /// Return an error if we have removed every address.
714
75
    pub fn retain_addrs<P>(&mut self, pred: P) -> Result<(), RetainAddrsError>
715
75
    where
716
75
        P: Fn(&std::net::SocketAddr) -> bool,
717
    {
718
        #[cfg(feature = "pt-client")]
719
        use PtTargetAddr as Pt;
720

            
721
67
        match self {
722
67
            ChannelMethod::Direct(d) if d.is_empty() => {}
723
67
            ChannelMethod::Direct(d) => {
724
67
                d.retain(pred);
725
67
                if d.is_empty() {
726
2
                    return Err(RetainAddrsError::NoAddrsLeft);
727
65
                }
728
            }
729
            #[cfg(feature = "pt-client")]
730
8
            ChannelMethod::Pluggable(PtTarget { addr, .. }) => match addr {
731
4
                Pt::IpPort(a) => {
732
4
                    if !pred(a) {
733
2
                        *addr = Pt::None;
734
2
                        return Err(RetainAddrsError::NoAddrsLeft);
735
2
                    }
736
                }
737
2
                Pt::HostPort(_, _) => {}
738
2
                Pt::None => {}
739
            },
740
        }
741
71
        Ok(())
742
75
    }
743

            
744
    /// Return true if every method to contact `self` is also a method to
745
    /// contact `other`.
746
12
    pub fn contained_by(&self, other: &ChannelMethod) -> bool {
747
        use ChannelMethod as CM;
748
12
        match (self, other) {
749
6
            (CM::Direct(our_addrs), CM::Direct(their_addrs)) => {
750
17
                our_addrs.iter().all(|a| their_addrs.contains(a))
751
            }
752
            #[cfg(feature = "pt-client")]
753
6
            (CM::Pluggable(our_target), CM::Pluggable(their_target)) => our_target == their_target,
754
            #[cfg(feature = "pt-client")]
755
            (_, _) => false,
756
        }
757
12
    }
758
}
759

            
760
/// An error that occurred while filtering addresses from a ChanMethod.
761
#[derive(Clone, Debug, thiserror::Error)]
762
pub enum RetainAddrsError {
763
    /// We removed all of the addresses from this method.
764
    #[error("All addresses were removed.")]
765
    NoAddrsLeft,
766
}
767

            
768
impl HasAddrs for PtTargetAddr {
769
8
    fn addrs(&self) -> impl Iterator<Item = SocketAddr> {
770
8
        match self {
771
4
            PtTargetAddr::IpPort(sockaddr) => slice::from_ref(sockaddr),
772
4
            PtTargetAddr::HostPort(..) | PtTargetAddr::None => &[],
773
        }
774
8
        .iter()
775
8
        .copied()
776
8
    }
777
}
778

            
779
impl HasAddrs for ChannelMethod {
780
2772
    fn addrs(&self) -> impl Iterator<Item = SocketAddr> {
781
2772
        let r = match self {
782
2772
            ChannelMethod::Direct(addrs) => Either::Left(addrs.iter().copied()),
783
            #[cfg(feature = "pt-client")]
784
            ChannelMethod::Pluggable(pt) => Either::Right(pt.addr.addrs()),
785
        };
786

            
787
        // Unfortunately, when pt-client is configured out, the compiler can't infer
788
        // the type for Either::Right.  Ideally we'd use Void rather than iter::Empty
789
        // but Void doesn't implement Iterator.
790
        #[cfg(not(feature = "pt-client"))]
791
        let _: &Either<_, std::iter::Empty<_>> = &r;
792

            
793
2772
        r
794
2772
    }
795
}
796

            
797
#[cfg(test)]
798
mod test {
799
    // @@ begin test lint list maintained by maint/add_warning @@
800
    #![allow(clippy::bool_assert_comparison)]
801
    #![allow(clippy::clone_on_copy)]
802
    #![allow(clippy::dbg_macro)]
803
    #![allow(clippy::mixed_attributes_style)]
804
    #![allow(clippy::print_stderr)]
805
    #![allow(clippy::print_stdout)]
806
    #![allow(clippy::single_char_pattern)]
807
    #![allow(clippy::unwrap_used)]
808
    #![allow(clippy::unchecked_time_subtraction)]
809
    #![allow(clippy::useless_vec)]
810
    #![allow(clippy::needless_pass_by_value)]
811
    #![allow(clippy::string_slice)] // See arti#2571
812
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
813
    use super::*;
814
    use itertools::Itertools;
815

            
816
    #[test]
817
    fn builtin() {
818
        assert!(TransportId::default().is_builtin());
819
        assert_eq!(
820
            TransportId::default(),
821
            "<none>".parse().expect("Couldn't parse default ID")
822
        );
823
    }
824

            
825
    #[test]
826
    #[cfg(not(feature = "pt-client"))]
827
    fn nosupport() {
828
        // We should get this error whenever we parse a non-default PT and we have no PT support.
829
        assert!(matches!(
830
            TransportId::from_str("obfs4"),
831
            Err(TransportIdError::NoSupport)
832
        ));
833
    }
834

            
835
    #[test]
836
    #[cfg(feature = "pt-client")]
837
    fn wellformed() {
838
        for id in &["snowflake", "obfs4", "_ohai", "Z", "future_WORK2"] {
839
            assert!(is_well_formed_id(id));
840
        }
841

            
842
        for id in &[" ", "Mölm", "12345", ""] {
843
            assert!(!is_well_formed_id(id));
844
        }
845
    }
846

            
847
    #[test]
848
    #[cfg(feature = "pt-client")]
849
    fn parsing() {
850
        let obfs = TransportId::from_str("obfs4").unwrap();
851
        let dflt = TransportId::default();
852
        let dflt2 = TransportId::from_str("<none>").unwrap();
853
        let dflt3 = TransportId::from_str("-").unwrap();
854
        let dflt4 = TransportId::from_str("").unwrap();
855
        let dflt5 = TransportId::from_str("bridge").unwrap();
856
        let snow = TransportId::from_str("snowflake").unwrap();
857
        let obfs_again = TransportId::from_str("obfs4").unwrap();
858

            
859
        assert_eq!(obfs, obfs_again);
860
        assert_eq!(dflt, dflt2);
861
        assert_eq!(dflt, dflt3);
862
        assert_eq!(dflt, dflt4);
863
        assert_eq!(dflt, dflt5);
864
        assert_ne!(snow, obfs);
865
        assert_ne!(snow, dflt);
866

            
867
        assert_eq!(dflt.to_string(), "-");
868

            
869
        assert!(matches!(
870
            TransportId::from_str("12345"),
871
            Err(TransportIdError::BadId(_))
872
        ));
873
        assert!(matches!(
874
            TransportId::from_str("Bridge"),
875
            Err(TransportIdError::BadId(_))
876
        ));
877
    }
878

            
879
    #[test]
880
    fn addr() {
881
        let chk_bridge_addr = |a: &PtTargetAddr, addr: &str| {
882
            let ba: BridgeAddr = addr.parse().unwrap();
883
            assert_eq!(&ba.to_string(), addr);
884

            
885
            assert_eq!(&PtTargetAddr::from(Some(ba.clone())), a);
886
            let reba: Option<BridgeAddr> = a.clone().into();
887
            assert_eq!(reba.as_ref(), Some(&ba));
888
        };
889

            
890
        for addr in &["1.2.3.4:555", "[::1]:9999"] {
891
            let a: PtTargetAddr = addr.parse().unwrap();
892
            assert_eq!(&a.to_string(), addr);
893

            
894
            let sa: SocketAddr = addr.parse().unwrap();
895
            assert_eq!(a.addrs().collect_vec(), &[sa]);
896

            
897
            chk_bridge_addr(&a, addr);
898
        }
899

            
900
        for addr in &["www.example.com:9100", "-"] {
901
            let a: PtTargetAddr = addr.parse().unwrap();
902
            assert_eq!(&a.to_string(), addr);
903
            assert_eq!(a.addrs().collect_vec(), &[]);
904

            
905
            if a == PtTargetAddr::None {
906
                let e = BridgeAddr::from_str(addr).unwrap_err();
907
                assert!(matches!(e, BridgeAddrError::BadAddress(_)));
908
            } else {
909
                chk_bridge_addr(&a, addr);
910
            }
911
        }
912

            
913
        for addr in &["foobar", "<<<>>>"] {
914
            let e = PtTargetAddr::from_str(addr).unwrap_err();
915
            assert!(matches!(e, BridgeAddrError::BadAddress(_)));
916

            
917
            let e = BridgeAddr::from_str(addr).unwrap_err();
918
            assert!(matches!(e, BridgeAddrError::BadAddress(_)));
919
        }
920
    }
921

            
922
    #[test]
923
    fn transport_id() {
924
        let id1: TransportId = "<none>".parse().unwrap();
925
        assert!(id1.is_builtin());
926
        assert_eq!(id1.to_string(), "-".to_string());
927

            
928
        #[cfg(feature = "pt-client")]
929
        {
930
            let id2: TransportId = "obfs4".parse().unwrap();
931
            assert_ne!(id2, id1);
932
            assert!(!id2.is_builtin());
933
            assert_eq!(id2.to_string(), "obfs4");
934

            
935
            assert!(matches!(
936
                TransportId::from_str("==="),
937
                Err(TransportIdError::BadId(_))
938
            ));
939
        }
940

            
941
        #[cfg(not(feature = "pt-client"))]
942
        {
943
            assert!(matches!(
944
                TransportId::from_str("obfs4"),
945
                Err(TransportIdError::NoSupport)
946
            ));
947
        }
948
    }
949

            
950
    #[test]
951
    fn settings() {
952
        let s = PtTargetSettings::try_from(vec![]).unwrap();
953
        assert_eq!(Vec::<_>::from(s), vec![]);
954

            
955
        let v = vec![("abc".into(), "def".into()), ("ghi".into(), "jkl".into())];
956
        let s = PtTargetSettings::try_from(v.clone()).unwrap();
957
        assert_eq!(Vec::<_>::from(s), v);
958

            
959
        let v = vec![("a=b".into(), "def".into())];
960
        let s = PtTargetSettings::try_from(v);
961
        assert!(matches!(s, Err(PtTargetInvalidSetting::Key(_))));
962

            
963
        let v = vec![("abc".into(), "d ef".into())];
964
        let s = PtTargetSettings::try_from(v);
965
        assert!(matches!(s, Err(PtTargetInvalidSetting::Value(_))));
966
    }
967

            
968
    #[test]
969
    fn chanmethod_direct() {
970
        let a1 = "127.0.0.1:8080".parse().unwrap();
971
        let a2 = "127.0.0.2:8181".parse().unwrap();
972
        let a3 = "127.0.0.3:8282".parse().unwrap();
973

            
974
        let m = ChannelMethod::Direct(vec![a1, a2]);
975
        assert_eq!(m.socket_addrs(), Some(&[a1, a2][..]));
976
        assert_eq!((m.target_addr()), Some(PtTargetAddr::IpPort(a1)));
977
        assert!(m.is_direct());
978
        assert_eq!(m.transport_id(), TransportId::default());
979

            
980
        let m2 = ChannelMethod::Direct(vec![a1, a2, a3]);
981
        assert!(m.contained_by(&m));
982
        assert!(m.contained_by(&m2));
983
        assert!(!m2.contained_by(&m));
984

            
985
        let mut m3 = m2.clone();
986
        m3.retain_addrs(|a| a.port() != 8282).unwrap();
987
        assert_eq!(m3, m);
988
        assert_ne!(m3, m2);
989
    }
990

            
991
    #[test]
992
    #[cfg(feature = "pt-client")]
993
    fn chanmethod_pt() {
994
        use itertools::Itertools;
995

            
996
        let transport = "giraffe".parse().unwrap();
997
        let addr1 = PtTargetAddr::HostPort("pt.example.com".into(), 1234);
998
        let target1 = PtTarget::new("giraffe".parse().unwrap(), addr1.clone());
999
        let m1 = ChannelMethod::Pluggable(target1);
        let addr2 = PtTargetAddr::IpPort("127.0.0.1:567".parse().unwrap());
        let target2 = PtTarget::new("giraffe".parse().unwrap(), addr2.clone());
        let m2 = ChannelMethod::Pluggable(target2);
        let addr3 = PtTargetAddr::None;
        let target3 = PtTarget::new("giraffe".parse().unwrap(), addr3.clone());
        let m3 = ChannelMethod::Pluggable(target3);
        assert_eq!(m1.socket_addrs(), None);
        assert_eq!(
            m2.socket_addrs(),
            Some(&["127.0.0.1:567".parse().unwrap()][..])
        );
        assert_eq!(m3.socket_addrs(), None);
        assert_eq!(m1.target_addr(), Some(addr1));
        assert_eq!(m2.target_addr(), Some(addr2));
        assert_eq!(m3.target_addr(), Some(addr3));
        assert!(!m1.is_direct());
        assert!(!m2.is_direct());
        assert!(!m3.is_direct());
        assert_eq!(m1.transport_id(), transport);
        assert_eq!(m2.transport_id(), transport);
        assert_eq!(m3.transport_id(), transport);
        for v in [&m1, &m2, &m3].iter().combinations(2) {
            let first = v[0];
            let second = v[1];
            assert_eq!(first.contained_by(second), first == second);
        }
        let mut m1new = m1.clone();
        let mut m2new = m2.clone();
        let mut m3new = m3.clone();
        // this will retain the IpPort target, and ignore the other targets.
        m1new.retain_addrs(|a| a.port() == 567).unwrap();
        m2new.retain_addrs(|a| a.port() == 567).unwrap();
        m3new.retain_addrs(|a| a.port() == 567).unwrap();
        assert_eq!(m1new, m1);
        assert_eq!(m2new, m2);
        assert_eq!(m3new, m3);
        // But if we try to remove the ipport target, we get an error.
        assert!(matches!(
            m2new.retain_addrs(|a| a.port() == 999),
            Err(RetainAddrsError::NoAddrsLeft)
        ));
    }
}