1use crate::parse::keyword::Keyword;
36use crate::parse::parser::{Section, SectionRules};
37use crate::parse::tokenize::{ItemResult, NetDocReader};
38use crate::types::family::{RelayFamily, RelayFamilyId};
39use crate::types::misc::*;
40use crate::types::policy::*;
41use crate::types::version::TorVersion;
42use crate::util::PeekableIterator;
43use crate::{AllowAnnotations, Error, NetdocErrorKind as EK, Result, doc};
44
45use ll::pk::ed25519::Ed25519Identity;
46use std::sync::Arc;
47use std::sync::LazyLock;
48use std::{net, time};
49use tor_cert::CertType;
50use tor_checkable::{Timebound, signed, timed};
51use tor_error::{internal, into_internal};
52use tor_llcrypto as ll;
53use tor_llcrypto::pk::rsa::RsaIdentity;
54
55use digest::Digest;
56
57pub const DOC_DIGEST_LEN: usize = 20;
59
60pub type RdDigest = [u8; DOC_DIGEST_LEN];
62
63#[non_exhaustive]
65pub struct AnnotatedRouterDesc {
66 pub ann: RouterAnnotation,
68 pub router: UncheckedRouterDesc,
70}
71
72#[derive(Default)]
74#[non_exhaustive]
75pub struct RouterAnnotation {
76 pub source: Option<String>,
78 pub downloaded: Option<time::SystemTime>,
80 pub purpose: Option<String>,
82}
83
84#[derive(Clone, Debug)]
98#[non_exhaustive]
99pub struct RouterDesc {
100 pub nickname: Nickname,
104 pub ipv4addr: Option<net::Ipv4Addr>,
106 pub orport: u16,
108 pub ipv6addr: Option<(net::Ipv6Addr, u16)>,
113 pub dirport: u16,
116 pub uptime: Option<u64>,
118 pub published: time::SystemTime,
120 pub identity_cert: tor_cert::Ed25519Cert,
123 pub rsa_identity_key: ll::pk::rsa::PublicKey,
126 pub rsa_identity: ll::pk::rsa::RsaIdentity,
129 pub ntor_onion_key: ll::pk::curve25519::PublicKey,
131 pub tap_onion_key: Option<ll::pk::rsa::PublicKey>,
134 pub proto: Arc<tor_protover::Protocols>,
136 pub is_dircache: bool,
138 pub is_extrainfo_cache: bool,
140 pub family: Arc<RelayFamily>,
143 family_ids: Vec<RelayFamilyId>,
146 pub platform: Option<RelayPlatform>,
148 pub ipv4_policy: AddrPolicy,
153 pub ipv6_policy: Arc<PortPolicy>,
156}
157
158#[derive(Debug, Clone, PartialEq, Eq)]
160#[non_exhaustive]
161pub enum RelayPlatform {
162 Tor(TorVersion, String),
164 Other(String),
166}
167
168impl std::str::FromStr for RelayPlatform {
169 type Err = Error;
170 fn from_str(args: &str) -> Result<Self> {
171 if args.starts_with("Tor ") {
172 let v: Vec<_> = args.splitn(4, ' ').collect();
173 match &v[..] {
174 ["Tor", ver, "on", p] => Ok(RelayPlatform::Tor(ver.parse()?, (*p).to_string())),
175 ["Tor", ver, ..] => Ok(RelayPlatform::Tor(ver.parse()?, "".to_string())),
176 _ => unreachable!(),
177 }
178 } else {
179 Ok(RelayPlatform::Other(args.to_string()))
180 }
181 }
182}
183
184decl_keyword! {
185 RouterKwd {
188 annotation "@source" => ANN_SOURCE,
189 annotation "@downloaded-at" => ANN_DOWNLOADED_AT,
190 annotation "@purpose" => ANN_PURPOSE,
191 "accept" | "reject" => POLICY,
192 "bandwidth" => BANDWIDTH,
193 "bridge-distribution-request" => BRIDGE_DISTRIBUTION_REQUEST,
194 "caches-extra-info" => CACHES_EXTRA_INFO,
195 "contact" => CONTACT,
196 "extra-info-digest" => EXTRA_INFO_DIGEST,
197 "family" => FAMILY,
198 "family-cert" => FAMILY_CERT,
199 "fingerprint" => FINGERPRINT,
200 "hibernating" => HIBERNATING,
201 "identity-ed25519" => IDENTITY_ED25519,
202 "ipv6-policy" => IPV6_POLICY,
203 "master-key-ed25519" => MASTER_KEY_ED25519,
204 "ntor-onion-key" => NTOR_ONION_KEY,
205 "ntor-onion-key-crosscert" => NTOR_ONION_KEY_CROSSCERT,
206 "onion-key" => ONION_KEY,
207 "onion-key-crosscert" => ONION_KEY_CROSSCERT,
208 "or-address" => OR_ADDRESS,
209 "platform" => PLATFORM,
210 "proto" => PROTO,
211 "published" => PUBLISHED,
212 "router" => ROUTER,
213 "router-sig-ed25519" => ROUTER_SIG_ED25519,
214 "router-signature" => ROUTER_SIGNATURE,
215 "signing-key" => SIGNING_KEY,
216 "tunnelled_dir_server" => TUNNELLED_DIR_SERVER,
217 "uptime" => UPTIME,
218 }
222}
223
224static ROUTER_ANNOTATIONS: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
226 use RouterKwd::*;
227
228 let mut rules = SectionRules::builder();
229 rules.add(ANN_SOURCE.rule());
230 rules.add(ANN_DOWNLOADED_AT.rule().args(1..));
231 rules.add(ANN_PURPOSE.rule().args(1..));
232 rules.add(ANN_UNRECOGNIZED.rule().may_repeat().obj_optional());
233 rules.reject_unrecognized();
236 rules.build()
237});
238static ROUTER_HEADER_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
241 use RouterKwd::*;
242
243 let mut rules = SectionRules::builder();
244 rules.add(ROUTER.rule().required().args(5..));
245 rules.add(IDENTITY_ED25519.rule().required().no_args().obj_required());
246 rules.reject_unrecognized();
248 rules.build()
249});
250static ROUTER_BODY_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
253 use RouterKwd::*;
254
255 let mut rules = SectionRules::builder();
256 rules.add(MASTER_KEY_ED25519.rule().required().args(1..));
257 rules.add(PLATFORM.rule());
258 rules.add(PUBLISHED.rule().required());
259 rules.add(FINGERPRINT.rule());
260 rules.add(UPTIME.rule().args(1..));
261 rules.add(ONION_KEY.rule().no_args().obj_required());
262 rules.add(ONION_KEY_CROSSCERT.rule().no_args().obj_required());
263 rules.add(NTOR_ONION_KEY.rule().required().args(1..));
264 rules.add(
265 NTOR_ONION_KEY_CROSSCERT
266 .rule()
267 .required()
268 .args(1..=1)
269 .obj_required(),
270 );
271 rules.add(SIGNING_KEY.rule().no_args().required().obj_required());
272 rules.add(POLICY.rule().may_repeat().args(1..));
273 rules.add(IPV6_POLICY.rule().args(2..));
274 rules.add(FAMILY.rule().args(1..));
275 rules.add(FAMILY_CERT.rule().obj_required().may_repeat());
276 rules.add(CACHES_EXTRA_INFO.rule().no_args());
277 rules.add(OR_ADDRESS.rule().may_repeat().args(1..));
278 rules.add(TUNNELLED_DIR_SERVER.rule());
279 rules.add(PROTO.rule().required().args(1..));
280 rules.add(UNRECOGNIZED.rule().may_repeat().obj_optional());
281 {
283 rules.add(BANDWIDTH.rule().required().args(3..));
284 rules.add(BRIDGE_DISTRIBUTION_REQUEST.rule().args(1..));
285 rules.add(HIBERNATING.rule().args(1..));
286 rules.add(CONTACT.rule());
287 }
288 {
290 rules.add(EXTRA_INFO_DIGEST.rule().args(1..));
291 }
292 rules.build()
293});
294
295static ROUTER_SIG_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
297 use RouterKwd::*;
298
299 let mut rules = SectionRules::builder();
300 rules.add(ROUTER_SIG_ED25519.rule().required().args(1..));
301 rules.add(ROUTER_SIGNATURE.rule().required().no_args().obj_required());
302 rules.reject_unrecognized();
304 rules.build()
305});
306
307impl RouterAnnotation {
308 fn take_from_reader(reader: &mut NetDocReader<'_, RouterKwd>) -> Result<RouterAnnotation> {
310 use RouterKwd::*;
311 let mut items = reader.pause_at(|item| item.is_ok_with_non_annotation());
312
313 let body = ROUTER_ANNOTATIONS.parse(&mut items)?;
314
315 let source = body.maybe(ANN_SOURCE).args_as_str().map(String::from);
316 let purpose = body.maybe(ANN_PURPOSE).args_as_str().map(String::from);
317 let downloaded = body
318 .maybe(ANN_DOWNLOADED_AT)
319 .parse_args_as_str::<Iso8601TimeSp>()?
320 .map(|t| t.into());
321 Ok(RouterAnnotation {
322 source,
323 downloaded,
324 purpose,
325 })
326 }
327}
328
329pub type UncheckedRouterDesc = signed::SignatureGated<timed::TimerangeBound<RouterDesc>>;
332
333const ROUTER_EXPIRY_SECONDS: u64 = 5 * 86400;
336
337const ROUTER_PRE_VALIDITY_SECONDS: u64 = 86400;
343
344impl RouterDesc {
345 pub fn rsa_identity(&self) -> &RsaIdentity {
347 &self.rsa_identity
348 }
349
350 pub fn ed_identity(&self) -> &Ed25519Identity {
352 self.identity_cert
353 .signing_key()
354 .expect("No ed25519 identity key on identity cert")
355 }
356
357 pub fn protocols(&self) -> &tor_protover::Protocols {
360 self.proto.as_ref()
361 }
362
363 pub fn ntor_onion_key(&self) -> &ll::pk::curve25519::PublicKey {
365 &self.ntor_onion_key
366 }
367
368 pub fn published(&self) -> time::SystemTime {
370 self.published
371 }
372
373 pub fn or_ports(&self) -> impl Iterator<Item = net::SocketAddr> + '_ {
376 self.ipv4addr
377 .map(|a| net::SocketAddr::new(a.into(), self.orport))
378 .into_iter()
379 .chain(self.ipv6addr.map(net::SocketAddr::from))
380 }
381
382 pub fn family(&self) -> Arc<RelayFamily> {
384 Arc::clone(&self.family)
385 }
386
387 pub fn family_ids(&self) -> &[RelayFamilyId] {
389 &self.family_ids[..]
390 }
391
392 fn parse_sections<'a>(
394 reader: &mut NetDocReader<'a, RouterKwd>,
395 ) -> Result<(
396 Section<'a, RouterKwd>,
397 Section<'a, RouterKwd>,
398 Section<'a, RouterKwd>,
399 )> {
400 use RouterKwd::*;
401
402 let header = ROUTER_HEADER_RULES.parse(
404 reader.pause_at(|item| item.is_ok_with_kwd_not_in(&[ROUTER, IDENTITY_ED25519])),
405 )?;
406
407 let body =
409 ROUTER_BODY_RULES.parse(reader.pause_at(|item| {
410 item.is_ok_with_kwd_in(&[ROUTER_SIGNATURE, ROUTER_SIG_ED25519])
411 }))?;
412
413 let sig = ROUTER_SIG_RULES.parse(reader.pause_at(|item| {
415 item.is_ok_with_annotation() || item.is_ok_with_kwd(ROUTER) || item.is_empty_line()
416 }))?;
417
418 Ok((header, body, sig))
419 }
420
421 pub fn parse(s: &str) -> Result<UncheckedRouterDesc> {
426 let mut reader = crate::parse::tokenize::NetDocReader::new(s)?;
427 let result = Self::parse_internal(&mut reader).map_err(|e| e.within(s))?;
428 reader
431 .should_be_exhausted_but_for_empty_lines()
432 .map_err(|e| e.within(s))?;
433 Ok(result)
434 }
435
436 fn parse_internal(r: &mut NetDocReader<'_, RouterKwd>) -> Result<UncheckedRouterDesc> {
442 use RouterKwd::*;
445
446 let s = r.str();
447 let (header, body, sig) = RouterDesc::parse_sections(r)?;
448
449 #[allow(clippy::unwrap_used)]
452 let start_offset = header.required(ROUTER)?.offset_in(s).unwrap();
453
454 let (identity_cert, ed25519_signing_key) = {
456 let cert_tok = header.required(IDENTITY_ED25519)?;
457 #[allow(clippy::unwrap_used)]
460 if cert_tok.offset_in(s).unwrap() < start_offset {
461 return Err(EK::MisplacedToken
462 .with_msg("identity-ed25519")
463 .at_pos(cert_tok.pos()));
464 }
465 let cert: tor_cert::UncheckedCert = cert_tok
466 .parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
467 .check_cert_type(tor_cert::CertType::IDENTITY_V_SIGNING)?
468 .into_unchecked()
469 .should_have_signing_key()
470 .map_err(|err| {
471 EK::BadObjectVal
472 .err()
473 .with_source(err)
474 .at_pos(cert_tok.pos())
475 })?;
476 let sk = *cert.peek_subject_key().as_ed25519().ok_or_else(|| {
477 EK::BadObjectVal
478 .at_pos(cert_tok.pos())
479 .with_msg("wrong type for signing key in cert")
480 })?;
481 let sk: ll::pk::ed25519::PublicKey = sk.try_into().map_err(|_| {
482 EK::BadObjectVal
483 .at_pos(cert_tok.pos())
484 .with_msg("invalid ed25519 signing key")
485 })?;
486 (cert, sk)
487 };
488
489 #[allow(unexpected_cfgs)]
491 {
492 let master_key_tok = body.required(MASTER_KEY_ED25519)?;
493 let ed_id: Ed25519Public = master_key_tok.parse_arg(0)?;
494 let ed_id: ll::pk::ed25519::Ed25519Identity = ed_id.into();
495 if ed_id != *identity_cert.peek_signing_key() {
496 #[cfg(not(fuzzing))] return Err(EK::BadObjectVal
498 .at_pos(master_key_tok.pos())
499 .with_msg("master-key-ed25519 does not match key in identity-ed25519"));
500 }
501 }
502
503 let rsa_identity_key: ll::pk::rsa::PublicKey = body
505 .required(SIGNING_KEY)?
506 .parse_obj::<RsaPublic>("RSA PUBLIC KEY")?
507 .check_len_eq(1024)?
508 .check_exponent(65537)?
509 .into();
510 let rsa_identity = rsa_identity_key.to_rsa_identity();
511
512 let ed_sig = sig.required(ROUTER_SIG_ED25519)?;
513 let rsa_sig = sig.required(ROUTER_SIGNATURE)?;
514 #[allow(clippy::unwrap_used)]
517 let ed_sig_pos = ed_sig.offset_in(s).unwrap();
518 #[allow(clippy::unwrap_used)]
519 let rsa_sig_pos = rsa_sig.offset_in(s).unwrap();
520
521 if ed_sig_pos > rsa_sig_pos {
522 return Err(EK::UnexpectedToken
523 .with_msg(ROUTER_SIG_ED25519.to_str())
524 .at_pos(ed_sig.pos()));
525 }
526
527 let ed_signature: ll::pk::ed25519::ValidatableEd25519Signature = {
529 let mut d = ll::d::Sha256::new();
530 d.update(&b"Tor router descriptor signature v1"[..]);
531 let signed_end = ed_sig_pos + b"router-sig-ed25519 ".len();
532 d.update(&s[start_offset..signed_end]);
533 let d = d.finalize();
534 let sig: [u8; 64] = ed_sig
535 .parse_arg::<B64>(0)?
536 .into_array()
537 .map_err(|_| EK::BadSignature.at_pos(ed_sig.pos()))?;
538 let sig = ll::pk::ed25519::Signature::from(sig);
539 ll::pk::ed25519::ValidatableEd25519Signature::new(ed25519_signing_key, sig, &d)
540 };
541
542 let rsa_signature: ll::pk::rsa::ValidatableRsaSignature = {
544 let mut d = ll::d::Sha1::new();
545 let signed_end = rsa_sig_pos + b"router-signature\n".len();
546 d.update(&s[start_offset..signed_end]);
547 let d = d.finalize();
548 let sig = rsa_sig.obj("SIGNATURE")?;
549 ll::pk::rsa::ValidatableRsaSignature::new(&rsa_identity_key, &sig, &d)
552 };
553
554 let (nickname, ipv4addr, orport, dirport) = {
556 let rtrline = header.required(ROUTER)?;
557 (
558 rtrline.parse_arg::<Nickname>(0)?,
559 Some(rtrline.parse_arg::<net::Ipv4Addr>(1)?),
560 rtrline.parse_arg(2)?,
561 rtrline.parse_arg(4)?,
563 )
564 };
565
566 let uptime = body.maybe(UPTIME).parse_arg(0)?;
568
569 let published = body
571 .required(PUBLISHED)?
572 .args_as_str()
573 .parse::<Iso8601TimeSp>()?
574 .into();
575
576 let ntor_onion_key: Curve25519Public = body.required(NTOR_ONION_KEY)?.parse_arg(0)?;
578 let ntor_onion_key: ll::pk::curve25519::PublicKey = ntor_onion_key.into();
579 let crosscert_cert: tor_cert::UncheckedCert = {
581 let cc = body.required(NTOR_ONION_KEY_CROSSCERT)?;
582 let sign: u8 = cc.parse_arg(0)?;
583 if sign != 0 && sign != 1 {
584 return Err(EK::BadArgument.at_pos(cc.arg_pos(0)).with_msg("not 0 or 1"));
585 }
586 let ntor_as_ed: ll::pk::ed25519::PublicKey =
587 ll::pk::keymanip::convert_curve25519_to_ed25519_public(&ntor_onion_key, sign)
588 .ok_or_else(|| {
589 EK::BadArgument
590 .at_pos(cc.pos())
591 .with_msg("Uncheckable crosscert")
592 })?;
593
594 cc.parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
595 .check_cert_type(tor_cert::CertType::NTOR_CC_IDENTITY)?
596 .check_subject_key_is(identity_cert.peek_signing_key())?
597 .into_unchecked()
598 .should_be_signed_with(&ntor_as_ed.into())
599 .map_err(|err| EK::BadSignature.err().with_source(err))?
600 };
601
602 let tap_onion_key: Option<ll::pk::rsa::PublicKey> = if let Some(tok) = body.get(ONION_KEY) {
604 Some(
605 tok.parse_obj::<RsaPublic>("RSA PUBLIC KEY")?
606 .check_len_eq(1024)?
607 .check_exponent(65537)?
608 .into(),
609 )
610 } else {
611 None
612 };
613
614 let tap_crosscert_sig = if let Some(cc_tok) = body.get(ONION_KEY_CROSSCERT) {
616 let cc_val = cc_tok.obj("CROSSCERT")?;
617 let mut signed = Vec::new();
618 signed.extend(rsa_identity.as_bytes());
619 signed.extend(identity_cert.peek_signing_key().as_bytes());
620 Some(ll::pk::rsa::ValidatableRsaSignature::new(
621 tap_onion_key.as_ref().ok_or_else(|| {
622 EK::MissingToken.with_msg("onion-key-crosscert without onion-key")
623 })?,
624 &cc_val,
625 &signed,
626 ))
627 } else if tap_onion_key.is_some() {
628 return Err(EK::MissingToken.with_msg("onion-key without onion-key-crosscert"));
629 } else {
630 None
631 };
632
633 let proto = {
635 let proto_tok = body.required(PROTO)?;
636 doc::PROTOVERS_CACHE.intern(
637 proto_tok
638 .args_as_str()
639 .parse::<tor_protover::Protocols>()
640 .map_err(|e| EK::BadArgument.at_pos(proto_tok.pos()).with_source(e))?,
641 )
642 };
643
644 let is_dircache = (dirport != 0) || body.get(TUNNELLED_DIR_SERVER).is_some();
646
647 let is_extrainfo_cache = body.get(CACHES_EXTRA_INFO).is_some();
649
650 if let Some(fp_tok) = body.get(FINGERPRINT) {
652 let fp: RsaIdentity = fp_tok.args_as_str().parse::<SpFingerprint>()?.into();
653 if fp != rsa_identity {
654 return Err(EK::BadArgument
655 .at_pos(fp_tok.pos())
656 .with_msg("fingerprint does not match RSA identity"));
657 }
658 }
659
660 let family = {
662 let mut family = body
663 .maybe(FAMILY)
664 .parse_args_as_str::<RelayFamily>()?
665 .unwrap_or_else(RelayFamily::new);
666 if !family.is_empty() {
667 family.push(rsa_identity);
673 }
674 family.intern()
675 };
676
677 let family_certs: Vec<tor_cert::UncheckedCert> = body
679 .slice(FAMILY_CERT)
680 .iter()
681 .map(|ent| {
682 ent.parse_obj::<UnvalidatedEdCert>("FAMILY CERT")?
683 .check_cert_type(CertType::FAMILY_V_IDENTITY)?
684 .check_subject_key_is(identity_cert.peek_signing_key())?
685 .into_unchecked()
686 .should_have_signing_key()
687 .map_err(|e| {
688 EK::BadObjectVal
689 .with_msg("missing public key")
690 .at_pos(ent.pos())
691 .with_source(e)
692 })
693 })
694 .collect::<Result<_>>()?;
695
696 let mut family_ids: Vec<_> = family_certs
697 .iter()
698 .map(|cert| RelayFamilyId::Ed25519(*cert.peek_signing_key()))
699 .collect();
700 family_ids.sort();
701 family_ids.dedup();
702
703 let mut ipv6addr = None;
707 for tok in body.slice(OR_ADDRESS) {
708 if let Ok(net::SocketAddr::V6(a)) = tok.parse_arg::<net::SocketAddr>(0) {
709 ipv6addr = Some((*a.ip(), a.port()));
710 break;
711 }
712 }
714
715 let platform = body.maybe(PLATFORM).parse_args_as_str::<RelayPlatform>()?;
717
718 let ipv4_policy = {
720 let mut pol = AddrPolicy::new();
721 for ruletok in body.slice(POLICY).iter() {
722 let accept = match ruletok.kwd_str() {
723 "accept" => RuleKind::Accept,
724 "reject" => RuleKind::Reject,
725 _ => {
726 return Err(Error::from(internal!(
727 "tried to parse a strange line as a policy"
728 ))
729 .at_pos(ruletok.pos()));
730 }
731 };
732 let pat: AddrPortPattern = ruletok
733 .args_as_str()
734 .parse()
735 .map_err(|e| EK::BadPolicy.at_pos(ruletok.pos()).with_source(e))?;
736 pol.push(accept, pat);
737 }
738 pol
739 };
740
741 let ipv6_policy = match body.get(IPV6_POLICY) {
743 Some(p) => p
744 .args_as_str()
745 .parse()
746 .map_err(|e| EK::BadPolicy.at_pos(p.pos()).with_source(e))?,
747 #[allow(clippy::unwrap_used)]
749 None => "reject 1-65535".parse::<PortPolicy>().unwrap(),
750 };
751
752 let (identity_cert, identity_sig) = identity_cert.dangerously_split().map_err(|err| {
754 EK::BadObjectVal
755 .with_msg("missing public key")
756 .with_source(err)
757 })?;
758 let (crosscert_cert, cc_sig) = crosscert_cert.dangerously_split().map_err(|err| {
759 EK::BadObjectVal
760 .with_msg("missing public key")
761 .with_source(err)
762 })?;
763 let mut signatures: Vec<Box<dyn ll::pk::ValidatableSignature>> = vec![
764 Box::new(rsa_signature),
765 Box::new(ed_signature),
766 Box::new(identity_sig),
767 Box::new(cc_sig),
768 ];
769 if let Some(s) = tap_crosscert_sig {
770 signatures.push(Box::new(s));
771 }
772
773 let identity_cert = identity_cert.dangerously_assume_timely();
774 let crosscert_cert = crosscert_cert.dangerously_assume_timely();
775 let mut expirations = vec![
776 published + time::Duration::new(ROUTER_EXPIRY_SECONDS, 0),
777 identity_cert.expiry(),
778 crosscert_cert.expiry(),
779 ];
780
781 for cert in family_certs {
782 let (inner, sig) = cert.dangerously_split().map_err(into_internal!(
783 "Missing a public key that was previously there."
784 ))?;
785 signatures.push(Box::new(sig));
786 expirations.push(inner.dangerously_assume_timely().expiry());
787 }
788
789 #[allow(clippy::unwrap_used)]
791 let expiry = *expirations.iter().min().unwrap();
792
793 let start_time = published - time::Duration::new(ROUTER_PRE_VALIDITY_SECONDS, 0);
794
795 let desc = RouterDesc {
796 nickname,
797 ipv4addr,
798 orport,
799 ipv6addr,
800 dirport,
801 uptime,
802 published,
803 identity_cert,
804 rsa_identity_key,
805 rsa_identity,
806 ntor_onion_key,
807 tap_onion_key,
808 proto,
809 is_dircache,
810 is_extrainfo_cache,
811 family,
812 family_ids,
813 platform,
814 ipv4_policy,
815 ipv6_policy: ipv6_policy.intern(),
816 };
817
818 let time_gated = timed::TimerangeBound::new(desc, start_time..expiry);
819 let sig_gated = signed::SignatureGated::new(time_gated, signatures);
820
821 Ok(sig_gated)
822 }
823}
824
825pub struct RouterReader<'a> {
831 annotated: bool,
833 reader: NetDocReader<'a, RouterKwd>,
835}
836
837fn advance_to_next_routerdesc(reader: &mut NetDocReader<'_, RouterKwd>, annotated: bool) {
842 use RouterKwd::*;
843 loop {
844 let item = reader.peek();
845 match item {
846 Some(Ok(t)) => {
847 let kwd = t.kwd();
848 if (annotated && kwd.is_annotation()) || kwd == ROUTER {
849 return;
850 }
851 }
852 Some(Err(_)) => {
853 }
855 None => {
856 return;
857 }
858 }
859 let _ = reader.next();
860 }
861}
862
863impl<'a> RouterReader<'a> {
864 pub fn new(s: &'a str, allow: &AllowAnnotations) -> Result<Self> {
866 let reader = NetDocReader::new(s)?;
867 let annotated = allow == &AllowAnnotations::AnnotationsAllowed;
868 Ok(RouterReader { annotated, reader })
869 }
870
871 fn take_annotation(&mut self) -> Result<RouterAnnotation> {
873 if self.annotated {
874 RouterAnnotation::take_from_reader(&mut self.reader)
875 } else {
876 Ok(RouterAnnotation::default())
877 }
878 }
879
880 fn take_annotated_routerdesc_raw(&mut self) -> Result<AnnotatedRouterDesc> {
884 let ann = self.take_annotation()?;
885 let router = RouterDesc::parse_internal(&mut self.reader)?;
886 Ok(AnnotatedRouterDesc { ann, router })
887 }
888
889 fn take_annotated_routerdesc(&mut self) -> Result<AnnotatedRouterDesc> {
893 let pos_orig = self.reader.pos();
894 let result = self.take_annotated_routerdesc_raw();
895 if result.is_err() {
896 if self.reader.pos() == pos_orig {
897 let _ = self.reader.next();
905 }
906 advance_to_next_routerdesc(&mut self.reader, self.annotated);
907 }
908 result
909 }
910}
911
912impl<'a> Iterator for RouterReader<'a> {
913 type Item = Result<AnnotatedRouterDesc>;
914 fn next(&mut self) -> Option<Self::Item> {
915 self.reader.peek()?;
917
918 Some(
919 self.take_annotated_routerdesc()
920 .map_err(|e| e.within(self.reader.str())),
921 )
922 }
923}
924
925#[cfg(test)]
926mod test {
927 #![allow(clippy::bool_assert_comparison)]
929 #![allow(clippy::clone_on_copy)]
930 #![allow(clippy::dbg_macro)]
931 #![allow(clippy::mixed_attributes_style)]
932 #![allow(clippy::print_stderr)]
933 #![allow(clippy::print_stdout)]
934 #![allow(clippy::single_char_pattern)]
935 #![allow(clippy::unwrap_used)]
936 #![allow(clippy::unchecked_duration_subtraction)]
937 #![allow(clippy::useless_vec)]
938 #![allow(clippy::needless_pass_by_value)]
939 use super::*;
941 const TESTDATA: &str = include_str!("../../testdata/routerdesc1.txt");
942 const TESTDATA2: &str = include_str!("../../testdata/routerdesc2.txt");
943 const TESTDATA3: &str = include_str!("../../testdata/routerdesc3.txt");
945
946 fn read_bad(fname: &str) -> String {
947 use std::fs;
948 use std::path::PathBuf;
949 let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
950 path.push("testdata");
951 path.push("bad-routerdesc");
952 path.push(fname);
953
954 fs::read_to_string(path).unwrap()
955 }
956
957 #[test]
958 fn parse_arbitrary() -> Result<()> {
959 use std::str::FromStr;
960 use tor_checkable::{SelfSigned, Timebound};
961 let rd = RouterDesc::parse(TESTDATA)?
962 .check_signature()?
963 .dangerously_assume_timely();
964
965 assert_eq!(rd.nickname.as_str(), "Akka");
966 assert_eq!(rd.orport, 443);
967 assert_eq!(rd.dirport, 0);
968 assert_eq!(rd.uptime, Some(1036923));
969 assert_eq!(
970 rd.family.as_ref(),
971 &RelayFamily::from_str(
972 "$303509ab910ef207b7438c27435c4a2fd579f1b1 \
973 $56927e61b51e6f363fb55498150a6ddfcf7077f2"
974 )
975 .unwrap()
976 );
977
978 assert_eq!(
979 rd.rsa_identity().to_string(),
980 "$56927e61b51e6f363fb55498150a6ddfcf7077f2"
981 );
982 assert_eq!(
983 rd.ed_identity().to_string(),
984 "CVTjf1oeaL616hH+1+UvYZ8OgkwF3z7UMITvJzm5r7A"
985 );
986 assert_eq!(
987 rd.protocols().to_string(),
988 "Cons=1-2 Desc=1-2 DirCache=2 FlowCtrl=1-2 HSDir=2 \
989 HSIntro=4-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 \
990 Padding=2 Relay=1-4"
991 );
992
993 assert_eq!(
994 hex::encode(rd.ntor_onion_key().to_bytes()),
995 "329b3b52991613392e35d1a821dd6753e1210458ecc3337f7b7d39bfcf5da273"
996 );
997 assert_eq!(
998 rd.published(),
999 humantime::parse_rfc3339("2022-11-14T19:58:52Z").unwrap()
1000 );
1001 assert_eq!(
1002 rd.or_ports().collect::<Vec<_>>(),
1003 vec![
1004 "95.216.33.58:443".parse().unwrap(),
1005 "[2a01:4f9:2a:2145::2]:443".parse().unwrap(),
1006 ]
1007 );
1008 assert!(rd.tap_onion_key.is_some());
1009
1010 Ok(())
1011 }
1012
1013 #[test]
1014 fn parse_no_tap_key() -> Result<()> {
1015 use tor_checkable::{SelfSigned, Timebound};
1016 let rd = RouterDesc::parse(TESTDATA2)?
1017 .check_signature()?
1018 .dangerously_assume_timely();
1019 assert!(rd.tap_onion_key.is_none());
1020
1021 Ok(())
1022 }
1023
1024 #[test]
1025 fn test_bad() {
1026 use crate::Pos;
1027 use crate::types::policy::PolicyError;
1028 fn check(fname: &str, e: &Error) {
1029 let text = read_bad(fname);
1030 let rd = RouterDesc::parse(&text);
1031 assert!(rd.is_err());
1032 assert_eq!(&rd.err().unwrap(), e);
1033 }
1034
1035 check(
1036 "bad-sig-order",
1037 &EK::UnexpectedToken
1038 .with_msg("router-sig-ed25519")
1039 .at_pos(Pos::from_line(50, 1)),
1040 );
1041 check(
1042 "bad-start1",
1043 &EK::MisplacedToken
1044 .with_msg("identity-ed25519")
1045 .at_pos(Pos::from_line(1, 1)),
1046 );
1047 check("bad-start2", &EK::MissingToken.with_msg("identity-ed25519"));
1048 check(
1049 "mismatched-fp",
1050 &EK::BadArgument
1051 .at_pos(Pos::from_line(12, 1))
1052 .with_msg("fingerprint does not match RSA identity"),
1053 );
1054 check("no-ed-sk", &EK::MissingToken.with_msg("identity-ed25519"));
1055
1056 check(
1057 "bad-cc-sign",
1058 &EK::BadArgument
1059 .at_pos(Pos::from_line(34, 26))
1060 .with_msg("not 0 or 1"),
1061 );
1062 check(
1063 "bad-ipv6policy",
1064 &EK::BadPolicy
1065 .at_pos(Pos::from_line(43, 1))
1066 .with_source(PolicyError::InvalidPolicy),
1067 );
1068 check(
1069 "no-ed-id-key-in-cert",
1070 &EK::BadObjectVal
1071 .at_pos(Pos::from_line(2, 1))
1072 .with_source(tor_cert::CertError::MissingPubKey),
1073 );
1074 check(
1075 "non-ed-sk-in-cert",
1076 &EK::BadObjectVal
1077 .at_pos(Pos::from_line(2, 1))
1078 .with_msg("wrong type for signing key in cert"),
1079 );
1080 check(
1081 "bad-ed-sk-in-cert",
1082 &EK::BadObjectVal
1083 .at_pos(Pos::from_line(2, 1))
1084 .with_msg("invalid ed25519 signing key"),
1085 );
1086 check(
1087 "mismatched-ed-sk-in-cert",
1088 &EK::BadObjectVal
1089 .at_pos(Pos::from_line(8, 1))
1090 .with_msg("master-key-ed25519 does not match key in identity-ed25519"),
1091 );
1092 }
1093
1094 #[test]
1095 fn parse_multiple_annotated() {
1096 use crate::AllowAnnotations;
1097 let mut s = read_bad("bad-cc-sign");
1098 s += "\
1099@uploaded-at 2020-09-26 18:15:41
1100@source \"127.0.0.1\"
1101";
1102 s += TESTDATA;
1103 s += "\
1104@uploaded-at 2020-09-26 18:15:41
1105@source \"127.0.0.1\"
1106";
1107 s += &read_bad("mismatched-fp");
1108
1109 let rd = RouterReader::new(&s, &AllowAnnotations::AnnotationsAllowed).unwrap();
1110 let v: Vec<_> = rd.collect();
1111 assert!(v[0].is_err());
1112 assert!(v[1].is_ok());
1113 assert_eq!(
1114 v[1].as_ref().unwrap().ann.source,
1115 Some("\"127.0.0.1\"".to_string())
1116 );
1117 assert!(v[2].is_err());
1118 }
1119
1120 #[test]
1121 fn test_platform() {
1122 let p = "Tor 0.4.4.4-alpha on a flying bison".parse::<RelayPlatform>();
1123 assert!(p.is_ok());
1124 assert_eq!(
1125 p.unwrap(),
1126 RelayPlatform::Tor(
1127 "0.4.4.4-alpha".parse().unwrap(),
1128 "a flying bison".to_string()
1129 )
1130 );
1131
1132 let p = "Tor 0.4.4.4-alpha on".parse::<RelayPlatform>();
1133 assert!(p.is_ok());
1134
1135 let p = "Tor 0.4.4.4-alpha ".parse::<RelayPlatform>();
1136 assert!(p.is_ok());
1137 let p = "Tor 0.4.4.4-alpha".parse::<RelayPlatform>();
1138 assert!(p.is_ok());
1139
1140 let p = "arti 0.0.0".parse::<RelayPlatform>();
1141 assert!(p.is_ok());
1142 assert_eq!(p.unwrap(), RelayPlatform::Other("arti 0.0.0".to_string()));
1143 }
1144
1145 #[test]
1146 fn test_family_ids() -> Result<()> {
1147 use tor_checkable::{SelfSigned, Timebound};
1148 let rd = RouterDesc::parse(TESTDATA3)?
1149 .check_signature()?
1150 .dangerously_assume_timely();
1151
1152 assert_eq!(
1153 rd.family_ids(),
1154 &[
1155 "ed25519:7sToQRuge1bU2hS0CG0ViMndc4m82JhO4B4kdrQey80"
1156 .parse()
1157 .unwrap(),
1158 "ed25519:szHUS3ItRd9uk85b1UVnOZx1gg4B0266jCpbuIMNjcM"
1159 .parse()
1160 .unwrap(),
1161 ]
1162 );
1163
1164 Ok(())
1165 }
1166}