Skip to main content

tor_netdoc/doc/netstatus/
rs.rs

1//! Routerstatus-specific parts of networkstatus parsing.
2//!
3//! This is a private module; relevant pieces are re-exported by its
4//! parent.
5
6#[cfg(feature = "build_docs")]
7pub(crate) mod build;
8pub(crate) mod md;
9pub(crate) mod plain;
10#[cfg(feature = "incomplete")]
11pub(crate) mod vote;
12
13use super::{ConsensusFlavor, ConsensusMethods, consensus_methods_comma_separated};
14use crate::doc::netstatus::{
15    IgnoredPublicationTimeSp, NetParams, NetstatusKwd, Protocols, RelayWeight, RelayWeightsItem,
16};
17use crate::encode::{EncodeOrd, ItemEncoder};
18use crate::parse::parser::Section;
19use crate::parse2::ItemArgumentParseable;
20use crate::types::misc::*;
21use crate::types::policy::PortPolicy;
22use crate::types::relay_flags::{self, DocRelayFlags, RelayFlag, RelayFlags};
23use crate::types::version::TorVersion;
24use crate::{Error, NetdocErrorKind as EK, Result};
25use derive_deftly::Deftly;
26use itertools::chain;
27use std::cmp::Ordering;
28use std::sync::Arc;
29use std::{net, time};
30use tor_basic_utils::intern::InternCache;
31use tor_error::{Bug, internal};
32use tor_llcrypto::pk::rsa::RsaIdentity;
33
34/// A version as presented in a router status.
35///
36/// This can either be a parsed Tor version, or an unparsed string.
37//
38// TODO: This might want to merge, at some point, with routerdesc::RelayPlatform.
39#[derive(Clone, Debug, Eq, PartialEq, Hash, derive_more::Display)]
40#[non_exhaustive]
41pub enum SoftwareVersion {
42    /// A Tor version
43    #[display("Tor {_0}")]
44    CTor(TorVersion),
45    /// A string we couldn't parse.
46    Other(Arc<str>),
47}
48
49/// A cache of unparsable version strings.
50///
51/// We use this because we expect there not to be very many distinct versions of
52/// relay software in existence.
53// TODO DIRAUTH: Improve the caching here.
54static OTHER_VERSION_CACHE: InternCache<str> = InternCache::new();
55
56/// `m` item in votes
57///
58/// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:m>
59///
60/// This is different to the `m` line in microdesc consensuses.
61/// Plain consensuses don't have `m` lines at all.
62///
63/// ### Non-invariants
64///
65///  * There may be overlapping or even contradictory information.
66///  * It might not be sorted.
67///    Users of the structure who need to emit reproducible document encodings.
68///    must sort it.
69///  * These non-invariants apply both within one instance of this struct,
70///    and across multiple instances of it within a `RouterStatus`.
71#[derive(Debug, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Deftly)]
72#[derive_deftly(ItemValueParseable)]
73#[cfg_attr(feature = "incomplete", derive_deftly(ItemValueEncodable))] // untested
74#[non_exhaustive]
75pub struct RouterStatusMdDigestsVote {
76    /// The methods for which this document is applicable.
77    #[deftly(netdoc(with = consensus_methods_comma_separated))]
78    pub consensus_methods: ConsensusMethods,
79
80    /// The various hashes of this document.
81    pub digests: Vec<IdentifiedDigest>,
82}
83
84impl std::str::FromStr for SoftwareVersion {
85    type Err = Error;
86
87    fn from_str(s: &str) -> Result<Self> {
88        let mut elts = s.splitn(3, ' ');
89        if elts.next() == Some("Tor") {
90            if let Some(Ok(v)) = elts.next().map(str::parse) {
91                return Ok(SoftwareVersion::CTor(v));
92            }
93        }
94
95        Ok(SoftwareVersion::Other(
96            OTHER_VERSION_CACHE.intern_ref(s).into(),
97        ))
98    }
99}
100
101/// Helper to decode a document digest in the format in which it
102/// appears in a given kind of routerstatus.
103trait FromRsString: Sized {
104    /// Try to decode the given object.
105    fn decode(s: &str) -> Result<Self>;
106}