tor_netdoc/doc/netstatus/rs/each_variety.rs
1//! router status entries - 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
13use super::*;
14
15// Explicit parsing arrangements for document digest field in `m` items.
16//
17// https://spec.torproject.org/dir-spec/consensus-formats.html#item:r
18// https://spec.torproject.org/dir-spec/consensus-formats.html#item:m
19// https://spec.torproject.org/dir-spec/computing-consensus.html#flavor:microdesc
20//
21// The document digest moves about, and vote `m` items are even more exciting.
22// This is for the benefit of the `with` annotations for RouterStatus.m.
23//
24// We need to make this an import that can be used with `deftly(netdoc(with = ))`.
25// `with` expects a path, not a type, so we can't use ns_type!.
26//
27// (Normally when trying to parse an item whose single field implements ItemArgumentParseable
28// but not ItemValueParseable, we would use #[deftly(netdoc(single_arg))]
29// but here we can't do that because we can't have variety-dependent attributes.)
30ns_choose! { (
31 use NotPresentEachValue as doc_digest_item_m;
32) (
33 // doc_digest_item_m implemented in rs/md.rs
34) (
35 use RouterStatusMdDigestsVote as doc_digest_item_m;
36) }
37
38/// Type of the referenced document digest in form suitable for parsing and encoding
39type DocDigestB64 = FixedB64<DOC_DIGEST_LEN>;
40
41/// Intro item for a router status entry
42///
43/// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:r>
44///
45/// <https://spec.torproject.org/dir-spec/computing-consensus.html#flavor:microdesc>
46/// `r` item.
47#[derive(Debug, Clone, Deftly)]
48#[derive_deftly(ItemValueParseable)]
49#[cfg_attr(feature = "incomplete", derive_deftly(ItemValueEncodable))] // untested
50#[non_exhaustive]
51pub struct RouterStatusIntroItem {
52 /// The nickname for this relay.
53 ///
54 /// Nicknames can be used for convenience purpose, but no more:
55 /// there is no mechanism to enforce their uniqueness.
56 pub nickname: Nickname,
57
58 /// Fingerprint of the old-style RSA identity for this relay.
59 pub identity: Base64Fingerprint,
60
61 /// Digest of the document for this relay (except md consensuses)
62 // TODO SPEC rename in the spec from `digest` to "doc_digest"
63 // TODO SPEC in md consensuses the referenced document digest is in a separate `m` item
64 pub doc_digest: ns_type!(DocDigestB64, NotPresent, DocDigestB64),
65
66 /// Publication time.
67 pub publication: ns_type!(
68 IgnoredPublicationTimeSp,
69 IgnoredPublicationTimeSp,
70 Iso8601TimeSp
71 ),
72
73 /// IPv4 address
74 pub ip: std::net::Ipv4Addr,
75
76 /// Relay port
77 pub or_port: u16,
78
79 /// Directory port
80 ///
81 /// Always 0 when read by the old parser.
82 pub dir_port: u16,
83}
84
85/// A single relay's status, in a network status document.
86///
87/// <https://spec.torproject.org/dir-spec/consensus-formats.html#section:router-status>
88///
89/// <https://spec.torproject.org/dir-spec/computing-consensus.html#flavor:microdesc>
90/// under "Changes to router status entries".
91//
92// In most netdocs we would use the item keywords as the field names. But routerstatus
93// entry keywords are chosen to be very short to minimise the consensus size, so we
94// use longer names in the struct and specify the keyword separately.
95#[derive(Debug, Clone, Deftly)]
96#[derive_deftly(NetdocParseable)]
97#[cfg_attr(feature = "incomplete", derive_deftly(NetdocEncodable))] // untested
98#[non_exhaustive]
99pub struct RouterStatus {
100 /// `r` --- Introduce a routerstatus entry
101 ///
102 /// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:r>
103 /// (and, the md version, which is different).
104 pub r: RouterStatusIntroItem,
105
106 /// `m` --- Microdescriptor or document digest
107 ///
108 /// In an md consensus, the hash of the document for this relay.
109 /// In a vote, microdescriptor hashes for the various consensus methods.
110 ///
111 /// <https://spec.torproject.org/dir-spec/computing-consensus.html#flavor:microdesc>
112 /// `r` item.
113 // We call this field `m` rather than `doc_digest` because it's not always the doc digest.
114 // TODO SPEC in all but md consensuses the referenced document digest is in the `r` intro item
115 //
116 // TODO SPEC Adjust microdesc consensus `m` item position in the spec.
117 // This item is here because this is where C Tor puts it.
118 #[deftly(netdoc(with = doc_digest_item_m))]
119 pub m: ns_type!(NotPresent, DocDigestB64, Vec<RouterStatusMdDigestsVote>),
120
121 /// `a` --- Further router address(es) (IPv6)
122 ///
123 /// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:a>
124 /// (and, the md version, which is different).
125 #[deftly(netdoc(single_arg))]
126 pub a: Vec<net::SocketAddr>,
127
128 /// `s` --- Router status flags
129 ///
130 /// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:s>
131 #[deftly(netdoc(
132 keyword = "s",
133 with = {
134 relay_flags::ParserEncoder::<ns_type!(
135 relay_flags::ConsensusRepr,
136 relay_flags::ConsensusRepr,
137 relay_flags::NoImplicitRepr,
138 )>
139 },
140 ))]
141 pub flags: DocRelayFlags,
142
143 /// `v` --- Relay's Tor software version
144 ///
145 /// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:v>
146 #[deftly(netdoc(keyword = "v"))]
147 pub version: Option<SoftwareVersion>,
148
149 /// `pr` --- Subprotocol capabilities supported
150 ///
151 /// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:v>
152 #[deftly(netdoc(keyword = "pr"))]
153 pub protos: Protocols,
154
155 /// `w` --- Bandwidth estimates
156 ///
157 /// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:w>
158 #[deftly(netdoc(flatten))]
159 pub weight: RelayWeightsItem,
160
161 /// `p` --- Exit ports summary
162 ///
163 /// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:p>
164 ///
165 /// This field is not properly parsed in plain consensuses by the old parser.
166 #[deftly(netdoc(keyword = "p"))]
167 pub port_policy: ns_type!(Option<Arc<PortPolicy>>, NotPresent, Option<Arc<PortPolicy>>),
168
169 /// `id` --- Relay’s (ed25519) identity
170 ///
171 /// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:id>
172 //
173 // TODO DIRAUTH: this is only right if torspec!499 is approved.
174 // otherwise, we are missing handling of `id none`.
175 #[deftly(netdoc(keyword = "id"))]
176 pub ed25519_id: ns_type!(NotPresent, NotPresent, Ed25519IdentityLine),
177
178 /// `stats` -- Statistics for this relay
179 ///
180 /// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:stats>
181 pub stats: ns_type!(NotPresent, NotPresent, NetParams<F64Finite>),
182}
183
184impl RouterStatus {
185 /// Return the digest of the document identified by this
186 /// routerstatus.
187 ///
188 /// The `doc_digest` method is provided on all varieties of routerstatus entry
189 /// to help paper over the protocol anomaly, that the digest is in a different place
190 /// in md routerstatus entries.
191 pub fn doc_digest(&self) -> &DocDigest {
192 ns_expr!(&self.r.doc_digest, &self.m, &self.r.doc_digest,)
193 }
194}
195
196impl EncodeOrd for RouterStatus {
197 fn encode_cmp(&self, other: &Self) -> Ordering {
198 // Type inference seems to need a *lot* of help here!
199 let k: for <'i> fn(&'i RouterStatus) -> &'i _ = |rs| &rs .r.identity;
200 EncodeOrd::encode_cmp(k(self), k(other))
201 }
202}