1
//! network status documents - items for all varieties, that vary
2
//!
3
//! **This file is reincluded multiple times**,
4
//! by the macros in [`crate::doc::ns_variety_definition_macros`],
5
//! once for votes, and once for each consensus flavour.
6
//! It is *not* a module `crate::doc::netstatus::rs::each_variety`.
7
//!
8
//! Each time this file is included by one of the macros mentioned above,
9
//! the `ns_***` macros (such as `ns_const_name!`) may expand to different values.
10
//!
11
//! See [`crate::doc::ns_variety_definition_macros`].
12

            
13
use super::*;
14

            
15
ns_use_this_variety! {
16
    pub use [crate::doc::netstatus::rs]::?::{RouterStatus};
17
}
18

            
19
/// Network status document - consensus, or vote
20
///
21
/// <https://spec.torproject.org/dir-spec/consensus-formats.html>
22
///
23
/// <https://spec.torproject.org/dir-spec/computing-consensus.html#flavors>
24
#[derive(Clone, Debug, Deftly)]
25
#[derive_deftly(Constructor, NetdocParseableUnverified)]
26
#[deftly(netdoc(doctype_for_error = NETSTATUS_DOCTYPE_FOR_ERROR))]
27
#[allow(clippy::exhaustive_structs)]
28
#[cfg(feature = "incomplete")] // untested
29
pub struct NetworkStatus {
30
    /// The `network-status-version` intro item
31
    ///
32
    /// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:network-status-version>
33
    ///
34
    /// In the "preamble" in the spec, but not in our `Preamble` type for Reasons.
35
    pub network_status_version: NetworkStatusVersionItem,
36

            
37
    /// `vote-status`
38
    ///
39
    /// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:vote-status>
40
    ///
41
    /// In the "preamble" in the spec, but not in our `Preamble` type for Reasons.
42
    #[deftly(netdoc(single_arg))]
43
    pub vote_status: ns_type!(
44
        VoteStatusConsensus,
45
        VoteStatusConsensus,
46
        VoteStatusVote,
47
    ),
48

            
49
    /// The rest of the preamble
50
    ///
51
    /// <https://spec.torproject.org/dir-spec/consensus-formats.html#section:preable>
52
    #[deftly(constructor, netdoc(flatten))]
53
    pub preamble: Preamble,
54

            
55
    /// Authority section
56
    ///
57
    /// <https://spec.torproject.org/dir-spec/consensus-formats.html#section:authority>
58
    #[deftly(constructor, netdoc(subdoc))]
59
    pub authority: ns_type!(
60
        ConsensusAuthoritySection,
61
        ConsensusAuthoritySection,
62
        VoteAuthoritySection,
63
    ),
64

            
65
    /// Router status entries
66
    ///
67
    /// <https://spec.torproject.org/dir-spec/consensus-formats.html#section:router-status>
68
    #[deftly(netdoc(subdoc))]
69
    pub routers: Vec<RouterStatus>,
70

            
71
    /// Footer
72
    ///
73
    /// <https://spec.torproject.org/dir-spec/consensus-formats.html#section:footer>
74
    #[deftly(netdoc(subdoc))]
75
    #[deftly(constructor)]
76
    pub footer: Footer,
77

            
78
    #[doc(hidden)]
79
    #[deftly(netdoc(skip))]
80
    pub __non_exhaustive: (),
81
}
82

            
83
/// `network-status-version` intro item in a consensus
84
///
85
/// This is hard to parse because it's so irregular (even, ambiguous).
86
///
87
/// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:network-status-version>
88
///
89
/// <https://spec.torproject.org/dir-spec/computing-consensus.html#flavor:microdesc>
90
///
91
/// <https://gitlab.torproject.org/tpo/core/torspec/-/work_items/359>
92
#[derive(Clone, Debug, Deftly, Default)]
93
#[derive_deftly(Constructor, ItemValueEncodable, ItemValueParseable)]
94
#[allow(clippy::exhaustive_structs)]
95
pub struct NetworkStatusVersionItem {
96
    /// The version number, always `3`
97
    pub version: NetworkStatusVersion,
98

            
99
    /// The `flavor` argument
100
    ///
101
    ///  * In a plain consensus, this is an optional `ns`.
102
    ///  * In an md consensus, this is always `microdesc`.
103
    ///  * In a vote, there is no variety, but to avoid ambiguity, we reject.
104
    pub variety: VarietyKeyword,
105

            
106
    #[doc(hidden)]
107
    #[deftly(netdoc(skip))]
108
    pub __non_exhaustive: (),
109
}
110

            
111
/// The preamble of a network status document, except for the intro and `vote-status` items.
112
///
113
/// <https://spec.torproject.org/dir-spec/consensus-formats.html#section:preable>
114
///
115
/// **Does not include `network-status-version` and `vote-status`**.
116
/// In the old parser this is not represented directly;
117
/// instead, in `Consensus.flavor`, there's just the `ConsensusFlavor`.
118
/// `parse2` doesn't (currently) support subdocuments which contain the parent's intro item
119
/// (ie, `#[deftly(netdoc(flatten))]` is not supported on the first field.)
120
//
121
// TODO DIRAUTH this is missing some fields that need to be included in votes,
122
// by dirauths, when voting.  They are not needed for calculating a consensus from votes.
123
// there are individual TODO comments about each such defect.
124
#[derive(Clone, Debug, Deftly)]
125
#[derive_deftly(Constructor, NetdocEncodableFields, NetdocParseableFields)]
126
#[allow(clippy::exhaustive_structs)]
127
pub struct Preamble {
128
    /// Consensus methods supported by this voter.
129
    #[deftly(constructor)]
130
    pub consensus_methods: ns_type!( NotPresent, NotPresent, ConsensusMethods ),
131

            
132
    /// What "method" was used to produce this consensus?  (A
133
    /// consensus method is a version number used by authorities to
134
    /// upgrade the consensus algorithm.)
135
    #[deftly(constructor)]
136
    // Not #[deftly(netdoc(single_arg))] because that would mean a consensuses
137
    // had an always-present singleton `consensus_method` item with no arguments.
138
    pub consensus_method: ns_type!( (u32,), (u32,), NotPresent ),
139

            
140
    /// Publication time (of a vote)
141
    #[deftly(constructor)]
142
    // Not #[deftly(netdoc(single_arg))] because that would mean a consensuses
143
    // had an always-present singleton `published` item with no arguments.
144
    pub published: ns_type!( NotPresent, NotPresent, (Iso8601TimeSp,) ),
145

            
146
    /// Over what time is this consensus valid?  (For votes, this is
147
    /// the time over which the voted-upon consensus should be valid.)
148
    #[deftly(constructor)]
149
    #[deftly(netdoc(flatten))]
150
    pub lifetime: Lifetime,
151

            
152
    /// How long in seconds should voters wait for votes and
153
    /// signatures (respectively) to propagate?
154
    pub voting_delay: Option<(u32, u32)>,
155

            
156
    /// List of recommended Tor client versions.
157
    ///
158
    /// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:client-versions>
159
    #[deftly(netdoc(default))]
160
    pub client_versions: RecommendedTorVersions,
161

            
162
    /// List of recommended Tor relay versions.
163
    ///
164
    /// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:server-versions>
165
    #[deftly(netdoc(default))]
166
    pub server_versions: RecommendedTorVersions,
167

            
168
    /// Router flags which could be determined
169
    #[deftly(constructor)]
170
    #[deftly(netdoc(with = "relay_flags::ParserEncoder::<relay_flags::NoImplicitRepr>"))]
171
    pub known_flags: DocRelayFlags,
172

            
173
    // TODO DIRAUTH torspec#404 missing field: flag-thresholds (in votes)
174

            
175
    /// Lists of recommended and required subprotocols.
176
    ///
177
    /// **`{recommended,required}-{client,relay}-protocols`**
178
    #[deftly(constructor)]
179
    #[deftly(netdoc(flatten))]
180
    pub proto_statuses: Arc<ProtoStatuses>,
181

            
182
    /// Declared parameters for tunable settings about how to the
183
    /// network should operator. Some of these adjust timeouts and
184
    /// whatnot; some features things on and off.
185
    #[deftly(constructor)]
186
    pub params: NetParams<i32>,
187

            
188
    /// Global shared-random values
189
    #[deftly(netdoc(flatten))]
190
    pub shared_rand: ns_type!( SharedRandStatuses, SharedRandStatuses, NotPresent ),
191

            
192
    // TODO DIRAUTH missing field: bandwidth-file-headers (in votes)
193
    // TODO DIRAUTH missing field: bandwidth-file-digest (in votes)
194

            
195
    #[doc(hidden)]
196
    #[deftly(netdoc(skip))]
197
    pub __non_exhaustive: (),
198
}
199

            
200
/// The footer of a network status document.
201
///
202
/// <https://spec.torproject.org/dir-spec/consensus-formats.html#section:footer>>
203
#[derive(Clone, Debug, Deftly)]
204
#[derive_deftly(Constructor, NetdocEncodable, NetdocParseable)]
205
#[allow(clippy::exhaustive_structs)]
206
pub struct Footer {
207
    /// Intro item
208
    ///
209
    /// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:directory-footer>
210
    pub directory_footer: (),
211

            
212
    /// Fields that appear in consensuses (only)
213
    #[deftly(constructor, netdoc(flatten))]
214
    pub consensus: ns_type!(ConsensusFooterFields, ConsensusFooterFields, NotPresent),
215

            
216
    #[doc(hidden)]
217
    #[deftly(netdoc(skip))]
218
    pub __non_exhaustive: (),
219
}
220

            
221
/// Signatures on a network status document
222
#[derive(Deftly, Clone, Debug)]
223
#[derive_deftly(NetdocParseableSignatures)]
224
#[deftly(netdoc(signatures(hashes_accu = "DirectorySignaturesHashesAccu")))]
225
#[non_exhaustive]
226
pub struct NetworkStatusSignatures {
227
    /// `directory-signature`s
228
    pub directory_signature: ns_type!(Vec<Signature>, Vec<Signature>, Signature),
229
}
230

            
231
impl Preamble {
232
    /// Calculate the validity range (time interval) for this network status document
233
382
    pub fn validity_time_range(&self) -> std::ops::Range<SystemTime> {
234
382
        let lifetime = self.lifetime.clone();
235
382
        let delay = self.voting_delay.unwrap_or((0, 0));
236
382
        let dist_interval = time::Duration::from_secs(delay.1.into());
237
382
        let starting_time = lifetime.valid_after.saturating_sub(dist_interval);
238
382
        starting_time..*lifetime.valid_until
239
382
    }
240
}