summaryrefslogtreecommitdiff
path: root/crates/tor-dircommon/src/authority.rs
blob: c53cfe49468a3d065a7fce320756484cec1f58af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//! Information about directory authorities
//!
//! From a client's point of view, an authority's role is to sign the
//! consensus directory.

use std::net::SocketAddr;

use derive_deftly::Deftly;
use getset::Getters;
use tor_config::define_list_builder_accessors;
use tor_config::derive::prelude::*;
use tor_llcrypto::pk::rsa::RsaIdentity;

/// The contact information for all directory authorities this implementation is
/// aware of.
///
/// This data structure makes use of proposal 330 in order to distinguish
/// authorities by their responsibilities, hence why the fields are divided.
#[derive(Debug, Clone, Deftly, Eq, PartialEq, Getters)]
#[derive_deftly(TorConfig)]
pub struct AuthorityContacts {
    // NOTE: We aren't using list builders here, since these never actually used sub-builders,
    // and therefore has a slightly different API.
    // We might later decide to change these to proper list-builders;
    // if so, it will be an API break.
    //
    /// The [`RsaIdentity`] keys that may be used to sign valid consensus documents.
    #[deftly(tor_config(no_magic, setter(skip), default = "default_v3idents()"))]
    #[getset(get = "pub")]
    v3idents: Vec<RsaIdentity>,

    /// The endpoints of authorities where upload of router descriptors and other
    /// documents is possible.
    ///
    /// This section is primarily of interest for relays.
    ///
    /// The use of nested a [`Vec`] serves the purpose to assign multiple IPs to
    /// a single logical authority, such as having an IPv4 and IPv6 address.
    #[deftly(tor_config(no_magic, setter(skip), default = "default_uploads()"))]
    #[getset(get = "pub")]
    uploads: Vec<Vec<SocketAddr>>,

    /// The endpoints of authorities where download of network documents is possible.
    ///
    /// This section is primarily of interest for directory mirrors.
    ///
    /// The use of nested a [`Vec`] serves the purpose to assign multiple IPs to
    /// a single logical authority, such as having an IPv4 and IPv6 address.
    #[deftly(tor_config(no_magic, setter(skip), default = "default_downloads()"))]
    #[getset(get = "pub")]
    downloads: Vec<Vec<SocketAddr>>,

    /// The endpoints of authorities where voting for consensus documents is possible.
    ///
    /// This section is primarily of interest for other directory authorities.
    ///
    /// The use of nested a [`Vec`] serves the purpose to assign multiple IPs to
    /// a single logical authority, such as having an IPv4 and IPv6 address.
    #[deftly(tor_config(no_magic, setter(skip), default = "default_votes()"))]
    #[getset(get = "pub")]
    votes: Vec<Vec<SocketAddr>>,
}

define_list_builder_accessors! {
    struct AuthorityContactsBuilder {
        pub v3idents: [RsaIdentity],
        pub uploads: [Vec<SocketAddr>],
        pub downloads: [Vec<SocketAddr>],
        pub votes: [Vec<SocketAddr>],
    }
}

/// Returns a list of the default [`RsaIdentity`]s for the directory authorities.
fn default_v3idents() -> Vec<RsaIdentity> {
    fn rsa(hex: &str) -> RsaIdentity {
        RsaIdentity::from_hex(hex).expect("invalid hex?!?")
    }

    vec![
        rsa("27102BC123E7AF1D4741AE047E160C91ADC76B21"), // bastet
        rsa("0232AF901C31A04EE9848595AF9BB7620D4C5B2E"), // dannenberg
        rsa("E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58"), // dizum
        rsa("70849B868D606BAECFB6128C5E3D782029AA394F"), // faravahar
        rsa("ED03BB616EB2F60BEC80151114BB25CEF515B226"), // gabelmoo
        rsa("23D15D965BC35114467363C165C4F724B64B4F66"), // longclaw
        rsa("49015F787433103580E3B66A1707A00E60F2D15B"), // maatuska
        rsa("F533C81CEF0BC0267857C99B2F471ADF249FA232"), // moria1
        rsa("2F3DF9CA0E5D36F2685A2DA67184EB8DCB8CBA8C"), // tor26
    ]
}

/// Returns a list of the [`SocketAddr`] for the directory authorities.
///
/// The nested [`Vec`] serves dual-stack purposes
/// (i.e. many IPs mapping to one logical authority).
fn default_uploads() -> Vec<Vec<SocketAddr>> {
    /// Converts a [`str`] to a [`SocketAddr`].
    fn sa(s: &str) -> SocketAddr {
        s.parse().expect("invalid socket address?!?")
    }

    vec![
        // bastet
        vec![
            sa("204.13.164.118:80"),
            sa("[2620:13:4000:6000::1000:118]:80"),
        ],
        // dannenberg
        vec![sa("193.23.244.244:80"), sa("[2001:678:558:1000::244]:80")],
        // dizum
        vec![sa("45.66.35.11:80"), sa("[2a09:61c0::1337]:80")],
        // faravahar
        vec![sa("216.218.219.41:80"), sa("[2001:470:164:2::2]:80")],
        // gabelmoo
        vec![
            sa("131.188.40.189:80"),
            sa("[2001:638:a000:4140::ffff:189]:80"),
        ],
        // longclaw
        vec![sa("199.58.81.140:80")],
        // maatuska
        vec![sa("171.25.193.9:443"), sa("[2001:67c:289c::9]:443")],
        // moria1
        vec![sa("128.31.0.39:9231")],
        // tor26
        vec![sa("217.196.147.77:80"), sa("[2a02:16a8:662:2203::1]:80")],
    ]
}

/// For now, an alias to [`default_uploads()`].
fn default_downloads() -> Vec<Vec<SocketAddr>> {
    default_uploads()
}

/// For now, an alias to [`default_uploads()`].
fn default_votes() -> Vec<Vec<SocketAddr>> {
    default_uploads()
}

#[cfg(test)]
mod test {
    // @@ begin test lint list maintained by maint/add_warning @@
    #![allow(clippy::bool_assert_comparison)]
    #![allow(clippy::clone_on_copy)]
    #![allow(clippy::dbg_macro)]
    #![allow(clippy::mixed_attributes_style)]
    #![allow(clippy::print_stderr)]
    #![allow(clippy::print_stdout)]
    #![allow(clippy::single_char_pattern)]
    #![allow(clippy::unwrap_used)]
    #![allow(clippy::unchecked_time_subtraction)]
    #![allow(clippy::useless_vec)]
    #![allow(clippy::needless_pass_by_value)]
    #![allow(clippy::string_slice)] // See arti#2571
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
    #![allow(clippy::unnecessary_wraps)]

    use super::*;

    #[test]
    fn default_auths() {
        let dflt = AuthorityContacts::builder().build().unwrap();
        assert_eq!(dflt.v3idents, default_v3idents());
        assert_eq!(dflt.uploads, default_uploads());
        assert_eq!(dflt.downloads, default_downloads());
        assert_eq!(dflt.votes, default_votes());

        assert_eq!(
            dflt.v3idents[8],
            RsaIdentity::from_hex("2F3DF9CA0E5D36F2685A2DA67184EB8DCB8CBA8C").unwrap()
        );
        assert_eq!(
            dflt.uploads[8],
            vec![
                "217.196.147.77:80".parse().unwrap(),
                "[2a02:16a8:662:2203::1]:80".parse().unwrap()
            ]
        );
        assert_eq!(dflt.uploads[8], dflt.downloads[8]);
        assert_eq!(dflt.uploads[8], dflt.votes[8]);
    }
}