tor_dircommon/
authority.rs

1//! Information about directory authorities
2//!
3//! From a client's point of view, an authority's role is to sign the
4//! consensus directory.
5
6use std::net::SocketAddr;
7
8use derive_builder::Builder;
9use getset::Getters;
10use serde::{Deserialize, Serialize};
11use tor_config::{ConfigBuildError, define_list_builder_accessors, impl_standard_builder};
12use tor_llcrypto::pk::rsa::RsaIdentity;
13
14/// The contact information for all directory authorities this implementation is
15/// aware of.
16///
17/// This data structure makes use of proposal 330 in order to distinguish
18/// authorities by their responsibilities, hence why the fields are divided.
19#[derive(Debug, Clone, Builder, Eq, PartialEq, Getters)]
20#[builder(build_fn(error = "ConfigBuildError"))]
21#[builder(derive(Debug, Serialize, Deserialize))]
22pub struct AuthorityContacts {
23    /// The [`RsaIdentity`] keys that may be used to sign valid consensus documents.
24    #[builder(setter(custom), default = "default_v3idents()")]
25    #[getset(get = "pub")]
26    v3idents: Vec<RsaIdentity>,
27    /// The endpoints of authorities where upload of router descriptors and other
28    /// documents is possible.
29    ///
30    /// This section is primarily of interest for relays.
31    ///
32    /// The use of nested a [`Vec`] serves the purpose to assign multiple IPs to
33    /// a single logical authority, such as having an IPv4 and IPv6 address.
34    #[builder(setter(custom), default = "default_uploads()")]
35    #[getset(get = "pub")]
36    uploads: Vec<Vec<SocketAddr>>,
37    #[builder(setter(custom), default = "default_downloads()")]
38    /// The endpoints of authorities where download of network documents is possible.
39    ///
40    /// This section is primarily of interest for directory mirrors.
41    ///
42    /// The use of nested a [`Vec`] serves the purpose to assign multiple IPs to
43    /// a single logical authority, such as having an IPv4 and IPv6 address.
44    #[getset(get = "pub")]
45    downloads: Vec<Vec<SocketAddr>>,
46    #[builder(setter(custom), default = "default_votes()")]
47    #[getset(get = "pub")]
48    /// The endpoints of authorities where voting for consensus documents is possible.
49    ///
50    /// This section is primarily of interest for other directory authorities.
51    ///
52    /// The use of nested a [`Vec`] serves the purpose to assign multiple IPs to
53    /// a single logical authority, such as having an IPv4 and IPv6 address.
54    votes: Vec<Vec<SocketAddr>>,
55}
56
57/// The legacy way of storing an authority before Arti 1.6.0.
58///
59/// Only for compatibility, see `crate::config::authority_compat`.
60#[derive(Debug, Serialize, Deserialize)]
61pub(crate) struct LegacyAuthority {
62    /// A memorable nickname for this authority.
63    pub(crate) name: String,
64    /// A SHA1 digest of the DER-encoded long-term v3 RSA identity key for
65    /// this authority.
66    // TODO: It would be lovely to use a better hash for these identities.
67    pub(crate) v3ident: RsaIdentity,
68}
69
70impl_standard_builder! { AuthorityContacts }
71
72define_list_builder_accessors! {
73    struct AuthorityContactsBuilder {
74        pub v3idents: [RsaIdentity],
75        pub uploads: [Vec<SocketAddr>],
76        pub downloads: [Vec<SocketAddr>],
77        pub votes: [Vec<SocketAddr>],
78    }
79}
80
81/// Returns a list of the default [`RsaIdentity`]s for the directory authorities.
82fn default_v3idents() -> Vec<RsaIdentity> {
83    fn rsa(hex: &str) -> RsaIdentity {
84        RsaIdentity::from_hex(hex).expect("invalid hex?!?")
85    }
86
87    vec![
88        rsa("27102BC123E7AF1D4741AE047E160C91ADC76B21"), // bastet
89        rsa("0232AF901C31A04EE9848595AF9BB7620D4C5B2E"), // dannenberg
90        rsa("E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58"), // dizum
91        rsa("70849B868D606BAECFB6128C5E3D782029AA394F"), // faravahar
92        rsa("ED03BB616EB2F60BEC80151114BB25CEF515B226"), // gabelmoo
93        rsa("23D15D965BC35114467363C165C4F724B64B4F66"), // longclaw
94        rsa("49015F787433103580E3B66A1707A00E60F2D15B"), // maatuska
95        rsa("F533C81CEF0BC0267857C99B2F471ADF249FA232"), // moria1
96        rsa("2F3DF9CA0E5D36F2685A2DA67184EB8DCB8CBA8C"), // tor26
97    ]
98}
99
100/// Returns a list of the [`SocketAddr`] for the directory authorities.
101///
102/// The nested [`Vec`] serves dual-stack purposes
103/// (i.e. many IPs mapping to one logical authority).
104fn default_uploads() -> Vec<Vec<SocketAddr>> {
105    /// Converts a [`str`] to a [`SocketAddr`].
106    fn sa(s: &str) -> SocketAddr {
107        s.parse().expect("invalid socket address?!?")
108    }
109
110    vec![
111        // bastet
112        vec![
113            sa("204.13.164.118:80"),
114            sa("[2620:13:4000:6000::1000:118]:80"),
115        ],
116        // dannenberg
117        vec![sa("193.23.244.244:80"), sa("[2001:678:558:1000::244]:80")],
118        // dizum
119        vec![sa("45.66.35.11:80"), sa("[2a09:61c0::1337]:80")],
120        // faravahar
121        vec![sa("216.218.219.41:80"), sa("[2001:470:164:2::2]:80")],
122        // gabelmoo
123        vec![
124            sa("131.188.40.189:80"),
125            sa("[2001:638:a000:4140::ffff:189]:80"),
126        ],
127        // longclaw
128        vec![sa("199.58.81.140:80")],
129        // maatuska
130        vec![sa("171.25.193.9:443"), sa("[2001:67c:289c::9]:443")],
131        // moria1
132        vec![sa("128.31.0.39:9231")],
133        // tor26
134        vec![sa("217.196.147.77:80"), sa("[2a02:16a8:662:2203::1]:80")],
135    ]
136}
137
138/// For now, an alias to [`default_uploads()`].
139fn default_downloads() -> Vec<Vec<SocketAddr>> {
140    default_uploads()
141}
142
143/// For now, an alias to [`default_uploads()`].
144fn default_votes() -> Vec<Vec<SocketAddr>> {
145    default_uploads()
146}
147
148#[cfg(test)]
149mod test {
150    // @@ begin test lint list maintained by maint/add_warning @@
151    #![allow(clippy::bool_assert_comparison)]
152    #![allow(clippy::clone_on_copy)]
153    #![allow(clippy::dbg_macro)]
154    #![allow(clippy::mixed_attributes_style)]
155    #![allow(clippy::print_stderr)]
156    #![allow(clippy::print_stdout)]
157    #![allow(clippy::single_char_pattern)]
158    #![allow(clippy::unwrap_used)]
159    #![allow(clippy::unchecked_duration_subtraction)]
160    #![allow(clippy::useless_vec)]
161    #![allow(clippy::needless_pass_by_value)]
162    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
163    #![allow(clippy::unnecessary_wraps)]
164
165    use super::*;
166
167    #[test]
168    fn default_auths() {
169        let dflt = AuthorityContacts::builder().build().unwrap();
170        assert_eq!(dflt.v3idents, default_v3idents());
171        assert_eq!(dflt.uploads, default_uploads());
172        assert_eq!(dflt.downloads, default_downloads());
173        assert_eq!(dflt.votes, default_votes());
174
175        assert_eq!(
176            dflt.v3idents[8],
177            RsaIdentity::from_hex("2F3DF9CA0E5D36F2685A2DA67184EB8DCB8CBA8C").unwrap()
178        );
179        assert_eq!(
180            dflt.uploads[8],
181            vec![
182                "217.196.147.77:80".parse().unwrap(),
183                "[2a02:16a8:662:2203::1]:80".parse().unwrap()
184            ]
185        );
186        assert_eq!(dflt.uploads[8], dflt.downloads[8]);
187        assert_eq!(dflt.uploads[8], dflt.votes[8]);
188    }
189}