1
//! Wrappers for using a CircTarget with a verbatim list of
2
//! [link specifiers](EncodedLinkSpec).
3

            
4
use crate::{ChanTarget, CircTarget, EncodedLinkSpec, HasAddrs, HasChanMethod, HasRelayIds};
5

            
6
/// A wrapper around an underlying [`CircTarget`] that provides a user-specified
7
/// list of [link specifiers](EncodedLinkSpec).
8
///
9
/// Onion services and their clients use this type of target when telling a
10
/// relay to extend a circuit to a target relay (an introduction point or
11
/// rendezvous point) chosen by some other party.
12
#[derive(Clone, Debug)]
13
pub struct VerbatimLinkSpecCircTarget<T> {
14
    /// The underlying CircTarget
15
    target: T,
16
    /// The link specifiers to provide.
17
    linkspecs: Vec<EncodedLinkSpec>,
18
}
19

            
20
impl<T> VerbatimLinkSpecCircTarget<T> {
21
    /// Construct a new `VerbatimLinkSpecCircTarget` to wrap an underlying
22
    /// `CircTarget` object, and provide it with a new set of encoded link
23
    /// specifiers that will be used when telling a relay to extend to this
24
    /// node.
25
    ///
26
    /// Note that nothing here will check that `linkspecs` is sufficient to
27
    /// actually connect to the chosen target, or to any target at all. It is
28
    /// the caller's responsibility to choose a valid set of link specifiers.
29
8
    pub fn new(target: T, linkspecs: Vec<EncodedLinkSpec>) -> Self {
30
8
        Self { target, linkspecs }
31
8
    }
32
}
33

            
34
// Now, the delegation functions.  All of these are simple delegations to
35
// self.target, except for `CircTarget::linkspecs` with returns self.linkspecs.
36

            
37
impl<T: HasRelayIds> HasRelayIds for VerbatimLinkSpecCircTarget<T> {
38
16
    fn identity(&self, key_type: crate::RelayIdType) -> Option<crate::RelayIdRef<'_>> {
39
16
        self.target.identity(key_type)
40
16
    }
41
}
42
impl<T: HasAddrs> HasAddrs for VerbatimLinkSpecCircTarget<T> {
43
8
    fn addrs(&self) -> &[std::net::SocketAddr] {
44
8
        self.target.addrs()
45
8
    }
46
}
47
impl<T: HasChanMethod> HasChanMethod for VerbatimLinkSpecCircTarget<T> {
48
6
    fn chan_method(&self) -> crate::ChannelMethod {
49
6
        self.target.chan_method()
50
6
    }
51
}
52
impl<T: ChanTarget> ChanTarget for VerbatimLinkSpecCircTarget<T> {}
53
impl<T: CircTarget> CircTarget for VerbatimLinkSpecCircTarget<T> {
54
2
    fn linkspecs(&self) -> tor_bytes::EncodeResult<Vec<EncodedLinkSpec>> {
55
2
        Ok(self.linkspecs.clone())
56
2
    }
57

            
58
8
    fn ntor_onion_key(&self) -> &tor_llcrypto::pk::curve25519::PublicKey {
59
8
        self.target.ntor_onion_key()
60
8
    }
61

            
62
8
    fn protovers(&self) -> &tor_protover::Protocols {
63
8
        self.target.protovers()
64
8
    }
65
}
66

            
67
#[cfg(test)]
68
mod test {
69
    // @@ begin test lint list maintained by maint/add_warning @@
70
    #![allow(clippy::bool_assert_comparison)]
71
    #![allow(clippy::clone_on_copy)]
72
    #![allow(clippy::dbg_macro)]
73
    #![allow(clippy::mixed_attributes_style)]
74
    #![allow(clippy::print_stderr)]
75
    #![allow(clippy::print_stdout)]
76
    #![allow(clippy::single_char_pattern)]
77
    #![allow(clippy::unwrap_used)]
78
    #![allow(clippy::unchecked_duration_subtraction)]
79
    #![allow(clippy::useless_vec)]
80
    #![allow(clippy::needless_pass_by_value)]
81
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
82

            
83
    use crate::OwnedCircTarget;
84

            
85
    use super::*;
86
    #[test]
87
    fn verbatim_linkspecs() {
88
        let mut builder = OwnedCircTarget::builder();
89
        builder
90
            .chan_target()
91
            .addrs(vec!["127.0.0.1:11".parse().unwrap()])
92
            .ed_identity([42; 32].into())
93
            .rsa_identity([45; 20].into());
94
        let inner = builder
95
            .ntor_onion_key([99; 32].into())
96
            .protocols("FlowCtrl=7".parse().unwrap())
97
            .build()
98
            .unwrap();
99
        let weird_linkspecs = vec![EncodedLinkSpec::new(
100
            77.into(),
101
            b"mysterious whisper".to_vec(),
102
        )];
103
        let wrapped = VerbatimLinkSpecCircTarget::new(inner.clone(), weird_linkspecs.clone());
104

            
105
        assert_eq!(wrapped.addrs(), inner.addrs());
106
        assert!(wrapped.same_relay_ids(&inner));
107
        assert_eq!(wrapped.ntor_onion_key(), inner.ntor_onion_key());
108
        assert_eq!(wrapped.protovers(), inner.protovers());
109

            
110
        assert_ne!(inner.linkspecs().unwrap(), weird_linkspecs);
111
        assert_eq!(wrapped.linkspecs().unwrap(), weird_linkspecs);
112
    }
113
}