tor_netdoc/doc/netstatus/
rs.rs1#[cfg(feature = "build_docs")]
7pub(crate) mod build;
8mod md;
9#[cfg(feature = "ns_consensus")]
10mod ns;
11
12use super::{ConsensusFlavor, NetstatusKwd, RelayFlags, RelayWeight};
13use crate::doc;
14use crate::parse::parser::Section;
15use crate::types::misc::*;
16use crate::types::version::TorVersion;
17use crate::util::intern::InternCache;
18use crate::{Error, NetdocErrorKind as EK, Result};
19use std::sync::Arc;
20use std::{net, time};
21
22use tor_llcrypto::pk::rsa::RsaIdentity;
23use tor_protover::Protocols;
24
25pub use md::MdConsensusRouterStatus;
26#[cfg(feature = "ns_consensus")]
27pub use ns::NsConsensusRouterStatus;
28
29#[cfg_attr(
31 feature = "dangerous-expose-struct-fields",
32 visible::StructFields(pub),
33 visibility::make(pub),
34 non_exhaustive
35)]
36#[derive(Debug, Clone)]
37struct GenericRouterStatus<D> {
38 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
43 nickname: Nickname,
44 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
46 identity: RsaIdentity,
47 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
49 addrs: Vec<net::SocketAddr>,
50 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
52 doc_digest: D,
53 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
55 flags: RelayFlags,
56 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
58 version: Option<Version>,
59 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
61 protos: Arc<Protocols>,
62 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
65 weight: RelayWeight,
66}
67
68#[derive(Clone, Debug, Eq, PartialEq, Hash, derive_more::Display)]
74#[non_exhaustive]
75pub enum Version {
76 Tor(TorVersion),
78 Other(Arc<str>),
80}
81
82static OTHER_VERSION_CACHE: InternCache<str> = InternCache::new();
87
88impl std::str::FromStr for Version {
89 type Err = Error;
90
91 fn from_str(s: &str) -> Result<Self> {
92 let mut elts = s.splitn(3, ' ');
93 if elts.next() == Some("Tor") {
94 if let Some(Ok(v)) = elts.next().map(str::parse) {
95 return Ok(Version::Tor(v));
96 }
97 }
98
99 Ok(Version::Other(OTHER_VERSION_CACHE.intern_ref(s)))
100 }
101}
102
103macro_rules! implement_accessors {
107 ($name:ident) => {
108 impl $name {
109 pub fn orport_addrs(&self) -> impl Iterator<Item = &net::SocketAddr> {
111 self.rs.addrs.iter()
112 }
113 pub fn weight(&self) -> &RelayWeight {
115 &self.rs.weight
116 }
117 pub fn addrs(&self) -> &[net::SocketAddr] {
119 &self.rs.addrs[..]
120 }
121 pub fn protovers(&self) -> &Protocols {
123 &self.rs.protos
124 }
125 pub fn nickname(&self) -> &str {
127 self.rs.nickname.as_str()
128 }
129 pub fn flags(&self) -> &RelayFlags {
131 &self.rs.flags
132 }
133 pub fn version(&self) -> Option<&crate::doc::netstatus::rs::Version> {
135 self.rs.version.as_ref()
136 }
137 pub fn ed25519_id_is_usable(&self) -> bool {
140 !self.rs.flags.contains(RelayFlags::NO_ED_CONSENSUS)
141 }
142 pub fn is_flagged_bad_exit(&self) -> bool {
144 self.rs.flags.contains(RelayFlags::BAD_EXIT)
145 }
146 pub fn is_flagged_v2dir(&self) -> bool {
148 self.rs.flags.contains(RelayFlags::V2DIR)
149 }
150 pub fn is_flagged_exit(&self) -> bool {
152 self.rs.flags.contains(RelayFlags::EXIT)
153 }
154 pub fn is_flagged_guard(&self) -> bool {
156 self.rs.flags.contains(RelayFlags::GUARD)
157 }
158 pub fn is_flagged_hsdir(&self) -> bool {
160 self.rs.flags.contains(RelayFlags::HSDIR)
161 }
162 pub fn is_flagged_stable(&self) -> bool {
164 self.rs.flags.contains(RelayFlags::STABLE)
165 }
166 pub fn is_flagged_fast(&self) -> bool {
168 self.rs.flags.contains(RelayFlags::FAST)
169 }
170 pub fn is_flagged_middle_only(&self) -> bool {
172 self.rs.flags.contains(RelayFlags::MIDDLE_ONLY)
173 }
174 }
175 };
176}
177
178pub(crate) use implement_accessors;
180
181#[cfg_attr(feature = "dangerous-expose-struct-fields", visibility::make(pub))]
184trait FromRsString: Sized {
185 fn decode(s: &str) -> Result<Self>;
187}
188
189impl<D> GenericRouterStatus<D>
190where
191 D: FromRsString,
192{
193 fn from_section(
198 sec: &Section<'_, NetstatusKwd>,
199 consensus_flavor: ConsensusFlavor,
200 ) -> Result<GenericRouterStatus<D>> {
201 use NetstatusKwd::*;
202 let r_item = sec.required(RS_R)?;
204 let nickname = r_item.required_arg(0)?.parse()?;
205 let ident = r_item.required_arg(1)?.parse::<B64>()?;
206 let identity = RsaIdentity::from_bytes(ident.as_bytes()).ok_or_else(|| {
207 EK::BadArgument
208 .at_pos(r_item.pos())
209 .with_msg("Wrong identity length")
210 })?;
211 let n_skip = match consensus_flavor {
213 ConsensusFlavor::Microdesc => 0,
214 ConsensusFlavor::Ns => 1,
215 };
216 let _ignore_published: time::SystemTime = {
219 let mut p = r_item.required_arg(2 + n_skip)?.to_string();
224 p.push(' ');
225 p.push_str(r_item.required_arg(3 + n_skip)?);
226 p.parse::<Iso8601TimeSp>()?.into()
227 };
228 let ipv4addr = r_item.required_arg(4 + n_skip)?.parse::<net::Ipv4Addr>()?;
229 let or_port = r_item.required_arg(5 + n_skip)?.parse::<u16>()?;
230 let _ = r_item.required_arg(6 + n_skip)?.parse::<u16>()?;
231
232 let a_items = sec.slice(RS_A);
234 let mut addrs = Vec::with_capacity(1 + a_items.len());
235 addrs.push(net::SocketAddr::V4(net::SocketAddrV4::new(
236 ipv4addr, or_port,
237 )));
238 for a_item in a_items {
239 addrs.push(a_item.required_arg(0)?.parse::<net::SocketAddr>()?);
240 }
241
242 let flags = RelayFlags::from_item(sec.required(RS_S)?)?;
244
245 let version = sec.maybe(RS_V).args_as_str().map(str::parse).transpose()?;
247
248 let protos = {
250 let tok = sec.required(RS_PR)?;
251 doc::PROTOVERS_CACHE.intern(
252 tok.args_as_str()
253 .parse::<Protocols>()
254 .map_err(|e| EK::BadArgument.at_pos(tok.pos()).with_source(e))?,
255 )
256 };
257
258 let weight = sec
260 .get(RS_W)
261 .map(RelayWeight::from_item)
262 .transpose()?
263 .unwrap_or_default();
264
265 let doc_digest: D = match consensus_flavor {
271 ConsensusFlavor::Microdesc => {
272 let m_item = sec.required(RS_M)?;
274 D::decode(m_item.required_arg(0)?)?
275 }
276 ConsensusFlavor::Ns => D::decode(r_item.required_arg(2)?)?,
277 };
278
279 Ok(GenericRouterStatus {
280 nickname,
281 identity,
282 addrs,
283 doc_digest,
284 flags,
285 version,
286 protos,
287 weight,
288 })
289 }
290}