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
#[cfg(feature = "plain-consensus")]
10
pub(crate) mod plain;
11
#[cfg(feature = "ns-vote")]
12
pub(crate) mod vote;
13

            
14
use super::{ConsensusFlavor, ConsensusMethods};
15
use crate::doc::netstatus::NetstatusKwd;
16
use crate::doc::netstatus::{IgnoredPublicationTimeSp, Protocols, RelayWeight};
17
use crate::parse::parser::Section;
18
use crate::types::misc::*;
19
use crate::types::relay_flags::{self, DocRelayFlags, RelayFlag, RelayFlags};
20
use crate::types::version::TorVersion;
21
use crate::{Error, NetdocErrorKind as EK, Result};
22
use itertools::chain;
23
use std::sync::Arc;
24
use std::{net, time};
25
use tor_basic_utils::intern::InternCache;
26
use tor_error::internal;
27
use tor_llcrypto::pk::rsa::RsaIdentity;
28

            
29
#[cfg(feature = "parse2")]
30
use {
31
    super::consensus_methods_comma_separated, //
32
    derive_deftly::Deftly,
33
};
34

            
35
/// A version as presented in a router status.
36
///
37
/// This can either be a parsed Tor version, or an unparsed string.
38
//
39
// TODO: This might want to merge, at some point, with routerdesc::RelayPlatform.
40
#[derive(Clone, Debug, Eq, PartialEq, Hash, derive_more::Display)]
41
#[non_exhaustive]
42
pub enum SoftwareVersion {
43
    /// A Tor version
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
static OTHER_VERSION_CACHE: InternCache<str> = InternCache::new();
54

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

            
82
    /// The various hashes of this document.
83
    pub digests: Vec<IdentifiedDigest>,
84
}
85

            
86
impl std::str::FromStr for SoftwareVersion {
87
    type Err = Error;
88

            
89
1962
    fn from_str(s: &str) -> Result<Self> {
90
1962
        let mut elts = s.splitn(3, ' ');
91
1962
        if elts.next() == Some("Tor") {
92
1958
            if let Some(Ok(v)) = elts.next().map(str::parse) {
93
1958
                return Ok(SoftwareVersion::CTor(v));
94
            }
95
4
        }
96

            
97
4
        Ok(SoftwareVersion::Other(OTHER_VERSION_CACHE.intern_ref(s)))
98
1962
    }
99
}
100

            
101
/// Helper to decode a document digest in the format in which it
102
/// appears in a given kind of routerstatus.
103
trait FromRsString: Sized {
104
    /// Try to decode the given object.
105
    fn decode(s: &str) -> Result<Self>;
106
}