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")]
7
pub(crate) mod build;
8
pub(crate) mod md;
9
pub(crate) mod plain;
10
pub(crate) mod vote;
11

            
12
use super::{ConsensusFlavor, ConsensusMethods, consensus_methods_comma_separated};
13
use crate::doc::netstatus::{
14
    IgnoredPublicationTimeSp, NetParams, NetstatusKwd, Protocols, RelayWeight, RelayWeightsItem,
15
};
16
use crate::encode::{EncodeOrd, ItemEncoder};
17
use crate::parse::parser::Section;
18
use crate::parse2::ItemArgumentParseable;
19
use crate::types::misc::*;
20
use crate::types::policy::PortPolicy;
21
use crate::types::relay_flags::{self, DocRelayFlags, RelayFlag, RelayFlags};
22
use crate::types::version::TorVersion;
23
use crate::{Error, NetdocErrorKind as EK, Result};
24
use derive_deftly::Deftly;
25
use itertools::chain;
26
use std::cmp::Ordering;
27
use std::{net, time};
28
use tor_basic_utils::intern::{Intern, InternCache};
29
use tor_error::{Bug, internal};
30
use tor_llcrypto::pk::rsa::RsaIdentity;
31

            
32
/// A version as presented in a router status.
33
///
34
/// This can either be a parsed Tor version, or an unparsed string.
35
//
36
// TODO: This might want to merge, at some point, with routerdesc::RelayPlatform.
37
#[derive(Clone, Debug, Eq, PartialEq, Hash, derive_more::Display)]
38
#[non_exhaustive]
39
pub enum SoftwareVersion {
40
    /// A Tor version
41
    #[display("Tor {_0}")]
42
    CTor(TorVersion),
43
    /// A string we couldn't parse.
44
    Other(Intern<str>),
45
}
46

            
47
/// A cache of unparsable version strings.
48
///
49
/// We use this because we expect there not to be very many distinct versions of
50
/// relay software in existence.
51
// TODO DIRAUTH: Improve the caching here.
52
static OTHER_VERSION_CACHE: InternCache<str> = InternCache::new();
53

            
54
/// `m` item in votes
55
///
56
/// <https://spec.torproject.org/dir-spec/consensus-formats.html#item:m>
57
///
58
/// This is different to the `m` line in microdesc consensuses.
59
/// Plain consensuses don't have `m` lines at all.
60
///
61
/// ### Non-invariants
62
///
63
///  * There may be overlapping or even contradictory information.
64
///  * It might not be sorted.
65
///    Users of the structure who need to emit reproducible document encodings.
66
///    must sort it.
67
///  * These non-invariants apply both within one instance of this struct,
68
///    and across multiple instances of it within a `RouterStatus`.
69
#[derive(Debug, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Deftly)]
70
#[derive_deftly(ItemValueEncodable, ItemValueParseable)]
71
#[non_exhaustive]
72
pub struct RouterStatusMdDigestsVote {
73
    /// The methods for which this document is applicable.
74
    #[deftly(netdoc(with = consensus_methods_comma_separated))]
75
    pub consensus_methods: ConsensusMethods,
76

            
77
    /// The various hashes of this document.
78
    pub digests: Vec<IdentifiedDigest>,
79
}
80

            
81
impl std::str::FromStr for SoftwareVersion {
82
    type Err = Error;
83

            
84
2632
    fn from_str(s: &str) -> Result<Self> {
85
2632
        let mut elts = s.splitn(3, ' ');
86
2632
        if elts.next() == Some("Tor") {
87
2628
            if let Some(Ok(v)) = elts.next().map(str::parse) {
88
2628
                return Ok(SoftwareVersion::CTor(v));
89
            }
90
4
        }
91

            
92
4
        Ok(SoftwareVersion::Other(OTHER_VERSION_CACHE.intern_ref(s)))
93
2632
    }
94
}
95

            
96
/// Helper to decode a document digest in the format in which it
97
/// appears in a given kind of routerstatus.
98
trait FromRsString: Sized {
99
    /// Try to decode the given object.
100
    fn decode(s: &str) -> Result<Self>;
101
}