1pub(crate) mod backward;
44pub(crate) mod forward;
45
46use std::sync::Arc;
47use std::time::Duration;
48
49use futures::StreamExt as _;
50use futures::channel::mpsc;
51
52use tor_cell::chancell::CircId;
53use tor_cell::relaycell::RelayCmd;
54use tor_linkspec::OwnedChanTarget;
55use tor_memquota::mq_queue::{ChannelSpec, MpscSpec};
56use tor_rtcompat::{DynTimeProvider, Runtime};
57
58use crate::channel::Channel;
59use crate::circuit::circhop::ReactorStreamComponents;
60use crate::circuit::circhop::{CircHopOutbound, HopSettings};
61use crate::circuit::reactor::Reactor as BaseReactor;
62use crate::circuit::reactor::hop_mgr::HopMgr;
63use crate::circuit::reactor::stream;
64use crate::circuit::{CircuitRxReceiver, UniqId};
65use crate::congestion::sendme::StreamRecvWindow;
66use crate::crypto::cell::{InboundRelayLayer, OutboundRelayLayer};
67use crate::memquota::{CircuitAccount, SpecificAccount};
68use crate::relay::RelayCirc;
69use crate::relay::channel_provider::ChannelProvider;
70use crate::relay::reactor::backward::Backward;
71use crate::relay::reactor::forward::Forward;
72use crate::stream::flow_ctrl::state::WithSidechannelMitigations;
73use crate::stream::flow_ctrl::xon_xoff::reader::XonXoffReaderCtrl;
74use crate::stream::incoming::{
75 IncomingCmdChecker, IncomingStream, IncomingStreamRequestFilter, IncomingStreamRequestHandler,
76 StreamReqInfo,
77};
78use crate::stream::raw::StreamReceiver;
79use crate::stream::{RECV_WINDOW_INIT, StreamComponents, StreamTarget, Tunnel};
80
81use crate::client::circuit::padding::{PaddingController, PaddingEventStream};
83
84type RelayBaseReactor<R> = BaseReactor<R, Forward, Backward>;
86
87#[must_use = "If you don't call run() on a reactor, the circuit won't work."]
89pub(crate) struct Reactor<R: Runtime>(RelayBaseReactor<R>);
90
91struct StreamHandler;
93
94impl stream::StreamHandler for StreamHandler {
95 fn halfstream_expiry(&self, hop: &CircHopOutbound) -> Duration {
96 let ccontrol = hop.ccontrol();
97
98 ccontrol
106 .lock()
107 .expect("poisoned lock")
108 .rtt()
109 .max_rtt()
110 .unwrap_or_default()
113 }
114
115 fn flowctrl_sidechannel_mitigations(&self) -> WithSidechannelMitigations {
116 WithSidechannelMitigations::Disabled
118 }
119}
120
121impl<R: Runtime> Reactor<R> {
122 #[allow(clippy::too_many_arguments)] pub(crate) fn new(
169 runtime: R,
170 channel: &Arc<Channel>,
171 circ_id: CircId,
172 unique_id: UniqId,
173 input: CircuitRxReceiver,
174 crypto_in: Box<dyn InboundRelayLayer + Send>,
175 crypto_out: Box<dyn OutboundRelayLayer + Send>,
176 settings: &HopSettings,
177 chan_provider: Arc<dyn ChannelProvider<BuildSpec = OwnedChanTarget> + Send + Sync>,
178 padding_ctrl: PaddingController,
179 padding_event_stream: PaddingEventStream,
180 incoming_filter: Box<dyn IncomingStreamRequestFilter>,
181 allowed_stream_cmds: &[RelayCmd],
182 memquota: &CircuitAccount,
183 ) -> crate::Result<(
184 Self,
185 Arc<RelayCirc>,
186 impl futures::Stream<Item = IncomingStream> + use<R>,
187 )> {
188 #[allow(clippy::disallowed_methods)]
193 let (stream_tx, stream_rx) = mpsc::channel(0);
194
195 const INCOMING_BUFFER: usize = crate::stream::STREAM_READER_BUFFER;
204
205 let time_provider = DynTimeProvider::new(runtime.clone());
206 let (incoming_sender, incoming_receiver) = MpscSpec::new(INCOMING_BUFFER)
207 .new_mq(time_provider.clone(), memquota.as_raw_account())?;
208
209 let cmd_checker = IncomingCmdChecker::new_any(allowed_stream_cmds);
215 let incoming_handler = IncomingStreamRequestHandler {
216 incoming_sender,
217 hop_num: None,
218 cmd_checker,
219 filter: incoming_filter,
220 };
221 let mut hop_mgr = HopMgr::new_with_incoming_handler(
222 runtime.clone(),
223 unique_id,
224 circ_id,
225 StreamHandler,
226 stream_tx,
227 incoming_handler,
228 memquota.clone(),
229 );
230
231 hop_mgr.add_hop(settings.clone())?;
236
237 #[allow(clippy::disallowed_methods)]
240 let (fwd_ev_tx, fwd_ev_rx) = mpsc::channel(0);
241 let forward = Forward::new(
242 channel,
243 circ_id,
244 unique_id,
245 crypto_out,
246 chan_provider,
247 fwd_ev_tx,
248 memquota.clone(),
249 );
250 let backward = Backward::new(crypto_in);
251
252 let (inner, handle) = BaseReactor::new(
253 runtime,
254 channel,
255 circ_id,
256 unique_id,
257 input,
258 forward,
259 backward,
260 hop_mgr,
261 padding_ctrl,
262 padding_event_stream,
263 stream_rx,
264 fwd_ev_rx,
265 memquota,
266 );
267
268 let reactor = Self(inner);
269 let handle = Arc::new(RelayCirc(handle));
270
271 let tunnel = Arc::clone(&handle);
273 let stream = incoming_receiver.map(move |req_ctx| {
275 let StreamReqInfo {
276 req,
277 stream_id,
278 hop,
279 stream_components:
280 ReactorStreamComponents {
281 stream_inbound_rx,
282 stream_outbound_tx,
283 rate_limit_rx,
284 drain_rate_request_rx,
285 },
286 memquota,
287 relay_cell_format,
288 } = req_ctx;
289
290 debug_assert!(hop.is_none());
292
293 let target = StreamTarget {
294 tunnel: Tunnel::Relay(Arc::clone(&tunnel)),
295 tx: stream_outbound_tx,
296 hop: None,
297 stream_id,
298 relay_cell_format,
299 rate_limit_stream: rate_limit_rx,
300 };
301
302 let xon_xoff_reader_ctrl =
304 XonXoffReaderCtrl::new(drain_rate_request_rx, target.clone());
305
306 let reader = StreamReceiver {
307 target: target.clone(),
308 receiver: stream_inbound_rx,
309 recv_window: StreamRecvWindow::new(RECV_WINDOW_INIT),
310 ended: false,
311 };
312
313 let components = StreamComponents {
314 stream_receiver: reader,
315 target,
316 memquota,
317 xon_xoff_reader_ctrl,
318 };
319
320 IncomingStream::new(time_provider.clone(), req, components)
321 });
322
323 Ok((reactor, handle, stream))
324 }
325
326 pub(crate) async fn run(self) -> crate::Result<()> {
332 self.0.run().await
333 }
334}
335
336#[cfg(test)]
337pub(crate) mod test {
338 #![allow(clippy::bool_assert_comparison)]
340 #![allow(clippy::clone_on_copy)]
341 #![allow(clippy::dbg_macro)]
342 #![allow(clippy::mixed_attributes_style)]
343 #![allow(clippy::print_stderr)]
344 #![allow(clippy::print_stdout)]
345 #![allow(clippy::single_char_pattern)]
346 #![allow(clippy::unwrap_used)]
347 #![allow(clippy::unchecked_time_subtraction)]
348 #![allow(clippy::useless_vec)]
349 #![allow(clippy::needless_pass_by_value)]
350 #![allow(clippy::string_slice)] use super::*;
354 use crate::channel::ChannelMode;
355 use crate::channel::CtrlMsg;
356 use crate::channel::circmap::CircIdRange;
357 use crate::channel::test_utils::DummyChan;
358 use crate::circuit::CircParameters;
359 use crate::circuit::circ_sender;
360 use crate::circuit::reactor::test::{AllowAllStreamsFilter, rmsg_to_ccmsg};
361 use crate::circuit::test::new_circ_net_params;
362 use crate::client::circuit::padding::new_padding;
363 use crate::congestion::test_utils::params::build_cc_vegas_params;
364 use crate::crypto::cell::RelayCellBody;
365 use crate::crypto::cell::{InboundRelayLayer, OutboundRelayLayer};
366 use crate::relay::CreateRequestHandler;
367 use crate::relay::channel::test::DummyChanProvider;
368 use crate::stream::flow_ctrl::params::FlowCtrlParameters;
369 use crate::stream::incoming::{IncomingStream, IncomingStreamRequest, NoOpRequestFilter};
370
371 use futures::AsyncReadExt as _;
372 use futures::SinkExt as _;
373 use oneshot_fused_workaround as oneshot;
374 use tracing_test::traced_test;
375
376 use tor_basic_utils::test_rng::{TestingRng, testing_rng};
377 use tor_cell::chancell::{ChanCell, ChanCmd, msg as chanmsg};
378 use tor_cell::relaycell::{AnyRelayMsgOuter, RelayCellFormat, StreamId, msg as relaymsg};
379 use tor_key_forge::Keygen;
380 use tor_linkspec::{EncodedLinkSpec, HasRelayIds, LinkSpec};
381 use tor_llcrypto::pk::curve25519::StaticKeypair;
382 use tor_llcrypto::pk::ed25519::Ed25519Identity;
383 use tor_llcrypto::pk::rsa::RsaIdentity;
384 use tor_llcrypto::rng::FakeEntropicRng;
385 use tor_protover::{Protocols, named};
386 use tor_relay_crypto::pk::RelayNtorKeys;
387 use tor_rtcompat::SpawnExt;
388 use tor_rtcompat::{DynTimeProvider, Runtime};
389 use tor_rtmock::MockRuntime;
390
391 use chanmsg::{AnyChanMsg, Destroy, DestroyReason, HandshakeType};
392 use relaymsg::SendmeTag;
393
394 use std::net::IpAddr;
395 use std::sync::{Arc, Mutex, Weak, mpsc};
396 use std::task::{Context, Poll, Waker};
397
398 struct DummyInboundCrypto {}
400
401 struct DummyOutboundCrypto {
403 recognized_rx: mpsc::Receiver<Recognized>,
408 }
409
410 const DUMMY_TAG: [u8; 20] = [1; 20];
411
412 impl InboundRelayLayer for DummyInboundCrypto {
413 fn originate(&mut self, _cmd: ChanCmd, _cell: &mut RelayCellBody) -> SendmeTag {
414 DUMMY_TAG.into()
415 }
416
417 fn encrypt_inbound(&mut self, _cmd: ChanCmd, _cell: &mut RelayCellBody) {}
418 }
419
420 impl OutboundRelayLayer for DummyOutboundCrypto {
421 fn decrypt_outbound(
422 &mut self,
423 _cmd: ChanCmd,
424 _cell: &mut RelayCellBody,
425 ) -> Option<SendmeTag> {
426 let recognized = self.recognized_rx.recv().unwrap();
428
429 match recognized {
430 Recognized::Yes => Some(DUMMY_TAG.into()),
431 Recognized::No => None,
432 }
433 }
434 }
435
436 struct ReactorTestCtrl {
450 relay_circ: Arc<RelayCirc>,
452 circid: CircId,
454 inbound_chan: DummyChan,
459 outbound_chan: Arc<Mutex<Option<DummyChan>>>,
469 recognized_tx: mpsc::Sender<Recognized>,
472 }
473
474 enum Recognized {
477 Yes,
479 No,
481 }
482
483 #[allow(dead_code)] enum DestroyDirection {
486 Forward,
488 Backward,
490 Both,
492 }
493
494 macro_rules! decode_relay_cell {
496 ($cell:expr, $expect_msg:tt) => {{
497 let rmsg = match $cell.msg() {
498 chanmsg::AnyChanMsg::Relay(r) => AnyRelayMsgOuter::decode_singleton(
499 RelayCellFormat::V0,
500 r.clone().into_relay_body(),
501 )
502 .unwrap(),
503 msg => panic!("unexpected forwarded {msg:?}"),
504 };
505
506 let msg = match rmsg.msg() {
507 relaymsg::AnyRelayMsg::$expect_msg(inner) => inner.clone(),
508 _ => panic!("unexpected relay message {rmsg:?}"),
509 };
510
511 (rmsg.stream_id(), msg)
512 }};
513 }
514
515 const DUMMY_ED25519_KEY: [u8; 32] = *b"32 bytes pretending to be a key!";
516 const DUMMY_RSA_KEY: [u8; 20] = *b"not really an RSA ky";
517
518 fn build_channel_mode<R: Runtime>(
520 chan_provider: Arc<DummyChanProvider<R>>,
521 allowed_stream_cmds: &[RelayCmd],
522 ) -> ChannelMode {
523 let our_ed25519_id = Ed25519Identity::from_bytes(&DUMMY_ED25519_KEY).unwrap();
524 let our_rsa_id = RsaIdentity::from_bytes(&DUMMY_RSA_KEY).unwrap();
525
526 let mut rng = FakeEntropicRng::<TestingRng>(testing_rng());
527 let relay_ntor_keys = StaticKeypair::generate(&mut rng).unwrap();
528
529 let (create_request_handler, _circuit_stream_rx) = CreateRequestHandler::new(
540 Arc::downgrade(&chan_provider) as Weak<_>,
541 new_circ_net_params(),
542 RelayNtorKeys::new(relay_ntor_keys.into()),
543 Box::new(|| Box::new(NoOpRequestFilter) as Box<_>),
545 allowed_stream_cmds,
546 );
547 let create_request_handler = Arc::new(create_request_handler);
548
549 ChannelMode::Relay {
550 create_request_handler,
551 our_ed25519_id,
552 our_rsa_id,
553 circ_id_range: CircIdRange::Low,
555 }
556 }
557
558 async fn prepare_inbound_chan<R: Runtime>(
570 rt: &R,
571 mode: ChannelMode,
572 ) -> (CircId, CircuitRxReceiver, DummyChan) {
573 let mut inbound_chan = DummyChan::run(rt, mode);
574
575 let memquota = CircuitAccount::new_noop();
576 let time_provider = DynTimeProvider::new(rt.clone());
577
578 let (sender, receiver) = MpscSpec::new(128)
579 .new_mq(time_provider, memquota.as_raw_account())
580 .unwrap();
581 let (sender, receiver) = circ_sender::channel(sender, receiver);
582 let (created_sender, created_receiver) = oneshot::channel();
583
584 let (tx, rx) = oneshot::channel();
585
586 inbound_chan
593 .channel
594 .send_control(CtrlMsg::AllocateCircuit {
595 created_sender,
596 sender,
597 tx,
598 })
599 .unwrap();
600 let (circid, _circ_unique_id, _padding_ctrl, _padding_stream) = rx.await.unwrap().unwrap();
601
602 let handshake = vec![];
613 let created2 = chanmsg::Created2::new(handshake.clone());
614 let cell = ChanCell::new(Some(circid), created2.into());
615 inbound_chan.tx.try_send(Ok(cell)).unwrap();
616
617 let _ = created_receiver.await;
619
620 (circid, receiver, inbound_chan)
621 }
622
623 impl ReactorTestCtrl {
624 async fn spawn_reactor<R: Runtime>(
627 rt: &R,
628 allowed_stream_cmds: &[RelayCmd],
629 ) -> (Self, impl futures::Stream<Item = IncomingStream>) {
630 let outbound_chan = Arc::new(Mutex::new(None));
631 let chan_provider = Arc::new(DummyChanProvider::new(
632 rt.clone(),
633 Arc::clone(&outbound_chan),
634 ));
635
636 let mode = build_channel_mode(Arc::clone(&chan_provider), allowed_stream_cmds);
637 let (circid, receiver, inbound_chan) = prepare_inbound_chan(rt, mode).await;
638
639 let unique_id = UniqId::new(8, 17);
640 let (padding_ctrl, padding_stream) = new_padding(DynTimeProvider::new(rt.clone()));
641 let params = CircParameters::new(
642 true,
643 build_cc_vegas_params(),
644 FlowCtrlParameters::defaults_for_tests(),
645 );
646 let settings = HopSettings::from_params_and_caps(
647 crate::circuit::circhop::HopNegotiationType::Full,
648 ¶ms,
649 &[named::FLOWCTRL_CC].into_iter().collect::<Protocols>(),
650 )
651 .unwrap();
652
653 let (recognized_tx, recognized_rx) = mpsc::channel();
654 let (reactor, relay_circ, incoming_streams) = Reactor::new(
655 rt.clone(),
656 &Arc::clone(&inbound_chan.channel),
657 circid,
658 unique_id,
659 receiver,
660 Box::new(DummyInboundCrypto {}),
661 Box::new(DummyOutboundCrypto { recognized_rx }),
662 &settings,
663 chan_provider,
664 padding_ctrl,
665 padding_stream,
666 Box::new(AllowAllStreamsFilter),
667 allowed_stream_cmds,
668 &CircuitAccount::new_noop(),
669 )
670 .unwrap();
671
672 rt.spawn(async {
673 let _ = reactor.run().await;
674 })
675 .unwrap();
676
677 let ctrl = Self {
678 relay_circ,
679 circid,
680 recognized_tx,
681 inbound_chan,
682 outbound_chan,
683 };
684
685 (ctrl, incoming_streams)
686 }
687
688 async fn send_fwd(
690 &mut self,
691 id: Option<StreamId>,
692 msg: relaymsg::AnyRelayMsg,
693 recognized: Recognized,
694 early: bool,
695 ) {
696 self.recognized_tx.send(recognized).unwrap();
701 self.send_fwd_cmsg(rmsg_to_ccmsg(id, msg, early)).await;
702 }
703
704 async fn send_fwd_cmsg(&mut self, msg: chanmsg::AnyChanMsg) {
706 let cell = ChanCell::new(Some(self.circid), msg);
707 self.inbound_chan.tx.send(Ok(cell)).await.unwrap();
708 }
709
710 fn outbound_chan_launched(&self) -> bool {
713 self.outbound_chan.lock().unwrap().is_some()
714 }
715
716 async fn do_create2_handshake(
718 &mut self,
719 rt: &MockRuntime,
720 expected_hs_type: HandshakeType,
721 ) -> Option<CircId> {
722 let (circid, msg) = self.read_outbound().into_circid_and_msg();
724 let _create2 = match msg {
725 chanmsg::AnyChanMsg::Create2(c) => {
726 assert_eq!(c.handshake_type(), expected_hs_type);
727 c
728 }
729 _ => panic!("unexpected forwarded {msg:?}"),
730 };
731
732 let handshake = vec![];
733 let created2 = chanmsg::Created2::new(handshake.clone());
734 self.write_outbound(circid, chanmsg::AnyChanMsg::Created2(created2));
737 rt.advance_until_stalled().await;
738
739 let msg = self.read_inbound();
741
742 let (_sid, e) = decode_relay_cell!(msg, Extended2);
743 assert_eq!(e.clone().into_body(), handshake);
744
745 circid
746 }
747
748 fn is_closing(&self) -> bool {
750 self.relay_circ.is_closing()
751 }
752
753 fn read_inbound(&mut self) -> ChanCell<AnyChanMsg> {
760 self.try_read_inbound().unwrap()
761 }
762
763 fn try_read_inbound(&mut self) -> Option<ChanCell<AnyChanMsg>> {
773 #[allow(deprecated)] self.inbound_chan.rx.try_next().ok().flatten()
775 }
776
777 fn read_outbound(&mut self) -> ChanCell<AnyChanMsg> {
785 self.try_read_outbound().unwrap()
786 }
787
788 fn try_read_outbound(&mut self) -> Option<ChanCell<AnyChanMsg>> {
799 let mut lock = self.outbound_chan.lock().unwrap();
800 let chan = lock.as_mut()?;
801 #[allow(deprecated)] chan.rx.try_next().ok().flatten()
803 }
804
805 fn write_outbound(&mut self, circid: Option<CircId>, msg: chanmsg::AnyChanMsg) {
811 let mut lock = self.outbound_chan.lock().unwrap();
812 let chan = lock.as_mut().unwrap();
813 let cell = ChanCell::new(circid, msg);
814
815 chan.tx.try_send(Ok(cell)).unwrap();
816 }
817 }
818
819 fn dummy_linkspecs() -> Vec<EncodedLinkSpec> {
820 vec![
821 LinkSpec::Ed25519Id([43; 32].into()).encode().unwrap(),
822 LinkSpec::RsaId([45; 20].into()).encode().unwrap(),
823 LinkSpec::OrPort("127.0.0.1".parse::<IpAddr>().unwrap(), 999)
824 .encode()
825 .unwrap(),
826 ]
827 }
828
829 macro_rules! assert_cell_is_destroy {
830 ($cell:expr, $reason:expr) => {{
831 match $cell.msg() {
832 chanmsg::AnyChanMsg::Destroy(d) => {
833 assert_eq!(d.reason(), $reason);
834 }
835 _ => panic!("unexpected ending {:?}", $cell),
836 }
837 }};
838 }
839
840 fn assert_destroy_sent(
846 ctrl: &mut ReactorTestCtrl,
847 reason: DestroyReason,
848 direction: DestroyDirection,
849 ) {
850 assert!(ctrl.is_closing());
851
852 match direction {
853 DestroyDirection::Backward => {
854 assert_cell_is_destroy!(ctrl.read_inbound(), reason);
855 assert!(ctrl.try_read_outbound().is_none());
856 }
857 DestroyDirection::Forward => {
858 assert_cell_is_destroy!(ctrl.read_outbound(), reason);
859 assert!(ctrl.try_read_inbound().is_none());
860 }
861 DestroyDirection::Both => {
862 assert_cell_is_destroy!(ctrl.read_inbound(), reason);
863 assert_cell_is_destroy!(ctrl.read_outbound(), reason);
864 }
865 }
866 }
867
868 macro_rules! expect_cell {
869 ($cell:expr, $chanmsg:tt, $relaymsg:tt) => {{
870 let msg = match $cell.msg() {
871 chanmsg::AnyChanMsg::$chanmsg(m) => {
872 let body = m.clone().into_relay_body();
873 AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, body).unwrap()
874 }
875 _ => panic!("unexpected forwarded {:?}", $cell),
876 };
877
878 match msg.msg() {
879 relaymsg::AnyRelayMsg::$relaymsg(m) => m.clone(),
880 _ => panic!("unexpected cell {msg:?}"),
881 }
882 }};
883 }
884
885 #[traced_test]
886 #[test]
887 fn reject_extend2_relay() {
888 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
889 let (mut ctrl, _incoming_streams) =
890 ReactorTestCtrl::spawn_reactor(&rt, &[RelayCmd::BEGIN]).await;
891 rt.advance_until_stalled().await;
892
893 let linkspecs = dummy_linkspecs();
894 let extend2 = relaymsg::Extend2::new(linkspecs, HandshakeType::NTOR_V3, vec![]).into();
895 ctrl.send_fwd(None, extend2, Recognized::Yes, false).await;
896 rt.advance_until_stalled().await;
897
898 assert!(logs_contain("got EXTEND2 in a RELAY cell?!"));
899 assert!(!ctrl.outbound_chan_launched());
900
901 assert_destroy_sent(&mut ctrl, DestroyReason::NONE, DestroyDirection::Backward);
904 });
905 }
906
907 #[traced_test]
908 #[test]
909 fn reject_extend2_previous_hop() {
910 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
911 let (mut ctrl, _incoming_streams) =
912 ReactorTestCtrl::spawn_reactor(&rt, &[RelayCmd::BEGIN]).await;
913 rt.advance_until_stalled().await;
914
915 assert!(!ctrl.outbound_chan_launched());
917
918 let mut linkspecs = ctrl
920 .inbound_chan
921 .channel
922 .target()
923 .identities()
924 .map(|id| LinkSpec::from(id.to_owned()).encode())
925 .collect::<Result<Vec<_>, _>>()
926 .unwrap();
927
928 assert_eq!(linkspecs.len(), 2);
931
932 linkspecs.push(
934 LinkSpec::OrPort("127.0.0.1".parse::<IpAddr>().unwrap(), 999)
935 .encode()
936 .unwrap(),
937 );
938 let handshake_type = HandshakeType::NTOR_V3;
939 let extend2 = relaymsg::Extend2::new(linkspecs, handshake_type, vec![]).into();
940 ctrl.send_fwd(None, extend2, Recognized::Yes, true).await;
941 rt.advance_until_stalled().await;
942
943 assert!(logs_contain("Cannot extend circuit to previous hop"));
945 assert!(!ctrl.outbound_chan_launched());
946 assert!(ctrl.is_closing());
947 });
948 }
949
950 #[traced_test]
951 #[test]
952 fn extend_and_forward() {
953 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
954 let (mut ctrl, _incoming_streams) =
955 ReactorTestCtrl::spawn_reactor(&rt, &[RelayCmd::BEGIN]).await;
956 rt.advance_until_stalled().await;
957
958 assert!(!ctrl.outbound_chan_launched());
960
961 let linkspecs = dummy_linkspecs();
962 let handshake_type = HandshakeType::NTOR_V3;
963 let extend2 = relaymsg::Extend2::new(linkspecs, handshake_type, vec![]).into();
964 ctrl.send_fwd(None, extend2, Recognized::Yes, true).await;
965 rt.advance_until_stalled().await;
966
967 assert!(logs_contain(
969 "Launched channel to the next hop circ_uniq_id=Circ 8.17"
970 ));
971 assert!(ctrl.outbound_chan_launched());
972 assert!(!ctrl.is_closing());
973
974 let _circid = ctrl.do_create2_handshake(&rt, handshake_type).await;
975 assert!(logs_contain("Got CREATED2 response from next hop"));
976 assert!(logs_contain("Extended circuit to the next hop"));
977
978 let early = false;
980 let begin = relaymsg::Begin::new("127.0.0.1", 1111, 0).unwrap();
981 ctrl.send_fwd(None, begin.clone().into(), Recognized::No, early)
982 .await;
983 rt.advance_until_stalled().await;
984
985 let cell = ctrl.read_outbound();
987 let recvd_begin = expect_cell!(cell, Relay, Begin);
988 assert_eq!(begin, recvd_begin);
989
990 let early = true;
992 let begin = relaymsg::Begin::new("127.0.0.1", 1111, 0).unwrap();
993 ctrl.send_fwd(None, begin.clone().into(), Recognized::No, early)
994 .await;
995 rt.advance_until_stalled().await;
996 let cell = ctrl.read_outbound();
997 let recvd_begin = expect_cell!(cell, RelayEarly, Begin);
998 assert_eq!(begin, recvd_begin);
999 });
1000 }
1001
1002 #[traced_test]
1003 #[test]
1004 fn forward_before_extend() {
1005 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
1006 let (mut ctrl, _incoming_streams) =
1007 ReactorTestCtrl::spawn_reactor(&rt, &[RelayCmd::BEGIN]).await;
1008 rt.advance_until_stalled().await;
1009
1010 let end = relaymsg::End::new_misc().into();
1013 ctrl.send_fwd(None, end, Recognized::No, true).await;
1014 rt.advance_until_stalled().await;
1015
1016 assert!(logs_contain(
1017 "Asked to forward cell before the circuit was extended?!"
1018 ));
1019
1020 assert_destroy_sent(&mut ctrl, DestroyReason::NONE, DestroyDirection::Backward);
1023 });
1024 }
1025
1026 #[traced_test]
1027 #[test]
1028 fn reject_invalid_begin() {
1029 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
1030 let (mut ctrl, _incoming_streams) =
1031 ReactorTestCtrl::spawn_reactor(&rt, &[RelayCmd::BEGIN]).await;
1032 rt.advance_until_stalled().await;
1033
1034 let begin = relaymsg::Begin::new("127.0.0.1", 1111, 0).unwrap().into();
1035
1036 ctrl.send_fwd(None, begin, Recognized::Yes, false).await;
1039 rt.advance_until_stalled().await;
1040
1041 assert!(logs_contain(
1042 "Invalid stream ID [scrubbed] for relay command BEGIN"
1043 ));
1044
1045 assert_destroy_sent(&mut ctrl, DestroyReason::NONE, DestroyDirection::Backward);
1048 });
1049 }
1050
1051 #[traced_test]
1052 #[test]
1053 fn destroy_from_client() {
1054 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
1055 let (mut ctrl, _incoming_streams) =
1056 ReactorTestCtrl::spawn_reactor(&rt, &[RelayCmd::BEGIN]).await;
1057 rt.advance_until_stalled().await;
1058
1059 let linkspecs = dummy_linkspecs();
1061 let handshake_type = HandshakeType::NTOR_V3;
1062 let extend2 = relaymsg::Extend2::new(linkspecs, handshake_type, vec![]).into();
1063 ctrl.send_fwd(None, extend2, Recognized::Yes, true).await;
1064 rt.advance_until_stalled().await;
1065 let _circid = ctrl.do_create2_handshake(&rt, handshake_type).await;
1066 assert!(logs_contain("Extended circuit to the next hop"));
1067 assert!(ctrl.outbound_chan_launched());
1068
1069 let destroy = Destroy::new(DestroyReason::PROTOCOL);
1071 ctrl.send_fwd_cmsg(destroy.into()).await;
1072 rt.advance_until_stalled().await;
1073
1074 assert!(logs_contain(
1075 "Received outbound DESTROY, circuit shutting down"
1076 ));
1077
1078 assert_destroy_sent(&mut ctrl, DestroyReason::NONE, DestroyDirection::Forward);
1082 });
1083 }
1084
1085 #[traced_test]
1086 #[test]
1087 fn destroy_from_next_hop() {
1088 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
1089 let (mut ctrl, _incoming_streams) =
1090 ReactorTestCtrl::spawn_reactor(&rt, &[RelayCmd::BEGIN]).await;
1091 rt.advance_until_stalled().await;
1092
1093 let linkspecs = dummy_linkspecs();
1095 let handshake_type = HandshakeType::NTOR_V3;
1096 let extend2 = relaymsg::Extend2::new(linkspecs, handshake_type, vec![]).into();
1097 ctrl.send_fwd(None, extend2, Recognized::Yes, true).await;
1098 rt.advance_until_stalled().await;
1099 let circid = ctrl.do_create2_handshake(&rt, handshake_type).await;
1100 assert!(logs_contain("Extended circuit to the next hop"));
1101 assert!(ctrl.outbound_chan_launched());
1102
1103 let destroy = Destroy::new(DestroyReason::PROTOCOL);
1105 ctrl.write_outbound(circid, destroy.into());
1106 rt.advance_until_stalled().await;
1107
1108 assert!(!logs_contain(
1110 "Received outbound DESTROY, circuit shutting down"
1111 ));
1112
1113 assert!(logs_contain(
1115 "Received inbound DESTROY, circuit shutting down"
1116 ));
1117
1118 assert_destroy_sent(&mut ctrl, DestroyReason::NONE, DestroyDirection::Backward);
1122 });
1123 }
1124
1125 #[traced_test]
1126 #[test]
1127 fn truncate() {
1128 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
1129 let (mut ctrl, _incoming_streams) =
1130 ReactorTestCtrl::spawn_reactor(&rt, &[RelayCmd::BEGIN]).await;
1131 rt.advance_until_stalled().await;
1132
1133 let truncate = relaymsg::Truncate::default().into();
1135 ctrl.send_fwd(None, truncate, Recognized::Yes, false).await;
1136 rt.advance_until_stalled().await;
1137
1138 assert!(logs_contain(
1139 "Circuit protocol violation: TRUNCATE not allowed"
1140 ));
1141
1142 assert_destroy_sent(&mut ctrl, DestroyReason::NONE, DestroyDirection::Backward);
1145 });
1146 }
1147
1148 #[traced_test]
1149 #[test]
1150 fn data_stream() {
1151 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
1152 const TO_SEND: &[u8] = b"The bells were musical in the silvery sun";
1153
1154 let (mut ctrl, mut incoming_streams) =
1155 ReactorTestCtrl::spawn_reactor(&rt, &[RelayCmd::BEGIN]).await;
1156 rt.advance_until_stalled().await;
1157
1158 let begin = relaymsg::Begin::new("127.0.0.1", 1111, 0).unwrap().into();
1159 ctrl.send_fwd(StreamId::new(1), begin, Recognized::Yes, false)
1160 .await;
1161 rt.advance_until_stalled().await;
1162
1163 let data = relaymsg::Data::new(TO_SEND).unwrap().into();
1164 ctrl.send_fwd(StreamId::new(1), data, Recognized::Yes, false)
1165 .await;
1166
1167 let pending = incoming_streams.next().await.unwrap();
1169
1170 let mut stream = pending
1172 .accept_data(relaymsg::Connected::new_empty())
1173 .await
1174 .unwrap();
1175
1176 let mut recv_buf = [0_u8; TO_SEND.len()];
1177 stream.read_exact(&mut recv_buf).await.unwrap();
1178 assert_eq!(recv_buf, TO_SEND);
1179 });
1180 }
1181
1182 #[traced_test]
1183 #[test]
1184 fn reject_stream() {
1185 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
1186 let (mut ctrl, mut incoming_streams) =
1187 ReactorTestCtrl::spawn_reactor(&rt, &[RelayCmd::BEGIN]).await;
1188 rt.advance_until_stalled().await;
1189
1190 let begin = relaymsg::Begin::new("127.0.0.1", 1111, 0).unwrap().into();
1191 ctrl.send_fwd(StreamId::new(1), begin, Recognized::Yes, false)
1192 .await;
1193 rt.advance_until_stalled().await;
1194
1195 let pending = incoming_streams.next().await.unwrap();
1197
1198 let end = relaymsg::End::new_misc();
1200 pending.reject(end.clone()).await.unwrap();
1201 rt.advance_until_stalled().await;
1202
1203 let cell = ctrl.read_inbound();
1206 let actual_end = expect_cell!(cell, Relay, End);
1207 assert_eq!(end.reason(), actual_end.reason());
1208
1209 let data = relaymsg::Data::new(b"no dice").unwrap().into();
1212 ctrl.send_fwd(StreamId::new(1), data, Recognized::Yes, false)
1213 .await;
1214 rt.advance_until_stalled().await;
1215
1216 assert!(logs_contain("Stream protocol violation"));
1217 assert!(logs_contain(
1218 "Unexpected RelayCmd(DATA) message on unknown stream 1"
1219 ));
1220 });
1221 }
1222
1223 #[traced_test]
1224 #[test]
1225 fn only_allow_begin_dir() {
1226 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
1227 let (mut ctrl, mut incoming_streams) = ReactorTestCtrl::spawn_reactor(
1228 &rt,
1229 &[RelayCmd::BEGIN_DIR],
1231 )
1232 .await;
1233 rt.advance_until_stalled().await;
1234
1235 let begin_dir = relaymsg::BeginDir::default().into();
1237 ctrl.send_fwd(StreamId::new(1), begin_dir, Recognized::Yes, false)
1238 .await;
1239 rt.advance_until_stalled().await;
1240
1241 let pending_dir_stream = incoming_streams.next().await.unwrap();
1242 assert!(matches!(
1243 pending_dir_stream.request(),
1244 IncomingStreamRequest::BeginDir(_)
1245 ));
1246
1247 let begin = relaymsg::Begin::new("127.0.0.1", 1111, 0).unwrap().into();
1248 ctrl.send_fwd(StreamId::new(2), begin, Recognized::Yes, false)
1249 .await;
1250 rt.advance_until_stalled().await;
1251
1252 assert!(logs_contain("stream reactor shut down"));
1254 assert!(logs_contain(
1255 "Stream protocol violation: Unexpected BEGIN on incoming stream circ_uniq_id=Circ 8.17"
1256 ));
1257
1258 let mut noop_cx = Context::from_waker(Waker::noop());
1261 assert_eq!(
1262 incoming_streams.poll_next_unpin(&mut noop_cx).map(|_| ()),
1263 Poll::Pending
1264 );
1265 });
1266 }
1267
1268 #[traced_test]
1269 #[test]
1270 fn resolve_stream() {
1271 tor_rtmock::MockRuntime::test_with_various(|rt| async move {
1272 let (mut ctrl, mut incoming_streams) =
1273 ReactorTestCtrl::spawn_reactor(&rt, &[RelayCmd::RESOLVE]).await;
1274 rt.advance_until_stalled().await;
1275
1276 let resolve = relaymsg::Resolve::new("example.com");
1277 let resolve_sid = StreamId::new(1337);
1278 ctrl.send_fwd(resolve_sid, resolve.into(), Recognized::Yes, false)
1279 .await;
1280 rt.advance_until_stalled().await;
1281
1282 let pending = incoming_streams.next().await.unwrap();
1284
1285 let mut resolved = relaymsg::Resolved::new_empty();
1286 let resolved_val = relaymsg::ResolvedVal::Ip(IpAddr::from([1, 2, 3, 4]));
1287 resolved.add_answer(resolved_val.clone(), 1337);
1288
1289 let expected_resolved = resolved.clone();
1291
1292 pending.resolve(resolved).await.unwrap();
1294
1295 rt.advance_until_stalled().await;
1296 let (sid, resolved) = decode_relay_cell!(ctrl.read_inbound(), Resolved);
1297
1298 assert_eq!(resolved.into_answers(), expected_resolved.into_answers());
1301 assert_eq!(sid, resolve_sid);
1302 assert!(logs_contain("Ending stream"));
1303 });
1304 }
1305}