tor_netdoc/doc/netstatus/rs/
each_flavor.rs1use super::*;
14
15impl RouterStatus {
16 pub fn addrs(&self) -> impl Iterator<Item = net::SocketAddr> {
18 chain!(
19 [std::net::SocketAddrV4::new(self.r.ip, self.r.or_port).into()],
20 self.a.iter().copied(),
21 )
22 }
23 pub fn weight(&self) -> &RelayWeight {
25 &self.weight
26 }
27 pub fn protovers(&self) -> &Protocols {
29 &self.protos
30 }
31 pub fn nickname(&self) -> &str {
33 self.r.nickname.as_str()
34 }
35 pub fn flags(&self) -> &RelayFlags {
37 &self.flags.known
38 }
39 pub fn version(&self) -> Option<&crate::doc::netstatus::rs::SoftwareVersion> {
41 self.version.as_ref()
42 }
43 pub fn ed25519_id_is_usable(&self) -> bool {
46 !self.flags.contains(RelayFlag::NoEdConsensus)
47 }
48 pub fn is_flagged_bad_exit(&self) -> bool {
50 self.flags.contains(RelayFlag::BadExit)
51 }
52 pub fn is_flagged_v2dir(&self) -> bool {
54 self.flags.contains(RelayFlag::V2Dir)
55 }
56 pub fn is_flagged_exit(&self) -> bool {
58 self.flags.contains(RelayFlag::Exit)
59 }
60 pub fn is_flagged_guard(&self) -> bool {
62 self.flags.contains(RelayFlag::Guard)
63 }
64 pub fn is_flagged_hsdir(&self) -> bool {
66 self.flags.contains(RelayFlag::HSDir)
67 }
68 pub fn is_flagged_stable(&self) -> bool {
70 self.flags.contains(RelayFlag::Stable)
71 }
72 pub fn is_flagged_fast(&self) -> bool {
74 self.flags.contains(RelayFlag::Fast)
75 }
76 pub fn is_flagged_middle_only(&self) -> bool {
78 self.flags.contains(RelayFlag::MiddleOnly)
79 }
80}
81
82impl RouterStatus {
83 pub fn rsa_identity(&self) -> &RsaIdentity {
85 &self.r.identity
86 }
87
88 pub(crate) fn flavor() -> ConsensusFlavor {
91 FLAVOR
92 }
93
94 pub(crate) fn from_section(sec: &Section<'_, NetstatusKwd>) -> Result<RouterStatus> {
99 use NetstatusKwd::*;
100 let r_item = sec.required(RS_R)?;
102 let nickname = r_item.required_arg(0)?.parse().map_err(|e: InvalidNickname| {
103 EK::BadArgument.with_msg(e.to_string()).at_pos(r_item.pos())
104 })?;
105 let ident = r_item.required_arg(1)?;
106 let identity = ident.parse::<Base64Fingerprint>()?;
107 let n_skip = match FLAVOR {
109 ConsensusFlavor::Microdesc => 0,
110 ConsensusFlavor::Plain => 1,
111 };
112 let _ignore_published: time::SystemTime = {
115 let mut p = r_item.required_arg(2 + n_skip)?.to_string();
120 p.push(' ');
121 p.push_str(r_item.required_arg(3 + n_skip)?);
122 p.parse::<Iso8601TimeSp>()?.into()
123 };
124 let ip = r_item.required_arg(4 + n_skip)?.parse::<net::Ipv4Addr>()?;
125 let or_port = r_item.required_arg(5 + n_skip)?.parse::<u16>()?;
126 let _ = r_item.required_arg(6 + n_skip)?.parse::<u16>()?;
127
128 let a_items = sec.slice(RS_A);
130 let a = a_items
131 .iter()
132 .map(|a_item| Ok(a_item.required_arg(0)?.parse::<net::SocketAddr>()?))
133 .collect::<Result<Vec<_>>>()?;
134
135 let flags = DocRelayFlags::from_item_consensus(sec.required(RS_S)?)?;
139
140 let version = sec.maybe(RS_V).args_as_str().map(str::parse).transpose()?;
142
143 let protos = {
145 let tok = sec.required(RS_PR)?;
146 tok.args_as_str()
147 .parse::<Protocols>()
148 .map_err(|e| EK::BadArgument.at_pos(tok.pos()).with_source(e))?
149 };
150
151 let weight = sec
153 .get(RS_W)
154 .map(RelayWeight::from_item)
155 .transpose()?
156 .unwrap_or_default();
157
158 let doc_digest: DocDigest = match FLAVOR {
164 ConsensusFlavor::Microdesc => {
165 let m_item = sec.required(RS_M)?;
167 DocDigest::decode(m_item.required_arg(0)?)?
168 }
169 ConsensusFlavor::Plain => DocDigest::decode(r_item.required_arg(2)?)?,
170 };
171
172 ns_choose! { (
173 let r_doc_digest = doc_digest;
174 let m_doc_digest = NotPresent;
175 ) (
176 let r_doc_digest = NotPresent;
177 let m_doc_digest = doc_digest;
178 ) (
179 let r_doc_digest = doc_digest;
180 let m_doc_digest = NotPresent;
181 ) };
182
183 Ok(RouterStatus {
184 r: RouterStatusIntroItem {
185 nickname,
186 identity,
187 or_port,
188 doc_digest: r_doc_digest,
189 publication: IgnoredPublicationTimeSp,
190 ip,
191 },
192 m: m_doc_digest,
193 a,
194 flags,
195 version,
196 protos,
197 weight,
198 })
199 }
200}
201
202impl FromRsString for DocDigest {
203 fn decode(s: &str) -> Result<DocDigest> {
204 s.parse::<B64>()?
205 .check_len(DOC_DIGEST_LEN..=DOC_DIGEST_LEN)?
206 .as_bytes()
207 .try_into()
208 .map_err(|_| Error::from(internal!("correct length on digest, but unable to convert")))
209 }
210}