1pub(crate) mod halfcirc;
39
40#[cfg(feature = "hs-common")]
41pub mod handshake;
42#[cfg(not(feature = "hs-common"))]
43pub(crate) mod handshake;
44
45pub(crate) mod padding;
46
47pub(super) mod path;
48
49use crate::channel::Channel;
50use crate::circuit::circhop::{HopNegotiationType, HopSettings};
51use crate::circuit::{CircuitRxReceiver, celltypes::*};
52#[cfg(feature = "circ-padding-manual")]
53use crate::client::CircuitPadder;
54use crate::client::circuit::padding::{PaddingController, PaddingEventStream};
55use crate::client::reactor::{CircuitHandshake, CtrlCmd, CtrlMsg, Reactor};
56use crate::crypto::cell::HopNum;
57use crate::crypto::handshake::ntor_v3::NtorV3PublicKey;
58use crate::memquota::CircuitAccount;
59use crate::util::skew::ClockSkew;
60use crate::{Error, Result};
61use derive_deftly::Deftly;
62use educe::Educe;
63use path::HopDetail;
64use tor_cell::chancell::{
65 CircId,
66 msg::{self as chanmsg},
67};
68use tor_error::{bad_api_usage, internal, into_internal};
69use tor_linkspec::{CircTarget, LinkSpecType, OwnedChanTarget, RelayIdType};
70use tor_protover::named;
71use tor_rtcompat::DynTimeProvider;
72use web_time_compat::Instant;
73
74use crate::circuit::UniqId;
75
76use super::{ClientTunnel, TargetHop};
77
78use futures::channel::mpsc;
79use oneshot_fused_workaround as oneshot;
80
81use futures::FutureExt as _;
82use std::collections::HashMap;
83use std::sync::{Arc, Mutex};
84use tor_memquota::derive_deftly_template_HasMemoryCost;
85
86use crate::crypto::handshake::ntor::NtorPublicKey;
87
88pub use crate::crypto::binding::CircuitBinding;
89pub use path::{Path, PathEntry};
90
91pub use crate::circuit::CircParameters;
93
94pub use crate::util::timeout::TimeoutEstimator;
96
97#[derive(Debug, Deftly)]
100#[allow(unreachable_pub)] #[derive_deftly(HasMemoryCost)]
102#[derive_deftly(RestrictedChanMsgSet)]
103#[deftly(usage = "on an open client circuit")]
104pub(super) enum ClientCircChanMsg {
105 Relay(chanmsg::Relay),
108 Destroy(chanmsg::Destroy),
110 }
112
113#[derive(Debug)]
114pub struct ClientCirc {
157 pub(super) mutable: Arc<TunnelMutableState>,
159 unique_id: UniqId,
161 pub(super) control: mpsc::UnboundedSender<CtrlMsg>,
163 pub(super) command: mpsc::UnboundedSender<CtrlCmd>,
165 #[cfg_attr(not(feature = "experimental-api"), allow(dead_code))]
168 reactor_closed_rx: futures::future::Shared<oneshot::Receiver<void::Void>>,
169 #[cfg(test)]
171 circid: CircId,
172 pub(super) memquota: CircuitAccount,
174 pub(super) time_provider: DynTimeProvider,
176 pub(super) is_multi_path: bool,
186}
187
188#[derive(Debug, Default)]
208pub(super) struct TunnelMutableState(Mutex<HashMap<UniqId, Arc<MutableState>>>);
209
210impl TunnelMutableState {
211 pub(super) fn insert(&self, unique_id: UniqId, mutable: Arc<MutableState>) {
213 #[allow(unused)] let state = self
215 .0
216 .lock()
217 .expect("lock poisoned")
218 .insert(unique_id, mutable);
219
220 debug_assert!(state.is_none());
221 }
222
223 pub(super) fn remove(&self, unique_id: UniqId) {
225 #[allow(unused)] let state = self.0.lock().expect("lock poisoned").remove(&unique_id);
227
228 debug_assert!(state.is_some());
229 }
230
231 fn all_paths(&self) -> Vec<Arc<Path>> {
233 let lock = self.0.lock().expect("lock poisoned");
234 lock.values().map(|mutable| mutable.path()).collect()
235 }
236
237 #[cfg(feature = "rpc")]
243 pub(super) fn tagged_paths(&self) -> HashMap<UniqId, Arc<Path>> {
244 let lock = self.0.lock().expect("lock poisoned");
245 lock.iter()
246 .map(|(id, mutable)| (*id, mutable.path()))
247 .collect()
248 }
249
250 #[allow(unstable_name_collisions)]
258 fn single_path(&self) -> Result<Arc<Path>> {
259 use itertools::Itertools as _;
260
261 self.all_paths().into_iter().exactly_one().map_err(|_| {
262 bad_api_usage!("requested the single path of a multi-path tunnel?!").into()
263 })
264 }
265
266 fn first_hop(&self, unique_id: UniqId) -> Result<Option<OwnedChanTarget>> {
271 let lock = self.0.lock().expect("lock poisoned");
272 let mutable = lock
273 .get(&unique_id)
274 .ok_or_else(|| bad_api_usage!("no circuit with unique ID {unique_id}"))?;
275
276 let first_hop = mutable.first_hop().map(|first_hop| match first_hop {
277 path::HopDetail::Relay(r) => r,
278 #[cfg(feature = "hs-common")]
279 path::HopDetail::Virtual => {
280 panic!("somehow made a circuit with a virtual first hop.")
281 }
282 });
283
284 Ok(first_hop)
285 }
286
287 pub(super) fn last_hop_num(&self, unique_id: UniqId) -> Result<Option<HopNum>> {
293 let lock = self.0.lock().expect("lock poisoned");
294 let mutable = lock
295 .get(&unique_id)
296 .ok_or_else(|| bad_api_usage!("no circuit with unique ID {unique_id}"))?;
297
298 Ok(mutable.last_hop_num())
299 }
300
301 fn n_hops(&self, unique_id: UniqId) -> Result<usize> {
305 let lock = self.0.lock().expect("lock poisoned");
306 let mutable = lock
307 .get(&unique_id)
308 .ok_or_else(|| bad_api_usage!("no circuit with unique ID {unique_id}"))?;
309
310 Ok(mutable.n_hops())
311 }
312}
313
314#[derive(Educe, Default)]
316#[educe(Debug)]
317pub(super) struct MutableState(Mutex<CircuitState>);
318
319impl MutableState {
320 pub(super) fn add_hop(&self, peer_id: HopDetail, binding: Option<CircuitBinding>) {
322 let mut mutable = self.0.lock().expect("poisoned lock");
323 Arc::make_mut(&mut mutable.path).push_hop(peer_id);
324 mutable.binding.push(binding);
325 }
326
327 pub(super) fn path(&self) -> Arc<path::Path> {
329 let mutable = self.0.lock().expect("poisoned lock");
330 Arc::clone(&mutable.path)
331 }
332
333 pub(super) fn binding_key(&self, hop: HopNum) -> Option<CircuitBinding> {
336 let mutable = self.0.lock().expect("poisoned lock");
337
338 mutable.binding.get::<usize>(hop.into()).cloned().flatten()
339 }
342
343 fn first_hop(&self) -> Option<HopDetail> {
345 let mutable = self.0.lock().expect("poisoned lock");
346 mutable.path.first_hop()
347 }
348
349 fn last_hop_num(&self) -> Option<HopNum> {
356 let mutable = self.0.lock().expect("poisoned lock");
357 mutable.path.last_hop_num()
358 }
359
360 fn n_hops(&self) -> usize {
367 let mutable = self.0.lock().expect("poisoned lock");
368 mutable.path.n_hops()
369 }
370}
371
372#[derive(Educe, Default)]
374#[educe(Debug)]
375pub(super) struct CircuitState {
376 path: Arc<path::Path>,
382
383 #[educe(Debug(ignore))]
391 binding: Vec<Option<CircuitBinding>>,
392}
393
394pub struct PendingClientTunnel {
399 recvcreated: oneshot::Receiver<CreateResponse>,
402 circ: ClientCirc,
404}
405
406impl ClientCirc {
407 pub fn into_tunnel(self) -> Result<ClientTunnel> {
409 self.try_into()
410 }
411
412 pub fn first_hop(&self) -> Result<OwnedChanTarget> {
420 Ok(self
421 .mutable
422 .first_hop(self.unique_id)
423 .map_err(|_| Error::CircuitClosed)?
424 .expect("called first_hop on an un-constructed circuit"))
425 }
426
427 pub fn last_hop_info(&self) -> Result<Option<OwnedChanTarget>> {
437 let all_paths = self.all_paths();
438 let path = all_paths.first().ok_or_else(|| {
439 tor_error::bad_api_usage!("Called last_hop_info on an un-constructed tunnel")
440 })?;
441 Ok(path
442 .hops()
443 .last()
444 .expect("Called last_hop on an un-constructed circuit")
445 .as_chan_target()
446 .map(OwnedChanTarget::from_chan_target))
447 }
448
449 pub fn last_hop_num(&self) -> Result<HopNum> {
459 Ok(self
460 .mutable
461 .last_hop_num(self.unique_id)?
462 .ok_or_else(|| internal!("no last hop index"))?)
463 }
464
465 pub fn last_hop(&self) -> Result<TargetHop> {
470 let hop_num = self
471 .mutable
472 .last_hop_num(self.unique_id)?
473 .ok_or_else(|| bad_api_usage!("no last hop"))?;
474 Ok((self.unique_id, hop_num).into())
475 }
476
477 pub fn all_paths(&self) -> Vec<Arc<Path>> {
482 self.mutable.all_paths()
483 }
484
485 pub fn single_path(&self) -> Result<Arc<Path>> {
489 self.mutable.single_path()
490 }
491
492 pub async fn disused_since(&self) -> Result<Option<Instant>> {
501 let (tx, rx) = oneshot::channel();
502 self.command
503 .unbounded_send(CtrlCmd::GetTunnelActivity { sender: tx })
504 .map_err(|_| Error::CircuitClosed)?;
505
506 Ok(rx.await.map_err(|_| Error::CircuitClosed)?.disused_since())
507 }
508
509 pub async fn first_hop_clock_skew(&self) -> Result<ClockSkew> {
513 let (tx, rx) = oneshot::channel();
514
515 self.control
516 .unbounded_send(CtrlMsg::FirstHopClockSkew { answer: tx })
517 .map_err(|_| Error::CircuitClosed)?;
518
519 Ok(rx.await.map_err(|_| Error::CircuitClosed)??)
520 }
521
522 pub fn mq_account(&self) -> &CircuitAccount {
524 &self.memquota
525 }
526
527 #[cfg(feature = "hs-service")]
535 pub async fn binding_key(&self, hop: TargetHop) -> Result<Option<CircuitBinding>> {
536 let (sender, receiver) = oneshot::channel();
537 let msg = CtrlCmd::GetBindingKey { hop, done: sender };
538 self.command
539 .unbounded_send(msg)
540 .map_err(|_| Error::CircuitClosed)?;
541
542 receiver.await.map_err(|_| Error::CircuitClosed)?
543 }
544
545 pub async fn extend<Tg>(&self, target: &Tg, params: CircParameters) -> Result<()>
548 where
549 Tg: CircTarget,
550 {
551 #![allow(deprecated)]
552
553 if target
565 .protovers()
566 .supports_named_subver(named::RELAY_NTORV3)
567 {
568 self.extend_ntor_v3(target, params).await
569 } else {
570 self.extend_ntor(target, params).await
571 }
572 }
573
574 #[deprecated(since = "1.6.1", note = "Use extend instead.")]
577 pub async fn extend_ntor<Tg>(&self, target: &Tg, params: CircParameters) -> Result<()>
578 where
579 Tg: CircTarget,
580 {
581 let key = NtorPublicKey {
582 id: *target
583 .rsa_identity()
584 .ok_or(Error::MissingId(RelayIdType::Rsa))?,
585 pk: *target.ntor_onion_key(),
586 };
587 let mut linkspecs = target
588 .linkspecs()
589 .map_err(into_internal!("Could not encode linkspecs for extend_ntor"))?;
590 if !params.extend_by_ed25519_id {
591 linkspecs.retain(|ls| ls.lstype() != LinkSpecType::ED25519ID);
592 }
593
594 let (tx, rx) = oneshot::channel();
595
596 let peer_id = OwnedChanTarget::from_chan_target(target);
597 let settings = HopSettings::from_params_and_caps(
598 HopNegotiationType::None,
599 ¶ms,
600 target.protovers(),
601 )?;
602 self.control
603 .unbounded_send(CtrlMsg::ExtendNtor {
604 peer_id,
605 public_key: key,
606 linkspecs,
607 settings,
608 done: tx,
609 })
610 .map_err(|_| Error::CircuitClosed)?;
611
612 rx.await.map_err(|_| Error::CircuitClosed)??;
613
614 Ok(())
615 }
616
617 #[deprecated(since = "1.6.1", note = "Use extend instead.")]
620 pub async fn extend_ntor_v3<Tg>(&self, target: &Tg, params: CircParameters) -> Result<()>
621 where
622 Tg: CircTarget,
623 {
624 let key = NtorV3PublicKey {
625 id: *target
626 .ed_identity()
627 .ok_or(Error::MissingId(RelayIdType::Ed25519))?,
628 pk: *target.ntor_onion_key(),
629 };
630 let mut linkspecs = target
631 .linkspecs()
632 .map_err(into_internal!("Could not encode linkspecs for extend_ntor"))?;
633 if !params.extend_by_ed25519_id {
634 linkspecs.retain(|ls| ls.lstype() != LinkSpecType::ED25519ID);
635 }
636
637 let (tx, rx) = oneshot::channel();
638
639 let peer_id = OwnedChanTarget::from_chan_target(target);
640 let settings = HopSettings::from_params_and_caps(
641 HopNegotiationType::Full,
642 ¶ms,
643 target.protovers(),
644 )?;
645 self.control
646 .unbounded_send(CtrlMsg::ExtendNtorV3 {
647 peer_id,
648 public_key: key,
649 linkspecs,
650 settings,
651 done: tx,
652 })
653 .map_err(|_| Error::CircuitClosed)?;
654
655 rx.await.map_err(|_| Error::CircuitClosed)??;
656
657 Ok(())
658 }
659
660 #[cfg(feature = "hs-common")]
692 pub async fn extend_virtual(
693 &self,
694 protocol: handshake::RelayProtocol,
695 role: handshake::HandshakeRole,
696 seed: impl handshake::KeyGenerator,
697 params: &CircParameters,
698 capabilities: &tor_protover::Protocols,
699 ) -> Result<()> {
700 use self::handshake::BoxedClientLayer;
701
702 let negotiation_type = match protocol {
704 handshake::RelayProtocol::HsV3 => HopNegotiationType::HsV3,
705 };
706 let protocol = handshake::RelayCryptLayerProtocol::from(protocol);
707
708 let BoxedClientLayer { fwd, back, binding } =
709 protocol.construct_client_layers(role, seed)?;
710
711 let settings = HopSettings::from_params_and_caps(negotiation_type, params, capabilities)?;
712 let (tx, rx) = oneshot::channel();
713 let message = CtrlCmd::ExtendVirtual {
714 cell_crypto: (fwd, back, binding),
715 settings,
716 done: tx,
717 };
718
719 self.command
720 .unbounded_send(message)
721 .map_err(|_| Error::CircuitClosed)?;
722
723 rx.await.map_err(|_| Error::CircuitClosed)?
724 }
725
726 #[cfg(feature = "circ-padding-manual")]
730 pub async fn start_padding_at_hop(&self, hop: HopNum, padder: CircuitPadder) -> Result<()> {
731 self.set_padder_impl(crate::HopLocation::Hop((self.unique_id, hop)), Some(padder))
732 .await
733 }
734
735 #[cfg(feature = "circ-padding-manual")]
739 pub async fn stop_padding_at_hop(&self, hop: HopNum) -> Result<()> {
740 self.set_padder_impl(crate::HopLocation::Hop((self.unique_id, hop)), None)
741 .await
742 }
743
744 #[cfg(feature = "circ-padding-manual")]
746 pub(super) async fn set_padder_impl(
747 &self,
748 hop: crate::HopLocation,
749 padder: Option<CircuitPadder>,
750 ) -> Result<()> {
751 let (tx, rx) = oneshot::channel();
752 let msg = CtrlCmd::SetPadder {
753 hop,
754 padder,
755 sender: tx,
756 };
757 self.command
758 .unbounded_send(msg)
759 .map_err(|_| Error::CircuitClosed)?;
760 rx.await.map_err(|_| Error::CircuitClosed)?
761 }
762
763 pub fn is_closing(&self) -> bool {
765 self.control.is_closed()
766 }
767
768 pub fn unique_id(&self) -> UniqId {
770 self.unique_id
771 }
772
773 pub fn n_hops(&self) -> Result<usize> {
780 self.mutable
781 .n_hops(self.unique_id)
782 .map_err(|_| Error::CircuitClosed)
783 }
784
785 pub fn wait_for_close(
792 &self,
793 ) -> impl futures::Future<Output = ()> + Send + Sync + 'static + use<> {
794 self.reactor_closed_rx.clone().map(|_| ())
795 }
796}
797
798impl PendingClientTunnel {
799 #[allow(clippy::too_many_arguments)]
803 pub(crate) fn new(
804 circ_id: CircId,
805 channel: Arc<Channel>,
806 createdreceiver: oneshot::Receiver<CreateResponse>,
807 input: CircuitRxReceiver,
808 unique_id: UniqId,
809 runtime: DynTimeProvider,
810 memquota: CircuitAccount,
811 padding_ctrl: PaddingController,
812 padding_stream: PaddingEventStream,
813 timeouts: Arc<dyn TimeoutEstimator>,
814 ) -> (PendingClientTunnel, crate::client::reactor::Reactor) {
815 let time_provider = channel.time_provider().clone();
816 let (reactor, control_tx, command_tx, reactor_closed_rx, mutable) = Reactor::new(
817 channel,
818 circ_id,
819 unique_id,
820 input,
821 runtime,
822 memquota.clone(),
823 padding_ctrl,
824 padding_stream,
825 timeouts,
826 );
827
828 let circuit = ClientCirc {
829 mutable,
830 unique_id,
831 control: control_tx,
832 command: command_tx,
833 reactor_closed_rx: reactor_closed_rx.shared(),
834 #[cfg(test)]
835 circid: circ_id,
836 memquota,
837 time_provider,
838 is_multi_path: false,
839 };
840
841 let pending = PendingClientTunnel {
842 recvcreated: createdreceiver,
843 circ: circuit,
844 };
845 (pending, reactor)
846 }
847
848 pub fn peek_unique_id(&self) -> UniqId {
850 self.circ.unique_id
851 }
852
853 pub async fn create_firsthop_fast(self, params: CircParameters) -> Result<ClientTunnel> {
860 let protocols = tor_protover::Protocols::new();
865 let settings =
866 HopSettings::from_params_and_caps(HopNegotiationType::None, ¶ms, &protocols)?;
867 let (tx, rx) = oneshot::channel();
868 self.circ
869 .control
870 .unbounded_send(CtrlMsg::Create {
871 recv_created: self.recvcreated,
872 handshake: CircuitHandshake::CreateFast,
873 settings,
874 done: tx,
875 })
876 .map_err(|_| Error::CircuitClosed)?;
877
878 rx.await.map_err(|_| Error::CircuitClosed)??;
879
880 self.circ.into_tunnel()
881 }
882
883 pub async fn create_firsthop<Tg>(
888 self,
889 target: &Tg,
890 params: CircParameters,
891 ) -> Result<ClientTunnel>
892 where
893 Tg: tor_linkspec::CircTarget,
894 {
895 #![allow(deprecated)]
896 if target
898 .protovers()
899 .supports_named_subver(named::RELAY_NTORV3)
900 {
901 self.create_firsthop_ntor_v3(target, params).await
902 } else {
903 self.create_firsthop_ntor(target, params).await
904 }
905 }
906
907 #[deprecated(since = "1.6.1", note = "Use create_firsthop instead.")]
912 pub async fn create_firsthop_ntor<Tg>(
913 self,
914 target: &Tg,
915 params: CircParameters,
916 ) -> Result<ClientTunnel>
917 where
918 Tg: tor_linkspec::CircTarget,
919 {
920 let (tx, rx) = oneshot::channel();
921 let settings = HopSettings::from_params_and_caps(
922 HopNegotiationType::None,
923 ¶ms,
924 target.protovers(),
925 )?;
926
927 self.circ
928 .control
929 .unbounded_send(CtrlMsg::Create {
930 recv_created: self.recvcreated,
931 handshake: CircuitHandshake::Ntor {
932 public_key: NtorPublicKey {
933 id: *target
934 .rsa_identity()
935 .ok_or(Error::MissingId(RelayIdType::Rsa))?,
936 pk: *target.ntor_onion_key(),
937 },
938 ed_identity: *target
939 .ed_identity()
940 .ok_or(Error::MissingId(RelayIdType::Ed25519))?,
941 },
942 settings,
943 done: tx,
944 })
945 .map_err(|_| Error::CircuitClosed)?;
946
947 rx.await.map_err(|_| Error::CircuitClosed)??;
948
949 self.circ.into_tunnel()
950 }
951
952 #[deprecated(since = "1.6.1", note = "Use create_firsthop instead.")]
961 pub async fn create_firsthop_ntor_v3<Tg>(
962 self,
963 target: &Tg,
964 params: CircParameters,
965 ) -> Result<ClientTunnel>
966 where
967 Tg: tor_linkspec::CircTarget,
968 {
969 let settings = HopSettings::from_params_and_caps(
970 HopNegotiationType::Full,
971 ¶ms,
972 target.protovers(),
973 )?;
974 let (tx, rx) = oneshot::channel();
975
976 self.circ
977 .control
978 .unbounded_send(CtrlMsg::Create {
979 recv_created: self.recvcreated,
980 handshake: CircuitHandshake::NtorV3 {
981 public_key: NtorV3PublicKey {
982 id: *target
983 .ed_identity()
984 .ok_or(Error::MissingId(RelayIdType::Ed25519))?,
985 pk: *target.ntor_onion_key(),
986 },
987 },
988 settings,
989 done: tx,
990 })
991 .map_err(|_| Error::CircuitClosed)?;
992
993 rx.await.map_err(|_| Error::CircuitClosed)??;
994
995 self.circ.into_tunnel()
996 }
997}
998
999#[cfg(test)]
1000pub(crate) mod test {
1001 #![allow(clippy::bool_assert_comparison)]
1003 #![allow(clippy::clone_on_copy)]
1004 #![allow(clippy::dbg_macro)]
1005 #![allow(clippy::mixed_attributes_style)]
1006 #![allow(clippy::print_stderr)]
1007 #![allow(clippy::print_stdout)]
1008 #![allow(clippy::single_char_pattern)]
1009 #![allow(clippy::unwrap_used)]
1010 #![allow(clippy::unchecked_time_subtraction)]
1011 #![allow(clippy::useless_vec)]
1012 #![allow(clippy::needless_pass_by_value)]
1013 #![allow(clippy::string_slice)] use super::*;
1017 use crate::channel::test::{CodecResult, new_reactor};
1018 use crate::circuit::CircuitRxSender;
1019 use crate::circuit::reactor::test::rmsg_to_ccmsg;
1020 use crate::circuit::test::fake_mpsc;
1021 use crate::client::circuit::padding::new_padding;
1022 use crate::client::stream::DataStream;
1023 use crate::congestion::params::CongestionControlParams;
1024 use crate::congestion::test_utils::params::build_cc_vegas_params;
1025 use crate::crypto::cell::RelayCellBody;
1026 use crate::crypto::handshake::ntor_v3::NtorV3Server;
1027 use crate::memquota::SpecificAccount as _;
1028 use crate::stream::flow_ctrl::params::FlowCtrlParameters;
1029 use crate::util::DummyTimeoutEstimator;
1030 use assert_matches::assert_matches;
1031 use chanmsg::{AnyChanMsg, Created2, CreatedFast};
1032 use futures::channel::mpsc::{Receiver, Sender};
1033 use futures::io::{AsyncReadExt, AsyncWriteExt};
1034 use futures::sink::SinkExt;
1035 use futures::stream::StreamExt;
1036 use hex_literal::hex;
1037 use std::collections::{HashMap, VecDeque};
1038 use std::fmt::Debug;
1039 use std::time::Duration;
1040 use tor_basic_utils::test_rng::testing_rng;
1041 use tor_cell::chancell::{AnyChanCell, BoxedCellBody, ChanCell, ChanCmd, msg as chanmsg};
1042 use tor_cell::relaycell::extend::{self as extend_ext, CircRequestExt, CircResponseExt};
1043 use tor_cell::relaycell::msg::SendmeTag;
1044 use tor_cell::relaycell::{
1045 AnyRelayMsgOuter, RelayCellFormat, RelayCmd, StreamId, msg as relaymsg, msg::AnyRelayMsg,
1046 };
1047 use tor_cell::relaycell::{RelayMsg, UnparsedRelayMsg};
1048 use tor_linkspec::OwnedCircTarget;
1049 use tor_rtcompat::Runtime;
1050 use tor_rtcompat::SpawnExt;
1051 use tracing::trace;
1052 use tracing_test::traced_test;
1053
1054 #[cfg(feature = "conflux")]
1055 use {
1056 crate::client::reactor::ConfluxHandshakeResult,
1057 crate::util::err::ConfluxHandshakeError,
1058 futures::future::FusedFuture,
1059 futures::lock::Mutex as AsyncMutex,
1060 std::pin::Pin,
1061 std::result::Result as StdResult,
1062 tor_cell::relaycell::conflux::{V1DesiredUx, V1LinkPayload, V1Nonce},
1063 tor_cell::relaycell::msg::ConfluxLink,
1064 tor_rtmock::MockRuntime,
1065 };
1066
1067 #[cfg(feature = "hs-service")]
1068 use crate::circuit::reactor::test::AllowAllStreamsFilter;
1069
1070 impl PendingClientTunnel {
1071 pub(crate) fn peek_circid(&self) -> CircId {
1073 self.circ.circid
1074 }
1075 }
1076
1077 impl ClientCirc {
1078 pub(crate) fn peek_circid(&self) -> CircId {
1080 self.circid
1081 }
1082 }
1083
1084 impl ClientTunnel {
1085 pub(crate) async fn resolve_last_hop(&self) -> TargetHop {
1086 let (sender, receiver) = oneshot::channel();
1087 let _ =
1088 self.as_single_circ()
1089 .unwrap()
1090 .command
1091 .unbounded_send(CtrlCmd::ResolveTargetHop {
1092 hop: TargetHop::LastHop,
1093 done: sender,
1094 });
1095 TargetHop::Hop(receiver.await.unwrap().unwrap())
1096 }
1097 }
1098
1099 const EXAMPLE_SK: [u8; 32] =
1101 hex!("7789d92a89711a7e2874c61ea495452cfd48627b3ca2ea9546aafa5bf7b55803");
1102 const EXAMPLE_PK: [u8; 32] =
1103 hex!("395cb26b83b3cd4b91dba9913e562ae87d21ecdd56843da7ca939a6a69001253");
1104 const EXAMPLE_ED_ID: [u8; 32] = [6; 32];
1105 const EXAMPLE_RSA_ID: [u8; 20] = [10; 20];
1106
1107 fn example_target() -> OwnedCircTarget {
1109 let mut builder = OwnedCircTarget::builder();
1110 builder
1111 .chan_target()
1112 .ed_identity(EXAMPLE_ED_ID.into())
1113 .rsa_identity(EXAMPLE_RSA_ID.into());
1114 builder
1115 .ntor_onion_key(EXAMPLE_PK.into())
1116 .protocols("FlowCtrl=1-2".parse().unwrap())
1117 .build()
1118 .unwrap()
1119 }
1120 fn example_ntor_key() -> crate::crypto::handshake::ntor::NtorSecretKey {
1121 crate::crypto::handshake::ntor::NtorSecretKey::new(
1122 EXAMPLE_SK.into(),
1123 EXAMPLE_PK.into(),
1124 EXAMPLE_RSA_ID.into(),
1125 )
1126 }
1127 fn example_ntor_v3_key() -> crate::crypto::handshake::ntor_v3::NtorV3SecretKey {
1128 crate::crypto::handshake::ntor_v3::NtorV3SecretKey::new(
1129 EXAMPLE_SK.into(),
1130 EXAMPLE_PK.into(),
1131 EXAMPLE_ED_ID.into(),
1132 )
1133 }
1134
1135 fn working_fake_channel<R: Runtime>(
1136 rt: &R,
1137 ) -> (Arc<Channel>, Receiver<AnyChanCell>, Sender<CodecResult>) {
1138 let (channel, chan_reactor, rx, tx) = new_reactor(rt.clone());
1139 rt.spawn(async {
1140 let _ignore = chan_reactor.run().await;
1141 })
1142 .unwrap();
1143 (channel, rx, tx)
1144 }
1145
1146 #[derive(Copy, Clone)]
1148 enum HandshakeType {
1149 Fast,
1150 Ntor,
1151 NtorV3,
1152 }
1153
1154 #[allow(deprecated)]
1155 async fn test_create<R: Runtime>(rt: &R, handshake_type: HandshakeType, with_cc: bool) {
1156 use crate::crypto::handshake::{ServerHandshake, fast::CreateFastServer, ntor::NtorServer};
1160
1161 let (chan, mut rx, _sink) = working_fake_channel(rt);
1162 let circid = CircId::new(128).unwrap();
1163 let (created_send, created_recv) = oneshot::channel();
1164 let (_circmsg_send, circmsg_recv) = fake_mpsc(64);
1165 let unique_id = UniqId::new(23, 17);
1166 let (padding_ctrl, padding_stream) = new_padding(DynTimeProvider::new(rt.clone()));
1167
1168 let (pending, reactor) = PendingClientTunnel::new(
1169 circid,
1170 chan,
1171 created_recv,
1172 circmsg_recv,
1173 unique_id,
1174 DynTimeProvider::new(rt.clone()),
1175 CircuitAccount::new_noop(),
1176 padding_ctrl,
1177 padding_stream,
1178 Arc::new(DummyTimeoutEstimator),
1179 );
1180
1181 rt.spawn(async {
1182 let _ignore = reactor.run().await;
1183 })
1184 .unwrap();
1185
1186 let simulate_relay_fut = async move {
1188 let mut rng = testing_rng();
1189 let create_cell = rx.next().await.unwrap();
1190 assert_eq!(create_cell.circid(), Some(circid));
1191 let reply = match handshake_type {
1192 HandshakeType::Fast => {
1193 let cf = match create_cell.msg() {
1194 AnyChanMsg::CreateFast(cf) => cf,
1195 other => panic!("{:?}", other),
1196 };
1197 let (_, rep) = CreateFastServer::server(
1198 &mut rng,
1199 &mut |_: &()| Some(()),
1200 &[()],
1201 cf.handshake(),
1202 )
1203 .unwrap();
1204 CreateResponse::CreatedFast(CreatedFast::new(rep))
1205 }
1206 HandshakeType::Ntor => {
1207 let c2 = match create_cell.msg() {
1208 AnyChanMsg::Create2(c2) => c2,
1209 other => panic!("{:?}", other),
1210 };
1211 let (_, rep) = NtorServer::server(
1212 &mut rng,
1213 &mut |_: &()| Some(()),
1214 &[example_ntor_key()],
1215 c2.body(),
1216 )
1217 .unwrap();
1218 CreateResponse::Created2(Created2::new(rep))
1219 }
1220 HandshakeType::NtorV3 => {
1221 let c2 = match create_cell.msg() {
1222 AnyChanMsg::Create2(c2) => c2,
1223 other => panic!("{:?}", other),
1224 };
1225 let mut reply_fn = if with_cc {
1226 |client_exts: &[CircRequestExt]| {
1227 let _ = client_exts
1228 .iter()
1229 .find(|e| matches!(e, CircRequestExt::CcRequest(_)))
1230 .expect("Client failed to request CC");
1231 Some(vec![CircResponseExt::CcResponse(
1234 extend_ext::CcResponse::new(31),
1235 )])
1236 }
1237 } else {
1238 |_: &_| Some(vec![])
1239 };
1240 let (_, rep) = NtorV3Server::server(
1241 &mut rng,
1242 &mut reply_fn,
1243 &[example_ntor_v3_key()],
1244 c2.body(),
1245 )
1246 .unwrap();
1247 CreateResponse::Created2(Created2::new(rep))
1248 }
1249 };
1250 created_send.send(reply).unwrap();
1251 };
1252 let client_fut = async move {
1254 let target = example_target();
1255 let params = CircParameters::default();
1256 let ret = match handshake_type {
1257 HandshakeType::Fast => {
1258 trace!("doing fast create");
1259 pending.create_firsthop_fast(params).await
1260 }
1261 HandshakeType::Ntor => {
1262 trace!("doing ntor create");
1263 pending.create_firsthop_ntor(&target, params).await
1264 }
1265 HandshakeType::NtorV3 => {
1266 let params = if with_cc {
1267 CircParameters::new(
1269 true,
1270 build_cc_vegas_params(),
1271 FlowCtrlParameters::defaults_for_tests(),
1272 )
1273 } else {
1274 params
1275 };
1276 trace!("doing ntor_v3 create");
1277 pending.create_firsthop_ntor_v3(&target, params).await
1278 }
1279 };
1280 trace!("create done: result {:?}", ret);
1281 ret
1282 };
1283
1284 let (circ, _) = futures::join!(client_fut, simulate_relay_fut);
1285
1286 let _circ = circ.unwrap();
1287
1288 assert_eq!(_circ.n_hops().unwrap(), 1);
1290 }
1291
1292 #[traced_test]
1293 #[test]
1294 fn test_create_fast() {
1295 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1296 test_create(&rt, HandshakeType::Fast, false).await;
1297 });
1298 }
1299 #[traced_test]
1300 #[test]
1301 fn test_create_ntor() {
1302 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1303 test_create(&rt, HandshakeType::Ntor, false).await;
1304 });
1305 }
1306 #[traced_test]
1307 #[test]
1308 fn test_create_ntor_v3() {
1309 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1310 test_create(&rt, HandshakeType::NtorV3, false).await;
1311 });
1312 }
1313 #[traced_test]
1314 #[test]
1315 #[cfg(feature = "flowctl-cc")]
1316 fn test_create_ntor_v3_with_cc() {
1317 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1318 test_create(&rt, HandshakeType::NtorV3, true).await;
1319 });
1320 }
1321
1322 pub(crate) struct DummyCrypto {
1325 counter_tag: [u8; 20],
1326 counter: u32,
1327 lasthop: bool,
1328 }
1329 impl DummyCrypto {
1330 fn next_tag(&mut self) -> SendmeTag {
1331 #![allow(clippy::identity_op)]
1332 self.counter_tag[0] = ((self.counter >> 0) & 255) as u8;
1333 self.counter_tag[1] = ((self.counter >> 8) & 255) as u8;
1334 self.counter_tag[2] = ((self.counter >> 16) & 255) as u8;
1335 self.counter_tag[3] = ((self.counter >> 24) & 255) as u8;
1336 self.counter += 1;
1337 self.counter_tag.into()
1338 }
1339 }
1340
1341 impl crate::crypto::cell::OutboundClientLayer for DummyCrypto {
1342 fn originate_for(&mut self, _cmd: ChanCmd, _cell: &mut RelayCellBody) -> SendmeTag {
1343 self.next_tag()
1344 }
1345 fn encrypt_outbound(&mut self, _cmd: ChanCmd, _cell: &mut RelayCellBody) {}
1346 }
1347 impl crate::crypto::cell::InboundClientLayer for DummyCrypto {
1348 fn decrypt_inbound(
1349 &mut self,
1350 _cmd: ChanCmd,
1351 _cell: &mut RelayCellBody,
1352 ) -> Option<SendmeTag> {
1353 if self.lasthop {
1354 Some(self.next_tag())
1355 } else {
1356 None
1357 }
1358 }
1359 }
1360 impl DummyCrypto {
1361 pub(crate) fn new(lasthop: bool) -> Self {
1362 DummyCrypto {
1363 counter_tag: [0; 20],
1364 counter: 0,
1365 lasthop,
1366 }
1367 }
1368 }
1369
1370 async fn newtunnel_ext<R: Runtime>(
1373 rt: &R,
1374 unique_id: UniqId,
1375 chan: Arc<Channel>,
1376 hops: Vec<path::HopDetail>,
1377 next_msg_from: HopNum,
1378 params: CircParameters,
1379 ) -> (ClientTunnel, CircuitRxSender) {
1380 let circid = CircId::new(128).unwrap();
1381 let (_created_send, created_recv) = oneshot::channel();
1382 let (circmsg_send, circmsg_recv) = fake_mpsc(64);
1383 let (padding_ctrl, padding_stream) = new_padding(DynTimeProvider::new(rt.clone()));
1384
1385 let (pending, reactor) = PendingClientTunnel::new(
1386 circid,
1387 chan,
1388 created_recv,
1389 circmsg_recv,
1390 unique_id,
1391 DynTimeProvider::new(rt.clone()),
1392 CircuitAccount::new_noop(),
1393 padding_ctrl,
1394 padding_stream,
1395 Arc::new(DummyTimeoutEstimator),
1396 );
1397
1398 rt.spawn(async {
1399 let _ignore = reactor.run().await;
1400 })
1401 .unwrap();
1402 let PendingClientTunnel {
1403 circ,
1404 recvcreated: _,
1405 } = pending;
1406
1407 let relay_cell_format = RelayCellFormat::V0;
1409
1410 let last_hop_num = u8::try_from(hops.len() - 1).unwrap();
1411 for (idx, peer_id) in hops.into_iter().enumerate() {
1412 let (tx, rx) = oneshot::channel();
1413 let idx = idx as u8;
1414
1415 circ.command
1416 .unbounded_send(CtrlCmd::AddFakeHop {
1417 relay_cell_format,
1418 fwd_lasthop: idx == last_hop_num,
1419 rev_lasthop: idx == u8::from(next_msg_from),
1420 peer_id,
1421 params: params.clone(),
1422 done: tx,
1423 })
1424 .unwrap();
1425 rx.await.unwrap().unwrap();
1426 }
1427 (circ.into_tunnel().unwrap(), circmsg_send)
1428 }
1429
1430 async fn newtunnel<R: Runtime>(
1433 rt: &R,
1434 chan: Arc<Channel>,
1435 ) -> (Arc<ClientTunnel>, CircuitRxSender) {
1436 let hops = std::iter::repeat_with(|| {
1437 let peer_id = tor_linkspec::OwnedChanTarget::builder()
1438 .ed_identity([4; 32].into())
1439 .rsa_identity([5; 20].into())
1440 .build()
1441 .expect("Could not construct fake hop");
1442
1443 path::HopDetail::Relay(peer_id)
1444 })
1445 .take(3)
1446 .collect();
1447
1448 let unique_id = UniqId::new(23, 17);
1449 let (tunnel, circmsg_send) = newtunnel_ext(
1450 rt,
1451 unique_id,
1452 chan,
1453 hops,
1454 2.into(),
1455 CircParameters::default(),
1456 )
1457 .await;
1458
1459 (Arc::new(tunnel), circmsg_send)
1460 }
1461
1462 fn hop_details(n: u8, start_idx: u8) -> Vec<path::HopDetail> {
1465 (0..n)
1466 .map(|idx| {
1467 let peer_id = tor_linkspec::OwnedChanTarget::builder()
1468 .ed_identity([idx + start_idx; 32].into())
1469 .rsa_identity([idx + start_idx + 1; 20].into())
1470 .build()
1471 .expect("Could not construct fake hop");
1472
1473 path::HopDetail::Relay(peer_id)
1474 })
1475 .collect()
1476 }
1477
1478 #[allow(deprecated)]
1479 async fn test_extend<R: Runtime>(rt: &R, handshake_type: HandshakeType) {
1480 use crate::crypto::handshake::{ServerHandshake, ntor::NtorServer};
1481
1482 let (chan, mut rx, _sink) = working_fake_channel(rt);
1483 let (tunnel, mut sink) = newtunnel(rt, chan).await;
1484 let circ = Arc::new(tunnel.as_single_circ().unwrap());
1485 let circid = circ.peek_circid();
1486 let params = CircParameters::default();
1487
1488 let extend_fut = async move {
1489 let target = example_target();
1490 match handshake_type {
1491 HandshakeType::Fast => panic!("Can't extend with Fast handshake"),
1492 HandshakeType::Ntor => circ.extend_ntor(&target, params).await.unwrap(),
1493 HandshakeType::NtorV3 => circ.extend_ntor_v3(&target, params).await.unwrap(),
1494 };
1495 circ };
1497 let reply_fut = async move {
1498 let (id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
1501 assert_eq!(id, Some(circid));
1502 let rmsg = match chmsg {
1503 AnyChanMsg::RelayEarly(r) => {
1504 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1505 .unwrap()
1506 }
1507 other => panic!("{:?}", other),
1508 };
1509 let e2 = match rmsg.msg() {
1510 AnyRelayMsg::Extend2(e2) => e2,
1511 other => panic!("{:?}", other),
1512 };
1513 let mut rng = testing_rng();
1514 let reply = match handshake_type {
1515 HandshakeType::Fast => panic!("Can't extend with Fast handshake"),
1516 HandshakeType::Ntor => {
1517 let (_keygen, reply) = NtorServer::server(
1518 &mut rng,
1519 &mut |_: &()| Some(()),
1520 &[example_ntor_key()],
1521 e2.handshake(),
1522 )
1523 .unwrap();
1524 reply
1525 }
1526 HandshakeType::NtorV3 => {
1527 let (_keygen, reply) = NtorV3Server::server(
1528 &mut rng,
1529 &mut |_: &[CircRequestExt]| Some(vec![]),
1530 &[example_ntor_v3_key()],
1531 e2.handshake(),
1532 )
1533 .unwrap();
1534 reply
1535 }
1536 };
1537
1538 let extended2 = relaymsg::Extended2::new(reply).into();
1539 sink.send(rmsg_to_ccmsg(None, extended2, false))
1540 .await
1541 .unwrap();
1542 (sink, rx) };
1544
1545 let (circ, (_sink, _rx)) = futures::join!(extend_fut, reply_fut);
1546
1547 assert_eq!(circ.n_hops().unwrap(), 4);
1549
1550 {
1552 let path = circ.single_path().unwrap();
1553 let path = path
1554 .all_hops()
1555 .filter_map(|hop| match hop {
1556 path::HopDetail::Relay(r) => Some(r),
1557 #[cfg(feature = "hs-common")]
1558 path::HopDetail::Virtual => None,
1559 })
1560 .collect::<Vec<_>>();
1561
1562 assert_eq!(path.len(), 4);
1563 use tor_linkspec::HasRelayIds;
1564 assert_eq!(path[3].ed_identity(), example_target().ed_identity());
1565 assert_ne!(path[0].ed_identity(), example_target().ed_identity());
1566 }
1567 {
1568 let path = circ.single_path().unwrap();
1569 assert_eq!(path.n_hops(), 4);
1570 use tor_linkspec::HasRelayIds;
1571 assert_eq!(
1572 path.hops()[3].as_chan_target().unwrap().ed_identity(),
1573 example_target().ed_identity()
1574 );
1575 assert_ne!(
1576 path.hops()[0].as_chan_target().unwrap().ed_identity(),
1577 example_target().ed_identity()
1578 );
1579 }
1580 }
1581
1582 #[traced_test]
1583 #[test]
1584 fn test_extend_ntor() {
1585 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1586 test_extend(&rt, HandshakeType::Ntor).await;
1587 });
1588 }
1589
1590 #[traced_test]
1591 #[test]
1592 fn test_extend_ntor_v3() {
1593 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1594 test_extend(&rt, HandshakeType::NtorV3).await;
1595 });
1596 }
1597
1598 #[allow(deprecated)]
1599 async fn bad_extend_test_impl<R: Runtime>(
1600 rt: &R,
1601 reply_hop: HopNum,
1602 bad_reply: AnyChanMsg,
1603 ) -> Error {
1604 let (chan, mut rx, _sink) = working_fake_channel(rt);
1605 let hops = std::iter::repeat_with(|| {
1606 let peer_id = tor_linkspec::OwnedChanTarget::builder()
1607 .ed_identity([4; 32].into())
1608 .rsa_identity([5; 20].into())
1609 .build()
1610 .expect("Could not construct fake hop");
1611
1612 path::HopDetail::Relay(peer_id)
1613 })
1614 .take(3)
1615 .collect();
1616
1617 let unique_id = UniqId::new(23, 17);
1618 let (tunnel, mut sink) = newtunnel_ext(
1619 rt,
1620 unique_id,
1621 chan,
1622 hops,
1623 reply_hop,
1624 CircParameters::default(),
1625 )
1626 .await;
1627 let params = CircParameters::default();
1628
1629 let target = example_target();
1630 let reply_task_handle = rt
1631 .spawn_with_handle(async move {
1632 let (_circid, chanmsg) = rx.next().await.unwrap().into_circid_and_msg();
1634 let AnyChanMsg::RelayEarly(relay_early) = chanmsg else {
1635 panic!("unexpected message {chanmsg:?}");
1636 };
1637 let relaymsg = UnparsedRelayMsg::from_singleton_body(
1638 RelayCellFormat::V0,
1639 relay_early.into_relay_body(),
1640 )
1641 .unwrap();
1642 assert_eq!(relaymsg.cmd(), RelayCmd::EXTEND2);
1643
1644 sink.send(bad_reply).await.unwrap();
1646 sink
1647 })
1648 .unwrap();
1649 let outcome = tunnel
1650 .as_single_circ()
1651 .unwrap()
1652 .extend_ntor(&target, params)
1653 .await;
1654 let _sink = reply_task_handle.await;
1655
1656 assert_eq!(tunnel.n_hops().unwrap(), 3);
1657 assert!(outcome.is_err());
1658 outcome.unwrap_err()
1659 }
1660
1661 #[traced_test]
1662 #[test]
1663 fn bad_extend_wronghop() {
1664 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1665 let extended2 = relaymsg::Extended2::new(vec![]).into();
1666 let cc = rmsg_to_ccmsg(None, extended2, false);
1667
1668 let error = bad_extend_test_impl(&rt, 1.into(), cc).await;
1669 match error {
1674 Error::CircuitClosed => {}
1675 x => panic!("got other error: {}", x),
1676 }
1677 });
1678 }
1679
1680 #[traced_test]
1681 #[test]
1682 fn bad_extend_wrongtype() {
1683 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1684 let extended = relaymsg::Extended::new(vec![7; 200]).into();
1685 let cc = rmsg_to_ccmsg(None, extended, false);
1686
1687 let error = bad_extend_test_impl(&rt, 2.into(), cc).await;
1688 match error {
1689 Error::BytesErr {
1690 err: tor_bytes::Error::InvalidMessage(_),
1691 object: "extended2 message",
1692 } => {}
1693 other => panic!("{:?}", other),
1694 }
1695 });
1696 }
1697
1698 #[traced_test]
1699 #[test]
1700 fn bad_extend_destroy() {
1701 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1702 let cc = AnyChanMsg::Destroy(chanmsg::Destroy::new(4.into()));
1703 let error = bad_extend_test_impl(&rt, 2.into(), cc).await;
1704 match error {
1705 Error::CircuitClosed => {}
1706 other => panic!("{:?}", other),
1707 }
1708 });
1709 }
1710
1711 #[traced_test]
1712 #[test]
1713 fn bad_extend_crypto() {
1714 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1715 let extended2 = relaymsg::Extended2::new(vec![99; 256]).into();
1716 let cc = rmsg_to_ccmsg(None, extended2, false);
1717 let error = bad_extend_test_impl(&rt, 2.into(), cc).await;
1718 assert_matches!(error, Error::BadCircHandshakeAuth);
1719 });
1720 }
1721
1722 #[traced_test]
1723 #[test]
1724 fn begindir() {
1725 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1726 let (chan, mut rx, _sink) = working_fake_channel(&rt);
1727 let (tunnel, mut sink) = newtunnel(&rt, chan).await;
1728 let circ = tunnel.as_single_circ().unwrap();
1729 let circid = circ.peek_circid();
1730
1731 let begin_and_send_fut = async move {
1732 let mut stream = tunnel.begin_dir_stream().await.unwrap();
1735 stream.write_all(b"HTTP/1.0 GET /\r\n").await.unwrap();
1736 stream.flush().await.unwrap();
1737 let mut buf = [0_u8; 1024];
1738 let n = stream.read(&mut buf).await.unwrap();
1739 assert_eq!(&buf[..n], b"HTTP/1.0 404 Not found\r\n");
1740 let n = stream.read(&mut buf).await.unwrap();
1741 assert_eq!(n, 0);
1742 stream
1743 };
1744 let reply_fut = async move {
1745 let (id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
1748 assert_eq!(id, Some(circid));
1749 let rmsg = match chmsg {
1750 AnyChanMsg::Relay(r) => {
1751 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1752 .unwrap()
1753 }
1754 other => panic!("{:?}", other),
1755 };
1756 let (streamid, rmsg) = rmsg.into_streamid_and_msg();
1757 assert_matches!(rmsg, AnyRelayMsg::BeginDir(_));
1758
1759 let connected = relaymsg::Connected::new_empty().into();
1761 sink.send(rmsg_to_ccmsg(streamid, connected, false))
1762 .await
1763 .unwrap();
1764
1765 let (id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
1767 assert_eq!(id, Some(circid));
1768 let rmsg = match chmsg {
1769 AnyChanMsg::Relay(r) => {
1770 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1771 .unwrap()
1772 }
1773 other => panic!("{:?}", other),
1774 };
1775 let (streamid_2, rmsg) = rmsg.into_streamid_and_msg();
1776 assert_eq!(streamid_2, streamid);
1777 if let AnyRelayMsg::Data(d) = rmsg {
1778 assert_eq!(d.as_ref(), &b"HTTP/1.0 GET /\r\n"[..]);
1779 } else {
1780 panic!();
1781 }
1782
1783 let data = relaymsg::Data::new(b"HTTP/1.0 404 Not found\r\n")
1785 .unwrap()
1786 .into();
1787 sink.send(rmsg_to_ccmsg(streamid, data, false))
1788 .await
1789 .unwrap();
1790
1791 let end = relaymsg::End::new_with_reason(relaymsg::EndReason::DONE).into();
1793 sink.send(rmsg_to_ccmsg(streamid, end, false))
1794 .await
1795 .unwrap();
1796
1797 (rx, sink) };
1799
1800 let (_stream, (_rx, _sink)) = futures::join!(begin_and_send_fut, reply_fut);
1801 });
1802 }
1803
1804 fn close_stream_helper(by_drop: bool) {
1806 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1807 let (chan, mut rx, _sink) = working_fake_channel(&rt);
1808 let (tunnel, mut sink) = newtunnel(&rt, chan).await;
1809
1810 let stream_fut = async move {
1811 let stream = tunnel
1812 .begin_stream("www.example.com", 80, None)
1813 .await
1814 .unwrap();
1815
1816 let (r, mut w) = stream.split();
1817 if by_drop {
1818 drop(r);
1820 drop(w);
1821 (None, tunnel) } else {
1823 w.close().await.unwrap();
1825 (Some(r), tunnel)
1826 }
1827 };
1828 let handler_fut = async {
1829 let (_, msg) = rx.next().await.unwrap().into_circid_and_msg();
1831 let rmsg = match msg {
1832 AnyChanMsg::Relay(r) => {
1833 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1834 .unwrap()
1835 }
1836 other => panic!("{:?}", other),
1837 };
1838 let (streamid, rmsg) = rmsg.into_streamid_and_msg();
1839 assert_eq!(rmsg.cmd(), RelayCmd::BEGIN);
1840
1841 let connected =
1843 relaymsg::Connected::new_with_addr("10.0.0.1".parse().unwrap(), 1234).into();
1844 sink.send(rmsg_to_ccmsg(streamid, connected, false))
1845 .await
1846 .unwrap();
1847
1848 let (_, msg) = rx.next().await.unwrap().into_circid_and_msg();
1850 let rmsg = match msg {
1851 AnyChanMsg::Relay(r) => {
1852 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1853 .unwrap()
1854 }
1855 other => panic!("{:?}", other),
1856 };
1857 let (_, rmsg) = rmsg.into_streamid_and_msg();
1858 assert_eq!(rmsg.cmd(), RelayCmd::END);
1859
1860 (rx, sink) };
1862
1863 let ((_opt_reader, _circ), (_rx, _sink)) = futures::join!(stream_fut, handler_fut);
1864 });
1865 }
1866
1867 #[traced_test]
1868 #[test]
1869 fn drop_stream() {
1870 close_stream_helper(true);
1871 }
1872
1873 #[traced_test]
1874 #[test]
1875 fn close_stream() {
1876 close_stream_helper(false);
1877 }
1878
1879 #[traced_test]
1880 #[test]
1881 fn expire_halfstreams() {
1882 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
1883 let (chan, mut rx, _sink) = working_fake_channel(&rt);
1884 let (tunnel, mut sink) = newtunnel(&rt, chan).await;
1885
1886 let client_fut = async move {
1887 let stream = tunnel
1888 .begin_stream("www.example.com", 80, None)
1889 .await
1890 .unwrap();
1891
1892 let (r, mut w) = stream.split();
1893 w.close().await.unwrap();
1895 (Some(r), tunnel)
1896 };
1897 let exit_fut = async {
1898 let (_, msg) = rx.next().await.unwrap().into_circid_and_msg();
1900 let rmsg = match msg {
1901 AnyChanMsg::Relay(r) => {
1902 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1903 .unwrap()
1904 }
1905 other => panic!("{:?}", other),
1906 };
1907 let (streamid, rmsg) = rmsg.into_streamid_and_msg();
1908 assert_eq!(rmsg.cmd(), RelayCmd::BEGIN);
1909
1910 let connected =
1912 relaymsg::Connected::new_with_addr("10.0.0.1".parse().unwrap(), 1234).into();
1913 sink.send(rmsg_to_ccmsg(streamid, connected, false))
1914 .await
1915 .unwrap();
1916
1917 (rx, streamid, sink) };
1919
1920 let ((_opt_reader, tunnel), (_rx, streamid, mut sink)) =
1921 futures::join!(client_fut, exit_fut);
1922
1923 rt.progress_until_stalled().await;
1926
1927 assert!(!tunnel.is_closed());
1929
1930 let data = relaymsg::Data::new(b"hello").unwrap();
1933 sink.send(rmsg_to_ccmsg(streamid, AnyRelayMsg::Data(data), false))
1934 .await
1935 .unwrap();
1936 rt.progress_until_stalled().await;
1937
1938 assert!(!tunnel.is_closed());
1940
1941 let stream_timeout = DummyTimeoutEstimator.circuit_build_timeout(3);
1946 rt.advance_by(2 * stream_timeout).await;
1947
1948 let data = relaymsg::Data::new(b"hello").unwrap();
1951 sink.send(rmsg_to_ccmsg(streamid, AnyRelayMsg::Data(data), false))
1952 .await
1953 .unwrap();
1954 rt.progress_until_stalled().await;
1955
1956 assert!(tunnel.is_closed());
1958 });
1959 }
1960
1961 async fn setup_incoming_sendme_case<R: Runtime>(
1963 rt: &R,
1964 n_to_send: usize,
1965 ) -> (
1966 Arc<ClientTunnel>,
1967 DataStream,
1968 CircuitRxSender,
1969 Option<StreamId>,
1970 usize,
1971 Receiver<AnyChanCell>,
1972 Sender<CodecResult>,
1973 ) {
1974 let (chan, mut rx, sink2) = working_fake_channel(rt);
1975 let (tunnel, mut sink) = newtunnel(rt, chan).await;
1976 let circid = tunnel.as_single_circ().unwrap().peek_circid();
1977
1978 let begin_and_send_fut = {
1979 let tunnel = tunnel.clone();
1980 async move {
1981 let mut stream = tunnel
1983 .begin_stream("www.example.com", 443, None)
1984 .await
1985 .unwrap();
1986 let junk = [0_u8; 1024];
1987 let mut remaining = n_to_send;
1988 while remaining > 0 {
1989 let n = std::cmp::min(remaining, junk.len());
1990 stream.write_all(&junk[..n]).await.unwrap();
1991 remaining -= n;
1992 }
1993 stream.flush().await.unwrap();
1994 stream
1995 }
1996 };
1997
1998 let receive_fut = async move {
1999 let (_id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
2001 let rmsg = match chmsg {
2002 AnyChanMsg::Relay(r) => {
2003 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
2004 .unwrap()
2005 }
2006 other => panic!("{:?}", other),
2007 };
2008 let (streamid, rmsg) = rmsg.into_streamid_and_msg();
2009 assert_matches!(rmsg, AnyRelayMsg::Begin(_));
2010 let connected = relaymsg::Connected::new_empty().into();
2012 sink.send(rmsg_to_ccmsg(streamid, connected, false))
2013 .await
2014 .unwrap();
2015 let mut bytes_received = 0_usize;
2017 let mut cells_received = 0_usize;
2018 while bytes_received < n_to_send {
2019 let (id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
2021 assert_eq!(id, Some(circid));
2022
2023 let rmsg = match chmsg {
2024 AnyChanMsg::Relay(r) => {
2025 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
2026 .unwrap()
2027 }
2028 other => panic!("{:?}", other),
2029 };
2030 let (streamid2, rmsg) = rmsg.into_streamid_and_msg();
2031 assert_eq!(streamid2, streamid);
2032 if let AnyRelayMsg::Data(dat) = rmsg {
2033 cells_received += 1;
2034 bytes_received += dat.as_ref().len();
2035 } else {
2036 panic!();
2037 }
2038 }
2039
2040 (sink, streamid, cells_received, rx)
2041 };
2042
2043 let (stream, (sink, streamid, cells_received, rx)) =
2044 futures::join!(begin_and_send_fut, receive_fut);
2045
2046 (tunnel, stream, sink, streamid, cells_received, rx, sink2)
2047 }
2048
2049 #[traced_test]
2050 #[test]
2051 fn accept_valid_sendme() {
2052 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2053 let (tunnel, _stream, mut sink, streamid, cells_received, _rx, _sink2) =
2054 setup_incoming_sendme_case(&rt, 300 * 498 + 3).await;
2055 let circ = tunnel.as_single_circ().unwrap();
2056
2057 assert_eq!(cells_received, 301);
2058
2059 {
2061 let (tx, rx) = oneshot::channel();
2062 circ.command
2063 .unbounded_send(CtrlCmd::QuerySendWindow {
2064 hop: 2.into(),
2065 leg: tunnel.unique_id(),
2066 done: tx,
2067 })
2068 .unwrap();
2069 let (window, tags) = rx.await.unwrap().unwrap();
2070 assert_eq!(window, 1000 - 301);
2071 assert_eq!(tags.len(), 3);
2072 assert_eq!(
2074 tags[0],
2075 SendmeTag::from(hex!("6400000000000000000000000000000000000000"))
2076 );
2077 assert_eq!(
2079 tags[1],
2080 SendmeTag::from(hex!("c800000000000000000000000000000000000000"))
2081 );
2082 assert_eq!(
2084 tags[2],
2085 SendmeTag::from(hex!("2c01000000000000000000000000000000000000"))
2086 );
2087 }
2088
2089 let reply_with_sendme_fut = async move {
2090 let c_sendme =
2092 relaymsg::Sendme::new_tag(hex!("6400000000000000000000000000000000000000"))
2093 .into();
2094 sink.send(rmsg_to_ccmsg(None, c_sendme, false))
2095 .await
2096 .unwrap();
2097
2098 let s_sendme = relaymsg::Sendme::new_empty().into();
2100 sink.send(rmsg_to_ccmsg(streamid, s_sendme, false))
2101 .await
2102 .unwrap();
2103
2104 sink
2105 };
2106
2107 let _sink = reply_with_sendme_fut.await;
2108
2109 rt.advance_until_stalled().await;
2110
2111 {
2114 let (tx, rx) = oneshot::channel();
2115 circ.command
2116 .unbounded_send(CtrlCmd::QuerySendWindow {
2117 hop: 2.into(),
2118 leg: tunnel.unique_id(),
2119 done: tx,
2120 })
2121 .unwrap();
2122 let (window, _tags) = rx.await.unwrap().unwrap();
2123 assert_eq!(window, 1000 - 201);
2124 }
2125 });
2126 }
2127
2128 #[traced_test]
2129 #[test]
2130 fn invalid_circ_sendme() {
2131 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2132 let (tunnel, _stream, mut sink, _streamid, _cells_received, _rx, _sink2) =
2136 setup_incoming_sendme_case(&rt, 300 * 498 + 3).await;
2137
2138 let reply_with_sendme_fut = async move {
2139 let c_sendme =
2141 relaymsg::Sendme::new_tag(hex!("FFFF0000000000000000000000000000000000FF"))
2142 .into();
2143 sink.send(rmsg_to_ccmsg(None, c_sendme, false))
2144 .await
2145 .unwrap();
2146 sink
2147 };
2148
2149 let _sink = reply_with_sendme_fut.await;
2150
2151 rt.advance_until_stalled().await;
2153 assert!(tunnel.is_closed());
2154 });
2155 }
2156
2157 #[traced_test]
2158 #[test]
2159 fn test_busy_stream_fairness() {
2160 const N_STREAMS: usize = 3;
2162 const N_CELLS: usize = 20;
2164 const N_BYTES: usize = relaymsg::Data::MAXLEN_V0 * N_CELLS;
2167 const MIN_EXPECTED_BYTES_PER_STREAM: usize =
2174 N_BYTES / N_STREAMS - relaymsg::Data::MAXLEN_V0;
2175
2176 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
2177 let (chan, mut rx, _sink) = working_fake_channel(&rt);
2178 let (tunnel, mut sink) = newtunnel(&rt, chan).await;
2179
2180 rt.spawn({
2186 let tunnel = tunnel.clone();
2189 async move {
2190 let mut clients = VecDeque::new();
2191 struct Client {
2192 stream: DataStream,
2193 to_write: &'static [u8],
2194 }
2195 for _ in 0..N_STREAMS {
2196 clients.push_back(Client {
2197 stream: tunnel
2198 .begin_stream("www.example.com", 80, None)
2199 .await
2200 .unwrap(),
2201 to_write: &[0_u8; N_BYTES][..],
2202 });
2203 }
2204 while let Some(mut client) = clients.pop_front() {
2205 if client.to_write.is_empty() {
2206 continue;
2208 }
2209 let written = client.stream.write(client.to_write).await.unwrap();
2210 client.to_write = &client.to_write[written..];
2211 clients.push_back(client);
2212 }
2213 }
2214 })
2215 .unwrap();
2216
2217 let channel_handler_fut = async {
2218 let mut stream_bytes_received = HashMap::<StreamId, usize>::new();
2219 let mut total_bytes_received = 0;
2220
2221 loop {
2222 let (_, msg) = rx.next().await.unwrap().into_circid_and_msg();
2223 let rmsg = match msg {
2224 AnyChanMsg::Relay(r) => AnyRelayMsgOuter::decode_singleton(
2225 RelayCellFormat::V0,
2226 r.into_relay_body(),
2227 )
2228 .unwrap(),
2229 other => panic!("Unexpected chanmsg: {other:?}"),
2230 };
2231 let (streamid, rmsg) = rmsg.into_streamid_and_msg();
2232 match rmsg.cmd() {
2233 RelayCmd::BEGIN => {
2234 let prev = stream_bytes_received.insert(streamid.unwrap(), 0);
2236 assert_eq!(prev, None);
2237 let connected = relaymsg::Connected::new_with_addr(
2239 "10.0.0.1".parse().unwrap(),
2240 1234,
2241 )
2242 .into();
2243 sink.send(rmsg_to_ccmsg(streamid, connected, false))
2244 .await
2245 .unwrap();
2246 }
2247 RelayCmd::DATA => {
2248 let data_msg = relaymsg::Data::try_from(rmsg).unwrap();
2249 let nbytes = data_msg.as_ref().len();
2250 total_bytes_received += nbytes;
2251 let streamid = streamid.unwrap();
2252 let stream_bytes = stream_bytes_received.get_mut(&streamid).unwrap();
2253 *stream_bytes += nbytes;
2254 if total_bytes_received >= N_BYTES {
2255 break;
2256 }
2257 }
2258 RelayCmd::END => {
2259 continue;
2264 }
2265 other => {
2266 panic!("Unexpected command {other:?}");
2267 }
2268 }
2269 }
2270
2271 (total_bytes_received, stream_bytes_received, rx, sink)
2274 };
2275
2276 let (total_bytes_received, stream_bytes_received, _rx, _sink) =
2277 channel_handler_fut.await;
2278 assert_eq!(stream_bytes_received.len(), N_STREAMS);
2279 for (sid, stream_bytes) in stream_bytes_received {
2280 assert!(
2281 stream_bytes >= MIN_EXPECTED_BYTES_PER_STREAM,
2282 "Only {stream_bytes} of {total_bytes_received} bytes received from {N_STREAMS} came from {sid:?}; expected at least {MIN_EXPECTED_BYTES_PER_STREAM}"
2283 );
2284 }
2285 });
2286 }
2287
2288 #[test]
2289 fn basic_params() {
2290 use super::CircParameters;
2291 let mut p = CircParameters::default();
2292 assert!(p.extend_by_ed25519_id);
2293
2294 p.extend_by_ed25519_id = false;
2295 assert!(!p.extend_by_ed25519_id);
2296 }
2297
2298 #[traced_test]
2299 #[test]
2300 #[cfg(feature = "hs-service")]
2301 fn allow_stream_requests_twice() {
2302 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
2303 let (chan, _rx, _sink) = working_fake_channel(&rt);
2304 let (tunnel, _send) = newtunnel(&rt, chan).await;
2305
2306 let _incoming = tunnel
2307 .allow_stream_requests(
2308 &[tor_cell::relaycell::RelayCmd::BEGIN],
2309 tunnel.resolve_last_hop().await,
2310 AllowAllStreamsFilter,
2311 )
2312 .await
2313 .unwrap();
2314
2315 let incoming = tunnel
2316 .allow_stream_requests(
2317 &[tor_cell::relaycell::RelayCmd::BEGIN],
2318 tunnel.resolve_last_hop().await,
2319 AllowAllStreamsFilter,
2320 )
2321 .await;
2322
2323 assert!(incoming.is_err());
2325 });
2326 }
2327
2328 #[traced_test]
2329 #[test]
2330 #[cfg(feature = "hs-service")]
2331 fn allow_stream_requests() {
2332 use tor_cell::relaycell::msg::BeginFlags;
2333
2334 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
2335 const TEST_DATA: &[u8] = b"ping";
2336
2337 let (chan, _rx, _sink) = working_fake_channel(&rt);
2338 let (tunnel, mut send) = newtunnel(&rt, chan).await;
2339
2340 let rfmt = RelayCellFormat::V0;
2341
2342 let (tx, rx) = oneshot::channel();
2344 let mut incoming = tunnel
2345 .allow_stream_requests(
2346 &[tor_cell::relaycell::RelayCmd::BEGIN],
2347 tunnel.resolve_last_hop().await,
2348 AllowAllStreamsFilter,
2349 )
2350 .await
2351 .unwrap();
2352
2353 let simulate_service = async move {
2354 let stream = incoming.next().await.unwrap();
2355 let mut data_stream = stream
2356 .accept_data(relaymsg::Connected::new_empty())
2357 .await
2358 .unwrap();
2359 tx.send(()).unwrap();
2361
2362 let mut buf = [0_u8; TEST_DATA.len()];
2364 data_stream.read_exact(&mut buf).await.unwrap();
2365 assert_eq!(&buf, TEST_DATA);
2366
2367 tunnel
2368 };
2369
2370 let simulate_client = async move {
2371 let begin = relaymsg::Begin::new("localhost", 80, BeginFlags::IPV6_OKAY).unwrap();
2372 let body: BoxedCellBody =
2373 AnyRelayMsgOuter::new(StreamId::new(12), AnyRelayMsg::Begin(begin))
2374 .encode(rfmt, &mut testing_rng())
2375 .unwrap();
2376 let begin_msg = chanmsg::Relay::from(body);
2377
2378 send.send(AnyChanMsg::Relay(begin_msg)).await.unwrap();
2380
2381 rx.await.unwrap();
2387 let data = relaymsg::Data::new(TEST_DATA).unwrap();
2389 let body: BoxedCellBody =
2390 AnyRelayMsgOuter::new(StreamId::new(12), AnyRelayMsg::Data(data))
2391 .encode(rfmt, &mut testing_rng())
2392 .unwrap();
2393 let data_msg = chanmsg::Relay::from(body);
2394
2395 send.send(AnyChanMsg::Relay(data_msg)).await.unwrap();
2396 send
2397 };
2398
2399 let (_circ, _send) = futures::join!(simulate_service, simulate_client);
2400 });
2401 }
2402
2403 #[traced_test]
2404 #[test]
2405 #[cfg(feature = "hs-service")]
2406 fn accept_stream_after_reject() {
2407 use tor_cell::relaycell::msg::AnyRelayMsg;
2408 use tor_cell::relaycell::msg::BeginFlags;
2409 use tor_cell::relaycell::msg::EndReason;
2410
2411 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
2412 const TEST_DATA: &[u8] = b"ping";
2413 const STREAM_COUNT: usize = 2;
2414 let rfmt = RelayCellFormat::V0;
2415
2416 let (chan, _rx, _sink) = working_fake_channel(&rt);
2417 let (tunnel, mut send) = newtunnel(&rt, chan).await;
2418
2419 let (mut tx, mut rx) = mpsc::channel(STREAM_COUNT);
2421
2422 let mut incoming = tunnel
2423 .allow_stream_requests(
2424 &[tor_cell::relaycell::RelayCmd::BEGIN],
2425 tunnel.resolve_last_hop().await,
2426 AllowAllStreamsFilter,
2427 )
2428 .await
2429 .unwrap();
2430
2431 let simulate_service = async move {
2432 for i in 0..STREAM_COUNT {
2434 let stream = incoming.next().await.unwrap();
2435
2436 if i == 0 {
2438 stream
2439 .reject(relaymsg::End::new_with_reason(EndReason::INTERNAL))
2440 .await
2441 .unwrap();
2442 tx.send(()).await.unwrap();
2444 continue;
2445 }
2446
2447 let mut data_stream = stream
2448 .accept_data(relaymsg::Connected::new_empty())
2449 .await
2450 .unwrap();
2451 tx.send(()).await.unwrap();
2453
2454 let mut buf = [0_u8; TEST_DATA.len()];
2456 data_stream.read_exact(&mut buf).await.unwrap();
2457 assert_eq!(&buf, TEST_DATA);
2458 }
2459
2460 tunnel
2461 };
2462
2463 let simulate_client = async move {
2464 let begin = relaymsg::Begin::new("localhost", 80, BeginFlags::IPV6_OKAY).unwrap();
2465 let body: BoxedCellBody =
2466 AnyRelayMsgOuter::new(StreamId::new(12), AnyRelayMsg::Begin(begin))
2467 .encode(rfmt, &mut testing_rng())
2468 .unwrap();
2469 let begin_msg = chanmsg::Relay::from(body);
2470
2471 for _ in 0..STREAM_COUNT {
2474 send.send(AnyChanMsg::Relay(begin_msg.clone()))
2475 .await
2476 .unwrap();
2477
2478 rx.next().await.unwrap();
2480 }
2481
2482 let data = relaymsg::Data::new(TEST_DATA).unwrap();
2484 let body: BoxedCellBody =
2485 AnyRelayMsgOuter::new(StreamId::new(12), AnyRelayMsg::Data(data))
2486 .encode(rfmt, &mut testing_rng())
2487 .unwrap();
2488 let data_msg = chanmsg::Relay::from(body);
2489
2490 send.send(AnyChanMsg::Relay(data_msg)).await.unwrap();
2491 send
2492 };
2493
2494 let (_circ, _send) = futures::join!(simulate_service, simulate_client);
2495 });
2496 }
2497
2498 #[traced_test]
2499 #[test]
2500 #[cfg(feature = "hs-service")]
2501 fn incoming_stream_bad_hop() {
2502 use tor_cell::relaycell::msg::BeginFlags;
2503
2504 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
2505 const EXPECTED_HOP: u8 = 1;
2507 let rfmt = RelayCellFormat::V0;
2508
2509 let (chan, _rx, _sink) = working_fake_channel(&rt);
2510 let (tunnel, mut send) = newtunnel(&rt, chan).await;
2511
2512 let mut incoming = tunnel
2514 .allow_stream_requests(
2515 &[tor_cell::relaycell::RelayCmd::BEGIN],
2516 (
2518 tunnel.as_single_circ().unwrap().unique_id(),
2519 EXPECTED_HOP.into(),
2520 )
2521 .into(),
2522 AllowAllStreamsFilter,
2523 )
2524 .await
2525 .unwrap();
2526
2527 let simulate_service = async move {
2528 assert!(incoming.next().await.is_none());
2531 tunnel
2532 };
2533
2534 let simulate_client = async move {
2535 let begin = relaymsg::Begin::new("localhost", 80, BeginFlags::IPV6_OKAY).unwrap();
2536 let body: BoxedCellBody =
2537 AnyRelayMsgOuter::new(StreamId::new(12), AnyRelayMsg::Begin(begin))
2538 .encode(rfmt, &mut testing_rng())
2539 .unwrap();
2540 let begin_msg = chanmsg::Relay::from(body);
2541
2542 send.send(AnyChanMsg::Relay(begin_msg)).await.unwrap();
2544
2545 send
2546 };
2547
2548 let (_circ, _send) = futures::join!(simulate_service, simulate_client);
2549 });
2550 }
2551
2552 #[traced_test]
2553 #[test]
2554 #[cfg(feature = "conflux")]
2555 fn multipath_circ_validation() {
2556 use std::error::Error as _;
2557
2558 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2559 let params = CircParameters::default();
2560 let invalid_tunnels = [
2561 setup_bad_conflux_tunnel(&rt).await,
2562 setup_conflux_tunnel(&rt, true, params).await,
2563 ];
2564
2565 for tunnel in invalid_tunnels {
2566 let TestTunnelCtx {
2567 tunnel: _tunnel,
2568 circs: _circs,
2569 conflux_link_rx,
2570 } = tunnel;
2571
2572 let conflux_hs_err = conflux_link_rx.await.unwrap().unwrap_err();
2573 let err_src = conflux_hs_err.source().unwrap();
2574
2575 assert!(
2578 err_src
2579 .to_string()
2580 .contains("one more conflux circuits are invalid")
2581 );
2582 }
2583 });
2584 }
2585
2586 #[derive(Debug)]
2590 #[allow(unused)]
2591 #[cfg(feature = "conflux")]
2592 struct TestCircuitCtx {
2593 chan_rx: Receiver<AnyChanCell>,
2594 chan_tx: Sender<std::result::Result<AnyChanCell, Error>>,
2595 circ_tx: CircuitRxSender,
2596 unique_id: UniqId,
2597 }
2598
2599 #[derive(Debug)]
2600 #[cfg(feature = "conflux")]
2601 struct TestTunnelCtx {
2602 tunnel: Arc<ClientTunnel>,
2603 circs: Vec<TestCircuitCtx>,
2604 conflux_link_rx: oneshot::Receiver<Result<ConfluxHandshakeResult>>,
2605 }
2606
2607 #[cfg(feature = "conflux")]
2609 async fn await_link_payload(rx: &mut Receiver<AnyChanCell>) -> ConfluxLink {
2610 let (_id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
2612 let rmsg = match chmsg {
2613 AnyChanMsg::Relay(r) => {
2614 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
2615 .unwrap()
2616 }
2617 other => panic!("{:?}", other),
2618 };
2619 let (streamid, rmsg) = rmsg.into_streamid_and_msg();
2620
2621 let link = match rmsg {
2622 AnyRelayMsg::ConfluxLink(link) => link,
2623 _ => panic!("unexpected relay message {rmsg:?}"),
2624 };
2625
2626 assert!(streamid.is_none());
2627
2628 link
2629 }
2630
2631 #[cfg(feature = "conflux")]
2632 async fn setup_conflux_tunnel(
2633 rt: &MockRuntime,
2634 same_hops: bool,
2635 params: CircParameters,
2636 ) -> TestTunnelCtx {
2637 let hops1 = hop_details(3, 0);
2638 let hops2 = if same_hops {
2639 hops1.clone()
2640 } else {
2641 hop_details(3, 10)
2642 };
2643
2644 let (chan1, rx1, chan_sink1) = working_fake_channel(rt);
2645 let (mut tunnel1, sink1) = newtunnel_ext(
2646 rt,
2647 UniqId::new(1, 3),
2648 chan1,
2649 hops1,
2650 2.into(),
2651 params.clone(),
2652 )
2653 .await;
2654
2655 let (chan2, rx2, chan_sink2) = working_fake_channel(rt);
2656
2657 let (tunnel2, sink2) =
2658 newtunnel_ext(rt, UniqId::new(2, 4), chan2, hops2, 2.into(), params).await;
2659
2660 let (answer_tx, answer_rx) = oneshot::channel();
2661 tunnel2
2662 .as_single_circ()
2663 .unwrap()
2664 .command
2665 .unbounded_send(CtrlCmd::ShutdownAndReturnCircuit { answer: answer_tx })
2666 .unwrap();
2667
2668 let circuit = answer_rx.await.unwrap().unwrap();
2669 rt.advance_until_stalled().await;
2671 assert!(tunnel2.is_closed());
2672
2673 let (conflux_link_tx, conflux_link_rx) = oneshot::channel();
2674 tunnel1
2676 .as_single_circ()
2677 .unwrap()
2678 .control
2679 .unbounded_send(CtrlMsg::LinkCircuits {
2680 circuits: vec![circuit],
2681 answer: conflux_link_tx,
2682 })
2683 .unwrap();
2684
2685 let circ_ctx1 = TestCircuitCtx {
2686 chan_rx: rx1,
2687 chan_tx: chan_sink1,
2688 circ_tx: sink1,
2689 unique_id: tunnel1.unique_id(),
2690 };
2691
2692 let circ_ctx2 = TestCircuitCtx {
2693 chan_rx: rx2,
2694 chan_tx: chan_sink2,
2695 circ_tx: sink2,
2696 unique_id: tunnel2.unique_id(),
2697 };
2698
2699 tunnel1.circ.is_multi_path = true;
2705 TestTunnelCtx {
2706 tunnel: Arc::new(tunnel1),
2707 circs: vec![circ_ctx1, circ_ctx2],
2708 conflux_link_rx,
2709 }
2710 }
2711
2712 #[cfg(feature = "conflux")]
2713 async fn setup_good_conflux_tunnel(
2714 rt: &MockRuntime,
2715 cc_params: CongestionControlParams,
2716 ) -> TestTunnelCtx {
2717 let same_hops = true;
2723 let flow_ctrl_params = FlowCtrlParameters::defaults_for_tests();
2724 let params = CircParameters::new(true, cc_params, flow_ctrl_params);
2725 setup_conflux_tunnel(rt, same_hops, params).await
2726 }
2727
2728 #[cfg(feature = "conflux")]
2729 async fn setup_bad_conflux_tunnel(rt: &MockRuntime) -> TestTunnelCtx {
2730 let same_hops = false;
2734 let flow_ctrl_params = FlowCtrlParameters::defaults_for_tests();
2735 let params = CircParameters::new(true, build_cc_vegas_params(), flow_ctrl_params);
2736 setup_conflux_tunnel(rt, same_hops, params).await
2737 }
2738
2739 #[traced_test]
2740 #[test]
2741 #[cfg(feature = "conflux")]
2742 fn reject_conflux_linked_before_hs() {
2743 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2744 let (chan, mut _rx, _sink) = working_fake_channel(&rt);
2745 let (tunnel, mut sink) = newtunnel(&rt, chan).await;
2746
2747 let nonce = V1Nonce::new(&mut testing_rng());
2748 let payload = V1LinkPayload::new(nonce, V1DesiredUx::NO_OPINION);
2749 let linked = relaymsg::ConfluxLinked::new(payload).into();
2751 sink.send(rmsg_to_ccmsg(None, linked, false)).await.unwrap();
2752
2753 rt.advance_until_stalled().await;
2754 assert!(tunnel.is_closed());
2755 });
2756 }
2757
2758 #[traced_test]
2759 #[test]
2760 #[cfg(feature = "conflux")]
2761 fn conflux_hs_timeout() {
2762 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2763 let TestTunnelCtx {
2764 tunnel: _tunnel,
2765 circs,
2766 conflux_link_rx,
2767 } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
2768
2769 let [mut circ1, _circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
2770
2771 let link = await_link_payload(&mut circ1.chan_rx).await;
2773
2774 let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
2776 circ1
2777 .circ_tx
2778 .send(rmsg_to_ccmsg(None, linked, false))
2779 .await
2780 .unwrap();
2781
2782 rt.advance_by(Duration::from_secs(60)).await;
2784
2785 let conflux_hs_res = conflux_link_rx.await.unwrap().unwrap();
2786
2787 let [res1, res2]: [StdResult<(), ConfluxHandshakeError>; 2] =
2789 conflux_hs_res.try_into().unwrap();
2790
2791 assert!(res1.is_ok());
2792
2793 let err = res2.unwrap_err();
2794 assert_matches!(err, ConfluxHandshakeError::Timeout);
2795 });
2796 }
2797
2798 #[traced_test]
2799 #[test]
2800 #[cfg(feature = "conflux")]
2801 fn conflux_bad_hs() {
2802 use crate::util::err::ConfluxHandshakeError;
2803
2804 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2805 let nonce = V1Nonce::new(&mut testing_rng());
2806 let bad_link_payload = V1LinkPayload::new(nonce, V1DesiredUx::NO_OPINION);
2807 let bad_hs_responses = [
2809 (
2810 rmsg_to_ccmsg(
2811 None,
2812 relaymsg::ConfluxLinked::new(bad_link_payload.clone()).into(),
2813 false,
2814 ),
2815 "Received CONFLUX_LINKED cell with mismatched nonce",
2816 ),
2817 (
2818 rmsg_to_ccmsg(
2819 None,
2820 relaymsg::ConfluxLink::new(bad_link_payload).into(),
2821 false,
2822 ),
2823 "Unexpected CONFLUX_LINK cell from hop #3 on client circuit",
2824 ),
2825 (
2826 rmsg_to_ccmsg(None, relaymsg::ConfluxSwitch::new(0).into(), false),
2827 "Received CONFLUX_SWITCH on unlinked circuit?!",
2828 ),
2829 ];
2838
2839 for (bad_cell, expected_err) in bad_hs_responses {
2840 let TestTunnelCtx {
2841 tunnel,
2842 circs,
2843 conflux_link_rx,
2844 } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
2845
2846 let [mut _circ1, mut circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
2847
2848 circ2.circ_tx.send(bad_cell).await.unwrap();
2850
2851 let conflux_hs_res = conflux_link_rx.await.unwrap().unwrap();
2852 let [res2]: [StdResult<(), ConfluxHandshakeError>; 1] =
2856 conflux_hs_res.try_into().unwrap();
2857
2858 match res2.unwrap_err() {
2859 ConfluxHandshakeError::Link(Error::CircProto(e)) => {
2860 assert_eq!(e, expected_err);
2861 }
2862 e => panic!("unexpected error: {e:?}"),
2863 }
2864
2865 assert!(tunnel.is_closed());
2866 }
2867 });
2868 }
2869
2870 #[traced_test]
2871 #[test]
2872 #[cfg(feature = "conflux")]
2873 fn unexpected_conflux_cell() {
2874 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2875 let nonce = V1Nonce::new(&mut testing_rng());
2876 let link_payload = V1LinkPayload::new(nonce, V1DesiredUx::NO_OPINION);
2877 let bad_cells = [
2878 rmsg_to_ccmsg(
2879 None,
2880 relaymsg::ConfluxLinked::new(link_payload.clone()).into(),
2881 false,
2882 ),
2883 rmsg_to_ccmsg(
2884 None,
2885 relaymsg::ConfluxLink::new(link_payload.clone()).into(),
2886 false,
2887 ),
2888 rmsg_to_ccmsg(None, relaymsg::ConfluxSwitch::new(0).into(), false),
2889 ];
2890
2891 for bad_cell in bad_cells {
2892 let (chan, mut _rx, _sink) = working_fake_channel(&rt);
2893 let (tunnel, mut sink) = newtunnel(&rt, chan).await;
2894
2895 sink.send(bad_cell).await.unwrap();
2896 rt.advance_until_stalled().await;
2897
2898 assert!(tunnel.is_closed());
2902 }
2903 });
2904 }
2905
2906 #[traced_test]
2907 #[test]
2908 #[cfg(feature = "conflux")]
2909 fn conflux_bad_linked() {
2910 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2911 let TestTunnelCtx {
2912 tunnel,
2913 circs,
2914 conflux_link_rx: _,
2915 } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
2916
2917 let [mut circ1, mut circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
2918
2919 let link = await_link_payload(&mut circ1.chan_rx).await;
2920
2921 let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
2923 circ1
2924 .circ_tx
2925 .send(rmsg_to_ccmsg(None, linked, false))
2926 .await
2927 .unwrap();
2928
2929 let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
2931 circ2
2932 .circ_tx
2933 .send(rmsg_to_ccmsg(None, linked, false))
2934 .await
2935 .unwrap();
2936 let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
2937 circ2
2938 .circ_tx
2939 .send(rmsg_to_ccmsg(None, linked, false))
2940 .await
2941 .unwrap();
2942
2943 rt.advance_until_stalled().await;
2944
2945 assert!(tunnel.is_closed());
2948 });
2949 }
2950
2951 #[traced_test]
2952 #[test]
2953 #[cfg(feature = "conflux")]
2954 fn conflux_bad_switch() {
2955 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2956 let cc_vegas_params = build_cc_vegas_params();
2957 let cwnd_init = cc_vegas_params.cwnd_params().cwnd_init();
2958 let bad_switch = [
2959 relaymsg::ConfluxSwitch::new(0),
2961 relaymsg::ConfluxSwitch::new(cwnd_init + 1),
2964 ];
2965
2966 for bad_cell in bad_switch {
2967 let TestTunnelCtx {
2968 tunnel,
2969 circs,
2970 conflux_link_rx,
2971 } = setup_good_conflux_tunnel(&rt, cc_vegas_params.clone()).await;
2972
2973 let [mut circ1, mut circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
2974
2975 let link = await_link_payload(&mut circ1.chan_rx).await;
2976
2977 for circ in [&mut circ1, &mut circ2] {
2979 let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
2980 circ.circ_tx
2981 .send(rmsg_to_ccmsg(None, linked, false))
2982 .await
2983 .unwrap();
2984 }
2985
2986 let conflux_hs_res = conflux_link_rx.await.unwrap().unwrap();
2987 assert!(conflux_hs_res.iter().all(|res| res.is_ok()));
2988
2989 let msg = rmsg_to_ccmsg(None, bad_cell.clone().into(), false);
2992 circ1.circ_tx.send(msg).await.unwrap();
2993
2994 rt.advance_until_stalled().await;
2996 assert!(tunnel.is_closed());
2997 }
2998 });
2999 }
3000
3001 #[traced_test]
3002 #[test]
3003 #[cfg(feature = "conflux")]
3004 fn conflux_consecutive_switch() {
3005 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
3006 let TestTunnelCtx {
3007 tunnel,
3008 circs,
3009 conflux_link_rx,
3010 } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
3011
3012 let [mut circ1, mut circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
3013
3014 let link = await_link_payload(&mut circ1.chan_rx).await;
3015
3016 for circ in [&mut circ1, &mut circ2] {
3018 let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
3019 circ.circ_tx
3020 .send(rmsg_to_ccmsg(None, linked, false))
3021 .await
3022 .unwrap();
3023 }
3024
3025 let conflux_hs_res = conflux_link_rx.await.unwrap().unwrap();
3026 assert!(conflux_hs_res.iter().all(|res| res.is_ok()));
3027
3028 let switch1 = relaymsg::ConfluxSwitch::new(10);
3030 let msg = rmsg_to_ccmsg(None, switch1.into(), false);
3031 circ1.circ_tx.send(msg).await.unwrap();
3032
3033 rt.advance_until_stalled().await;
3035 assert!(!tunnel.is_closed());
3036
3037 let switch2 = relaymsg::ConfluxSwitch::new(12);
3039 let msg = rmsg_to_ccmsg(None, switch2.into(), false);
3040 circ1.circ_tx.send(msg).await.unwrap();
3041
3042 rt.advance_until_stalled().await;
3045 assert!(tunnel.is_closed());
3046 });
3047 }
3048
3049 #[traced_test]
3052 #[test]
3053 #[cfg(feature = "conflux")]
3054 fn shutdown_and_return_circ_multipath() {
3055 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
3056 let TestTunnelCtx {
3057 tunnel,
3058 circs,
3059 conflux_link_rx: _,
3060 } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
3061
3062 rt.progress_until_stalled().await;
3063
3064 let (answer_tx, answer_rx) = oneshot::channel();
3065 tunnel
3066 .circ
3067 .command
3068 .unbounded_send(CtrlCmd::ShutdownAndReturnCircuit { answer: answer_tx })
3069 .unwrap();
3070
3071 #[allow(clippy::unused_unit, clippy::semicolon_if_nothing_returned)]
3073 let err = answer_rx
3074 .await
3075 .unwrap()
3076 .map(|_| {
3077 ()
3080 })
3081 .unwrap_err();
3082
3083 const MSG: &str = "not a single leg conflux set (got at least 2 elements when exactly one was expected)";
3084 assert!(err.to_string().contains(MSG), "{err}");
3085
3086 rt.progress_until_stalled().await;
3089 assert!(tunnel.is_closed());
3090
3091 drop(circs);
3094 });
3095 }
3096
3097 #[cfg(feature = "conflux")]
3099 #[derive(Debug)]
3100 enum ConfluxTestEndpoint<I: Iterator<Item = Option<Duration>>> {
3101 Relay(ConfluxExitState<I>),
3103 Client {
3105 conflux_link_rx: oneshot::Receiver<Result<ConfluxHandshakeResult>>,
3107 tunnel: Arc<ClientTunnel>,
3109 send_data: Vec<u8>,
3111 recv_data: Vec<u8>,
3113 },
3114 }
3115
3116 #[allow(unused, clippy::large_enum_variant)]
3119 #[derive(Debug)]
3120 #[cfg(feature = "conflux")]
3121 enum ConfluxEndpointResult {
3122 Circuit {
3123 tunnel: Arc<ClientTunnel>,
3124 stream: DataStream,
3125 },
3126 Relay {
3127 circ: TestCircuitCtx,
3128 },
3129 }
3130
3131 #[derive(Debug)]
3133 #[cfg(feature = "conflux")]
3134 struct ConfluxStreamState {
3135 data_recvd: Vec<u8>,
3137 expected_data_len: usize,
3139 begin_recvd: bool,
3141 end_recvd: bool,
3143 end_sent: bool,
3145 }
3146
3147 #[cfg(feature = "conflux")]
3148 impl ConfluxStreamState {
3149 fn new(expected_data_len: usize) -> Self {
3150 Self {
3151 data_recvd: vec![],
3152 expected_data_len,
3153 begin_recvd: false,
3154 end_recvd: false,
3155 end_sent: false,
3156 }
3157 }
3158 }
3159
3160 #[derive(Debug)]
3163 #[cfg(feature = "conflux")]
3164 struct ExpectedSwitch {
3165 cells_so_far: usize,
3168 seqno: u32,
3170 }
3171
3172 #[cfg(feature = "conflux")]
3178 struct CellDispatcher {
3179 leg_tx: HashMap<UniqId, mpsc::Sender<CellToSend>>,
3181 cells_to_send: Vec<(UniqId, AnyRelayMsg)>,
3183 }
3184
3185 #[cfg(feature = "conflux")]
3186 impl CellDispatcher {
3187 async fn run(mut self) {
3188 while !self.cells_to_send.is_empty() {
3189 let (circ_id, cell) = self.cells_to_send.remove(0);
3190 let cell_tx = self.leg_tx.get_mut(&circ_id).unwrap();
3191 let (done_tx, done_rx) = oneshot::channel();
3192 cell_tx.send(CellToSend { done_tx, cell }).await.unwrap();
3193 let () = done_rx.await.unwrap();
3195 }
3196 }
3197 }
3198
3199 #[cfg(feature = "conflux")]
3201 #[derive(Debug)]
3202 struct CellToSend {
3203 done_tx: oneshot::Sender<()>,
3205 cell: AnyRelayMsg,
3207 }
3208
3209 #[derive(Debug)]
3211 #[cfg(feature = "conflux")]
3212 struct ConfluxExitState<I: Iterator<Item = Option<Duration>>> {
3213 runtime: Arc<AsyncMutex<MockRuntime>>,
3220 tunnel: Arc<ClientTunnel>,
3222 circ: TestCircuitCtx,
3224 rtt_delays: I,
3228 stream_state: Arc<Mutex<ConfluxStreamState>>,
3231 expect_switch: Vec<ExpectedSwitch>,
3234 event_rx: mpsc::Receiver<MockExitEvent>,
3236 event_tx: mpsc::Sender<MockExitEvent>,
3238 is_sending_leg: bool,
3240 cells_rx: mpsc::Receiver<CellToSend>,
3242 }
3243
3244 #[cfg(feature = "conflux")]
3245 async fn good_exit_handshake(
3246 runtime: &Arc<AsyncMutex<MockRuntime>>,
3247 init_rtt_delay: Option<Duration>,
3248 rx: &mut Receiver<ChanCell<AnyChanMsg>>,
3249 sink: &mut CircuitRxSender,
3250 ) {
3251 let link = await_link_payload(rx).await;
3253
3254 if let Some(init_rtt_delay) = init_rtt_delay {
3257 runtime.lock().await.advance_by(init_rtt_delay).await;
3258 }
3259
3260 let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
3262 sink.send(rmsg_to_ccmsg(None, linked, false)).await.unwrap();
3263
3264 let (_id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
3266 let rmsg = match chmsg {
3267 AnyChanMsg::Relay(r) => {
3268 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
3269 .unwrap()
3270 }
3271 other => panic!("{other:?}"),
3272 };
3273 let (_streamid, rmsg) = rmsg.into_streamid_and_msg();
3274
3275 assert_matches!(rmsg, AnyRelayMsg::ConfluxLinkedAck(_));
3276 }
3277
3278 #[derive(Copy, Clone, Debug)]
3280 enum MockExitEvent {
3281 Done,
3283 BeginRecvd(StreamId),
3285 }
3286
3287 #[cfg(feature = "conflux")]
3288 async fn run_mock_conflux_exit<I: Iterator<Item = Option<Duration>>>(
3289 state: ConfluxExitState<I>,
3290 ) -> ConfluxEndpointResult {
3291 let ConfluxExitState {
3292 runtime,
3293 tunnel,
3294 mut circ,
3295 rtt_delays,
3296 stream_state,
3297 mut expect_switch,
3298 mut event_tx,
3299 mut event_rx,
3300 is_sending_leg,
3301 mut cells_rx,
3302 } = state;
3303
3304 let mut rtt_delays = rtt_delays.into_iter();
3305
3306 let stream_len = stream_state.lock().unwrap().expected_data_len;
3308 let mut data_cells_received = 0_usize;
3309 let mut cell_count = 0_usize;
3310 let mut tags = vec![];
3311 let mut streamid = None;
3312 let mut done_writing = false;
3313
3314 loop {
3315 let should_exit = {
3316 let stream_state = stream_state.lock().unwrap();
3317 let done_reading = stream_state.data_recvd.len() >= stream_len;
3318
3319 (stream_state.begin_recvd || stream_state.end_recvd) && done_reading && done_writing
3320 };
3321
3322 if should_exit {
3323 break;
3324 }
3325
3326 use futures::select;
3327
3328 let mut next_cell = if streamid.is_some() && !done_writing {
3331 Box::pin(cells_rx.next().fuse())
3332 as Pin<Box<dyn FusedFuture<Output = Option<CellToSend>> + Send>>
3333 } else {
3334 Box::pin(std::future::pending().fuse())
3335 };
3336
3337 let res = select! {
3340 res = circ.chan_rx.next() => {
3341 res.unwrap()
3342 },
3343 res = event_rx.next() => {
3344 let Some(event) = res else {
3345 break;
3346 };
3347
3348 match event {
3349 MockExitEvent::Done => {
3350 break;
3351 },
3352 MockExitEvent::BeginRecvd(id) => {
3353 streamid = Some(id);
3356 continue;
3357 },
3358 }
3359 }
3360 res = next_cell => {
3361 if let Some(cell_to_send) = res {
3362 let CellToSend { cell, done_tx } = cell_to_send;
3363
3364 let streamid = if matches!(cell, AnyRelayMsg::ConfluxSwitch(_)) {
3366 None
3367 } else {
3368 streamid
3369 };
3370
3371 circ.circ_tx
3372 .send(rmsg_to_ccmsg(streamid, cell, false))
3373 .await
3374 .unwrap();
3375
3376 runtime.lock().await.advance_until_stalled().await;
3377 done_tx.send(()).unwrap();
3378 } else {
3379 done_writing = true;
3380 }
3381
3382 continue;
3383 }
3384 };
3385
3386 let (_id, chmsg) = res.into_circid_and_msg();
3387 cell_count += 1;
3388 let rmsg = match chmsg {
3389 AnyChanMsg::Relay(r) => {
3390 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
3391 .unwrap()
3392 }
3393 other => panic!("{:?}", other),
3394 };
3395 let (new_streamid, rmsg) = rmsg.into_streamid_and_msg();
3396 if streamid.is_none() {
3397 streamid = new_streamid;
3398 }
3399
3400 let begin_recvd = stream_state.lock().unwrap().begin_recvd;
3401 let end_recvd = stream_state.lock().unwrap().end_recvd;
3402 match rmsg {
3403 AnyRelayMsg::Begin(_) if begin_recvd => {
3404 panic!("client tried to open two streams?!");
3405 }
3406 AnyRelayMsg::Begin(_) if !begin_recvd => {
3407 stream_state.lock().unwrap().begin_recvd = true;
3408 let connected = relaymsg::Connected::new_empty().into();
3410 circ.circ_tx
3411 .send(rmsg_to_ccmsg(streamid, connected, false))
3412 .await
3413 .unwrap();
3414 event_tx
3416 .send(MockExitEvent::BeginRecvd(streamid.unwrap()))
3417 .await
3418 .unwrap();
3419 }
3420 AnyRelayMsg::End(_) if !end_recvd => {
3421 stream_state.lock().unwrap().end_recvd = true;
3422 break;
3423 }
3424 AnyRelayMsg::End(_) if end_recvd => {
3425 panic!("received two END cells for the same stream?!");
3426 }
3427 AnyRelayMsg::ConfluxSwitch(cell) => {
3428 let expected = expect_switch.remove(0);
3430
3431 assert_eq!(expected.cells_so_far, cell_count);
3432 assert_eq!(expected.seqno, cell.seqno());
3433
3434 continue;
3440 }
3441 AnyRelayMsg::Data(dat) => {
3442 data_cells_received += 1;
3443 stream_state
3444 .lock()
3445 .unwrap()
3446 .data_recvd
3447 .extend_from_slice(dat.as_ref());
3448
3449 let is_next_cell_sendme = data_cells_received.is_multiple_of(31);
3450 if is_next_cell_sendme {
3451 if tags.is_empty() {
3452 runtime.lock().await.advance_until_stalled().await;
3457 let (tx, rx) = oneshot::channel();
3458 tunnel
3459 .circ
3460 .command
3461 .unbounded_send(CtrlCmd::QuerySendWindow {
3462 hop: 2.into(),
3463 leg: circ.unique_id,
3464 done: tx,
3465 })
3466 .unwrap();
3467
3468 let (_window, new_tags) = rx.await.unwrap().unwrap();
3470 tags = new_tags;
3471 }
3472
3473 let tag = tags.remove(0);
3474
3475 if let Some(rtt_delay) = rtt_delays.next().flatten() {
3478 runtime.lock().await.advance_by(rtt_delay).await;
3479 }
3480 let sendme = relaymsg::Sendme::from(tag).into();
3482
3483 circ.circ_tx
3484 .send(rmsg_to_ccmsg(None, sendme, false))
3485 .await
3486 .unwrap();
3487 }
3488 }
3489 _ => panic!("unexpected message {rmsg:?} on leg {}", circ.unique_id),
3490 }
3491 }
3492
3493 let end_recvd = stream_state.lock().unwrap().end_recvd;
3494
3495 if is_sending_leg && !end_recvd {
3497 let end = relaymsg::End::new_with_reason(relaymsg::EndReason::DONE).into();
3498 circ.circ_tx
3499 .send(rmsg_to_ccmsg(streamid, end, false))
3500 .await
3501 .unwrap();
3502 stream_state.lock().unwrap().end_sent = true;
3503 }
3504
3505 let _ = event_tx.send(MockExitEvent::Done).await;
3507
3508 assert!(
3510 expect_switch.is_empty(),
3511 "expect_switch = {expect_switch:?}"
3512 );
3513
3514 ConfluxEndpointResult::Relay { circ }
3515 }
3516
3517 #[cfg(feature = "conflux")]
3518 async fn run_conflux_client(
3519 tunnel: Arc<ClientTunnel>,
3520 conflux_link_rx: oneshot::Receiver<Result<ConfluxHandshakeResult>>,
3521 send_data: Vec<u8>,
3522 recv_data: Vec<u8>,
3523 ) -> ConfluxEndpointResult {
3524 let res = conflux_link_rx.await;
3525
3526 let res = res.unwrap().unwrap();
3527 assert_eq!(res.len(), 2);
3528
3529 let mut stream = tunnel
3534 .begin_stream("www.example.com", 443, None)
3535 .await
3536 .unwrap();
3537
3538 stream.write_all(&send_data).await.unwrap();
3539 stream.flush().await.unwrap();
3540
3541 let mut recv: Vec<u8> = Vec::new();
3542 let recv_len = stream.read_to_end(&mut recv).await.unwrap();
3543 assert_eq!(recv_len, recv_data.len());
3544 assert_eq!(recv_data, recv);
3545
3546 ConfluxEndpointResult::Circuit { tunnel, stream }
3547 }
3548
3549 #[cfg(feature = "conflux")]
3550 async fn run_conflux_endpoint<I: Iterator<Item = Option<Duration>>>(
3551 endpoint: ConfluxTestEndpoint<I>,
3552 ) -> ConfluxEndpointResult {
3553 match endpoint {
3554 ConfluxTestEndpoint::Relay(state) => run_mock_conflux_exit(state).await,
3555 ConfluxTestEndpoint::Client {
3556 tunnel,
3557 conflux_link_rx,
3558 send_data,
3559 recv_data,
3560 } => run_conflux_client(tunnel, conflux_link_rx, send_data, recv_data).await,
3561 }
3562 }
3563
3564 #[traced_test]
3582 #[test]
3583 #[cfg(feature = "conflux")]
3584 fn multipath_client_to_exit() {
3585 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
3586 const NUM_CELLS: usize = 300;
3588 const CELL_SIZE: usize = 498;
3590
3591 let TestTunnelCtx {
3592 tunnel,
3593 circs,
3594 conflux_link_rx,
3595 } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
3596 let [circ1, circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
3597
3598 let mut send_data = (0..255_u8)
3600 .cycle()
3601 .take(NUM_CELLS * CELL_SIZE)
3602 .collect::<Vec<_>>();
3603 let stream_state = Arc::new(Mutex::new(ConfluxStreamState::new(send_data.len())));
3604
3605 let mut tasks = vec![];
3606
3607 let (tx1, rx1) = mpsc::channel(1);
3610 let (tx2, rx2) = mpsc::channel(1);
3611
3612 let circ1_rtt_delays = [
3617 Some(Duration::from_millis(100)),
3619 Some(Duration::from_millis(500)),
3623 Some(Duration::from_millis(700)),
3624 Some(Duration::from_millis(900)),
3625 Some(Duration::from_millis(1100)),
3626 Some(Duration::from_millis(1300)),
3627 Some(Duration::from_millis(1500)),
3628 Some(Duration::from_millis(1700)),
3629 Some(Duration::from_millis(1900)),
3630 Some(Duration::from_millis(2100)),
3631 ]
3632 .into_iter();
3633
3634 let circ2_rtt_delays = [
3635 Some(Duration::from_millis(200)),
3636 Some(Duration::from_millis(400)),
3637 Some(Duration::from_millis(600)),
3638 Some(Duration::from_millis(800)),
3639 Some(Duration::from_millis(1000)),
3640 Some(Duration::from_millis(1200)),
3641 Some(Duration::from_millis(1400)),
3642 Some(Duration::from_millis(1600)),
3643 Some(Duration::from_millis(1800)),
3644 Some(Duration::from_millis(2000)),
3645 ]
3646 .into_iter();
3647
3648 let expected_switches1 = vec![ExpectedSwitch {
3649 cells_so_far: 126,
3657 seqno: 124,
3666 }];
3667
3668 let expected_switches2 = vec![ExpectedSwitch {
3669 cells_so_far: 1,
3672 seqno: 125,
3674 }];
3675
3676 let relay_runtime = Arc::new(AsyncMutex::new(rt.clone()));
3677
3678 let (_, cells_rx1) = mpsc::channel(1);
3681 let (_, cells_rx2) = mpsc::channel(1);
3682
3683 let relay1 = ConfluxExitState {
3684 runtime: Arc::clone(&relay_runtime),
3685 tunnel: Arc::clone(&tunnel),
3686 circ: circ1,
3687 rtt_delays: circ1_rtt_delays,
3688 stream_state: Arc::clone(&stream_state),
3689 expect_switch: expected_switches1,
3690 event_tx: tx1,
3691 event_rx: rx2,
3692 is_sending_leg: true,
3693 cells_rx: cells_rx1,
3694 };
3695
3696 let relay2 = ConfluxExitState {
3697 runtime: Arc::clone(&relay_runtime),
3698 tunnel: Arc::clone(&tunnel),
3699 circ: circ2,
3700 rtt_delays: circ2_rtt_delays,
3701 stream_state: Arc::clone(&stream_state),
3702 expect_switch: expected_switches2,
3703 event_tx: tx2,
3704 event_rx: rx1,
3705 is_sending_leg: false,
3706 cells_rx: cells_rx2,
3707 };
3708
3709 for mut mock_relay in [relay1, relay2] {
3710 let leg = mock_relay.circ.unique_id;
3711
3712 good_exit_handshake(
3720 &relay_runtime,
3721 mock_relay.rtt_delays.next().flatten(),
3722 &mut mock_relay.circ.chan_rx,
3723 &mut mock_relay.circ.circ_tx,
3724 )
3725 .await;
3726
3727 let relay = ConfluxTestEndpoint::Relay(mock_relay);
3728
3729 tasks.push(rt.spawn_join(format!("relay task {leg}"), run_conflux_endpoint(relay)));
3730 }
3731
3732 tasks.push(rt.spawn_join(
3733 "client task".to_string(),
3734 run_conflux_endpoint(ConfluxTestEndpoint::Client {
3735 tunnel,
3736 conflux_link_rx,
3737 send_data: send_data.clone(),
3738 recv_data: vec![],
3739 }),
3740 ));
3741 let _sinks = futures::future::join_all(tasks).await;
3742 let mut stream_state = stream_state.lock().unwrap();
3743 assert!(stream_state.begin_recvd);
3744
3745 stream_state.data_recvd.sort();
3746 send_data.sort();
3747 assert_eq!(stream_state.data_recvd, send_data);
3748 });
3749 }
3750
3751 #[cfg(feature = "conflux")]
3762 async fn run_multipath_exit_to_client_test(
3763 rt: MockRuntime,
3764 tunnel: TestTunnelCtx,
3765 cells_to_send: Vec<(UniqId, AnyRelayMsg)>,
3766 send_data: Vec<u8>,
3767 recv_data: Vec<u8>,
3768 ) -> Arc<Mutex<ConfluxStreamState>> {
3769 let TestTunnelCtx {
3770 tunnel,
3771 circs,
3772 conflux_link_rx,
3773 } = tunnel;
3774 let [circ1, circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
3775
3776 let stream_state = Arc::new(Mutex::new(ConfluxStreamState::new(send_data.len())));
3777
3778 let mut tasks = vec![];
3779 let relay_runtime = Arc::new(AsyncMutex::new(rt.clone()));
3780 let (cells_tx1, cells_rx1) = mpsc::channel(1);
3781 let (cells_tx2, cells_rx2) = mpsc::channel(1);
3782
3783 let dispatcher = CellDispatcher {
3784 leg_tx: [(circ1.unique_id, cells_tx1), (circ2.unique_id, cells_tx2)]
3785 .into_iter()
3786 .collect(),
3787 cells_to_send,
3788 };
3789
3790 let (tx1, rx1) = mpsc::channel(1);
3793 let (tx2, rx2) = mpsc::channel(1);
3794
3795 let relay1 = ConfluxExitState {
3796 runtime: Arc::clone(&relay_runtime),
3797 tunnel: Arc::clone(&tunnel),
3798 circ: circ1,
3799 rtt_delays: [].into_iter(),
3800 stream_state: Arc::clone(&stream_state),
3801 expect_switch: vec![],
3803 event_tx: tx1,
3804 event_rx: rx2,
3805 is_sending_leg: false,
3806 cells_rx: cells_rx1,
3807 };
3808
3809 let relay2 = ConfluxExitState {
3810 runtime: Arc::clone(&relay_runtime),
3811 tunnel: Arc::clone(&tunnel),
3812 circ: circ2,
3813 rtt_delays: [].into_iter(),
3814 stream_state: Arc::clone(&stream_state),
3815 expect_switch: vec![],
3817 event_tx: tx2,
3818 event_rx: rx1,
3819 is_sending_leg: true,
3820 cells_rx: cells_rx2,
3821 };
3822
3823 rt.spawn(dispatcher.run()).unwrap();
3828
3829 for mut mock_relay in [relay1, relay2] {
3830 let leg = mock_relay.circ.unique_id;
3831
3832 good_exit_handshake(
3833 &relay_runtime,
3834 mock_relay.rtt_delays.next().flatten(),
3835 &mut mock_relay.circ.chan_rx,
3836 &mut mock_relay.circ.circ_tx,
3837 )
3838 .await;
3839
3840 let relay = ConfluxTestEndpoint::Relay(mock_relay);
3841
3842 tasks.push(rt.spawn_join(format!("relay task {leg}"), run_conflux_endpoint(relay)));
3843 }
3844
3845 tasks.push(rt.spawn_join(
3846 "client task".to_string(),
3847 run_conflux_endpoint(ConfluxTestEndpoint::Client {
3848 tunnel,
3849 conflux_link_rx,
3850 send_data: send_data.clone(),
3851 recv_data,
3852 }),
3853 ));
3854
3855 let _sinks = futures::future::join_all(tasks).await;
3857
3858 stream_state
3859 }
3860
3861 #[traced_test]
3862 #[test]
3863 #[cfg(feature = "conflux")]
3864 fn multipath_exit_to_client() {
3865 const TO_SEND: &[u8] =
3867 b"But something about Buster Friendly irritated John Isidore, one specific thing";
3868
3869 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
3870 const CIRC1: usize = 0;
3872 const CIRC2: usize = 1;
3873
3874 let simple_switch = vec![
3898 (CIRC1, relaymsg::Data::new(&TO_SEND[0..5]).unwrap().into()),
3899 (CIRC1, relaymsg::Data::new(&TO_SEND[5..10]).unwrap().into()),
3900 (CIRC2, relaymsg::ConfluxSwitch::new(4).into()),
3902 (CIRC2, relaymsg::Data::new(&TO_SEND[20..30]).unwrap().into()),
3904 (CIRC1, relaymsg::Data::new(&TO_SEND[10..20]).unwrap().into()),
3907 (CIRC2, relaymsg::Data::new(&TO_SEND[30..40]).unwrap().into()),
3908 (CIRC2, relaymsg::Data::new(&TO_SEND[40..]).unwrap().into()),
3909 ];
3910
3911 let multiple_switches = vec![
3958 (CIRC2, relaymsg::ConfluxSwitch::new(3).into()),
3961 (CIRC2, relaymsg::Data::new(&TO_SEND[15..20]).unwrap().into()),
3963 (CIRC2, relaymsg::Data::new(&TO_SEND[20..30]).unwrap().into()),
3964 (CIRC1, relaymsg::Data::new(&TO_SEND[0..10]).unwrap().into()),
3966 (CIRC1, relaymsg::Data::new(&TO_SEND[10..15]).unwrap().into()),
3967 (CIRC1, relaymsg::ConfluxSwitch::new(3).into()),
3969 (CIRC1, relaymsg::Data::new(&TO_SEND[31..40]).unwrap().into()),
3971 (CIRC2, relaymsg::Data::new(&TO_SEND[30..31]).unwrap().into()),
3973 (CIRC1, relaymsg::Data::new(&TO_SEND[40..]).unwrap().into()),
3975 (CIRC2, relaymsg::ConfluxSwitch::new(2).into()),
3977 ];
3978
3979 let tests = [simple_switch, multiple_switches];
3985
3986 for cells_to_send in tests {
3987 let tunnel = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
3988 assert_eq!(tunnel.circs.len(), 2);
3989 let circ_ids = [tunnel.circs[0].unique_id, tunnel.circs[1].unique_id];
3990 let cells_to_send = cells_to_send
3991 .into_iter()
3992 .map(|(i, cell)| (circ_ids[i], cell))
3993 .collect();
3994
3995 let send_data = vec![];
3997 let stream_state = run_multipath_exit_to_client_test(
3998 rt.clone(),
3999 tunnel,
4000 cells_to_send,
4001 send_data.clone(),
4002 TO_SEND.into(),
4003 )
4004 .await;
4005 let stream_state = stream_state.lock().unwrap();
4006 assert!(stream_state.begin_recvd);
4007 assert!(stream_state.data_recvd.is_empty());
4009 }
4010 });
4011 }
4012
4013 #[traced_test]
4014 #[test]
4015 #[cfg(all(feature = "conflux", feature = "hs-service"))]
4016 fn conflux_incoming_stream() {
4017 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
4018 use std::error::Error as _;
4019
4020 const EXPECTED_HOP: u8 = 1;
4021
4022 let TestTunnelCtx {
4023 tunnel,
4024 circs,
4025 conflux_link_rx,
4026 } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
4027
4028 let [mut circ1, mut circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
4029
4030 let link = await_link_payload(&mut circ1.chan_rx).await;
4031 for circ in [&mut circ1, &mut circ2] {
4032 let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
4033 circ.circ_tx
4034 .send(rmsg_to_ccmsg(None, linked, false))
4035 .await
4036 .unwrap();
4037 }
4038
4039 let conflux_hs_res = conflux_link_rx.await.unwrap().unwrap();
4040 assert!(conflux_hs_res.iter().all(|res| res.is_ok()));
4041
4042 let err = tunnel
4044 .allow_stream_requests(
4045 &[tor_cell::relaycell::RelayCmd::BEGIN],
4046 (tunnel.circ.unique_id(), EXPECTED_HOP.into()).into(),
4047 AllowAllStreamsFilter,
4048 )
4049 .await
4050 .map(|_| ())
4052 .unwrap_err();
4053
4054 let err_src = err.source().unwrap().to_string();
4055 assert!(
4056 err_src.contains("Cannot allow stream requests on a multi-path tunnel"),
4057 "{err_src}"
4058 );
4059 });
4060 }
4061
4062 #[test]
4063 fn client_circ_chan_msg() {
4064 use tor_cell::chancell::msg::{self, AnyChanMsg};
4065 fn good(m: AnyChanMsg) {
4066 assert!(ClientCircChanMsg::try_from(m).is_ok());
4067 }
4068 fn bad(m: AnyChanMsg) {
4069 assert!(ClientCircChanMsg::try_from(m).is_err());
4070 }
4071
4072 good(msg::Destroy::new(2.into()).into());
4073 bad(msg::CreatedFast::new(&b"guaranteed in this world"[..]).into());
4074 bad(msg::Created2::new(&b"and the next"[..]).into());
4075 good(msg::Relay::new(&b"guaranteed guaranteed"[..]).into());
4076 bad(msg::AnyChanMsg::RelayEarly(
4077 msg::Relay::new(&b"for the world and its mother"[..]).into(),
4078 ));
4079 bad(msg::Versions::new([1, 2, 3]).unwrap().into());
4080 }
4081}