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

            
11
use super::{NamedSubver, ProtoKind};
12
use paste::paste;
13

            
14
/// Helper: define a set of named aliases for specific subprotocol versions
15
macro_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

            
30
def_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]
197
macro_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
4
                fn from(set: $name) -> Self {
232
4
                    Self::from_iter(
233
4
                        [$(set.[<$field:lower>].then_some($crate::named::$field)),*]
234
4
                        .into_iter()
235
4
                        .filter_map(|x| x)
236
                    )
237
4
                }
238
            }
239
        }
240
    };
241
}
242

            
243
#[cfg(test)]
244
mod 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
}