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::ChannelMode;
1018 use crate::channel::test_utils::{CodecResult, DummyChan};
1019 use crate::circuit::CircuitRxSender;
1020 use crate::circuit::reactor::test::rmsg_to_ccmsg;
1021 use crate::circuit::test::fake_mpsc;
1022 use crate::client::circuit::padding::new_padding;
1023 use crate::client::stream::DataStream;
1024 use crate::congestion::params::CongestionControlParams;
1025 use crate::congestion::test_utils::params::build_cc_vegas_params;
1026 use crate::crypto::cell::RelayCellBody;
1027 use crate::crypto::handshake::ntor_v3::NtorV3Server;
1028 use crate::memquota::SpecificAccount as _;
1029 use crate::stream::flow_ctrl::params::FlowCtrlParameters;
1030 use crate::util::DummyTimeoutEstimator;
1031 use assert_matches::assert_matches;
1032 use chanmsg::{AnyChanMsg, Created2, CreatedFast};
1033 use futures::channel::mpsc::{Receiver, Sender};
1034 use futures::io::{AsyncReadExt, AsyncWriteExt};
1035 use futures::sink::SinkExt;
1036 use futures::stream::StreamExt;
1037 use hex_literal::hex;
1038 use std::collections::{HashMap, VecDeque};
1039 use std::fmt::Debug;
1040 use std::time::Duration;
1041 use tor_basic_utils::test_rng::testing_rng;
1042 use tor_cell::chancell::{AnyChanCell, BoxedCellBody, ChanCell, ChanCmd, msg as chanmsg};
1043 use tor_cell::relaycell::extend::{self as extend_ext, CircRequestExt, CircResponseExt};
1044 use tor_cell::relaycell::msg::SendmeTag;
1045 use tor_cell::relaycell::{
1046 AnyRelayMsgOuter, RelayCellFormat, RelayCmd, StreamId, msg as relaymsg, msg::AnyRelayMsg,
1047 };
1048 use tor_cell::relaycell::{RelayMsg, UnparsedRelayMsg};
1049 use tor_linkspec::OwnedCircTarget;
1050 use tor_rtcompat::Runtime;
1051 use tor_rtcompat::SpawnExt;
1052 use tracing::trace;
1053 use tracing_test::traced_test;
1054
1055 #[cfg(feature = "conflux")]
1056 use {
1057 crate::client::reactor::ConfluxHandshakeResult,
1058 crate::util::err::ConfluxHandshakeError,
1059 futures::future::FusedFuture,
1060 futures::lock::Mutex as AsyncMutex,
1061 std::pin::Pin,
1062 std::result::Result as StdResult,
1063 tor_cell::relaycell::conflux::{V1DesiredUx, V1LinkPayload, V1Nonce},
1064 tor_cell::relaycell::msg::ConfluxLink,
1065 tor_rtmock::MockRuntime,
1066 };
1067
1068 #[cfg(feature = "hs-service")]
1069 use crate::circuit::reactor::test::AllowAllStreamsFilter;
1070
1071 impl PendingClientTunnel {
1072 pub(crate) fn peek_circid(&self) -> CircId {
1074 self.circ.circid
1075 }
1076 }
1077
1078 impl ClientCirc {
1079 pub(crate) fn peek_circid(&self) -> CircId {
1081 self.circid
1082 }
1083 }
1084
1085 impl ClientTunnel {
1086 pub(crate) async fn resolve_last_hop(&self) -> TargetHop {
1087 let (sender, receiver) = oneshot::channel();
1088 let _ =
1089 self.as_single_circ()
1090 .unwrap()
1091 .command
1092 .unbounded_send(CtrlCmd::ResolveTargetHop {
1093 hop: TargetHop::LastHop,
1094 done: sender,
1095 });
1096 TargetHop::Hop(receiver.await.unwrap().unwrap())
1097 }
1098 }
1099
1100 const EXAMPLE_SK: [u8; 32] =
1102 hex!("7789d92a89711a7e2874c61ea495452cfd48627b3ca2ea9546aafa5bf7b55803");
1103 const EXAMPLE_PK: [u8; 32] =
1104 hex!("395cb26b83b3cd4b91dba9913e562ae87d21ecdd56843da7ca939a6a69001253");
1105 const EXAMPLE_ED_ID: [u8; 32] = [6; 32];
1106 const EXAMPLE_RSA_ID: [u8; 20] = [10; 20];
1107
1108 fn example_target() -> OwnedCircTarget {
1110 let mut builder = OwnedCircTarget::builder();
1111 builder
1112 .chan_target()
1113 .ed_identity(EXAMPLE_ED_ID.into())
1114 .rsa_identity(EXAMPLE_RSA_ID.into());
1115 builder
1116 .ntor_onion_key(EXAMPLE_PK.into())
1117 .protocols("FlowCtrl=1-2".parse().unwrap())
1118 .build()
1119 .unwrap()
1120 }
1121 fn example_ntor_key() -> crate::crypto::handshake::ntor::NtorSecretKey {
1122 crate::crypto::handshake::ntor::NtorSecretKey::new(
1123 EXAMPLE_SK.into(),
1124 EXAMPLE_PK.into(),
1125 EXAMPLE_RSA_ID.into(),
1126 )
1127 }
1128 fn example_ntor_v3_key() -> crate::crypto::handshake::ntor_v3::NtorV3SecretKey {
1129 crate::crypto::handshake::ntor_v3::NtorV3SecretKey::new(
1130 EXAMPLE_SK.into(),
1131 EXAMPLE_PK.into(),
1132 EXAMPLE_ED_ID.into(),
1133 )
1134 }
1135
1136 #[derive(Copy, Clone)]
1138 enum HandshakeType {
1139 Fast,
1140 Ntor,
1141 NtorV3,
1142 }
1143
1144 #[allow(deprecated)]
1145 async fn test_create<R: Runtime>(rt: &R, handshake_type: HandshakeType, with_cc: bool) {
1146 use crate::crypto::handshake::{ServerHandshake, fast::CreateFastServer, ntor::NtorServer};
1150
1151 let DummyChan {
1152 channel,
1153 mut rx,
1154 tx: _sink,
1155 } = DummyChan::run(rt, ChannelMode::Client);
1156 let circid = CircId::new(128).unwrap();
1157 let (created_send, created_recv) = oneshot::channel();
1158 let (_circmsg_send, circmsg_recv) = fake_mpsc(64);
1159 let unique_id = UniqId::new(23, 17);
1160 let (padding_ctrl, padding_stream) = new_padding(DynTimeProvider::new(rt.clone()));
1161
1162 let (pending, reactor) = PendingClientTunnel::new(
1163 circid,
1164 channel,
1165 created_recv,
1166 circmsg_recv,
1167 unique_id,
1168 DynTimeProvider::new(rt.clone()),
1169 CircuitAccount::new_noop(),
1170 padding_ctrl,
1171 padding_stream,
1172 Arc::new(DummyTimeoutEstimator),
1173 );
1174
1175 rt.spawn(async {
1176 let _ignore = reactor.run().await;
1177 })
1178 .unwrap();
1179
1180 let simulate_relay_fut = async move {
1182 let mut rng = testing_rng();
1183 let create_cell = rx.next().await.unwrap();
1184 assert_eq!(create_cell.circid(), Some(circid));
1185 let reply = match handshake_type {
1186 HandshakeType::Fast => {
1187 let cf = match create_cell.msg() {
1188 AnyChanMsg::CreateFast(cf) => cf,
1189 other => panic!("{:?}", other),
1190 };
1191 let (_, rep) = CreateFastServer::server(
1192 &mut rng,
1193 &mut |_: &()| Some(()),
1194 &[],
1195 cf.handshake(),
1196 )
1197 .unwrap();
1198 CreateResponse::CreatedFast(CreatedFast::new(rep))
1199 }
1200 HandshakeType::Ntor => {
1201 let c2 = match create_cell.msg() {
1202 AnyChanMsg::Create2(c2) => c2,
1203 other => panic!("{:?}", other),
1204 };
1205 let (_, rep) = NtorServer::server(
1206 &mut rng,
1207 &mut |_: &()| Some(()),
1208 &[example_ntor_key()],
1209 c2.body(),
1210 )
1211 .unwrap();
1212 CreateResponse::Created2(Created2::new(rep))
1213 }
1214 HandshakeType::NtorV3 => {
1215 let c2 = match create_cell.msg() {
1216 AnyChanMsg::Create2(c2) => c2,
1217 other => panic!("{:?}", other),
1218 };
1219 let mut reply_fn = if with_cc {
1220 |client_exts: &[CircRequestExt]| {
1221 let _ = client_exts
1222 .iter()
1223 .find(|e| matches!(e, CircRequestExt::CcRequest(_)))
1224 .expect("Client failed to request CC");
1225 Some(vec![CircResponseExt::CcResponse(
1228 extend_ext::CcResponse::new(31),
1229 )])
1230 }
1231 } else {
1232 |_: &_| Some(vec![])
1233 };
1234 let (_, rep) = NtorV3Server::server(
1235 &mut rng,
1236 &mut reply_fn,
1237 &[example_ntor_v3_key()],
1238 c2.body(),
1239 )
1240 .unwrap();
1241 CreateResponse::Created2(Created2::new(rep))
1242 }
1243 };
1244 created_send.send(reply).unwrap();
1245 };
1246 let client_fut = async move {
1248 let target = example_target();
1249 let params = CircParameters::default();
1250 let ret = match handshake_type {
1251 HandshakeType::Fast => {
1252 trace!("doing fast create");
1253 pending.create_firsthop_fast(params).await
1254 }
1255 HandshakeType::Ntor => {
1256 trace!("doing ntor create");
1257 pending.create_firsthop_ntor(&target, params).await
1258 }
1259 HandshakeType::NtorV3 => {
1260 let params = if with_cc {
1261 CircParameters::new(
1263 true,
1264 build_cc_vegas_params(),
1265 FlowCtrlParameters::defaults_for_tests(),
1266 )
1267 } else {
1268 params
1269 };
1270 trace!("doing ntor_v3 create");
1271 pending.create_firsthop_ntor_v3(&target, params).await
1272 }
1273 };
1274 trace!("create done: result {:?}", ret);
1275 ret
1276 };
1277
1278 let (circ, _) = futures::join!(client_fut, simulate_relay_fut);
1279
1280 let _circ = circ.unwrap();
1281
1282 assert_eq!(_circ.n_hops().unwrap(), 1);
1284 }
1285
1286 #[traced_test]
1287 #[test]
1288 fn test_create_fast() {
1289 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1290 test_create(&rt, HandshakeType::Fast, false).await;
1291 });
1292 }
1293 #[traced_test]
1294 #[test]
1295 fn test_create_ntor() {
1296 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1297 test_create(&rt, HandshakeType::Ntor, false).await;
1298 });
1299 }
1300 #[traced_test]
1301 #[test]
1302 fn test_create_ntor_v3() {
1303 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1304 test_create(&rt, HandshakeType::NtorV3, false).await;
1305 });
1306 }
1307 #[traced_test]
1308 #[test]
1309 fn test_create_ntor_v3_with_cc() {
1310 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1311 test_create(&rt, HandshakeType::NtorV3, true).await;
1312 });
1313 }
1314
1315 pub(crate) struct DummyCrypto {
1318 counter_tag: [u8; 20],
1319 counter: u32,
1320 lasthop: bool,
1321 }
1322 impl DummyCrypto {
1323 fn next_tag(&mut self) -> SendmeTag {
1324 #![allow(clippy::identity_op)]
1325 self.counter_tag[0] = ((self.counter >> 0) & 255) as u8;
1326 self.counter_tag[1] = ((self.counter >> 8) & 255) as u8;
1327 self.counter_tag[2] = ((self.counter >> 16) & 255) as u8;
1328 self.counter_tag[3] = ((self.counter >> 24) & 255) as u8;
1329 self.counter += 1;
1330 self.counter_tag.into()
1331 }
1332 }
1333
1334 impl crate::crypto::cell::OutboundClientLayer for DummyCrypto {
1335 fn originate_for(&mut self, _cmd: ChanCmd, _cell: &mut RelayCellBody) -> SendmeTag {
1336 self.next_tag()
1337 }
1338 fn encrypt_outbound(&mut self, _cmd: ChanCmd, _cell: &mut RelayCellBody) {}
1339 }
1340 impl crate::crypto::cell::InboundClientLayer for DummyCrypto {
1341 fn decrypt_inbound(
1342 &mut self,
1343 _cmd: ChanCmd,
1344 _cell: &mut RelayCellBody,
1345 ) -> Option<SendmeTag> {
1346 if self.lasthop {
1347 Some(self.next_tag())
1348 } else {
1349 None
1350 }
1351 }
1352 }
1353 impl DummyCrypto {
1354 pub(crate) fn new(lasthop: bool) -> Self {
1355 DummyCrypto {
1356 counter_tag: [0; 20],
1357 counter: 0,
1358 lasthop,
1359 }
1360 }
1361 }
1362
1363 async fn newtunnel_ext<R: Runtime>(
1366 rt: &R,
1367 unique_id: UniqId,
1368 chan: Arc<Channel>,
1369 hops: Vec<path::HopDetail>,
1370 next_msg_from: HopNum,
1371 params: CircParameters,
1372 ) -> (ClientTunnel, CircuitRxSender) {
1373 let circid = CircId::new(128).unwrap();
1374 let (_created_send, created_recv) = oneshot::channel();
1375 let (circmsg_send, circmsg_recv) = fake_mpsc(64);
1376 let (padding_ctrl, padding_stream) = new_padding(DynTimeProvider::new(rt.clone()));
1377
1378 let (pending, reactor) = PendingClientTunnel::new(
1379 circid,
1380 chan,
1381 created_recv,
1382 circmsg_recv,
1383 unique_id,
1384 DynTimeProvider::new(rt.clone()),
1385 CircuitAccount::new_noop(),
1386 padding_ctrl,
1387 padding_stream,
1388 Arc::new(DummyTimeoutEstimator),
1389 );
1390
1391 rt.spawn(async {
1392 let _ignore = reactor.run().await;
1393 })
1394 .unwrap();
1395 let PendingClientTunnel {
1396 circ,
1397 recvcreated: _,
1398 } = pending;
1399
1400 let relay_cell_format = RelayCellFormat::V0;
1402
1403 let last_hop_num = u8::try_from(hops.len() - 1).unwrap();
1404 for (idx, peer_id) in hops.into_iter().enumerate() {
1405 let (tx, rx) = oneshot::channel();
1406 let idx = idx as u8;
1407
1408 circ.command
1409 .unbounded_send(CtrlCmd::AddFakeHop {
1410 relay_cell_format,
1411 fwd_lasthop: idx == last_hop_num,
1412 rev_lasthop: idx == u8::from(next_msg_from),
1413 peer_id,
1414 params: Box::new(params.clone()),
1415 done: tx,
1416 })
1417 .unwrap();
1418 rx.await.unwrap().unwrap();
1419 }
1420 (circ.into_tunnel().unwrap(), circmsg_send)
1421 }
1422
1423 async fn newtunnel<R: Runtime>(
1426 rt: &R,
1427 chan: Arc<Channel>,
1428 ) -> (Arc<ClientTunnel>, CircuitRxSender) {
1429 let hops = std::iter::repeat_with(|| {
1430 let peer_id = tor_linkspec::OwnedChanTarget::builder()
1431 .ed_identity([4; 32].into())
1432 .rsa_identity([5; 20].into())
1433 .build()
1434 .expect("Could not construct fake hop");
1435
1436 path::HopDetail::Relay(peer_id)
1437 })
1438 .take(3)
1439 .collect();
1440
1441 let unique_id = UniqId::new(23, 17);
1442 let (tunnel, circmsg_send) = newtunnel_ext(
1443 rt,
1444 unique_id,
1445 chan,
1446 hops,
1447 2.into(),
1448 CircParameters::default(),
1449 )
1450 .await;
1451
1452 (Arc::new(tunnel), circmsg_send)
1453 }
1454
1455 fn hop_details(n: u8, start_idx: u8) -> Vec<path::HopDetail> {
1458 (0..n)
1459 .map(|idx| {
1460 let peer_id = tor_linkspec::OwnedChanTarget::builder()
1461 .ed_identity([idx + start_idx; 32].into())
1462 .rsa_identity([idx + start_idx + 1; 20].into())
1463 .build()
1464 .expect("Could not construct fake hop");
1465
1466 path::HopDetail::Relay(peer_id)
1467 })
1468 .collect()
1469 }
1470
1471 #[allow(deprecated)]
1472 async fn test_extend<R: Runtime>(rt: &R, handshake_type: HandshakeType) {
1473 use crate::crypto::handshake::{ServerHandshake, ntor::NtorServer};
1474
1475 let DummyChan {
1476 channel,
1477 mut rx,
1478 tx: _sink,
1479 } = DummyChan::run(rt, ChannelMode::Client);
1480 let (tunnel, mut sink) = newtunnel(rt, channel).await;
1481 let circ = Arc::new(tunnel.as_single_circ().unwrap());
1482 let circid = circ.peek_circid();
1483 let params = CircParameters::default();
1484
1485 let extend_fut = async move {
1486 let target = example_target();
1487 match handshake_type {
1488 HandshakeType::Fast => panic!("Can't extend with Fast handshake"),
1489 HandshakeType::Ntor => circ.extend_ntor(&target, params).await.unwrap(),
1490 HandshakeType::NtorV3 => circ.extend_ntor_v3(&target, params).await.unwrap(),
1491 };
1492 circ };
1494 let reply_fut = async move {
1495 let (id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
1498 assert_eq!(id, Some(circid));
1499 let rmsg = match chmsg {
1500 AnyChanMsg::RelayEarly(r) => {
1501 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1502 .unwrap()
1503 }
1504 other => panic!("{:?}", other),
1505 };
1506 let e2 = match rmsg.msg() {
1507 AnyRelayMsg::Extend2(e2) => e2,
1508 other => panic!("{:?}", other),
1509 };
1510 let mut rng = testing_rng();
1511 let reply = match handshake_type {
1512 HandshakeType::Fast => panic!("Can't extend with Fast handshake"),
1513 HandshakeType::Ntor => {
1514 let (_keygen, reply) = NtorServer::server(
1515 &mut rng,
1516 &mut |_: &()| Some(()),
1517 &[example_ntor_key()],
1518 e2.handshake(),
1519 )
1520 .unwrap();
1521 reply
1522 }
1523 HandshakeType::NtorV3 => {
1524 let (_keygen, reply) = NtorV3Server::server(
1525 &mut rng,
1526 &mut |_: &[CircRequestExt]| Some(vec![]),
1527 &[example_ntor_v3_key()],
1528 e2.handshake(),
1529 )
1530 .unwrap();
1531 reply
1532 }
1533 };
1534
1535 let extended2 = relaymsg::Extended2::new(reply).into();
1536 sink.send(rmsg_to_ccmsg(None, extended2, false))
1537 .await
1538 .unwrap();
1539 (sink, rx) };
1541
1542 let (circ, (_sink, _rx)) = futures::join!(extend_fut, reply_fut);
1543
1544 assert_eq!(circ.n_hops().unwrap(), 4);
1546
1547 {
1549 let path = circ.single_path().unwrap();
1550 #[allow(clippy::unnecessary_filter_map)]
1552 let path = path
1553 .all_hops()
1554 .filter_map(|hop| match hop {
1555 path::HopDetail::Relay(r) => Some(r),
1556 #[cfg(feature = "hs-common")]
1557 path::HopDetail::Virtual => None,
1558 })
1559 .collect::<Vec<_>>();
1560
1561 assert_eq!(path.len(), 4);
1562 use tor_linkspec::HasRelayIds;
1563 assert_eq!(path[3].ed_identity(), example_target().ed_identity());
1564 assert_ne!(path[0].ed_identity(), example_target().ed_identity());
1565 }
1566 {
1567 let path = circ.single_path().unwrap();
1568 assert_eq!(path.n_hops(), 4);
1569 use tor_linkspec::HasRelayIds;
1570 assert_eq!(
1571 path.hops()[3].as_chan_target().unwrap().ed_identity(),
1572 example_target().ed_identity()
1573 );
1574 assert_ne!(
1575 path.hops()[0].as_chan_target().unwrap().ed_identity(),
1576 example_target().ed_identity()
1577 );
1578 }
1579 }
1580
1581 #[traced_test]
1582 #[test]
1583 fn test_extend_ntor() {
1584 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1585 test_extend(&rt, HandshakeType::Ntor).await;
1586 });
1587 }
1588
1589 #[traced_test]
1590 #[test]
1591 fn test_extend_ntor_v3() {
1592 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1593 test_extend(&rt, HandshakeType::NtorV3).await;
1594 });
1595 }
1596
1597 #[allow(deprecated)]
1598 async fn bad_extend_test_impl<R: Runtime>(
1599 rt: &R,
1600 reply_hop: HopNum,
1601 bad_reply: AnyChanMsg,
1602 ) -> Error {
1603 let DummyChan {
1604 channel,
1605 mut rx,
1606 tx: _sink,
1607 } = DummyChan::run(rt, ChannelMode::Client);
1608 let hops = std::iter::repeat_with(|| {
1609 let peer_id = tor_linkspec::OwnedChanTarget::builder()
1610 .ed_identity([4; 32].into())
1611 .rsa_identity([5; 20].into())
1612 .build()
1613 .expect("Could not construct fake hop");
1614
1615 path::HopDetail::Relay(peer_id)
1616 })
1617 .take(3)
1618 .collect();
1619
1620 let unique_id = UniqId::new(23, 17);
1621 let (tunnel, mut sink) = newtunnel_ext(
1622 rt,
1623 unique_id,
1624 channel,
1625 hops,
1626 reply_hop,
1627 CircParameters::default(),
1628 )
1629 .await;
1630 let params = CircParameters::default();
1631
1632 let target = example_target();
1633 let reply_task_handle = rt
1634 .spawn_with_handle(async move {
1635 let (_circid, chanmsg) = rx.next().await.unwrap().into_circid_and_msg();
1637 let AnyChanMsg::RelayEarly(relay_early) = chanmsg else {
1638 panic!("unexpected message {chanmsg:?}");
1639 };
1640 let relaymsg = UnparsedRelayMsg::from_singleton_body(
1641 RelayCellFormat::V0,
1642 relay_early.into_relay_body(),
1643 )
1644 .unwrap();
1645 assert_eq!(relaymsg.cmd(), RelayCmd::EXTEND2);
1646
1647 sink.send(bad_reply).await.unwrap();
1649 sink
1650 })
1651 .unwrap();
1652 let outcome = tunnel
1653 .as_single_circ()
1654 .unwrap()
1655 .extend_ntor(&target, params)
1656 .await;
1657 let _sink = reply_task_handle.await;
1658
1659 assert_eq!(tunnel.n_hops().unwrap(), 3);
1660 assert!(outcome.is_err());
1661 outcome.unwrap_err()
1662 }
1663
1664 #[traced_test]
1665 #[test]
1666 fn bad_extend_wronghop() {
1667 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1668 let extended2 = relaymsg::Extended2::new(vec![]).into();
1669 let cc = rmsg_to_ccmsg(None, extended2, false);
1670
1671 let error = bad_extend_test_impl(&rt, 1.into(), cc).await;
1672 match error {
1677 Error::CircuitClosed => {}
1678 x => panic!("got other error: {}", x),
1679 }
1680 });
1681 }
1682
1683 #[traced_test]
1684 #[test]
1685 fn bad_extend_wrongtype() {
1686 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1687 let extended = relaymsg::Extended::new(vec![7; 200]).into();
1688 let cc = rmsg_to_ccmsg(None, extended, false);
1689
1690 let error = bad_extend_test_impl(&rt, 2.into(), cc).await;
1691 match error {
1692 Error::BytesErr {
1693 err: tor_bytes::Error::InvalidMessage(_),
1694 object: "extended2 message",
1695 } => {}
1696 other => panic!("{:?}", other),
1697 }
1698 });
1699 }
1700
1701 #[traced_test]
1702 #[test]
1703 fn bad_extend_destroy() {
1704 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1705 let cc = AnyChanMsg::Destroy(chanmsg::Destroy::new(4.into()));
1706 let error = bad_extend_test_impl(&rt, 2.into(), cc).await;
1707 match error {
1708 Error::CircuitClosed => {}
1709 other => panic!("{:?}", other),
1710 }
1711 });
1712 }
1713
1714 #[traced_test]
1715 #[test]
1716 fn bad_extend_crypto() {
1717 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1718 let extended2 = relaymsg::Extended2::new(vec![99; 256]).into();
1719 let cc = rmsg_to_ccmsg(None, extended2, false);
1720 let error = bad_extend_test_impl(&rt, 2.into(), cc).await;
1721 assert_matches!(error, Error::BadCircHandshakeAuth);
1722 });
1723 }
1724
1725 #[traced_test]
1726 #[test]
1727 fn begindir() {
1728 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1729 let DummyChan {
1730 channel,
1731 mut rx,
1732 tx: _sink,
1733 } = DummyChan::run(&rt, ChannelMode::Client);
1734 let (tunnel, mut sink) = newtunnel(&rt, channel).await;
1735 let circ = tunnel.as_single_circ().unwrap();
1736 let circid = circ.peek_circid();
1737
1738 let begin_and_send_fut = async move {
1739 let mut stream = tunnel.begin_dir_stream().await.unwrap();
1742 stream.write_all(b"HTTP/1.0 GET /\r\n").await.unwrap();
1743 stream.flush().await.unwrap();
1744 let mut buf = [0_u8; 1024];
1745 let n = stream.read(&mut buf).await.unwrap();
1746 assert_eq!(&buf[..n], b"HTTP/1.0 404 Not found\r\n");
1747 let n = stream.read(&mut buf).await.unwrap();
1748 assert_eq!(n, 0);
1749 stream
1750 };
1751 let reply_fut = async move {
1752 let (id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
1755 assert_eq!(id, Some(circid));
1756 let rmsg = match chmsg {
1757 AnyChanMsg::Relay(r) => {
1758 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1759 .unwrap()
1760 }
1761 other => panic!("{:?}", other),
1762 };
1763 let (streamid, rmsg) = rmsg.into_streamid_and_msg();
1764 assert_matches!(rmsg, AnyRelayMsg::BeginDir(_));
1765
1766 let connected = relaymsg::Connected::new_empty().into();
1768 sink.send(rmsg_to_ccmsg(streamid, connected, false))
1769 .await
1770 .unwrap();
1771
1772 let (id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
1774 assert_eq!(id, Some(circid));
1775 let rmsg = match chmsg {
1776 AnyChanMsg::Relay(r) => {
1777 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1778 .unwrap()
1779 }
1780 other => panic!("{:?}", other),
1781 };
1782 let (streamid_2, rmsg) = rmsg.into_streamid_and_msg();
1783 assert_eq!(streamid_2, streamid);
1784 if let AnyRelayMsg::Data(d) = rmsg {
1785 assert_eq!(d.as_ref(), &b"HTTP/1.0 GET /\r\n"[..]);
1786 } else {
1787 panic!();
1788 }
1789
1790 let data = relaymsg::Data::new(b"HTTP/1.0 404 Not found\r\n")
1792 .unwrap()
1793 .into();
1794 sink.send(rmsg_to_ccmsg(streamid, data, false))
1795 .await
1796 .unwrap();
1797
1798 let end = relaymsg::End::new_with_reason(relaymsg::EndReason::DONE).into();
1800 sink.send(rmsg_to_ccmsg(streamid, end, false))
1801 .await
1802 .unwrap();
1803
1804 (rx, sink) };
1806
1807 let (_stream, (_rx, _sink)) = futures::join!(begin_and_send_fut, reply_fut);
1808 });
1809 }
1810
1811 fn close_stream_helper(by_drop: bool) {
1813 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1814 let DummyChan {
1815 channel,
1816 mut rx,
1817 tx: _sink,
1818 } = DummyChan::run(&rt, ChannelMode::Client);
1819 let (tunnel, mut sink) = newtunnel(&rt, channel).await;
1820
1821 let stream_fut = async move {
1822 let stream = tunnel
1823 .begin_stream("www.example.com", 80, None)
1824 .await
1825 .unwrap();
1826
1827 let (r, mut w) = stream.split();
1828 if by_drop {
1829 drop(r);
1831 drop(w);
1832 (None, tunnel) } else {
1834 w.close().await.unwrap();
1836 (Some(r), tunnel)
1837 }
1838 };
1839 let handler_fut = async {
1840 let (_, msg) = rx.next().await.unwrap().into_circid_and_msg();
1842 let rmsg = match msg {
1843 AnyChanMsg::Relay(r) => {
1844 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1845 .unwrap()
1846 }
1847 other => panic!("{:?}", other),
1848 };
1849 let (streamid, rmsg) = rmsg.into_streamid_and_msg();
1850 assert_eq!(rmsg.cmd(), RelayCmd::BEGIN);
1851
1852 let connected =
1854 relaymsg::Connected::new_with_addr("10.0.0.1".parse().unwrap(), 1234).into();
1855 sink.send(rmsg_to_ccmsg(streamid, connected, false))
1856 .await
1857 .unwrap();
1858
1859 let (_, msg) = rx.next().await.unwrap().into_circid_and_msg();
1861 let rmsg = match msg {
1862 AnyChanMsg::Relay(r) => {
1863 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1864 .unwrap()
1865 }
1866 other => panic!("{:?}", other),
1867 };
1868 let (_, rmsg) = rmsg.into_streamid_and_msg();
1869 assert_eq!(rmsg.cmd(), RelayCmd::END);
1870
1871 (rx, sink) };
1873
1874 let ((_opt_reader, _circ), (_rx, _sink)) = futures::join!(stream_fut, handler_fut);
1875 });
1876 }
1877
1878 #[traced_test]
1879 #[test]
1880 fn drop_stream() {
1881 close_stream_helper(true);
1882 }
1883
1884 #[traced_test]
1885 #[test]
1886 fn close_stream() {
1887 close_stream_helper(false);
1888 }
1889
1890 #[traced_test]
1891 #[test]
1892 fn expire_halfstreams() {
1893 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
1894 let DummyChan {
1895 channel,
1896 mut rx,
1897 tx: _sink,
1898 } = DummyChan::run(&rt, ChannelMode::Client);
1899 let (tunnel, mut sink) = newtunnel(&rt, channel).await;
1900
1901 let client_fut = async move {
1902 let stream = tunnel
1903 .begin_stream("www.example.com", 80, None)
1904 .await
1905 .unwrap();
1906
1907 let (r, mut w) = stream.split();
1908 w.close().await.unwrap();
1910 (Some(r), tunnel)
1911 };
1912 let exit_fut = async {
1913 let (_, msg) = rx.next().await.unwrap().into_circid_and_msg();
1915 let rmsg = match msg {
1916 AnyChanMsg::Relay(r) => {
1917 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1918 .unwrap()
1919 }
1920 other => panic!("{:?}", other),
1921 };
1922 let (streamid, rmsg) = rmsg.into_streamid_and_msg();
1923 assert_eq!(rmsg.cmd(), RelayCmd::BEGIN);
1924
1925 let connected =
1927 relaymsg::Connected::new_with_addr("10.0.0.1".parse().unwrap(), 1234).into();
1928 sink.send(rmsg_to_ccmsg(streamid, connected, false))
1929 .await
1930 .unwrap();
1931
1932 (rx, streamid, sink) };
1934
1935 let ((_opt_reader, tunnel), (_rx, streamid, mut sink)) =
1936 futures::join!(client_fut, exit_fut);
1937
1938 rt.progress_until_stalled().await;
1941
1942 assert!(!tunnel.is_closed());
1944
1945 let data = relaymsg::Data::new(b"hello").unwrap();
1948 sink.send(rmsg_to_ccmsg(streamid, AnyRelayMsg::Data(data), false))
1949 .await
1950 .unwrap();
1951 rt.progress_until_stalled().await;
1952
1953 assert!(!tunnel.is_closed());
1955
1956 let stream_timeout = DummyTimeoutEstimator.circuit_build_timeout(3);
1961 rt.advance_by(2 * stream_timeout).await;
1962
1963 let data = relaymsg::Data::new(b"hello").unwrap();
1966 sink.send(rmsg_to_ccmsg(streamid, AnyRelayMsg::Data(data), false))
1967 .await
1968 .unwrap();
1969 rt.progress_until_stalled().await;
1970
1971 assert!(tunnel.is_closed());
1973 });
1974 }
1975
1976 async fn setup_incoming_sendme_case<R: Runtime>(
1978 rt: &R,
1979 n_to_send: usize,
1980 ) -> (
1981 Arc<ClientTunnel>,
1982 DataStream,
1983 CircuitRxSender,
1984 Option<StreamId>,
1985 usize,
1986 Receiver<AnyChanCell>,
1987 Sender<CodecResult>,
1988 ) {
1989 let DummyChan {
1990 channel,
1991 mut rx,
1992 tx: sink2,
1993 } = DummyChan::run(rt, ChannelMode::Client);
1994 let (tunnel, mut sink) = newtunnel(rt, channel).await;
1995 let circid = tunnel.as_single_circ().unwrap().peek_circid();
1996
1997 let begin_and_send_fut = {
1998 let tunnel = tunnel.clone();
1999 async move {
2000 let mut stream = tunnel
2002 .begin_stream("www.example.com", 443, None)
2003 .await
2004 .unwrap();
2005 let junk = [0_u8; 1024];
2006 let mut remaining = n_to_send;
2007 while remaining > 0 {
2008 let n = std::cmp::min(remaining, junk.len());
2009 stream.write_all(&junk[..n]).await.unwrap();
2010 remaining -= n;
2011 }
2012 stream.flush().await.unwrap();
2013 stream
2014 }
2015 };
2016
2017 let receive_fut = async move {
2018 let (_id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
2020 let rmsg = match chmsg {
2021 AnyChanMsg::Relay(r) => {
2022 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
2023 .unwrap()
2024 }
2025 other => panic!("{:?}", other),
2026 };
2027 let (streamid, rmsg) = rmsg.into_streamid_and_msg();
2028 assert_matches!(rmsg, AnyRelayMsg::Begin(_));
2029 let connected = relaymsg::Connected::new_empty().into();
2031 sink.send(rmsg_to_ccmsg(streamid, connected, false))
2032 .await
2033 .unwrap();
2034 let mut bytes_received = 0_usize;
2036 let mut cells_received = 0_usize;
2037 while bytes_received < n_to_send {
2038 let (id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
2040 assert_eq!(id, Some(circid));
2041
2042 let rmsg = match chmsg {
2043 AnyChanMsg::Relay(r) => {
2044 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
2045 .unwrap()
2046 }
2047 other => panic!("{:?}", other),
2048 };
2049 let (streamid2, rmsg) = rmsg.into_streamid_and_msg();
2050 assert_eq!(streamid2, streamid);
2051 if let AnyRelayMsg::Data(dat) = rmsg {
2052 cells_received += 1;
2053 bytes_received += dat.as_ref().len();
2054 } else {
2055 panic!();
2056 }
2057 }
2058
2059 (sink, streamid, cells_received, rx)
2060 };
2061
2062 let (stream, (sink, streamid, cells_received, rx)) =
2063 futures::join!(begin_and_send_fut, receive_fut);
2064
2065 (tunnel, stream, sink, streamid, cells_received, rx, sink2)
2066 }
2067
2068 #[traced_test]
2069 #[test]
2070 fn accept_valid_sendme() {
2071 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2072 let (tunnel, _stream, mut sink, streamid, cells_received, _rx, _sink2) =
2073 setup_incoming_sendme_case(&rt, 300 * 498 + 3).await;
2074 let circ = tunnel.as_single_circ().unwrap();
2075
2076 assert_eq!(cells_received, 301);
2077
2078 {
2080 let (tx, rx) = oneshot::channel();
2081 circ.command
2082 .unbounded_send(CtrlCmd::QuerySendWindow {
2083 hop: 2.into(),
2084 leg: tunnel.unique_id(),
2085 done: tx,
2086 })
2087 .unwrap();
2088 let (window, tags) = rx.await.unwrap().unwrap();
2089 assert_eq!(window, 1000 - 301);
2090 assert_eq!(tags.len(), 3);
2091 assert_eq!(
2093 tags[0],
2094 SendmeTag::from(hex!("6400000000000000000000000000000000000000"))
2095 );
2096 assert_eq!(
2098 tags[1],
2099 SendmeTag::from(hex!("c800000000000000000000000000000000000000"))
2100 );
2101 assert_eq!(
2103 tags[2],
2104 SendmeTag::from(hex!("2c01000000000000000000000000000000000000"))
2105 );
2106 }
2107
2108 let reply_with_sendme_fut = async move {
2109 let c_sendme =
2111 relaymsg::Sendme::new_tag(hex!("6400000000000000000000000000000000000000"))
2112 .into();
2113 sink.send(rmsg_to_ccmsg(None, c_sendme, false))
2114 .await
2115 .unwrap();
2116
2117 let s_sendme = relaymsg::Sendme::new_empty().into();
2119 sink.send(rmsg_to_ccmsg(streamid, s_sendme, false))
2120 .await
2121 .unwrap();
2122
2123 sink
2124 };
2125
2126 let _sink = reply_with_sendme_fut.await;
2127
2128 rt.advance_until_stalled().await;
2129
2130 {
2133 let (tx, rx) = oneshot::channel();
2134 circ.command
2135 .unbounded_send(CtrlCmd::QuerySendWindow {
2136 hop: 2.into(),
2137 leg: tunnel.unique_id(),
2138 done: tx,
2139 })
2140 .unwrap();
2141 let (window, _tags) = rx.await.unwrap().unwrap();
2142 assert_eq!(window, 1000 - 201);
2143 }
2144 });
2145 }
2146
2147 #[traced_test]
2148 #[test]
2149 fn invalid_circ_sendme() {
2150 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2151 let (tunnel, _stream, mut sink, _streamid, _cells_received, _rx, _sink2) =
2155 setup_incoming_sendme_case(&rt, 300 * 498 + 3).await;
2156
2157 let reply_with_sendme_fut = async move {
2158 let c_sendme =
2160 relaymsg::Sendme::new_tag(hex!("FFFF0000000000000000000000000000000000FF"))
2161 .into();
2162 sink.send(rmsg_to_ccmsg(None, c_sendme, false))
2163 .await
2164 .unwrap();
2165 sink
2166 };
2167
2168 let _sink = reply_with_sendme_fut.await;
2169
2170 rt.advance_until_stalled().await;
2172 assert!(tunnel.is_closed());
2173 });
2174 }
2175
2176 #[traced_test]
2177 #[test]
2178 fn test_busy_stream_fairness() {
2179 const N_STREAMS: usize = 3;
2181 const N_CELLS: usize = 20;
2183 const N_BYTES: usize = relaymsg::Data::MAXLEN_V0 * N_CELLS;
2186 const MIN_EXPECTED_BYTES_PER_STREAM: usize =
2193 N_BYTES / N_STREAMS - relaymsg::Data::MAXLEN_V0;
2194
2195 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
2196 let DummyChan {
2197 channel,
2198 mut rx,
2199 tx: _sink,
2200 } = DummyChan::run(&rt, ChannelMode::Client);
2201 let (tunnel, mut sink) = newtunnel(&rt, channel).await;
2202
2203 rt.spawn({
2209 let tunnel = tunnel.clone();
2212 async move {
2213 let mut clients = VecDeque::new();
2214 struct Client {
2215 stream: DataStream,
2216 to_write: &'static [u8],
2217 }
2218 for _ in 0..N_STREAMS {
2219 clients.push_back(Client {
2220 stream: tunnel
2221 .begin_stream("www.example.com", 80, None)
2222 .await
2223 .unwrap(),
2224 to_write: &[0_u8; N_BYTES][..],
2225 });
2226 }
2227 while let Some(mut client) = clients.pop_front() {
2228 if client.to_write.is_empty() {
2229 continue;
2231 }
2232 let written = client.stream.write(client.to_write).await.unwrap();
2233 client.to_write = &client.to_write[written..];
2234 clients.push_back(client);
2235 }
2236 }
2237 })
2238 .unwrap();
2239
2240 let channel_handler_fut = async {
2241 let mut stream_bytes_received = HashMap::<StreamId, usize>::new();
2242 let mut total_bytes_received = 0;
2243
2244 loop {
2245 let (_, msg) = rx.next().await.unwrap().into_circid_and_msg();
2246 let rmsg = match msg {
2247 AnyChanMsg::Relay(r) => AnyRelayMsgOuter::decode_singleton(
2248 RelayCellFormat::V0,
2249 r.into_relay_body(),
2250 )
2251 .unwrap(),
2252 other => panic!("Unexpected chanmsg: {other:?}"),
2253 };
2254 let (streamid, rmsg) = rmsg.into_streamid_and_msg();
2255 match rmsg.cmd() {
2256 RelayCmd::BEGIN => {
2257 let prev = stream_bytes_received.insert(streamid.unwrap(), 0);
2259 assert_eq!(prev, None);
2260 let connected = relaymsg::Connected::new_with_addr(
2262 "10.0.0.1".parse().unwrap(),
2263 1234,
2264 )
2265 .into();
2266 sink.send(rmsg_to_ccmsg(streamid, connected, false))
2267 .await
2268 .unwrap();
2269 }
2270 RelayCmd::DATA => {
2271 let data_msg = relaymsg::Data::try_from(rmsg).unwrap();
2272 let nbytes = data_msg.as_ref().len();
2273 total_bytes_received += nbytes;
2274 let streamid = streamid.unwrap();
2275 let stream_bytes = stream_bytes_received.get_mut(&streamid).unwrap();
2276 *stream_bytes += nbytes;
2277 if total_bytes_received >= N_BYTES {
2278 break;
2279 }
2280 }
2281 RelayCmd::END => {
2282 continue;
2287 }
2288 other => {
2289 panic!("Unexpected command {other:?}");
2290 }
2291 }
2292 }
2293
2294 (total_bytes_received, stream_bytes_received, rx, sink)
2297 };
2298
2299 let (total_bytes_received, stream_bytes_received, _rx, _sink) =
2300 channel_handler_fut.await;
2301 assert_eq!(stream_bytes_received.len(), N_STREAMS);
2302 for (sid, stream_bytes) in stream_bytes_received {
2303 assert!(
2304 stream_bytes >= MIN_EXPECTED_BYTES_PER_STREAM,
2305 "Only {stream_bytes} of {total_bytes_received} bytes received from {N_STREAMS} came from {sid:?}; expected at least {MIN_EXPECTED_BYTES_PER_STREAM}"
2306 );
2307 }
2308 });
2309 }
2310
2311 #[test]
2312 fn basic_params() {
2313 use super::CircParameters;
2314 let mut p = CircParameters::default();
2315 assert!(p.extend_by_ed25519_id);
2316
2317 p.extend_by_ed25519_id = false;
2318 assert!(!p.extend_by_ed25519_id);
2319 }
2320
2321 #[traced_test]
2322 #[test]
2323 #[cfg(feature = "hs-service")]
2324 fn allow_stream_requests_twice() {
2325 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
2326 let DummyChan {
2327 channel,
2328 rx: _rx,
2329 tx: _sink,
2330 } = DummyChan::run(&rt, ChannelMode::Client);
2331 let (tunnel, _send) = newtunnel(&rt, channel).await;
2332
2333 let _incoming = tunnel
2334 .allow_stream_requests(
2335 &[tor_cell::relaycell::RelayCmd::BEGIN],
2336 tunnel.resolve_last_hop().await,
2337 AllowAllStreamsFilter,
2338 )
2339 .await
2340 .unwrap();
2341
2342 let incoming = tunnel
2343 .allow_stream_requests(
2344 &[tor_cell::relaycell::RelayCmd::BEGIN],
2345 tunnel.resolve_last_hop().await,
2346 AllowAllStreamsFilter,
2347 )
2348 .await;
2349
2350 assert!(incoming.is_err());
2352 });
2353 }
2354
2355 #[traced_test]
2356 #[test]
2357 #[cfg(feature = "hs-service")]
2358 fn allow_stream_requests() {
2359 use tor_cell::relaycell::msg::BeginFlags;
2360
2361 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
2362 const TEST_DATA: &[u8] = b"ping";
2363
2364 let DummyChan {
2365 channel,
2366 rx: _rx,
2367 tx: _sink,
2368 } = DummyChan::run(&rt, ChannelMode::Client);
2369 let (tunnel, mut send) = newtunnel(&rt, channel).await;
2370
2371 let rfmt = RelayCellFormat::V0;
2372
2373 let (tx, rx) = oneshot::channel();
2375 let mut incoming = tunnel
2376 .allow_stream_requests(
2377 &[tor_cell::relaycell::RelayCmd::BEGIN],
2378 tunnel.resolve_last_hop().await,
2379 AllowAllStreamsFilter,
2380 )
2381 .await
2382 .unwrap();
2383
2384 let simulate_service = async move {
2385 let stream = incoming.next().await.unwrap();
2386 let mut data_stream = stream
2387 .accept_data(relaymsg::Connected::new_empty())
2388 .await
2389 .unwrap();
2390 tx.send(()).unwrap();
2392
2393 let mut buf = [0_u8; TEST_DATA.len()];
2395 data_stream.read_exact(&mut buf).await.unwrap();
2396 assert_eq!(&buf, TEST_DATA);
2397
2398 tunnel
2399 };
2400
2401 let simulate_client = async move {
2402 let begin = relaymsg::Begin::new("localhost", 80, BeginFlags::IPV6_OKAY).unwrap();
2403 let body: BoxedCellBody =
2404 AnyRelayMsgOuter::new(StreamId::new(12), AnyRelayMsg::Begin(begin))
2405 .encode(rfmt, &mut testing_rng())
2406 .unwrap();
2407 let begin_msg = chanmsg::Relay::from(body);
2408
2409 send.send(AnyChanMsg::Relay(begin_msg)).await.unwrap();
2411
2412 rx.await.unwrap();
2418 let data = relaymsg::Data::new(TEST_DATA).unwrap();
2420 let body: BoxedCellBody =
2421 AnyRelayMsgOuter::new(StreamId::new(12), AnyRelayMsg::Data(data))
2422 .encode(rfmt, &mut testing_rng())
2423 .unwrap();
2424 let data_msg = chanmsg::Relay::from(body);
2425
2426 send.send(AnyChanMsg::Relay(data_msg)).await.unwrap();
2427 send
2428 };
2429
2430 let (_circ, _send) = futures::join!(simulate_service, simulate_client);
2431 });
2432 }
2433
2434 #[traced_test]
2435 #[test]
2436 #[cfg(feature = "hs-service")]
2437 fn accept_stream_after_reject() {
2438 use tor_cell::relaycell::msg::AnyRelayMsg;
2439 use tor_cell::relaycell::msg::BeginFlags;
2440 use tor_cell::relaycell::msg::EndReason;
2441
2442 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
2443 const TEST_DATA: &[u8] = b"ping";
2444 const STREAM_COUNT: usize = 2;
2445 let rfmt = RelayCellFormat::V0;
2446
2447 let DummyChan {
2448 channel,
2449 rx: _rx,
2450 tx: _sink,
2451 } = DummyChan::run(&rt, ChannelMode::Client);
2452 let (tunnel, mut send) = newtunnel(&rt, channel).await;
2453
2454 let (mut tx, mut rx) = mpsc::channel(STREAM_COUNT);
2456
2457 let mut incoming = tunnel
2458 .allow_stream_requests(
2459 &[tor_cell::relaycell::RelayCmd::BEGIN],
2460 tunnel.resolve_last_hop().await,
2461 AllowAllStreamsFilter,
2462 )
2463 .await
2464 .unwrap();
2465
2466 let simulate_service = async move {
2467 for i in 0..STREAM_COUNT {
2469 let stream = incoming.next().await.unwrap();
2470
2471 if i == 0 {
2473 stream
2474 .reject(relaymsg::End::new_with_reason(EndReason::INTERNAL))
2475 .await
2476 .unwrap();
2477 tx.send(()).await.unwrap();
2479 continue;
2480 }
2481
2482 let mut data_stream = stream
2483 .accept_data(relaymsg::Connected::new_empty())
2484 .await
2485 .unwrap();
2486 tx.send(()).await.unwrap();
2488
2489 let mut buf = [0_u8; TEST_DATA.len()];
2491 data_stream.read_exact(&mut buf).await.unwrap();
2492 assert_eq!(&buf, TEST_DATA);
2493 }
2494
2495 tunnel
2496 };
2497
2498 let simulate_client = async move {
2499 let begin = relaymsg::Begin::new("localhost", 80, BeginFlags::IPV6_OKAY).unwrap();
2500 let body: BoxedCellBody =
2501 AnyRelayMsgOuter::new(StreamId::new(12), AnyRelayMsg::Begin(begin))
2502 .encode(rfmt, &mut testing_rng())
2503 .unwrap();
2504 let begin_msg = chanmsg::Relay::from(body);
2505
2506 for _ in 0..STREAM_COUNT {
2509 send.send(AnyChanMsg::Relay(begin_msg.clone()))
2510 .await
2511 .unwrap();
2512
2513 rx.next().await.unwrap();
2515 }
2516
2517 let data = relaymsg::Data::new(TEST_DATA).unwrap();
2519 let body: BoxedCellBody =
2520 AnyRelayMsgOuter::new(StreamId::new(12), AnyRelayMsg::Data(data))
2521 .encode(rfmt, &mut testing_rng())
2522 .unwrap();
2523 let data_msg = chanmsg::Relay::from(body);
2524
2525 send.send(AnyChanMsg::Relay(data_msg)).await.unwrap();
2526 send
2527 };
2528
2529 let (_circ, _send) = futures::join!(simulate_service, simulate_client);
2530 });
2531 }
2532
2533 #[traced_test]
2534 #[test]
2535 #[cfg(feature = "hs-service")]
2536 fn incoming_stream_bad_hop() {
2537 use tor_cell::relaycell::msg::BeginFlags;
2538
2539 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
2540 const EXPECTED_HOP: u8 = 1;
2542 let rfmt = RelayCellFormat::V0;
2543
2544 let DummyChan {
2545 channel,
2546 rx: _rx,
2547 tx: _sink,
2548 } = DummyChan::run(&rt, ChannelMode::Client);
2549 let (tunnel, mut send) = newtunnel(&rt, channel).await;
2550
2551 let mut incoming = tunnel
2553 .allow_stream_requests(
2554 &[tor_cell::relaycell::RelayCmd::BEGIN],
2555 (
2557 tunnel.as_single_circ().unwrap().unique_id(),
2558 EXPECTED_HOP.into(),
2559 )
2560 .into(),
2561 AllowAllStreamsFilter,
2562 )
2563 .await
2564 .unwrap();
2565
2566 let simulate_service = async move {
2567 assert!(incoming.next().await.is_none());
2570 tunnel
2571 };
2572
2573 let simulate_client = async move {
2574 let begin = relaymsg::Begin::new("localhost", 80, BeginFlags::IPV6_OKAY).unwrap();
2575 let body: BoxedCellBody =
2576 AnyRelayMsgOuter::new(StreamId::new(12), AnyRelayMsg::Begin(begin))
2577 .encode(rfmt, &mut testing_rng())
2578 .unwrap();
2579 let begin_msg = chanmsg::Relay::from(body);
2580
2581 send.send(AnyChanMsg::Relay(begin_msg)).await.unwrap();
2583
2584 send
2585 };
2586
2587 let (_circ, _send) = futures::join!(simulate_service, simulate_client);
2588 });
2589 }
2590
2591 #[traced_test]
2592 #[test]
2593 #[cfg(feature = "conflux")]
2594 fn multipath_circ_validation() {
2595 use std::error::Error as _;
2596
2597 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2598 let params = CircParameters::default();
2599 let invalid_tunnels = [
2600 setup_bad_conflux_tunnel(&rt).await,
2601 setup_conflux_tunnel(&rt, true, params).await,
2602 ];
2603
2604 for tunnel in invalid_tunnels {
2605 let TestTunnelCtx {
2606 tunnel: _tunnel,
2607 circs: _circs,
2608 conflux_link_rx,
2609 } = tunnel;
2610
2611 let conflux_hs_err = conflux_link_rx.await.unwrap().unwrap_err();
2612 let err_src = conflux_hs_err.source().unwrap();
2613
2614 assert!(
2617 err_src
2618 .to_string()
2619 .contains("one more conflux circuits are invalid")
2620 );
2621 }
2622 });
2623 }
2624
2625 #[derive(Debug)]
2629 #[allow(unused)]
2630 #[cfg(feature = "conflux")]
2631 struct TestCircuitCtx {
2632 chan_rx: Receiver<AnyChanCell>,
2633 chan_tx: Sender<std::result::Result<AnyChanCell, Error>>,
2634 circ_tx: CircuitRxSender,
2635 unique_id: UniqId,
2636 }
2637
2638 #[derive(Debug)]
2639 #[cfg(feature = "conflux")]
2640 struct TestTunnelCtx {
2641 tunnel: Arc<ClientTunnel>,
2642 circs: Vec<TestCircuitCtx>,
2643 conflux_link_rx: oneshot::Receiver<Result<ConfluxHandshakeResult>>,
2644 }
2645
2646 #[cfg(feature = "conflux")]
2648 async fn await_link_payload(rx: &mut Receiver<AnyChanCell>) -> ConfluxLink {
2649 let (_id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
2651 let rmsg = match chmsg {
2652 AnyChanMsg::Relay(r) => {
2653 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
2654 .unwrap()
2655 }
2656 other => panic!("{:?}", other),
2657 };
2658 let (streamid, rmsg) = rmsg.into_streamid_and_msg();
2659
2660 let link = match rmsg {
2661 AnyRelayMsg::ConfluxLink(link) => link,
2662 _ => panic!("unexpected relay message {rmsg:?}"),
2663 };
2664
2665 assert!(streamid.is_none());
2666
2667 link
2668 }
2669
2670 #[cfg(feature = "conflux")]
2671 async fn setup_conflux_tunnel(
2672 rt: &MockRuntime,
2673 same_hops: bool,
2674 params: CircParameters,
2675 ) -> TestTunnelCtx {
2676 let hops1 = hop_details(3, 0);
2677 let hops2 = if same_hops {
2678 hops1.clone()
2679 } else {
2680 hop_details(3, 10)
2681 };
2682
2683 let DummyChan {
2684 channel: chan1,
2685 rx: rx1,
2686 tx: chan_sink1,
2687 } = DummyChan::run(rt, ChannelMode::Client);
2688 let (mut tunnel1, sink1) = newtunnel_ext(
2689 rt,
2690 UniqId::new(1, 3),
2691 chan1,
2692 hops1,
2693 2.into(),
2694 params.clone(),
2695 )
2696 .await;
2697
2698 let DummyChan {
2699 channel: chan2,
2700 rx: rx2,
2701 tx: chan_sink2,
2702 } = DummyChan::run(rt, ChannelMode::Client);
2703
2704 let (tunnel2, sink2) =
2705 newtunnel_ext(rt, UniqId::new(2, 4), chan2, hops2, 2.into(), params).await;
2706
2707 let (answer_tx, answer_rx) = oneshot::channel();
2708 tunnel2
2709 .as_single_circ()
2710 .unwrap()
2711 .command
2712 .unbounded_send(CtrlCmd::ShutdownAndReturnCircuit { answer: answer_tx })
2713 .unwrap();
2714
2715 let circuit = answer_rx.await.unwrap().unwrap();
2716 rt.advance_until_stalled().await;
2718 assert!(tunnel2.is_closed());
2719
2720 let (conflux_link_tx, conflux_link_rx) = oneshot::channel();
2721 tunnel1
2723 .as_single_circ()
2724 .unwrap()
2725 .control
2726 .unbounded_send(CtrlMsg::LinkCircuits {
2727 circuits: vec![circuit],
2728 answer: conflux_link_tx,
2729 })
2730 .unwrap();
2731
2732 let circ_ctx1 = TestCircuitCtx {
2733 chan_rx: rx1,
2734 chan_tx: chan_sink1,
2735 circ_tx: sink1,
2736 unique_id: tunnel1.unique_id(),
2737 };
2738
2739 let circ_ctx2 = TestCircuitCtx {
2740 chan_rx: rx2,
2741 chan_tx: chan_sink2,
2742 circ_tx: sink2,
2743 unique_id: tunnel2.unique_id(),
2744 };
2745
2746 tunnel1.circ.is_multi_path = true;
2752 TestTunnelCtx {
2753 tunnel: Arc::new(tunnel1),
2754 circs: vec![circ_ctx1, circ_ctx2],
2755 conflux_link_rx,
2756 }
2757 }
2758
2759 #[cfg(feature = "conflux")]
2760 async fn setup_good_conflux_tunnel(
2761 rt: &MockRuntime,
2762 cc_params: CongestionControlParams,
2763 ) -> TestTunnelCtx {
2764 let same_hops = true;
2770 let flow_ctrl_params = FlowCtrlParameters::defaults_for_tests();
2771 let params = CircParameters::new(true, cc_params, flow_ctrl_params);
2772 setup_conflux_tunnel(rt, same_hops, params).await
2773 }
2774
2775 #[cfg(feature = "conflux")]
2776 async fn setup_bad_conflux_tunnel(rt: &MockRuntime) -> TestTunnelCtx {
2777 let same_hops = false;
2781 let flow_ctrl_params = FlowCtrlParameters::defaults_for_tests();
2782 let params = CircParameters::new(true, build_cc_vegas_params(), flow_ctrl_params);
2783 setup_conflux_tunnel(rt, same_hops, params).await
2784 }
2785
2786 #[traced_test]
2787 #[test]
2788 #[cfg(feature = "conflux")]
2789 fn reject_conflux_linked_before_hs() {
2790 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2791 let DummyChan {
2792 channel,
2793 rx: _,
2794 tx: _sink,
2795 } = DummyChan::run(&rt, ChannelMode::Client);
2796 let (tunnel, mut sink) = newtunnel(&rt, channel).await;
2797
2798 let nonce = V1Nonce::new(&mut testing_rng());
2799 let payload = V1LinkPayload::new(nonce, V1DesiredUx::NO_OPINION);
2800 let linked = relaymsg::ConfluxLinked::new(payload).into();
2802 sink.send(rmsg_to_ccmsg(None, linked, false)).await.unwrap();
2803
2804 rt.advance_until_stalled().await;
2805 assert!(tunnel.is_closed());
2806 });
2807 }
2808
2809 #[traced_test]
2810 #[test]
2811 #[cfg(feature = "conflux")]
2812 fn conflux_hs_timeout() {
2813 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2814 let TestTunnelCtx {
2815 tunnel: _tunnel,
2816 circs,
2817 conflux_link_rx,
2818 } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
2819
2820 let [mut circ1, _circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
2821
2822 let link = await_link_payload(&mut circ1.chan_rx).await;
2824
2825 let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
2827 circ1
2828 .circ_tx
2829 .send(rmsg_to_ccmsg(None, linked, false))
2830 .await
2831 .unwrap();
2832
2833 rt.advance_by(Duration::from_secs(60)).await;
2835
2836 let conflux_hs_res = conflux_link_rx.await.unwrap().unwrap();
2837
2838 let [res1, res2]: [StdResult<(), ConfluxHandshakeError>; 2] =
2840 conflux_hs_res.try_into().unwrap();
2841
2842 assert!(res1.is_ok());
2843
2844 let err = res2.unwrap_err();
2845 assert_matches!(err, ConfluxHandshakeError::Timeout);
2846 });
2847 }
2848
2849 #[traced_test]
2850 #[test]
2851 #[cfg(feature = "conflux")]
2852 fn conflux_bad_hs() {
2853 use crate::util::err::ConfluxHandshakeError;
2854
2855 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2856 let nonce = V1Nonce::new(&mut testing_rng());
2857 let bad_link_payload = V1LinkPayload::new(nonce, V1DesiredUx::NO_OPINION);
2858 let bad_hs_responses = [
2860 (
2861 rmsg_to_ccmsg(
2862 None,
2863 relaymsg::ConfluxLinked::new(bad_link_payload.clone()).into(),
2864 false,
2865 ),
2866 "Received CONFLUX_LINKED cell with mismatched nonce",
2867 ),
2868 (
2869 rmsg_to_ccmsg(
2870 None,
2871 relaymsg::ConfluxLink::new(bad_link_payload).into(),
2872 false,
2873 ),
2874 "Unexpected CONFLUX_LINK cell from hop #3 on client circuit",
2875 ),
2876 (
2877 rmsg_to_ccmsg(None, relaymsg::ConfluxSwitch::new(0).into(), false),
2878 "Received CONFLUX_SWITCH on unlinked circuit?!",
2879 ),
2880 ];
2889
2890 for (bad_cell, expected_err) in bad_hs_responses {
2891 let TestTunnelCtx {
2892 tunnel,
2893 circs,
2894 conflux_link_rx,
2895 } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
2896
2897 let [mut _circ1, mut circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
2898
2899 circ2.circ_tx.send(bad_cell).await.unwrap();
2901
2902 let conflux_hs_res = conflux_link_rx.await.unwrap().unwrap();
2903 let [res2]: [StdResult<(), ConfluxHandshakeError>; 1] =
2907 conflux_hs_res.try_into().unwrap();
2908
2909 match res2.unwrap_err() {
2910 ConfluxHandshakeError::Link(Error::CircProto(e)) => {
2911 assert_eq!(e, expected_err);
2912 }
2913 e => panic!("unexpected error: {e:?}"),
2914 }
2915
2916 assert!(tunnel.is_closed());
2917 }
2918 });
2919 }
2920
2921 #[traced_test]
2922 #[test]
2923 #[cfg(feature = "conflux")]
2924 fn unexpected_conflux_cell() {
2925 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2926 let nonce = V1Nonce::new(&mut testing_rng());
2927 let link_payload = V1LinkPayload::new(nonce, V1DesiredUx::NO_OPINION);
2928 let bad_cells = [
2929 rmsg_to_ccmsg(
2930 None,
2931 relaymsg::ConfluxLinked::new(link_payload.clone()).into(),
2932 false,
2933 ),
2934 rmsg_to_ccmsg(
2935 None,
2936 relaymsg::ConfluxLink::new(link_payload.clone()).into(),
2937 false,
2938 ),
2939 rmsg_to_ccmsg(None, relaymsg::ConfluxSwitch::new(0).into(), false),
2940 ];
2941
2942 for bad_cell in bad_cells {
2943 let DummyChan {
2944 channel,
2945 rx: _rx,
2946 tx: _sink,
2947 } = DummyChan::run(&rt, ChannelMode::Client);
2948 let (tunnel, mut sink) = newtunnel(&rt, channel).await;
2949
2950 sink.send(bad_cell).await.unwrap();
2951 rt.advance_until_stalled().await;
2952
2953 assert!(tunnel.is_closed());
2957 }
2958 });
2959 }
2960
2961 #[traced_test]
2962 #[test]
2963 #[cfg(feature = "conflux")]
2964 fn conflux_bad_linked() {
2965 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2966 let TestTunnelCtx {
2967 tunnel,
2968 circs,
2969 conflux_link_rx: _,
2970 } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
2971
2972 let [mut circ1, mut circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
2973
2974 let link = await_link_payload(&mut circ1.chan_rx).await;
2975
2976 let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
2978 circ1
2979 .circ_tx
2980 .send(rmsg_to_ccmsg(None, linked, false))
2981 .await
2982 .unwrap();
2983
2984 let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
2986 circ2
2987 .circ_tx
2988 .send(rmsg_to_ccmsg(None, linked, false))
2989 .await
2990 .unwrap();
2991 let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
2992 circ2
2993 .circ_tx
2994 .send(rmsg_to_ccmsg(None, linked, false))
2995 .await
2996 .unwrap();
2997
2998 rt.advance_until_stalled().await;
2999
3000 assert!(tunnel.is_closed());
3003 });
3004 }
3005
3006 #[traced_test]
3007 #[test]
3008 #[cfg(feature = "conflux")]
3009 fn conflux_bad_switch() {
3010 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
3011 let cc_vegas_params = build_cc_vegas_params();
3012 let cwnd_init = cc_vegas_params.cwnd_params().cwnd_init();
3013 let bad_switch = [
3014 relaymsg::ConfluxSwitch::new(0),
3016 relaymsg::ConfluxSwitch::new(cwnd_init + 1),
3019 ];
3020
3021 for bad_cell in bad_switch {
3022 let TestTunnelCtx {
3023 tunnel,
3024 circs,
3025 conflux_link_rx,
3026 } = setup_good_conflux_tunnel(&rt, cc_vegas_params.clone()).await;
3027
3028 let [mut circ1, mut circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
3029
3030 let link = await_link_payload(&mut circ1.chan_rx).await;
3031
3032 for circ in [&mut circ1, &mut circ2] {
3034 let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
3035 circ.circ_tx
3036 .send(rmsg_to_ccmsg(None, linked, false))
3037 .await
3038 .unwrap();
3039 }
3040
3041 let conflux_hs_res = conflux_link_rx.await.unwrap().unwrap();
3042 assert!(conflux_hs_res.iter().all(|res| res.is_ok()));
3043
3044 let msg = rmsg_to_ccmsg(None, bad_cell.clone().into(), false);
3047 circ1.circ_tx.send(msg).await.unwrap();
3048
3049 rt.advance_until_stalled().await;
3051 assert!(tunnel.is_closed());
3052 }
3053 });
3054 }
3055
3056 #[traced_test]
3057 #[test]
3058 #[cfg(feature = "conflux")]
3059 fn conflux_consecutive_switch() {
3060 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
3061 let TestTunnelCtx {
3062 tunnel,
3063 circs,
3064 conflux_link_rx,
3065 } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
3066
3067 let [mut circ1, mut circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
3068
3069 let link = await_link_payload(&mut circ1.chan_rx).await;
3070
3071 for circ in [&mut circ1, &mut circ2] {
3073 let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
3074 circ.circ_tx
3075 .send(rmsg_to_ccmsg(None, linked, false))
3076 .await
3077 .unwrap();
3078 }
3079
3080 let conflux_hs_res = conflux_link_rx.await.unwrap().unwrap();
3081 assert!(conflux_hs_res.iter().all(|res| res.is_ok()));
3082
3083 let switch1 = relaymsg::ConfluxSwitch::new(10);
3085 let msg = rmsg_to_ccmsg(None, switch1.into(), false);
3086 circ1.circ_tx.send(msg).await.unwrap();
3087
3088 rt.advance_until_stalled().await;
3090 assert!(!tunnel.is_closed());
3091
3092 let switch2 = relaymsg::ConfluxSwitch::new(12);
3094 let msg = rmsg_to_ccmsg(None, switch2.into(), false);
3095 circ1.circ_tx.send(msg).await.unwrap();
3096
3097 rt.advance_until_stalled().await;
3100 assert!(tunnel.is_closed());
3101 });
3102 }
3103
3104 #[traced_test]
3107 #[test]
3108 #[cfg(feature = "conflux")]
3109 fn shutdown_and_return_circ_multipath() {
3110 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
3111 let TestTunnelCtx {
3112 tunnel,
3113 circs,
3114 conflux_link_rx: _,
3115 } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
3116
3117 rt.progress_until_stalled().await;
3118
3119 let (answer_tx, answer_rx) = oneshot::channel();
3120 tunnel
3121 .circ
3122 .command
3123 .unbounded_send(CtrlCmd::ShutdownAndReturnCircuit { answer: answer_tx })
3124 .unwrap();
3125
3126 #[allow(clippy::unused_unit, clippy::semicolon_if_nothing_returned)]
3128 let err = answer_rx
3129 .await
3130 .unwrap()
3131 .map(|_| {
3132 ()
3135 })
3136 .unwrap_err();
3137
3138 const MSG: &str = "not a single leg conflux set (got at least 2 elements when exactly one was expected)";
3139 assert!(err.to_string().contains(MSG), "{err}");
3140
3141 rt.progress_until_stalled().await;
3144 assert!(tunnel.is_closed());
3145
3146 drop(circs);
3149 });
3150 }
3151
3152 #[cfg(feature = "conflux")]
3154 #[derive(Debug)]
3155 enum ConfluxTestEndpoint<I: Iterator<Item = Option<Duration>>> {
3156 Relay(ConfluxExitState<I>),
3158 Client {
3160 conflux_link_rx: oneshot::Receiver<Result<ConfluxHandshakeResult>>,
3162 tunnel: Arc<ClientTunnel>,
3164 send_data: Vec<u8>,
3166 recv_data: Vec<u8>,
3168 },
3169 }
3170
3171 #[allow(unused, clippy::large_enum_variant)]
3174 #[derive(Debug)]
3175 #[cfg(feature = "conflux")]
3176 enum ConfluxEndpointResult {
3177 Circuit {
3178 tunnel: Arc<ClientTunnel>,
3179 stream: DataStream,
3180 },
3181 Relay {
3182 circ: TestCircuitCtx,
3183 },
3184 }
3185
3186 #[derive(Debug)]
3188 #[cfg(feature = "conflux")]
3189 struct ConfluxStreamState {
3190 data_recvd: Vec<u8>,
3192 expected_data_len: usize,
3194 begin_recvd: bool,
3196 end_recvd: bool,
3198 end_sent: bool,
3200 }
3201
3202 #[cfg(feature = "conflux")]
3203 impl ConfluxStreamState {
3204 fn new(expected_data_len: usize) -> Self {
3205 Self {
3206 data_recvd: vec![],
3207 expected_data_len,
3208 begin_recvd: false,
3209 end_recvd: false,
3210 end_sent: false,
3211 }
3212 }
3213 }
3214
3215 #[derive(Debug)]
3218 #[cfg(feature = "conflux")]
3219 struct ExpectedSwitch {
3220 cells_so_far: usize,
3223 seqno: u32,
3225 }
3226
3227 #[cfg(feature = "conflux")]
3233 struct CellDispatcher {
3234 leg_tx: HashMap<UniqId, mpsc::Sender<CellToSend>>,
3236 cells_to_send: Vec<(UniqId, AnyRelayMsg)>,
3238 }
3239
3240 #[cfg(feature = "conflux")]
3241 impl CellDispatcher {
3242 async fn run(mut self) {
3243 while !self.cells_to_send.is_empty() {
3244 let (circ_id, cell) = self.cells_to_send.remove(0);
3245 let cell_tx = self.leg_tx.get_mut(&circ_id).unwrap();
3246 let (done_tx, done_rx) = oneshot::channel();
3247 cell_tx.send(CellToSend { done_tx, cell }).await.unwrap();
3248 let () = done_rx.await.unwrap();
3250 }
3251 }
3252 }
3253
3254 #[cfg(feature = "conflux")]
3256 #[derive(Debug)]
3257 struct CellToSend {
3258 done_tx: oneshot::Sender<()>,
3260 cell: AnyRelayMsg,
3262 }
3263
3264 #[derive(Debug)]
3266 #[cfg(feature = "conflux")]
3267 struct ConfluxExitState<I: Iterator<Item = Option<Duration>>> {
3268 runtime: Arc<AsyncMutex<MockRuntime>>,
3275 tunnel: Arc<ClientTunnel>,
3277 circ: TestCircuitCtx,
3279 rtt_delays: I,
3283 stream_state: Arc<Mutex<ConfluxStreamState>>,
3286 expect_switch: Vec<ExpectedSwitch>,
3289 event_rx: mpsc::Receiver<MockExitEvent>,
3291 event_tx: mpsc::Sender<MockExitEvent>,
3293 is_sending_leg: bool,
3295 cells_rx: mpsc::Receiver<CellToSend>,
3297 }
3298
3299 #[cfg(feature = "conflux")]
3300 async fn good_exit_handshake(
3301 runtime: &Arc<AsyncMutex<MockRuntime>>,
3302 init_rtt_delay: Option<Duration>,
3303 rx: &mut Receiver<ChanCell<AnyChanMsg>>,
3304 sink: &mut CircuitRxSender,
3305 ) {
3306 let link = await_link_payload(rx).await;
3308
3309 if let Some(init_rtt_delay) = init_rtt_delay {
3312 runtime.lock().await.advance_by(init_rtt_delay).await;
3313 }
3314
3315 let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
3317 sink.send(rmsg_to_ccmsg(None, linked, false)).await.unwrap();
3318
3319 let (_id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
3321 let rmsg = match chmsg {
3322 AnyChanMsg::Relay(r) => {
3323 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
3324 .unwrap()
3325 }
3326 other => panic!("{other:?}"),
3327 };
3328 let (_streamid, rmsg) = rmsg.into_streamid_and_msg();
3329
3330 assert_matches!(rmsg, AnyRelayMsg::ConfluxLinkedAck(_));
3331 }
3332
3333 #[derive(Copy, Clone, Debug)]
3335 enum MockExitEvent {
3336 Done,
3338 BeginRecvd(StreamId),
3340 }
3341
3342 #[cfg(feature = "conflux")]
3343 async fn run_mock_conflux_exit<I: Iterator<Item = Option<Duration>>>(
3344 state: ConfluxExitState<I>,
3345 ) -> ConfluxEndpointResult {
3346 let ConfluxExitState {
3347 runtime,
3348 tunnel,
3349 mut circ,
3350 rtt_delays,
3351 stream_state,
3352 mut expect_switch,
3353 mut event_tx,
3354 mut event_rx,
3355 is_sending_leg,
3356 mut cells_rx,
3357 } = state;
3358
3359 let mut rtt_delays = rtt_delays.into_iter();
3360
3361 let stream_len = stream_state.lock().unwrap().expected_data_len;
3363 let mut data_cells_received = 0_usize;
3364 let mut cell_count = 0_usize;
3365 let mut tags = vec![];
3366 let mut streamid = None;
3367 let mut done_writing = false;
3368
3369 loop {
3370 let should_exit = {
3371 let stream_state = stream_state.lock().unwrap();
3372 let done_reading = stream_state.data_recvd.len() >= stream_len;
3373
3374 (stream_state.begin_recvd || stream_state.end_recvd) && done_reading && done_writing
3375 };
3376
3377 if should_exit {
3378 break;
3379 }
3380
3381 use futures::select;
3382
3383 let mut next_cell = if streamid.is_some() && !done_writing {
3386 Box::pin(cells_rx.next().fuse())
3387 as Pin<Box<dyn FusedFuture<Output = Option<CellToSend>> + Send>>
3388 } else {
3389 Box::pin(std::future::pending().fuse())
3390 };
3391
3392 let res = select! {
3395 res = circ.chan_rx.next() => {
3396 res.unwrap()
3397 },
3398 res = event_rx.next() => {
3399 let Some(event) = res else {
3400 break;
3401 };
3402
3403 match event {
3404 MockExitEvent::Done => {
3405 break;
3406 },
3407 MockExitEvent::BeginRecvd(id) => {
3408 streamid = Some(id);
3411 continue;
3412 },
3413 }
3414 }
3415 res = next_cell => {
3416 if let Some(cell_to_send) = res {
3417 let CellToSend { cell, done_tx } = cell_to_send;
3418
3419 let streamid = if matches!(cell, AnyRelayMsg::ConfluxSwitch(_)) {
3421 None
3422 } else {
3423 streamid
3424 };
3425
3426 circ.circ_tx
3427 .send(rmsg_to_ccmsg(streamid, cell, false))
3428 .await
3429 .unwrap();
3430
3431 runtime.lock().await.advance_until_stalled().await;
3432 done_tx.send(()).unwrap();
3433 } else {
3434 done_writing = true;
3435 }
3436
3437 continue;
3438 }
3439 };
3440
3441 let (_id, chmsg) = res.into_circid_and_msg();
3442 cell_count += 1;
3443 let rmsg = match chmsg {
3444 AnyChanMsg::Relay(r) => {
3445 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
3446 .unwrap()
3447 }
3448 other => panic!("{:?}", other),
3449 };
3450 let (new_streamid, rmsg) = rmsg.into_streamid_and_msg();
3451 if streamid.is_none() {
3452 streamid = new_streamid;
3453 }
3454
3455 let begin_recvd = stream_state.lock().unwrap().begin_recvd;
3456 let end_recvd = stream_state.lock().unwrap().end_recvd;
3457 match rmsg {
3458 AnyRelayMsg::Begin(_) if begin_recvd => {
3459 panic!("client tried to open two streams?!");
3460 }
3461 AnyRelayMsg::Begin(_) if !begin_recvd => {
3462 stream_state.lock().unwrap().begin_recvd = true;
3463 let connected = relaymsg::Connected::new_empty().into();
3465 circ.circ_tx
3466 .send(rmsg_to_ccmsg(streamid, connected, false))
3467 .await
3468 .unwrap();
3469 event_tx
3471 .send(MockExitEvent::BeginRecvd(streamid.unwrap()))
3472 .await
3473 .unwrap();
3474 }
3475 AnyRelayMsg::End(_) if !end_recvd => {
3476 stream_state.lock().unwrap().end_recvd = true;
3477 break;
3478 }
3479 AnyRelayMsg::End(_) if end_recvd => {
3480 panic!("received two END cells for the same stream?!");
3481 }
3482 AnyRelayMsg::ConfluxSwitch(cell) => {
3483 let expected = expect_switch.remove(0);
3485
3486 assert_eq!(expected.cells_so_far, cell_count);
3487 assert_eq!(expected.seqno, cell.seqno());
3488
3489 continue;
3495 }
3496 AnyRelayMsg::Data(dat) => {
3497 data_cells_received += 1;
3498 stream_state
3499 .lock()
3500 .unwrap()
3501 .data_recvd
3502 .extend_from_slice(dat.as_ref());
3503
3504 let is_next_cell_sendme = data_cells_received.is_multiple_of(31);
3505 if is_next_cell_sendme {
3506 if tags.is_empty() {
3507 runtime.lock().await.advance_until_stalled().await;
3512 let (tx, rx) = oneshot::channel();
3513 tunnel
3514 .circ
3515 .command
3516 .unbounded_send(CtrlCmd::QuerySendWindow {
3517 hop: 2.into(),
3518 leg: circ.unique_id,
3519 done: tx,
3520 })
3521 .unwrap();
3522
3523 let (_window, new_tags) = rx.await.unwrap().unwrap();
3525 tags = new_tags;
3526 }
3527
3528 let tag = tags.remove(0);
3529
3530 if let Some(rtt_delay) = rtt_delays.next().flatten() {
3533 runtime.lock().await.advance_by(rtt_delay).await;
3534 }
3535 let sendme = relaymsg::Sendme::from(tag).into();
3537
3538 circ.circ_tx
3539 .send(rmsg_to_ccmsg(None, sendme, false))
3540 .await
3541 .unwrap();
3542 }
3543 }
3544 _ => panic!("unexpected message {rmsg:?} on leg {}", circ.unique_id),
3545 }
3546 }
3547
3548 let end_recvd = stream_state.lock().unwrap().end_recvd;
3549
3550 if is_sending_leg && !end_recvd {
3552 let end = relaymsg::End::new_with_reason(relaymsg::EndReason::DONE).into();
3553 circ.circ_tx
3554 .send(rmsg_to_ccmsg(streamid, end, false))
3555 .await
3556 .unwrap();
3557 stream_state.lock().unwrap().end_sent = true;
3558 }
3559
3560 let _ = event_tx.send(MockExitEvent::Done).await;
3562
3563 assert!(
3565 expect_switch.is_empty(),
3566 "expect_switch = {expect_switch:?}"
3567 );
3568
3569 ConfluxEndpointResult::Relay { circ }
3570 }
3571
3572 #[cfg(feature = "conflux")]
3573 async fn run_conflux_client(
3574 tunnel: Arc<ClientTunnel>,
3575 conflux_link_rx: oneshot::Receiver<Result<ConfluxHandshakeResult>>,
3576 send_data: Vec<u8>,
3577 recv_data: Vec<u8>,
3578 ) -> ConfluxEndpointResult {
3579 let res = conflux_link_rx.await;
3580
3581 let res = res.unwrap().unwrap();
3582 assert_eq!(res.len(), 2);
3583
3584 let mut stream = tunnel
3589 .begin_stream("www.example.com", 443, None)
3590 .await
3591 .unwrap();
3592
3593 stream.write_all(&send_data).await.unwrap();
3594 stream.flush().await.unwrap();
3595
3596 let mut recv: Vec<u8> = Vec::new();
3597 let recv_len = stream.read_to_end(&mut recv).await.unwrap();
3598 assert_eq!(recv_len, recv_data.len());
3599 assert_eq!(recv_data, recv);
3600
3601 ConfluxEndpointResult::Circuit { tunnel, stream }
3602 }
3603
3604 #[cfg(feature = "conflux")]
3605 async fn run_conflux_endpoint<I: Iterator<Item = Option<Duration>>>(
3606 endpoint: ConfluxTestEndpoint<I>,
3607 ) -> ConfluxEndpointResult {
3608 match endpoint {
3609 ConfluxTestEndpoint::Relay(state) => run_mock_conflux_exit(state).await,
3610 ConfluxTestEndpoint::Client {
3611 tunnel,
3612 conflux_link_rx,
3613 send_data,
3614 recv_data,
3615 } => run_conflux_client(tunnel, conflux_link_rx, send_data, recv_data).await,
3616 }
3617 }
3618
3619 #[traced_test]
3637 #[test]
3638 #[cfg(feature = "conflux")]
3639 fn multipath_client_to_exit() {
3640 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
3641 const NUM_CELLS: usize = 300;
3643 const CELL_SIZE: usize = 498;
3645
3646 let TestTunnelCtx {
3647 tunnel,
3648 circs,
3649 conflux_link_rx,
3650 } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
3651 let [circ1, circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
3652
3653 let mut send_data = (0..255_u8)
3655 .cycle()
3656 .take(NUM_CELLS * CELL_SIZE)
3657 .collect::<Vec<_>>();
3658 let stream_state = Arc::new(Mutex::new(ConfluxStreamState::new(send_data.len())));
3659
3660 let mut tasks = vec![];
3661
3662 let (tx1, rx1) = mpsc::channel(1);
3665 let (tx2, rx2) = mpsc::channel(1);
3666
3667 let circ1_rtt_delays = [
3672 Some(Duration::from_millis(100)),
3674 Some(Duration::from_millis(500)),
3678 Some(Duration::from_millis(700)),
3679 Some(Duration::from_millis(900)),
3680 Some(Duration::from_millis(1100)),
3681 Some(Duration::from_millis(1300)),
3682 Some(Duration::from_millis(1500)),
3683 Some(Duration::from_millis(1700)),
3684 Some(Duration::from_millis(1900)),
3685 Some(Duration::from_millis(2100)),
3686 ]
3687 .into_iter();
3688
3689 let circ2_rtt_delays = [
3690 Some(Duration::from_millis(200)),
3691 Some(Duration::from_millis(400)),
3692 Some(Duration::from_millis(600)),
3693 Some(Duration::from_millis(800)),
3694 Some(Duration::from_millis(1000)),
3695 Some(Duration::from_millis(1200)),
3696 Some(Duration::from_millis(1400)),
3697 Some(Duration::from_millis(1600)),
3698 Some(Duration::from_millis(1800)),
3699 Some(Duration::from_millis(2000)),
3700 ]
3701 .into_iter();
3702
3703 let expected_switches1 = vec![ExpectedSwitch {
3704 cells_so_far: 126,
3712 seqno: 124,
3721 }];
3722
3723 let expected_switches2 = vec![ExpectedSwitch {
3724 cells_so_far: 1,
3727 seqno: 125,
3729 }];
3730
3731 let relay_runtime = Arc::new(AsyncMutex::new(rt.clone()));
3732
3733 let (_, cells_rx1) = mpsc::channel(1);
3736 let (_, cells_rx2) = mpsc::channel(1);
3737
3738 let relay1 = ConfluxExitState {
3739 runtime: Arc::clone(&relay_runtime),
3740 tunnel: Arc::clone(&tunnel),
3741 circ: circ1,
3742 rtt_delays: circ1_rtt_delays,
3743 stream_state: Arc::clone(&stream_state),
3744 expect_switch: expected_switches1,
3745 event_tx: tx1,
3746 event_rx: rx2,
3747 is_sending_leg: true,
3748 cells_rx: cells_rx1,
3749 };
3750
3751 let relay2 = ConfluxExitState {
3752 runtime: Arc::clone(&relay_runtime),
3753 tunnel: Arc::clone(&tunnel),
3754 circ: circ2,
3755 rtt_delays: circ2_rtt_delays,
3756 stream_state: Arc::clone(&stream_state),
3757 expect_switch: expected_switches2,
3758 event_tx: tx2,
3759 event_rx: rx1,
3760 is_sending_leg: false,
3761 cells_rx: cells_rx2,
3762 };
3763
3764 for mut mock_relay in [relay1, relay2] {
3765 let leg = mock_relay.circ.unique_id;
3766
3767 good_exit_handshake(
3775 &relay_runtime,
3776 mock_relay.rtt_delays.next().flatten(),
3777 &mut mock_relay.circ.chan_rx,
3778 &mut mock_relay.circ.circ_tx,
3779 )
3780 .await;
3781
3782 let relay = ConfluxTestEndpoint::Relay(mock_relay);
3783
3784 tasks.push(rt.spawn_join(format!("relay task {leg}"), run_conflux_endpoint(relay)));
3785 }
3786
3787 tasks.push(rt.spawn_join(
3788 "client task".to_string(),
3789 run_conflux_endpoint(ConfluxTestEndpoint::Client {
3790 tunnel,
3791 conflux_link_rx,
3792 send_data: send_data.clone(),
3793 recv_data: vec![],
3794 }),
3795 ));
3796 let _sinks = futures::future::join_all(tasks).await;
3797 let mut stream_state = stream_state.lock().unwrap();
3798 assert!(stream_state.begin_recvd);
3799
3800 stream_state.data_recvd.sort();
3801 send_data.sort();
3802 assert_eq!(stream_state.data_recvd, send_data);
3803 });
3804 }
3805
3806 #[cfg(feature = "conflux")]
3817 async fn run_multipath_exit_to_client_test(
3818 rt: MockRuntime,
3819 tunnel: TestTunnelCtx,
3820 cells_to_send: Vec<(UniqId, AnyRelayMsg)>,
3821 send_data: Vec<u8>,
3822 recv_data: Vec<u8>,
3823 ) -> Arc<Mutex<ConfluxStreamState>> {
3824 let TestTunnelCtx {
3825 tunnel,
3826 circs,
3827 conflux_link_rx,
3828 } = tunnel;
3829 let [circ1, circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
3830
3831 let stream_state = Arc::new(Mutex::new(ConfluxStreamState::new(send_data.len())));
3832
3833 let mut tasks = vec![];
3834 let relay_runtime = Arc::new(AsyncMutex::new(rt.clone()));
3835 let (cells_tx1, cells_rx1) = mpsc::channel(1);
3836 let (cells_tx2, cells_rx2) = mpsc::channel(1);
3837
3838 let dispatcher = CellDispatcher {
3839 leg_tx: [(circ1.unique_id, cells_tx1), (circ2.unique_id, cells_tx2)]
3840 .into_iter()
3841 .collect(),
3842 cells_to_send,
3843 };
3844
3845 let (tx1, rx1) = mpsc::channel(1);
3848 let (tx2, rx2) = mpsc::channel(1);
3849
3850 let relay1 = ConfluxExitState {
3851 runtime: Arc::clone(&relay_runtime),
3852 tunnel: Arc::clone(&tunnel),
3853 circ: circ1,
3854 rtt_delays: [].into_iter(),
3855 stream_state: Arc::clone(&stream_state),
3856 expect_switch: vec![],
3858 event_tx: tx1,
3859 event_rx: rx2,
3860 is_sending_leg: false,
3861 cells_rx: cells_rx1,
3862 };
3863
3864 let relay2 = ConfluxExitState {
3865 runtime: Arc::clone(&relay_runtime),
3866 tunnel: Arc::clone(&tunnel),
3867 circ: circ2,
3868 rtt_delays: [].into_iter(),
3869 stream_state: Arc::clone(&stream_state),
3870 expect_switch: vec![],
3872 event_tx: tx2,
3873 event_rx: rx1,
3874 is_sending_leg: true,
3875 cells_rx: cells_rx2,
3876 };
3877
3878 rt.spawn(dispatcher.run()).unwrap();
3883
3884 for mut mock_relay in [relay1, relay2] {
3885 let leg = mock_relay.circ.unique_id;
3886
3887 good_exit_handshake(
3888 &relay_runtime,
3889 mock_relay.rtt_delays.next().flatten(),
3890 &mut mock_relay.circ.chan_rx,
3891 &mut mock_relay.circ.circ_tx,
3892 )
3893 .await;
3894
3895 let relay = ConfluxTestEndpoint::Relay(mock_relay);
3896
3897 tasks.push(rt.spawn_join(format!("relay task {leg}"), run_conflux_endpoint(relay)));
3898 }
3899
3900 tasks.push(rt.spawn_join(
3901 "client task".to_string(),
3902 run_conflux_endpoint(ConfluxTestEndpoint::Client {
3903 tunnel,
3904 conflux_link_rx,
3905 send_data: send_data.clone(),
3906 recv_data,
3907 }),
3908 ));
3909
3910 let _sinks = futures::future::join_all(tasks).await;
3912
3913 stream_state
3914 }
3915
3916 #[traced_test]
3917 #[test]
3918 #[cfg(feature = "conflux")]
3919 fn multipath_exit_to_client() {
3920 const TO_SEND: &[u8] =
3922 b"But something about Buster Friendly irritated John Isidore, one specific thing";
3923
3924 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
3925 const CIRC1: usize = 0;
3927 const CIRC2: usize = 1;
3928
3929 let simple_switch = vec![
3953 (CIRC1, relaymsg::Data::new(&TO_SEND[0..5]).unwrap().into()),
3954 (CIRC1, relaymsg::Data::new(&TO_SEND[5..10]).unwrap().into()),
3955 (CIRC2, relaymsg::ConfluxSwitch::new(4).into()),
3957 (CIRC2, relaymsg::Data::new(&TO_SEND[20..30]).unwrap().into()),
3959 (CIRC1, relaymsg::Data::new(&TO_SEND[10..20]).unwrap().into()),
3962 (CIRC2, relaymsg::Data::new(&TO_SEND[30..40]).unwrap().into()),
3963 (CIRC2, relaymsg::Data::new(&TO_SEND[40..]).unwrap().into()),
3964 ];
3965
3966 let multiple_switches = vec![
4013 (CIRC2, relaymsg::ConfluxSwitch::new(3).into()),
4016 (CIRC2, relaymsg::Data::new(&TO_SEND[15..20]).unwrap().into()),
4018 (CIRC2, relaymsg::Data::new(&TO_SEND[20..30]).unwrap().into()),
4019 (CIRC1, relaymsg::Data::new(&TO_SEND[0..10]).unwrap().into()),
4021 (CIRC1, relaymsg::Data::new(&TO_SEND[10..15]).unwrap().into()),
4022 (CIRC1, relaymsg::ConfluxSwitch::new(3).into()),
4024 (CIRC1, relaymsg::Data::new(&TO_SEND[31..40]).unwrap().into()),
4026 (CIRC2, relaymsg::Data::new(&TO_SEND[30..31]).unwrap().into()),
4028 (CIRC1, relaymsg::Data::new(&TO_SEND[40..]).unwrap().into()),
4030 (CIRC2, relaymsg::ConfluxSwitch::new(2).into()),
4032 ];
4033
4034 let tests = [simple_switch, multiple_switches];
4040
4041 for cells_to_send in tests {
4042 let tunnel = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
4043 assert_eq!(tunnel.circs.len(), 2);
4044 let circ_ids = [tunnel.circs[0].unique_id, tunnel.circs[1].unique_id];
4045 let cells_to_send = cells_to_send
4046 .into_iter()
4047 .map(|(i, cell)| (circ_ids[i], cell))
4048 .collect();
4049
4050 let send_data = vec![];
4052 let stream_state = run_multipath_exit_to_client_test(
4053 rt.clone(),
4054 tunnel,
4055 cells_to_send,
4056 send_data.clone(),
4057 TO_SEND.into(),
4058 )
4059 .await;
4060 let stream_state = stream_state.lock().unwrap();
4061 assert!(stream_state.begin_recvd);
4062 assert!(stream_state.data_recvd.is_empty());
4064 }
4065 });
4066 }
4067
4068 #[traced_test]
4069 #[test]
4070 #[cfg(all(feature = "conflux", feature = "hs-service"))]
4071 fn conflux_incoming_stream() {
4072 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
4073 use std::error::Error as _;
4074
4075 const EXPECTED_HOP: u8 = 1;
4076
4077 let TestTunnelCtx {
4078 tunnel,
4079 circs,
4080 conflux_link_rx,
4081 } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
4082
4083 let [mut circ1, mut circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
4084
4085 let link = await_link_payload(&mut circ1.chan_rx).await;
4086 for circ in [&mut circ1, &mut circ2] {
4087 let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
4088 circ.circ_tx
4089 .send(rmsg_to_ccmsg(None, linked, false))
4090 .await
4091 .unwrap();
4092 }
4093
4094 let conflux_hs_res = conflux_link_rx.await.unwrap().unwrap();
4095 assert!(conflux_hs_res.iter().all(|res| res.is_ok()));
4096
4097 let err = tunnel
4099 .allow_stream_requests(
4100 &[tor_cell::relaycell::RelayCmd::BEGIN],
4101 (tunnel.circ.unique_id(), EXPECTED_HOP.into()).into(),
4102 AllowAllStreamsFilter,
4103 )
4104 .await
4105 .map(|_| ())
4107 .unwrap_err();
4108
4109 let err_src = err.source().unwrap().to_string();
4110 assert!(
4111 err_src.contains("Cannot allow stream requests on a multi-path tunnel"),
4112 "{err_src}"
4113 );
4114 });
4115 }
4116
4117 #[test]
4118 fn client_circ_chan_msg() {
4119 use tor_cell::chancell::msg::{self, AnyChanMsg};
4120 fn good(m: AnyChanMsg) {
4121 assert!(ClientCircChanMsg::try_from(m).is_ok());
4122 }
4123 fn bad(m: AnyChanMsg) {
4124 assert!(ClientCircChanMsg::try_from(m).is_err());
4125 }
4126
4127 good(msg::Destroy::new(2.into()).into());
4128 bad(msg::CreatedFast::new(&b"guaranteed in this world"[..]).into());
4129 bad(msg::Created2::new(&b"and the next"[..]).into());
4130 good(msg::Relay::new(&b"guaranteed guaranteed"[..]).into());
4131 bad(msg::AnyChanMsg::RelayEarly(
4132 msg::Relay::new(&b"for the world and its mother"[..]).into(),
4133 ));
4134 bad(msg::Versions::new([1, 2, 3]).unwrap().into());
4135 }
4136}