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| {
330 let addr = addr.ip().to_canonical();
336
337 match addr {
338 IpAddr::V4(v4) => {
339 !(v4.is_loopback() || v4.is_private() || v4.is_unspecified() || v4.is_documentation() || v4.is_multicast() || v4.is_link_local()) }
346 IpAddr::V6(v6) => {
347 !(v6.is_loopback() || v6.is_multicast() || v6.is_unspecified() || v6.is_unique_local() || v6.is_unicast_link_local()) }
353 }
354 })
355 }
356
357 fn has_all_nonzero_port(&self) -> bool {
359 self.addrs().all(|addr| addr.port() != 0)
360 }
361}
362
363pub trait CircTarget: ChanTarget {
368 fn linkspecs(&self) -> tor_bytes::EncodeResult<Vec<crate::EncodedLinkSpec>> {
383 let mut result: Vec<_> = self.identities().map(|id| id.to_owned().into()).collect();
384 #[allow(irrefutable_let_patterns)]
385 if let ChannelMethod::Direct(addrs) = self.chan_method() {
386 result.extend(addrs.into_iter().map(crate::LinkSpec::from));
387 }
388 crate::LinkSpec::sort_by_type(&mut result[..]);
389 result.into_iter().map(|ls| ls.encode()).collect()
390 }
391 fn ntor_onion_key(&self) -> &pk::curve25519::PublicKey;
393 fn protovers(&self) -> &tor_protover::Protocols;
395}
396
397#[derive(Debug, Clone)]
400pub struct DisplayChanTarget<'a, T> {
401 inner: &'a T,
403}
404
405impl<'a, T: ChanTarget> DisplayChanTarget<'a, T> {
406 fn fmt_impl(&self, f: &mut fmt::Formatter<'_>, redact: bool) -> fmt::Result {
408 write!(f, "[")?;
409 match self.inner.chan_method() {
413 ChannelMethod::Direct(v) if v.is_empty() => write!(f, "?")?,
414 ChannelMethod::Direct(v) if v.len() == 1 => {
415 write!(f, "{}", v[0].maybe_redacted(redact))?;
416 }
417 ChannelMethod::Direct(v) => write!(f, "{}+", v[0].maybe_redacted(redact))?,
418 #[cfg(feature = "pt-client")]
419 ChannelMethod::Pluggable(target) => {
420 match target.addr() {
421 PtTargetAddr::None => {}
422 other => write!(f, "{} ", other.maybe_redacted(redact))?,
423 }
424 write!(f, "via {}", target.transport())?;
425 }
428 }
429
430 write!(f, " ")?;
431 self.inner.display_relay_ids().fmt_impl(f, redact)?;
432
433 write!(f, "]")
434 }
435}
436
437impl<'a, T: ChanTarget> fmt::Display for DisplayChanTarget<'a, T> {
438 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
439 self.fmt_impl(f, false)
440 }
441}
442
443impl<'a, T: ChanTarget + fmt::Debug> safelog::Redactable for DisplayChanTarget<'a, T> {
444 fn display_redacted(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
445 self.fmt_impl(f, true)
446 }
447 fn debug_redacted(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
448 write!(f, "ChanTarget({:?})", self.redacted().to_string())
449 }
450}
451
452#[cfg(test)]
453mod test {
454 #![allow(clippy::bool_assert_comparison)]
456 #![allow(clippy::clone_on_copy)]
457 #![allow(clippy::dbg_macro)]
458 #![allow(clippy::mixed_attributes_style)]
459 #![allow(clippy::print_stderr)]
460 #![allow(clippy::print_stdout)]
461 #![allow(clippy::single_char_pattern)]
462 #![allow(clippy::unwrap_used)]
463 #![allow(clippy::unchecked_time_subtraction)]
464 #![allow(clippy::useless_vec)]
465 #![allow(clippy::needless_pass_by_value)]
466 #![allow(clippy::string_slice)] use super::*;
469 use crate::{OwnedChanTarget, RelayIds};
470 use hex_literal::hex;
471 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
472 use tor_llcrypto::pk::{self, ed25519::Ed25519Identity, rsa::RsaIdentity};
473
474 struct Example {
475 addrs: Vec<SocketAddr>,
476 ed_id: pk::ed25519::Ed25519Identity,
477 rsa_id: pk::rsa::RsaIdentity,
478 ntor: pk::curve25519::PublicKey,
479 pv: tor_protover::Protocols,
480 }
481 impl HasAddrs for Example {
482 fn addrs(&self) -> impl Iterator<Item = SocketAddr> {
483 self.addrs.iter().copied()
484 }
485 }
486 impl DirectChanMethodsHelper for Example {}
487 impl HasRelayIdsLegacy for Example {
488 fn ed_identity(&self) -> &pk::ed25519::Ed25519Identity {
489 &self.ed_id
490 }
491 fn rsa_identity(&self) -> &pk::rsa::RsaIdentity {
492 &self.rsa_id
493 }
494 }
495 impl ChanTarget for Example {}
496 impl CircTarget for Example {
497 fn ntor_onion_key(&self) -> &pk::curve25519::PublicKey {
498 &self.ntor
499 }
500 fn protovers(&self) -> &tor_protover::Protocols {
501 &self.pv
502 }
503 }
504
505 fn example() -> Example {
507 Example {
508 addrs: vec![
509 "127.0.0.1:99".parse::<SocketAddr>().unwrap(),
510 "[::1]:909".parse::<SocketAddr>().unwrap(),
511 ],
512 ed_id: pk::ed25519::PublicKey::from_bytes(&hex!(
513 "fc51cd8e6218a1a38da47ed00230f058
514 0816ed13ba3303ac5deb911548908025"
515 ))
516 .unwrap()
517 .into(),
518 rsa_id: pk::rsa::RsaIdentity::from_bytes(&hex!(
519 "1234567890abcdef12341234567890abcdef1234"
520 ))
521 .unwrap(),
522 ntor: pk::curve25519::PublicKey::from(hex!(
523 "e6db6867583030db3594c1a424b15f7c
524 726624ec26b3353b10a903a6d0ab1c4c"
525 )),
526 pv: tor_protover::Protocols::default(),
527 }
528 }
529
530 #[test]
531 fn test_linkspecs() {
532 let ex = example();
533 let specs = ex
534 .linkspecs()
535 .unwrap()
536 .into_iter()
537 .map(|ls| ls.parse())
538 .collect::<Result<Vec<_>, _>>()
539 .unwrap();
540 assert_eq!(4, specs.len());
541
542 use crate::ls::LinkSpec;
543 assert_eq!(
544 specs[0],
545 LinkSpec::OrPort("127.0.0.1".parse::<IpAddr>().unwrap(), 99)
546 );
547 assert_eq!(
548 specs[1],
549 LinkSpec::RsaId(
550 pk::rsa::RsaIdentity::from_bytes(&hex!("1234567890abcdef12341234567890abcdef1234"))
551 .unwrap()
552 )
553 );
554 assert_eq!(
555 specs[2],
556 LinkSpec::Ed25519Id(
557 pk::ed25519::PublicKey::from_bytes(&hex!(
558 "fc51cd8e6218a1a38da47ed00230f058
559 0816ed13ba3303ac5deb911548908025"
560 ))
561 .unwrap()
562 .into()
563 )
564 );
565 assert_eq!(
566 specs[3],
567 LinkSpec::OrPort("::1".parse::<IpAddr>().unwrap(), 909)
568 );
569 }
570
571 #[test]
572 fn cmp_by_ids() {
573 use crate::RelayIds;
574 use std::cmp::Ordering;
575 fn b(ed: Option<Ed25519Identity>, rsa: Option<RsaIdentity>) -> RelayIds {
576 let mut b = RelayIds::builder();
577 if let Some(ed) = ed {
578 b.ed_identity(ed);
579 }
580 if let Some(rsa) = rsa {
581 b.rsa_identity(rsa);
582 }
583 b.build().unwrap()
584 }
585 fn assert_sorted(v: &[RelayIds]) {
587 for slice in v.windows(2) {
588 assert_eq!(slice[0].cmp_by_relay_ids(&slice[1]), Ordering::Less);
589 assert_eq!(slice[1].cmp_by_relay_ids(&slice[0]), Ordering::Greater);
590 assert_eq!(slice[0].cmp_by_relay_ids(&slice[0]), Ordering::Equal);
591 }
592 }
593
594 let ed1 = hex!("0a54686973206973207468652043656e7472616c205363727574696e697a6572").into();
595 let ed2 = hex!("6962696c69747920746f20656e666f72636520616c6c20746865206c6177730a").into();
596 let ed3 = hex!("73736564207965740a497420697320616c736f206d7920726573706f6e736962").into();
597 let rsa1 = hex!("2e2e2e0a4974206973206d7920726573706f6e73").into();
598 let rsa2 = hex!("5468617420686176656e2774206265656e207061").into();
599 let rsa3 = hex!("696c69747920746f20616c65727420656163680a").into();
600
601 assert_sorted(&[
602 b(Some(ed1), None),
603 b(Some(ed2), None),
604 b(Some(ed3), None),
605 b(Some(ed3), Some(rsa1)),
606 ]);
607 assert_sorted(&[
608 b(Some(ed1), Some(rsa3)),
609 b(Some(ed2), Some(rsa2)),
610 b(Some(ed3), Some(rsa1)),
611 b(Some(ed3), Some(rsa2)),
612 ]);
613 assert_sorted(&[
614 b(Some(ed1), Some(rsa1)),
615 b(Some(ed1), Some(rsa2)),
616 b(Some(ed1), Some(rsa3)),
617 ]);
618 assert_sorted(&[
619 b(None, Some(rsa1)),
620 b(None, Some(rsa2)),
621 b(None, Some(rsa3)),
622 ]);
623 assert_sorted(&[
624 b(None, Some(rsa1)),
625 b(Some(ed1), None),
626 b(Some(ed1), Some(rsa1)),
627 ]);
628 }
629
630 #[test]
631 fn compare_id_sets() {
632 let ed1 = hex!("0a54686973206973207468652043656e7472616c205363727574696e697a6572").into();
634 let rsa1 = hex!("2e2e2e0a4974206973206d7920726573706f6e73").into();
635 let rsa2 = RsaIdentity::from(hex!("5468617420686176656e2774206265656e207061"));
636
637 let both1 = RelayIds::builder()
638 .ed_identity(ed1)
639 .rsa_identity(rsa1)
640 .build()
641 .unwrap();
642 let mixed = RelayIds::builder()
643 .ed_identity(ed1)
644 .rsa_identity(rsa2)
645 .build()
646 .unwrap();
647 let ed1 = RelayIds::builder().ed_identity(ed1).build().unwrap();
648 let rsa1 = RelayIds::builder().rsa_identity(rsa1).build().unwrap();
649 let rsa2 = RelayIds::builder().rsa_identity(rsa2).build().unwrap();
650
651 fn chk_equal(v: &impl HasRelayIds) {
652 assert!(v.same_relay_ids(v));
653 assert!(v.has_all_relay_ids_from(v));
654 assert!(v.has_any_relay_id_from(v));
655 }
656 fn chk_strict_subset(bigger: &impl HasRelayIds, smaller: &impl HasRelayIds) {
657 assert!(!bigger.same_relay_ids(smaller));
658 assert!(bigger.has_all_relay_ids_from(smaller));
659 assert!(bigger.has_any_relay_id_from(smaller));
660 assert!(!smaller.same_relay_ids(bigger));
661 assert!(!smaller.has_all_relay_ids_from(bigger));
662 assert!(smaller.has_any_relay_id_from(bigger));
663 }
664 fn chk_nontrivially_overlapping_one_way(a: &impl HasRelayIds, b: &impl HasRelayIds) {
665 assert!(!a.same_relay_ids(b));
666 assert!(!a.has_all_relay_ids_from(b));
667 assert!(a.has_any_relay_id_from(b));
668 }
669 fn chk_nontrivially_overlapping(a: &impl HasRelayIds, b: &impl HasRelayIds) {
670 chk_nontrivially_overlapping_one_way(a, b);
671 chk_nontrivially_overlapping_one_way(b, a);
672 }
673
674 chk_equal(&ed1);
675 chk_equal(&rsa1);
676 chk_equal(&both1);
677
678 chk_strict_subset(&both1, &ed1);
679 chk_strict_subset(&both1, &rsa1);
680 chk_strict_subset(&mixed, &ed1);
681 chk_strict_subset(&mixed, &rsa2);
682
683 chk_nontrivially_overlapping(&both1, &mixed);
684 }
685
686 #[test]
687 fn display() {
688 let e1 = example();
689 assert_eq!(
690 e1.display_chan_target().to_string(),
691 "[127.0.0.1:99+ ed25519:/FHNjmIYoaONpH7QAjDwWAgW7RO6MwOsXeuRFUiQgCU \
692 $1234567890abcdef12341234567890abcdef1234]"
693 );
694
695 #[cfg(feature = "pt-client")]
696 {
697 use crate::PtTarget;
698
699 let rsa = hex!("234461644a6f6b6523436f726e794f6e4d61696e").into();
700 let mut b = crate::OwnedChanTarget::builder();
701 b.ids().rsa_identity(rsa);
702 let e2 = b
703 .method(ChannelMethod::Pluggable(PtTarget::new(
704 "obfs4".parse().unwrap(),
705 "127.0.0.1:99".parse().unwrap(),
706 )))
707 .build()
708 .unwrap();
709 assert_eq!(
710 e2.to_string(),
711 "[127.0.0.1:99 via obfs4 $234461644a6f6b6523436f726e794f6e4d61696e]"
712 );
713 }
714 }
715
716 #[test]
717 fn has_id() {
718 use crate::RelayIds;
719 assert!(example().has_any_identity());
720 assert!(!RelayIds::empty().has_any_identity());
721 }
722
723 #[test]
724 fn allowed_for_outgoing_channels() {
725 fn build_target(addrs: &[SocketAddr]) -> OwnedChanTarget {
726 OwnedChanTarget::builder()
727 .addrs(addrs.to_vec())
728 .build()
729 .unwrap()
730 }
731
732 fn to_mapped(addr: &SocketAddrV4) -> SocketAddrV6 {
734 SocketAddrV6::new(addr.ip().to_ipv6_mapped(), addr.port(), 0, 0)
735 }
736
737 let localhost_v4 = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 1234);
739 let localhost_v4_mapped = to_mapped(&localhost_v4);
740 let localhost_v6 = SocketAddrV6::new(Ipv6Addr::LOCALHOST, 1234, 0, 0);
741 let unspecified_v4 = SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 1234);
742 let unspecified_v4_mapped = to_mapped(&unspecified_v4);
743 let unspecified_v6 = SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 1234, 0, 0);
744 let private_v4 = SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 1), 1234);
745 let private_v4_mapped = to_mapped(&private_v4);
746
747 let not_allowed = [
748 localhost_v4.into(),
749 localhost_v6.into(),
750 unspecified_v4.into(),
751 unspecified_v6.into(),
752 private_v4.into(),
753 localhost_v4_mapped.into(),
754 unspecified_v4_mapped.into(),
755 private_v4_mapped.into(),
756 ];
757
758 let google_dns_v4 = SocketAddrV4::new(Ipv4Addr::new(8, 8, 8, 8), 1234);
760 let google_dns_v4_mapped = to_mapped(&google_dns_v4);
761
762 let allowed = [google_dns_v4.into(), google_dns_v4_mapped.into()];
763
764 let target = build_target(&[]);
765 assert!(target.all_addrs_allowed_for_outgoing_channels());
766
767 for addr in not_allowed {
768 let target = build_target(&[addr]);
769 assert!(
770 !target.all_addrs_allowed_for_outgoing_channels(),
771 "addr: {addr}",
772 );
773 }
774
775 for addr in allowed {
776 let target = build_target(&[addr]);
777 assert!(
778 target.all_addrs_allowed_for_outgoing_channels(),
779 "addr: {addr}",
780 );
781 }
782
783 let target = build_target(&[google_dns_v4.into(), google_dns_v4_mapped.into()]);
786 assert!(target.all_addrs_allowed_for_outgoing_channels());
787
788 let target = build_target(&[google_dns_v4.into(), localhost_v4_mapped.into()]);
789 assert!(!target.all_addrs_allowed_for_outgoing_channels());
790
791 let target = build_target(&[localhost_v4.into(), localhost_v4_mapped.into()]);
792 assert!(!target.all_addrs_allowed_for_outgoing_channels());
793 }
794}