Skip to main content

tor_protover/
named.rs

1//! Define protocol versions by name.
2//!
3//! Protocol versions obsolete at the time of this writing (Mar 2025)
4//! are not included.
5//!
6//! For more details about specific versions,
7//! see the [relevant section of the spec][spec].
8//!
9//! [spec]: https://spec.torproject.org/tor-spec/subprotocol-versioning.html
10
11use super::{NamedSubver, ProtoKind};
12use paste::paste;
13
14/// Helper: define a set of named aliases for specific subprotocol versions
15macro_rules! def_named {
16    { $( $protocol:ident {
17        $(
18            $(#[$meta:meta])*
19            $subver:ident = $num:expr;
20        )*
21      })*
22    } => {paste!{
23        $($(
24            $(#[$meta])*
25            pub const [<$protocol:upper _ $subver>] : NamedSubver = NamedSubver::new(ProtoKind::$protocol, $num);
26        )*)*
27    }}
28}
29
30def_named! {
31
32    Link {
33        /// Obsolete version 1 link protocol.
34        ///
35        /// This protocol used RSA-based TLS certificate chains with specific properties.
36        V1 = 1;
37        /// Obsolete version 2 link protocol.
38        ///
39        /// This protocol used TLS renegotiation.
40        V2 = 2;
41        /// Version 3 link protocol.
42        ///
43        /// This protocol uses a single server certificate in TLS,
44        /// and then exchanges additional certificates and authentication
45        /// within the protocol.
46        V3 = 3;
47        /// Version 4 link protocol.
48        ///
49        /// This protocol extends the version 3 link protocol
50        /// by changing the length of Circuit IDs from 2 bytes to 4 bytes.
51        V4 = 4;
52        /// Version 5 link protocol.
53        ///
54        /// This protocol extends the version 4 link protocol
55        /// by adding support for link padding.
56        V5 = 5;
57    }
58
59    LinkAuth {
60        /// TLS authentication based on signing key-exported material with an Ed25519 key.
61        ///
62        /// ([Specification](https://spec.torproject.org/tor-spec/negotiating-channels.html#Ed25519-SHA256-RFC5705))
63        ED25519_SHA256_EXPORTER = 3;
64    }
65
66    Relay {
67        /// Support for ntor key exchange, CREATE2, CREATED2, EXTEND2, EXTENDED2.
68        NTOR = 2;
69
70        /// Support for extending over IPv6 properly using EXTEND2 messages.
71        EXTEND_IPv6 = 3;
72
73        /// Support for ntor v3 key exchange, including "extra data" in circuit handshakes
74        /// in the format described in
75        /// [the "ntor-v3" handshake](https://spec.torproject.org/tor-spec/create-created-cells.md#ntor-v3).
76        NTORV3 = 4;
77
78        /// Support for the ntorv3 [protocol request extension][prop346].
79        ///
80        /// (Reserved.)
81        ///
82        /// [prop346]: https://spec.torproject.org/proposals/346-protovers-again.html
83        NEGOTIATE_SUBPROTO = 5;
84
85        /// Support for counter galois onion relay encryption.
86        ///
87        /// (Reserved.)
88        ///
89        /// [prop359]: https://spec.torproject.org/proposals/359-cgo-redux.html
90        CRYPT_CGO = 6;
91    }
92
93    HSIntro {
94        /// Version 3 hidden service introduction point support.
95        V3 = 4;
96
97        /// Support for rate-limiting anti-DOS extensions in the`ESTABLISH_INTRO` message.
98        RATELIM = 5;
99    }
100
101    HSRend {
102        /// Support for RENDEZVOUS2 messages of arbitrary length.
103        V3 = 2;
104    }
105
106    HSDir {
107        /// Support for version 3 hidden service descriptors,
108        /// including blinded keys.
109        V3 = 2;
110    }
111
112    DirCache {
113        /// Support for consensus diffs.
114        CONSDIFF = 2;
115    }
116
117    Desc {
118        /// Support for signing with ed25519 keys,
119        /// and cross-signing with onion keys.
120        CROSSSIGN = 2;
121
122        /// Support for parsing relay descriptors without TAP onion-keys (`KP_onion_tap`),
123        /// and generating them without TAP onion keys when `publish-dummy-tap-key` is 0.
124        NO_TAP = 3;
125
126        /// Support for understanding and building paths according to
127        /// the "happy families" design.
128        FAMILY_IDS = 4;
129    }
130
131    Microdesc {
132        /// Support for generating and parsing microdescriptors with Ed25159 identities
133        /// (`KP_relayid_ed`)
134        ED25519_KEY = 2;
135
136        /// Support for parsing microdescriptors without TAP keys (`KP_onion_tap``).
137        NO_TAP = 3;
138    }
139
140    Cons {
141        /// Support for consensus method 21, which moved ed25519 identity keys (`KP_relayid_ed`)
142        /// to microdescriptors.
143        ED25519_MDS = 2;
144    }
145
146    Padding {
147        /// Support for padding machines to hide HS circuit setup patterns.
148        MACHINES_CIRC_SETUP = 2;
149    }
150
151    FlowCtrl {
152        /// Support for authenticated circuit-level SENDME messages.
153        AUTH_SENDME = 1;
154
155        /// Support for congestion control.
156        CC = 2;
157    }
158
159    Conflux {
160        /// Support for the core conflux protocol.
161        BASE = 1;
162    }
163
164}
165
166/// Define a restricted set of subprotocol versions.
167///
168/// This supports a set of named subprotocols as defined in [`tor_protover::named`](crate::named).
169///
170/// This is useful when you want to restrict what subprotocol versions are allowed,
171/// and also want to be able to exhaustively handle each subprotocol version.
172/// If you don't care about (or don't want) the exhaustive property,
173/// you might be better off defining a wrapper around [`Protocols`]($crate::Protocols) instead.
174///
175/// Example:
176///
177/// ```
178/// tor_protover::subprotocol_restricted_set! {
179///     #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
180///     pub(crate) struct SupportedSubprotocols {
181///         RELAY_CRYPT_CGO,
182///         RELAY_NTORV3,
183///     }
184/// }
185/// ```
186///
187/// generates a struct of the form:
188///
189/// ```
190/// #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
191/// pub(crate) struct SupportedSubprotocols {
192///     pub(crate) relay_crypt_cgo: bool,
193///     pub(crate) relay_ntorv3: bool,
194/// }
195/// ```
196#[macro_export]
197macro_rules! subprotocol_restricted_set {
198    {
199        $(#[$meta:meta])*
200        $v:vis struct $name:ident {
201            $(
202                $(#[$field_meta:meta])*
203                $field:ident
204            ),* $(,)?
205        }
206    } => {
207        $crate::macro_export::paste::paste!{
208            // We don't make this `non_exhaustive` because the goal of this type is to support
209            // exhaustively handling all elements.
210            $(#[$meta])*
211            $v struct $name {
212                $(
213                    $(#[$field_meta])*
214                    #[doc = concat!(
215                        "The [`", stringify!($field), "`](",
216                        stringify!($crate), "::named::", stringify!($field),
217                        ") subprotocol version."
218                    )]
219                    $v [<$field:lower>]: bool,
220                )*
221            }
222
223            impl $name {
224                /// All subprotocol versions that are supported by this set.
225                $v const ALL: Self = Self {$(
226                    [<$field:lower>]: true,
227                )*};
228            }
229
230            impl From<$name> for $crate::Protocols {
231                fn from(set: $name) -> Self {
232                    Self::from_iter(
233                        [$(set.[<$field:lower>].then_some($crate::named::$field)),*]
234                        .into_iter()
235                        .filter_map(|x| x)
236                    )
237                }
238            }
239        }
240    };
241}
242
243#[cfg(test)]
244mod test {
245    // @@ begin test lint list maintained by maint/add_warning @@
246    #![allow(clippy::bool_assert_comparison)]
247    #![allow(clippy::clone_on_copy)]
248    #![allow(clippy::dbg_macro)]
249    #![allow(clippy::mixed_attributes_style)]
250    #![allow(clippy::print_stderr)]
251    #![allow(clippy::print_stdout)]
252    #![allow(clippy::single_char_pattern)]
253    #![allow(clippy::unwrap_used)]
254    #![allow(clippy::unchecked_time_subtraction)]
255    #![allow(clippy::useless_vec)]
256    #![allow(clippy::needless_pass_by_value)]
257    #![allow(clippy::string_slice)] // See arti#2571
258    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
259
260    use crate::Protocols;
261
262    subprotocol_restricted_set! {
263        #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
264        struct SupportedSubprotocols {
265            RELAY_CRYPT_CGO,
266            RELAY_NTORV3,
267        }
268    }
269
270    #[test]
271    fn restricted_set_constants() {
272        assert_eq!(
273            SupportedSubprotocols::ALL,
274            SupportedSubprotocols {
275                relay_crypt_cgo: true,
276                relay_ntorv3: true,
277            },
278        );
279    }
280
281    #[test]
282    fn restricted_set() {
283        let protocols: Protocols = "Relay=4".parse().unwrap();
284
285        assert_eq!(
286            Protocols::from(SupportedSubprotocols {
287                relay_crypt_cgo: false,
288                relay_ntorv3: true,
289            }),
290            protocols,
291        );
292    }
293}