1use derive_deftly::derive_deftly_adhoc;
5use itertools::Itertools;
6use safelog::Redactable;
7use std::{
8 fmt,
9 iter::FusedIterator,
10 net::{IpAddr, SocketAddr},
11};
12use tor_llcrypto::pk;
13
14use crate::{ChannelMethod, RelayIdRef, RelayIdType, RelayIdTypeIter};
15
16#[cfg(feature = "pt-client")]
17use crate::PtTargetAddr;
18
19pub trait HasRelayIdsLegacy {
24 fn ed_identity(&self) -> &pk::ed25519::Ed25519Identity;
26 fn rsa_identity(&self) -> &pk::rsa::RsaIdentity;
28}
29
30pub trait HasRelayIds {
36 fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>>;
42
43 fn identities(&self) -> RelayIdIter<'_, Self> {
45 RelayIdIter {
46 info: self,
47 next_key: RelayIdType::all_types(),
48 }
49 }
50
51 fn ed_identity(&self) -> Option<&pk::ed25519::Ed25519Identity> {
53 self.identity(RelayIdType::Ed25519)
54 .map(RelayIdRef::unwrap_ed25519)
55 }
56
57 fn rsa_identity(&self) -> Option<&pk::rsa::RsaIdentity> {
59 self.identity(RelayIdType::Rsa).map(RelayIdRef::unwrap_rsa)
60 }
61
62 fn has_identity(&self, id: RelayIdRef<'_>) -> bool {
71 self.identity(id.id_type()).map(|my_id| my_id == id) == Some(true)
72 }
73
74 fn has_any_identity(&self) -> bool {
76 RelayIdType::all_types().any(|id_type| self.identity(id_type).is_some())
77 }
78
79 #[allow(clippy::nonminimal_bool)] fn same_relay_ids<T: HasRelayIds + ?Sized>(&self, other: &T) -> bool {
91 derive_deftly_adhoc! {
122 RelayIdType:
123 $(
124 self.identity($vtype) == other.identity($vtype) &&
125 )
126 true
127 }
128 }
129
130 fn has_all_relay_ids_from<T: HasRelayIds + ?Sized>(&self, other: &T) -> bool {
135 RelayIdType::all_types().all(|key_type| {
136 match (self.identity(key_type), other.identity(key_type)) {
137 (Some(mine), Some(theirs)) if mine == theirs => true,
139 (_, Some(_theirs)) => false,
141 (_, None) => true,
143 }
144 })
145 }
146
147 fn has_any_relay_id_from<T: HasRelayIds + ?Sized>(&self, other: &T) -> bool {
152 RelayIdType::all_types()
153 .filter_map(|key_type| Some((self.identity(key_type)?, other.identity(key_type)?)))
154 .any(|(self_id, other_id)| self_id == other_id)
155 }
156
157 fn cmp_by_relay_ids<T: HasRelayIds + ?Sized>(&self, other: &T) -> std::cmp::Ordering {
166 for key_type in RelayIdType::all_types() {
167 let ordering = Ord::cmp(&self.identity(key_type), &other.identity(key_type));
168 if ordering.is_ne() {
169 return ordering;
170 }
171 }
172 std::cmp::Ordering::Equal
173 }
174
175 fn display_relay_ids(&self) -> DisplayRelayIds<'_, Self> {
178 DisplayRelayIds { inner: self }
179 }
180}
181
182impl<T: HasRelayIdsLegacy> HasRelayIds for T {
183 fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>> {
184 match key_type {
185 RelayIdType::Rsa => Some(self.rsa_identity().into()),
186 RelayIdType::Ed25519 => Some(self.ed_identity().into()),
187 }
188 }
189}
190
191#[derive(Clone)]
194pub struct DisplayRelayIds<'a, T: HasRelayIds + ?Sized> {
195 inner: &'a T,
197}
198impl<'a, T: HasRelayIds + ?Sized> fmt::Debug for DisplayRelayIds<'a, T> {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 f.debug_struct("DisplayRelayIds").finish_non_exhaustive()
202 }
203}
204
205impl<'a, T: HasRelayIds + ?Sized> DisplayRelayIds<'a, T> {
206 fn fmt_impl(&self, f: &mut fmt::Formatter<'_>, redact: bool) -> fmt::Result {
208 let mut iter = self.inner.identities();
209 if let Some(ident) = iter.next() {
210 write!(f, "{}", ident.maybe_redacted(redact))?;
211 }
212 if redact {
213 return Ok(());
214 }
215 for ident in iter {
216 write!(f, " {}", ident.maybe_redacted(redact))?;
217 }
218 Ok(())
219 }
220}
221impl<'a, T: HasRelayIds + ?Sized> fmt::Display for DisplayRelayIds<'a, T> {
222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223 self.fmt_impl(f, false)
224 }
225}
226impl<'a, T: HasRelayIds + ?Sized> Redactable for DisplayRelayIds<'a, T> {
227 fn display_redacted(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 self.fmt_impl(f, true)
229 }
230}
231
232#[derive(Clone)]
234pub struct RelayIdIter<'a, T: HasRelayIds + ?Sized> {
235 info: &'a T,
237 next_key: RelayIdTypeIter,
239}
240
241impl<'a, T: HasRelayIds + ?Sized> Iterator for RelayIdIter<'a, T> {
242 type Item = RelayIdRef<'a>;
243
244 fn next(&mut self) -> Option<Self::Item> {
245 for key_type in &mut self.next_key {
246 if let Some(key) = self.info.identity(key_type) {
247 return Some(key);
248 }
249 }
250 None
251 }
252}
253impl<'a, T: HasRelayIds + ?Sized> FusedIterator for RelayIdIter<'a, T> {}
255
256pub trait HasAddrs {
258 fn addrs(&self) -> impl Iterator<Item = SocketAddr>;
274}
275
276impl<T: HasAddrs> HasAddrs for &T {
277 fn addrs(&self) -> impl Iterator<Item = SocketAddr> {
278 <T as HasAddrs>::addrs(self)
280 }
281}
282
283pub trait HasChanMethod {
285 fn chan_method(&self) -> ChannelMethod;
290}
291
292pub trait DirectChanMethodsHelper: HasAddrs {}
296
297impl<D: DirectChanMethodsHelper> HasChanMethod for D {
298 fn chan_method(&self) -> ChannelMethod {
299 ChannelMethod::Direct(self.addrs().collect_vec())
300 }
301}
302
303pub trait ChanTarget: HasRelayIds + HasAddrs + HasChanMethod {
309 fn display_chan_target(&self) -> DisplayChanTarget<'_, Self>
315 where
316 Self: Sized,
317 {
318 DisplayChanTarget { inner: self }
319 }
320
321 fn all_addrs_allowed_for_outgoing_channels(&self) -> bool {
329 self.addrs().all(|addr| match addr.ip() {
330 IpAddr::V4(v4) => {
331 !(v4.is_loopback() || v4.is_private() || v4.is_unspecified() || v4.is_documentation() || v4.is_multicast() || v4.is_link_local()) }
338 IpAddr::V6(v6) => {
339 !(v6.is_loopback() || v6.is_multicast() || v6.is_unspecified() || v6.is_unique_local() || v6.is_unicast_link_local()) }
345 })
346 }
347
348 fn has_all_nonzero_port(&self) -> bool {
350 self.addrs().all(|addr| addr.port() != 0)
351 }
352}
353
354pub trait CircTarget: ChanTarget {
359 fn linkspecs(&self) -> tor_bytes::EncodeResult<Vec<crate::EncodedLinkSpec>> {
374 let mut result: Vec<_> = self.identities().map(|id| id.to_owned().into()).collect();
375 #[allow(irrefutable_let_patterns)]
376 if let ChannelMethod::Direct(addrs) = self.chan_method() {
377 result.extend(addrs.into_iter().map(crate::LinkSpec::from));
378 }
379 crate::LinkSpec::sort_by_type(&mut result[..]);
380 result.into_iter().map(|ls| ls.encode()).collect()
381 }
382 fn ntor_onion_key(&self) -> &pk::curve25519::PublicKey;
384 fn protovers(&self) -> &tor_protover::Protocols;
386}
387
388#[derive(Debug, Clone)]
391pub struct DisplayChanTarget<'a, T> {
392 inner: &'a T,
394}
395
396impl<'a, T: ChanTarget> DisplayChanTarget<'a, T> {
397 fn fmt_impl(&self, f: &mut fmt::Formatter<'_>, redact: bool) -> fmt::Result {
399 write!(f, "[")?;
400 match self.inner.chan_method() {
404 ChannelMethod::Direct(v) if v.is_empty() => write!(f, "?")?,
405 ChannelMethod::Direct(v) if v.len() == 1 => {
406 write!(f, "{}", v[0].maybe_redacted(redact))?;
407 }
408 ChannelMethod::Direct(v) => write!(f, "{}+", v[0].maybe_redacted(redact))?,
409 #[cfg(feature = "pt-client")]
410 ChannelMethod::Pluggable(target) => {
411 match target.addr() {
412 PtTargetAddr::None => {}
413 other => write!(f, "{} ", other.maybe_redacted(redact))?,
414 }
415 write!(f, "via {}", target.transport())?;
416 }
419 }
420
421 write!(f, " ")?;
422 self.inner.display_relay_ids().fmt_impl(f, redact)?;
423
424 write!(f, "]")
425 }
426}
427
428impl<'a, T: ChanTarget> fmt::Display for DisplayChanTarget<'a, T> {
429 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
430 self.fmt_impl(f, false)
431 }
432}
433
434impl<'a, T: ChanTarget + fmt::Debug> safelog::Redactable for DisplayChanTarget<'a, T> {
435 fn display_redacted(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
436 self.fmt_impl(f, true)
437 }
438 fn debug_redacted(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
439 write!(f, "ChanTarget({:?})", self.redacted().to_string())
440 }
441}
442
443#[cfg(test)]
444mod test {
445 #![allow(clippy::bool_assert_comparison)]
447 #![allow(clippy::clone_on_copy)]
448 #![allow(clippy::dbg_macro)]
449 #![allow(clippy::mixed_attributes_style)]
450 #![allow(clippy::print_stderr)]
451 #![allow(clippy::print_stdout)]
452 #![allow(clippy::single_char_pattern)]
453 #![allow(clippy::unwrap_used)]
454 #![allow(clippy::unchecked_time_subtraction)]
455 #![allow(clippy::useless_vec)]
456 #![allow(clippy::needless_pass_by_value)]
457 use super::*;
459 use crate::RelayIds;
460 use hex_literal::hex;
461 use std::net::IpAddr;
462 use tor_llcrypto::pk::{self, ed25519::Ed25519Identity, rsa::RsaIdentity};
463
464 struct Example {
465 addrs: Vec<SocketAddr>,
466 ed_id: pk::ed25519::Ed25519Identity,
467 rsa_id: pk::rsa::RsaIdentity,
468 ntor: pk::curve25519::PublicKey,
469 pv: tor_protover::Protocols,
470 }
471 impl HasAddrs for Example {
472 fn addrs(&self) -> impl Iterator<Item = SocketAddr> {
473 self.addrs.iter().copied()
474 }
475 }
476 impl DirectChanMethodsHelper for Example {}
477 impl HasRelayIdsLegacy for Example {
478 fn ed_identity(&self) -> &pk::ed25519::Ed25519Identity {
479 &self.ed_id
480 }
481 fn rsa_identity(&self) -> &pk::rsa::RsaIdentity {
482 &self.rsa_id
483 }
484 }
485 impl ChanTarget for Example {}
486 impl CircTarget for Example {
487 fn ntor_onion_key(&self) -> &pk::curve25519::PublicKey {
488 &self.ntor
489 }
490 fn protovers(&self) -> &tor_protover::Protocols {
491 &self.pv
492 }
493 }
494
495 fn example() -> Example {
497 Example {
498 addrs: vec![
499 "127.0.0.1:99".parse::<SocketAddr>().unwrap(),
500 "[::1]:909".parse::<SocketAddr>().unwrap(),
501 ],
502 ed_id: pk::ed25519::PublicKey::from_bytes(&hex!(
503 "fc51cd8e6218a1a38da47ed00230f058
504 0816ed13ba3303ac5deb911548908025"
505 ))
506 .unwrap()
507 .into(),
508 rsa_id: pk::rsa::RsaIdentity::from_bytes(&hex!(
509 "1234567890abcdef12341234567890abcdef1234"
510 ))
511 .unwrap(),
512 ntor: pk::curve25519::PublicKey::from(hex!(
513 "e6db6867583030db3594c1a424b15f7c
514 726624ec26b3353b10a903a6d0ab1c4c"
515 )),
516 pv: tor_protover::Protocols::default(),
517 }
518 }
519
520 #[test]
521 fn test_linkspecs() {
522 let ex = example();
523 let specs = ex
524 .linkspecs()
525 .unwrap()
526 .into_iter()
527 .map(|ls| ls.parse())
528 .collect::<Result<Vec<_>, _>>()
529 .unwrap();
530 assert_eq!(4, specs.len());
531
532 use crate::ls::LinkSpec;
533 assert_eq!(
534 specs[0],
535 LinkSpec::OrPort("127.0.0.1".parse::<IpAddr>().unwrap(), 99)
536 );
537 assert_eq!(
538 specs[1],
539 LinkSpec::RsaId(
540 pk::rsa::RsaIdentity::from_bytes(&hex!("1234567890abcdef12341234567890abcdef1234"))
541 .unwrap()
542 )
543 );
544 assert_eq!(
545 specs[2],
546 LinkSpec::Ed25519Id(
547 pk::ed25519::PublicKey::from_bytes(&hex!(
548 "fc51cd8e6218a1a38da47ed00230f058
549 0816ed13ba3303ac5deb911548908025"
550 ))
551 .unwrap()
552 .into()
553 )
554 );
555 assert_eq!(
556 specs[3],
557 LinkSpec::OrPort("::1".parse::<IpAddr>().unwrap(), 909)
558 );
559 }
560
561 #[test]
562 fn cmp_by_ids() {
563 use crate::RelayIds;
564 use std::cmp::Ordering;
565 fn b(ed: Option<Ed25519Identity>, rsa: Option<RsaIdentity>) -> RelayIds {
566 let mut b = RelayIds::builder();
567 if let Some(ed) = ed {
568 b.ed_identity(ed);
569 }
570 if let Some(rsa) = rsa {
571 b.rsa_identity(rsa);
572 }
573 b.build().unwrap()
574 }
575 fn assert_sorted(v: &[RelayIds]) {
577 for slice in v.windows(2) {
578 assert_eq!(slice[0].cmp_by_relay_ids(&slice[1]), Ordering::Less);
579 assert_eq!(slice[1].cmp_by_relay_ids(&slice[0]), Ordering::Greater);
580 assert_eq!(slice[0].cmp_by_relay_ids(&slice[0]), Ordering::Equal);
581 }
582 }
583
584 let ed1 = hex!("0a54686973206973207468652043656e7472616c205363727574696e697a6572").into();
585 let ed2 = hex!("6962696c69747920746f20656e666f72636520616c6c20746865206c6177730a").into();
586 let ed3 = hex!("73736564207965740a497420697320616c736f206d7920726573706f6e736962").into();
587 let rsa1 = hex!("2e2e2e0a4974206973206d7920726573706f6e73").into();
588 let rsa2 = hex!("5468617420686176656e2774206265656e207061").into();
589 let rsa3 = hex!("696c69747920746f20616c65727420656163680a").into();
590
591 assert_sorted(&[
592 b(Some(ed1), None),
593 b(Some(ed2), None),
594 b(Some(ed3), None),
595 b(Some(ed3), Some(rsa1)),
596 ]);
597 assert_sorted(&[
598 b(Some(ed1), Some(rsa3)),
599 b(Some(ed2), Some(rsa2)),
600 b(Some(ed3), Some(rsa1)),
601 b(Some(ed3), Some(rsa2)),
602 ]);
603 assert_sorted(&[
604 b(Some(ed1), Some(rsa1)),
605 b(Some(ed1), Some(rsa2)),
606 b(Some(ed1), Some(rsa3)),
607 ]);
608 assert_sorted(&[
609 b(None, Some(rsa1)),
610 b(None, Some(rsa2)),
611 b(None, Some(rsa3)),
612 ]);
613 assert_sorted(&[
614 b(None, Some(rsa1)),
615 b(Some(ed1), None),
616 b(Some(ed1), Some(rsa1)),
617 ]);
618 }
619
620 #[test]
621 fn compare_id_sets() {
622 let ed1 = hex!("0a54686973206973207468652043656e7472616c205363727574696e697a6572").into();
624 let rsa1 = hex!("2e2e2e0a4974206973206d7920726573706f6e73").into();
625 let rsa2 = RsaIdentity::from(hex!("5468617420686176656e2774206265656e207061"));
626
627 let both1 = RelayIds::builder()
628 .ed_identity(ed1)
629 .rsa_identity(rsa1)
630 .build()
631 .unwrap();
632 let mixed = RelayIds::builder()
633 .ed_identity(ed1)
634 .rsa_identity(rsa2)
635 .build()
636 .unwrap();
637 let ed1 = RelayIds::builder().ed_identity(ed1).build().unwrap();
638 let rsa1 = RelayIds::builder().rsa_identity(rsa1).build().unwrap();
639 let rsa2 = RelayIds::builder().rsa_identity(rsa2).build().unwrap();
640
641 fn chk_equal(v: &impl HasRelayIds) {
642 assert!(v.same_relay_ids(v));
643 assert!(v.has_all_relay_ids_from(v));
644 assert!(v.has_any_relay_id_from(v));
645 }
646 fn chk_strict_subset(bigger: &impl HasRelayIds, smaller: &impl HasRelayIds) {
647 assert!(!bigger.same_relay_ids(smaller));
648 assert!(bigger.has_all_relay_ids_from(smaller));
649 assert!(bigger.has_any_relay_id_from(smaller));
650 assert!(!smaller.same_relay_ids(bigger));
651 assert!(!smaller.has_all_relay_ids_from(bigger));
652 assert!(smaller.has_any_relay_id_from(bigger));
653 }
654 fn chk_nontrivially_overlapping_one_way(a: &impl HasRelayIds, b: &impl HasRelayIds) {
655 assert!(!a.same_relay_ids(b));
656 assert!(!a.has_all_relay_ids_from(b));
657 assert!(a.has_any_relay_id_from(b));
658 }
659 fn chk_nontrivially_overlapping(a: &impl HasRelayIds, b: &impl HasRelayIds) {
660 chk_nontrivially_overlapping_one_way(a, b);
661 chk_nontrivially_overlapping_one_way(b, a);
662 }
663
664 chk_equal(&ed1);
665 chk_equal(&rsa1);
666 chk_equal(&both1);
667
668 chk_strict_subset(&both1, &ed1);
669 chk_strict_subset(&both1, &rsa1);
670 chk_strict_subset(&mixed, &ed1);
671 chk_strict_subset(&mixed, &rsa2);
672
673 chk_nontrivially_overlapping(&both1, &mixed);
674 }
675
676 #[test]
677 fn display() {
678 let e1 = example();
679 assert_eq!(
680 e1.display_chan_target().to_string(),
681 "[127.0.0.1:99+ ed25519:/FHNjmIYoaONpH7QAjDwWAgW7RO6MwOsXeuRFUiQgCU \
682 $1234567890abcdef12341234567890abcdef1234]"
683 );
684
685 #[cfg(feature = "pt-client")]
686 {
687 use crate::PtTarget;
688
689 let rsa = hex!("234461644a6f6b6523436f726e794f6e4d61696e").into();
690 let mut b = crate::OwnedChanTarget::builder();
691 b.ids().rsa_identity(rsa);
692 let e2 = b
693 .method(ChannelMethod::Pluggable(PtTarget::new(
694 "obfs4".parse().unwrap(),
695 "127.0.0.1:99".parse().unwrap(),
696 )))
697 .build()
698 .unwrap();
699 assert_eq!(
700 e2.to_string(),
701 "[127.0.0.1:99 via obfs4 $234461644a6f6b6523436f726e794f6e4d61696e]"
702 );
703 }
704 }
705
706 #[test]
707 fn has_id() {
708 use crate::RelayIds;
709 assert!(example().has_any_identity());
710 assert!(!RelayIds::empty().has_any_identity());
711 }
712}