1use crate::FlowCtrlParameters;
4use crate::ccparams::{
5 AlgorithmDiscriminants, CongestionWindowParams, FixedWindowParams, RoundTripEstimatorParams,
6 VegasParams,
7};
8use crate::channel::Channel;
9use crate::circuit::celltypes::{CreateRequest, CreateResponse};
10use crate::circuit::circhop::{HandshakeParamsError, HopSettings};
11use crate::circuit::{
12 CircuitRxSender, HandshakeSubprotocols, InvalidHandshakeSubprotocolError, UniqId,
13};
14use crate::client::circuit::padding::PaddingController;
15use crate::crypto::binding::CircuitBinding;
16use crate::crypto::cell::CryptInit as _;
17use crate::crypto::cell::{
18 CgoRelayCrypto, InboundRelayLayer, OutboundRelayLayer, RelayLayer, Tor1RelayCrypto,
19};
20use crate::crypto::handshake::RelayHandshakeError;
21use crate::crypto::handshake::ServerHandshake as _;
22use crate::crypto::handshake::fast::CreateFastServer;
23use crate::crypto::handshake::ntor::{NtorSecretKey, NtorServer};
24use crate::crypto::handshake::ntor_v3::{NtorV3SecretKey, NtorV3Server};
25use crate::memquota::SpecificAccount as _;
26use crate::memquota::{ChannelAccount, CircuitAccount};
27use crate::relay::channel_provider::ChannelProvider;
28use crate::relay::reactor::Reactor;
29use crate::relay::{IncomingStreamRequestFilter, RelayCirc};
30use crate::stream::IncomingStream;
31use futures::channel::mpsc;
32use futures::{SinkExt, Stream};
33use smallvec::SmallVec;
34use std::sync::{Arc, RwLock, Weak};
35use tor_cell::chancell::ChanMsg as _;
36use tor_cell::chancell::CircId;
37use tor_cell::chancell::msg::{
38 CreateFast, Created2, CreatedFast, Destroy, DestroyReason, HandshakeType,
39};
40use tor_cell::relaycell::RelayCmd;
41use tor_cell::relaycell::extend::{
42 CcRequest, CcResponse, CircRequestExt, CircResponseExt, SubprotocolRequest,
43};
44use tor_error::{ErrorKind, HasKind, debug_report, internal, into_internal, warn_report};
45use tor_linkspec::OwnedChanTarget;
46use tor_llcrypto::pk::ed25519::Ed25519Identity;
47use tor_llcrypto::pk::rsa::RsaIdentity;
48use tor_memquota::mq_queue::ChannelSpec as _;
49use tor_memquota::mq_queue::MpscSpec;
50use tor_relay_crypto::pk::{RelayNtorKeypair, RelayNtorKeys};
51use tor_rtcompat::SpawnExt as _;
52use tor_rtcompat::{DynTimeProvider, Runtime};
53use tracing::{debug, trace};
54
55#[derive(derive_more::Debug)]
57pub struct CreateRequestHandler {
58 chan_provider: Weak<dyn ChannelProvider<BuildSpec = OwnedChanTarget> + Send + Sync>,
60 circ_net_params: RwLock<CircNetParameters>,
62 #[debug(skip)]
64 ntor_keys: RwLock<RelayNtorKeys>,
65 #[debug(skip)]
75 incoming_filter_factory: Box<dyn IncomingStreamRequestFilterFactory + Send + Sync>,
76 allowed_stream_cmds: SmallVec<[RelayCmd; 3]>,
84 #[debug(skip)]
97 circuit_stream_tx: mpsc::Sender<Box<dyn Stream<Item = IncomingStream> + Send + Sync + Unpin>>,
98}
99
100#[expect(clippy::unused_async)]
103impl CreateRequestHandler {
104 pub fn new(
107 chan_provider: Weak<dyn ChannelProvider<BuildSpec = OwnedChanTarget> + Send + Sync>,
108 circ_net_params: CircNetParameters,
109 ntor_keys: RelayNtorKeys,
110 incoming_filter_factory: Box<dyn IncomingStreamRequestFilterFactory + Send + Sync>,
111 allowed_stream_cmds: &[RelayCmd],
112 ) -> (Self, CircuitIncomingStreamReceiver) {
113 const CIRC_STREAM_BUF_SIZE: usize = 1024;
119
120 #[allow(clippy::disallowed_methods)]
124 let (stream_tx, stream_rx) = mpsc::channel(CIRC_STREAM_BUF_SIZE);
125
126 let handler = Self {
127 chan_provider,
128 circ_net_params: RwLock::new(circ_net_params),
129 ntor_keys: RwLock::new(ntor_keys),
130 incoming_filter_factory,
131 allowed_stream_cmds: allowed_stream_cmds.into(),
132 circuit_stream_tx: stream_tx,
133 };
134
135 let circuit_stream_rx = CircuitIncomingStreamReceiver {
136 circuit_stream_rx: stream_rx,
137 };
138
139 (handler, circuit_stream_rx)
140 }
141
142 pub fn update_params(&self, circ_net_params: CircNetParameters) {
144 *self.circ_net_params.write().expect("rwlock poisoned") = circ_net_params;
145 }
146
147 pub fn update_ntor_keys(&self, ntor_keys: RelayNtorKeys) {
151 *self.ntor_keys.write().expect("rwlock poisoned") = ntor_keys;
152 }
153
154 #[allow(clippy::too_many_arguments)]
162 pub(crate) async fn handle_create<R: Runtime>(
163 &self,
164 runtime: &R,
165 channel: &Arc<Channel>,
166 our_ed25519_id: &Ed25519Identity,
167 our_rsa_id: &RsaIdentity,
168 circ_id: CircId,
169 msg: &CreateRequest,
170 memquota: &ChannelAccount,
171 circ_unique_id: UniqId,
172 ) -> Result<(CreateResponse, RelayCircComponents), Destroy> {
173 let result = self
174 .handle_create_inner(
175 runtime,
176 channel,
177 our_ed25519_id,
178 our_rsa_id,
179 circ_id,
180 msg,
181 memquota,
182 circ_unique_id,
183 )
184 .await;
185
186 match result {
187 Ok(x) => Ok(x),
188 Err(e) => {
189 let cmd = msg.cmd();
191 debug_report!(&e, %cmd, "Failed to handle circuit create request");
192
193 Err(Destroy::new(DestroyReason::NONE))
197 }
198 }
199 }
200
201 #[allow(clippy::too_many_arguments)]
203 async fn handle_create_inner<R: Runtime>(
204 &self,
205 runtime: &R,
206 channel: &Arc<Channel>,
207 our_ed25519_id: &Ed25519Identity,
208 our_rsa_id: &RsaIdentity,
209 circ_id: CircId,
210 msg: &CreateRequest,
211 memquota: &ChannelAccount,
212 circ_unique_id: UniqId,
213 ) -> Result<(CreateResponse, RelayCircComponents), HandleCreateError> {
214 let handshake_components = match msg {
216 CreateRequest::CreateFast(msg) => self.handle_create_fast(msg).await?,
217 CreateRequest::Create2(msg) => match msg.handshake_type() {
218 HandshakeType::NTOR_V3 => {
219 self.handle_create2_ntorv3(msg.body(), our_ed25519_id)
220 .await?
221 }
222 HandshakeType::NTOR => self.handle_create2_ntor(msg.body(), our_rsa_id).await?,
223 x @ HandshakeType::TAP | x => {
224 return Err(HandleCreateError::Create2HandshakeType(x));
225 }
226 },
227 };
228
229 let memquota = CircuitAccount::new(memquota)?;
230
231 let time_provider = DynTimeProvider::new(runtime.clone());
237 let account = memquota.as_raw_account();
238 let (sender, receiver) =
239 MpscSpec::new(10_000_000).new_mq(time_provider.clone(), account)?;
240 let (sender, receiver) = crate::circuit::circ_sender::channel(sender, receiver);
241
242 let (padding_ctrl, padding_stream) =
244 crate::client::circuit::padding::new_padding(DynTimeProvider::new(runtime.clone()));
245
246 let Some(chan_provider) = self.chan_provider.upgrade() else {
248 return Err(internal!("Unable to upgrade weak `ChannelProvider`").into());
249 };
250
251 let incoming_filter = self.incoming_filter_factory.current_filter();
258
259 let (reactor, circ, incoming_streams) = Reactor::new(
261 runtime.clone(),
262 channel,
263 circ_id,
264 circ_unique_id,
265 receiver,
266 handshake_components.crypto_in,
267 handshake_components.crypto_out,
268 &handshake_components.hop_settings,
269 chan_provider,
270 padding_ctrl.clone(),
271 padding_stream,
272 incoming_filter,
273 &self.allowed_stream_cmds,
274 &memquota,
275 )
276 .map_err(into_internal!("Failed to start circuit reactor"))?;
277
278 let mut circuit_stream_tx = self.circuit_stream_tx.clone();
279 let () = runtime.spawn(async move {
281 if let Err(e) = circuit_stream_tx.send(Box::new(incoming_streams)).await {
282 warn_report!(e, "IncomingStream handler disappeared?!");
283 drop(reactor);
290 } else {
291 match reactor.run().await {
294 Ok(()) => {}
295 Err(e) => {
296 debug_report!(e, "Relay circuit reactor exited with an error");
297 }
298 }
299 }
300 })?;
301
302 Ok((
303 handshake_components.response,
304 RelayCircComponents {
305 circ,
306 sender,
307 padding_ctrl,
308 },
309 ))
310 }
311
312 async fn handle_create_fast(
314 &self,
315 msg: &CreateFast,
316 ) -> Result<CompletedHandshakeComponents, HandleCreateError> {
317 let (keygen, handshake_msg) = CreateFastServer::server(
319 &mut rand::rng(),
320 &mut |_: &()| Some(()),
323 &[()],
325 msg.handshake(),
326 )?;
327
328 let circ_net_params = self
329 .circ_net_params
330 .read()
331 .expect("rwlock poisoned")
332 .clone();
333
334 let subprotos = HandshakeSubprotocols::default();
336
337 let hop_settings = HopSettings::from_handshake_params(
338 circ_net_params,
339 AlgorithmDiscriminants::FixedWindow,
341 subprotos,
342 )?;
343
344 let crypt = Tor1RelayCrypto::construct(keygen)
345 .map_err(into_internal!("Circuit crypt state construction failed"))?;
346
347 let (crypto_out, crypto_in, _binding) = split_relay_layer(crypt);
348
349 let response = CreatedFast::new(handshake_msg);
350 let response = CreateResponse::CreatedFast(response);
351
352 trace!("Completed CREATE_FAST handshake");
353
354 Ok(CompletedHandshakeComponents {
355 response,
356 hop_settings,
357 crypto_out,
358 crypto_in,
359 })
360 }
361
362 async fn handle_create2_ntor(
364 &self,
365 msg_body: &[u8],
366 our_rsa_id: &RsaIdentity,
367 ) -> Result<CompletedHandshakeComponents, HandleCreateError> {
368 let ntor_keys = self.ntor_keys(|k| {
369 NtorSecretKey::new(k.secret().clone(), *k.public().inner(), *our_rsa_id)
370 });
371
372 let (keygen, handshake_msg) = NtorServer::server(
374 &mut rand::rng(),
375 &mut |_: &()| Some(()),
378 ntor_keys.as_ref(),
379 msg_body,
380 )?;
381
382 let circ_net_params = self
383 .circ_net_params
384 .read()
385 .expect("rwlock poisoned")
386 .clone();
387
388 let subprotos = HandshakeSubprotocols::default();
390
391 let hop_settings = HopSettings::from_handshake_params(
392 circ_net_params,
393 AlgorithmDiscriminants::FixedWindow,
395 subprotos,
396 )?;
397
398 let crypt = Tor1RelayCrypto::construct(keygen)
399 .map_err(into_internal!("Circuit crypt state construction failed"))?;
400
401 let (crypto_out, crypto_in, _binding) = split_relay_layer(crypt);
402
403 let response = Created2::new(handshake_msg);
404 let response = CreateResponse::Created2(response);
405
406 trace!("Completed ntor handshake");
407
408 Ok(CompletedHandshakeComponents {
409 response,
410 hop_settings,
411 crypto_out,
412 crypto_in,
413 })
414 }
415
416 async fn handle_create2_ntorv3(
418 &self,
419 msg_body: &[u8],
420 our_ed25519_id: &Ed25519Identity,
421 ) -> Result<CompletedHandshakeComponents, HandleCreateError> {
422 let ntor_keys = self.ntor_keys(|k| {
423 NtorV3SecretKey::new(k.secret().clone(), *k.public().inner(), *our_ed25519_id)
424 });
425
426 let circ_net_params = self
427 .circ_net_params
428 .read()
429 .expect("rwlock poisoned")
430 .clone();
431
432 let mut cc_algorithm = AlgorithmDiscriminants::FixedWindow;
434
435 let mut subprotos = SubprotocolRequest::default();
438
439 let mut ext_reply_fn = |client_exts: &[CircRequestExt]| {
442 let mut response_exts = Vec::new();
443
444 let mut handled_cc_request = false;
455 let mut handled_subproto_request = false;
456
457 for ext in client_exts {
458 match ext {
459 CircRequestExt::CcRequest(CcRequest { .. }) => {
460 if handled_cc_request {
461 continue;
462 }
463 handled_cc_request = true;
464
465 cc_algorithm = AlgorithmDiscriminants::Vegas;
466
467 let sendme_inc: u8 = circ_net_params.cc.cwnd.sendme_inc();
468 let response = CcResponse::new(sendme_inc);
469 response_exts.push(CircResponseExt::CcResponse(response));
470 }
471 CircRequestExt::SubprotocolRequest(subproto_request) => {
476 if handled_subproto_request {
477 continue;
478 }
479 handled_subproto_request = true;
480
481 subprotos = subproto_request.clone();
483 }
484 CircRequestExt::Unrecognized(ext) => {
485 debug!(
489 ?ext,
490 "CREATE2 ntor-v3 handshake requested unrecognized extension",
491 );
492 }
493 ext => {
494 debug!(
503 ?ext,
504 "CREATE2 ntor-v3 handshake requested unsupported extension",
505 );
506 }
507 }
508 }
509
510 Some(response_exts)
511 };
512
513 let (keygen, handshake_msg) = NtorV3Server::server(
515 &mut rand::rng(),
516 &mut ext_reply_fn,
517 ntor_keys.as_ref(),
518 msg_body,
519 )?;
520
521 let subprotos = HandshakeSubprotocols::try_from_request(subprotos)?;
523
524 let hop_settings =
525 HopSettings::from_handshake_params(circ_net_params, cc_algorithm, subprotos)?;
526
527 let (crypto_out, crypto_in, _binding) = if subprotos.relay_crypt_cgo {
528 let crypt = CgoRelayCrypto::construct(keygen)
529 .map_err(into_internal!("Circuit crypt state construction failed"))?;
530 split_relay_layer(crypt)
531 } else {
532 let crypt = Tor1RelayCrypto::construct(keygen)
533 .map_err(into_internal!("Circuit crypt state construction failed"))?;
534 split_relay_layer(crypt)
535 };
536
537 let response = Created2::new(handshake_msg);
538 let response = CreateResponse::Created2(response);
539
540 trace!(?cc_algorithm, ?subprotos, "Completed ntor-v3 handshake");
541
542 Ok(CompletedHandshakeComponents {
543 response,
544 hop_settings,
545 crypto_out,
546 crypto_in,
547 })
548 }
549
550 fn ntor_keys<T>(&self, map: impl FnMut(&RelayNtorKeypair) -> T) -> impl AsRef<[T]> {
558 let ntor_keys = self.ntor_keys.read().expect("rwlock poisoned");
559 let ntor_keys = [Some(ntor_keys.latest()), ntor_keys.previous()];
560 ntor_keys
561 .into_iter()
562 .flatten()
563 .map(map)
564 .collect::<SmallVec<[T; 2]>>()
565 }
566}
567
568pub struct CircuitIncomingStreamReceiver {
584 circuit_stream_rx: mpsc::Receiver<<Self as Stream>::Item>,
589}
590
591impl Stream for CircuitIncomingStreamReceiver {
592 type Item = Box<dyn Stream<Item = IncomingStream> + Send + Sync + Unpin>;
596
597 fn poll_next(
598 mut self: std::pin::Pin<&mut Self>,
599 cx: &mut std::task::Context<'_>,
600 ) -> std::task::Poll<Option<Self::Item>> {
601 use futures::StreamExt as _;
602
603 self.circuit_stream_rx.poll_next_unpin(cx)
604 }
605}
606
607fn split_relay_layer<F, B>(
609 crypt: impl RelayLayer<F, B>,
610) -> (
611 Box<dyn OutboundRelayLayer + Send>,
612 Box<dyn InboundRelayLayer + Send>,
613 CircuitBinding,
614)
615where
616 F: OutboundRelayLayer + Send + 'static,
617 B: InboundRelayLayer + Send + 'static,
618{
619 let (crypto_out, crypto_in, binding) = crypt.split_relay_layer();
620 let (crypto_out, crypto_in) = (Box::new(crypto_out), Box::new(crypto_in));
621
622 (crypto_out, crypto_in, binding)
623}
624
625#[derive(Debug, thiserror::Error)]
627enum HandleCreateError {
628 #[error("Circuit relay handshake failed")]
630 Handshake(#[from] RelayHandshakeError),
631 #[error("Failed to process the circuit relay handshake parameters")]
633 HandshakeParameters(#[from] HandshakeParamsError),
634 #[error("Client requested subprotocol(s) which aren't supported")]
636 HandshakeSubprotocols(#[from] InvalidHandshakeSubprotocolError),
637 #[error("Unsupported handshake type {0}")]
639 Create2HandshakeType(HandshakeType),
640 #[error("Memquota error")]
642 Memquota(#[from] tor_memquota::Error),
643 #[error("Runtime task spawn error")]
645 Spawn(#[from] futures::task::SpawnError),
646 #[error("Internal error")]
651 Internal(#[from] tor_error::Bug),
652}
653
654impl HasKind for HandleCreateError {
655 fn kind(&self) -> ErrorKind {
656 match self {
657 Self::Handshake(e) => e.kind(),
658 Self::HandshakeParameters(e) => e.kind(),
659 Self::HandshakeSubprotocols(e) => e.kind(),
660 Self::Create2HandshakeType(_) => ErrorKind::NotImplemented,
661 Self::Memquota(e) => e.kind(),
662 Self::Spawn(e) => e.kind(),
663 Self::Internal(_) => ErrorKind::Internal,
664 }
665 }
666}
667
668struct CompletedHandshakeComponents {
670 response: CreateResponse,
672 hop_settings: HopSettings,
674 crypto_out: Box<dyn OutboundRelayLayer + Send>,
676 crypto_in: Box<dyn InboundRelayLayer + Send>,
678}
679
680pub(crate) struct RelayCircComponents {
682 pub(crate) circ: Arc<RelayCirc>,
684 pub(crate) sender: CircuitRxSender,
686 pub(crate) padding_ctrl: PaddingController,
688}
689
690#[derive(Debug, Clone)]
692#[allow(clippy::exhaustive_structs)]
693pub struct CongestionControlNetParams {
694 pub fixed_window: FixedWindowParams,
696
697 pub vegas_exit: VegasParams,
702
703 pub cwnd: CongestionWindowParams,
705
706 pub rtt: RoundTripEstimatorParams,
708
709 pub flow_ctrl: FlowCtrlParameters,
711}
712
713impl CongestionControlNetParams {
714 #[cfg(test)]
715 pub(crate) fn defaults_for_tests() -> Self {
717 Self {
718 fixed_window: FixedWindowParams::defaults_for_tests(),
719 vegas_exit: VegasParams::defaults_for_tests(),
720 cwnd: CongestionWindowParams::defaults_for_tests(),
721 rtt: RoundTripEstimatorParams::defaults_for_tests(),
722 flow_ctrl: FlowCtrlParameters::defaults_for_tests(),
723 }
724 }
725}
726
727#[derive(Debug, Clone)]
735#[allow(clippy::exhaustive_structs)]
736pub struct CircNetParameters {
737 pub cc: CongestionControlNetParams,
739}
740
741pub trait IncomingStreamRequestFilterFactory {
747 fn current_filter(&self) -> Box<dyn IncomingStreamRequestFilter>;
750}
751
752impl<F> IncomingStreamRequestFilterFactory for F
753where
754 F: Fn() -> Box<dyn IncomingStreamRequestFilter>,
755{
756 fn current_filter(&self) -> Box<dyn IncomingStreamRequestFilter> {
757 (self)()
758 }
759}
760
761#[cfg(test)]
762mod test {
763 #![allow(clippy::bool_assert_comparison)]
765 #![allow(clippy::clone_on_copy)]
766 #![allow(clippy::dbg_macro)]
767 #![allow(clippy::mixed_attributes_style)]
768 #![allow(clippy::print_stderr)]
769 #![allow(clippy::print_stdout)]
770 #![allow(clippy::single_char_pattern)]
771 #![allow(clippy::unwrap_used)]
772 #![allow(clippy::unchecked_time_subtraction)]
773 #![allow(clippy::useless_vec)]
774 #![allow(clippy::needless_pass_by_value)]
775 #![allow(clippy::string_slice)] use tor_cell::chancell::msg::{AnyChanMsg, Create2, CreateFast, HandshakeType};
779 use tor_cell::chancell::{AnyChanCell, ChanCmd, ChanMsg as _};
780 use tor_rtcompat::test_with_one_runtime;
781
782 use crate::channel::test_utils;
783 use crate::circuit::CircParameters;
784
785 #[test]
787 fn create_fast() {
788 test_with_one_runtime!(|rt| async move {
789 let mut conn_inspector = test_utils::ConnInspector::new();
790
791 let (client_chan, relay_chan, _circuit_stream_rx, _target_builder) =
792 test_utils::new_channel_pair_with_keys(&rt, &conn_inspector);
793
794 let pending_tunnel = test_utils::new_pending_tunnel(&rt, &client_chan).await;
795
796 let circ_params = CircParameters::default();
797
798 let tunnel = pending_tunnel
799 .create_firsthop_fast(circ_params)
800 .await
801 .unwrap();
802
803 assert_eq!(
805 conn_inspector.try_client_cell().unwrap().msg().cmd(),
806 ChanCmd::CREATE_FAST,
807 );
808 assert_eq!(
809 conn_inspector.try_relay_cell().unwrap().msg().cmd(),
810 ChanCmd::CREATED_FAST,
811 );
812
813 drop(tunnel);
814
815 assert_eq!(
816 conn_inspector.client_cell().await.unwrap().msg().cmd(),
817 ChanCmd::DESTROY,
818 );
819
820 let wait_fut =
822 futures::future::join(client_chan.wait_for_close(), relay_chan.wait_for_close());
823 drop((client_chan, relay_chan));
824 let _ = wait_fut.await;
825
826 assert!(conn_inspector.try_client_cell().is_none());
828 assert!(conn_inspector.try_relay_cell().is_none());
829 });
830 }
831
832 #[test]
834 fn create_fast_fail() {
835 test_with_one_runtime!(|rt| async move {
836 let mut conn_inspector = test_utils::ConnInspector::new();
837
838 conn_inspector.set_client_cell_modifier(|cell: &mut AnyChanCell| {
841 let circ_id = cell.circid();
842 if let AnyChanMsg::CreateFast(msg) = cell.msg() {
843 let mut new_handshake = msg.handshake().to_vec();
844
845 for byte in &mut new_handshake {
847 *byte = !*byte;
848 }
849
850 let new_msg = CreateFast::new(new_handshake);
852 *cell = AnyChanCell::new(circ_id, AnyChanMsg::CreateFast(new_msg));
853 }
854 });
855
856 let (client_chan, relay_chan, _circuit_stream_rx, _target_builder) =
857 test_utils::new_channel_pair_with_keys(&rt, &conn_inspector);
858
859 let pending_tunnel = test_utils::new_pending_tunnel(&rt, &client_chan).await;
860
861 let circ_params = CircParameters::default();
862
863 assert!(matches!(
871 pending_tunnel.create_firsthop_fast(circ_params).await,
872 Err(crate::Error::BadCircHandshakeAuth),
873 ));
874
875 assert_eq!(
877 conn_inspector.try_client_cell().unwrap().msg().cmd(),
878 ChanCmd::CREATE_FAST,
879 );
880 assert_eq!(
881 conn_inspector.try_relay_cell().unwrap().msg().cmd(),
882 ChanCmd::CREATED_FAST,
883 );
884
885 assert_eq!(
888 conn_inspector.client_cell().await.unwrap().msg().cmd(),
889 ChanCmd::DESTROY,
890 );
891
892 let wait_fut =
894 futures::future::join(client_chan.wait_for_close(), relay_chan.wait_for_close());
895 drop((client_chan, relay_chan));
896 let _ = wait_fut.await;
897
898 assert!(conn_inspector.try_client_cell().is_none());
900 assert!(conn_inspector.try_relay_cell().is_none());
901 });
902 }
903
904 #[test]
907 fn tap() {
908 test_with_one_runtime!(|rt| async move {
909 let mut conn_inspector = test_utils::ConnInspector::new();
910
911 let (client_chan, _relay_chan, _circuit_stream_rx, mut target_builder) =
912 test_utils::new_channel_pair_with_keys(&rt, &conn_inspector);
913
914 let pending_tunnel = test_utils::new_pending_tunnel(&rt, &client_chan).await;
915
916 let circ_params = CircParameters::default();
917
918 let protocols = "Relay=1".parse().unwrap();
921 let target = target_builder.protocols(protocols).build().unwrap();
922
923 let _tunnel = pending_tunnel
927 .create_firsthop(&target, circ_params)
928 .await
929 .unwrap();
930
931 assert_eq!(
933 conn_inspector.try_client_cell().unwrap().msg().cmd(),
934 ChanCmd::CREATE2,
935 );
936 assert_eq!(
937 conn_inspector.try_relay_cell().unwrap().msg().cmd(),
938 ChanCmd::CREATED2,
939 );
940 });
941 }
942
943 #[test]
945 fn ntor() {
946 test_with_one_runtime!(|rt| async move {
947 let mut conn_inspector = test_utils::ConnInspector::new();
948
949 let (client_chan, relay_chan, _circuit_stream_rx, mut target_builder) =
950 test_utils::new_channel_pair_with_keys(&rt, &conn_inspector);
951
952 for relay_version in [2, 3] {
956 let pending_tunnel = test_utils::new_pending_tunnel(&rt, &client_chan).await;
957
958 let circ_params = CircParameters::default();
959
960 let protocols = format!("Relay=2-{relay_version}").parse().unwrap();
961 let target = target_builder.protocols(protocols).build().unwrap();
962
963 let tunnel = pending_tunnel
964 .create_firsthop(&target, circ_params)
965 .await
966 .unwrap();
967
968 let client_cell = conn_inspector.try_client_cell().unwrap().msg().clone();
969 let relay_cell = conn_inspector.try_relay_cell().unwrap().msg().clone();
970
971 assert_eq!(client_cell.cmd(), ChanCmd::CREATE2);
973 assert_eq!(relay_cell.cmd(), ChanCmd::CREATED2);
974
975 let AnyChanMsg::Create2(client_cell) = client_cell else {
977 unreachable!("CREATE2 checked above");
978 };
979 assert_eq!(client_cell.handshake_type(), HandshakeType::NTOR);
980
981 drop(tunnel);
982
983 assert_eq!(
984 conn_inspector.client_cell().await.unwrap().msg().cmd(),
985 ChanCmd::DESTROY,
986 );
987
988 assert!(conn_inspector.try_client_cell().is_none());
990 assert!(conn_inspector.try_relay_cell().is_none());
991 }
992
993 let wait_fut =
995 futures::future::join(client_chan.wait_for_close(), relay_chan.wait_for_close());
996 drop((client_chan, relay_chan));
997 let _ = wait_fut.await;
998
999 assert!(conn_inspector.try_client_cell().is_none());
1001 assert!(conn_inspector.try_relay_cell().is_none());
1002 });
1003 }
1004
1005 #[test]
1007 fn ntor_fail() {
1008 test_with_one_runtime!(|rt| async move {
1009 let mut conn_inspector = test_utils::ConnInspector::new();
1010
1011 conn_inspector.set_client_cell_modifier(|cell: &mut AnyChanCell| {
1013 let circ_id = cell.circid();
1014 if let AnyChanMsg::Create2(msg) = cell.msg() {
1015 let mut new_body = msg.body().to_vec();
1016
1017 new_body[10] = !new_body[10];
1019
1020 let new_msg = Create2::new(msg.handshake_type(), new_body);
1022 *cell = AnyChanCell::new(circ_id, AnyChanMsg::Create2(new_msg));
1023 }
1024 });
1025
1026 let (client_chan, relay_chan, _circuit_stream_rx, mut target_builder) =
1027 test_utils::new_channel_pair_with_keys(&rt, &conn_inspector);
1028
1029 for relay_version in [2, 3] {
1033 let pending_tunnel = test_utils::new_pending_tunnel(&rt, &client_chan).await;
1034
1035 let circ_params = CircParameters::default();
1036
1037 let protocols = format!("Relay=2-{relay_version}").parse().unwrap();
1038 let target = target_builder.protocols(protocols).build().unwrap();
1039
1040 assert!(matches!(
1043 pending_tunnel.create_firsthop(&target, circ_params).await,
1044 Err(crate::Error::CircRefused(_)),
1045 ));
1046
1047 assert_eq!(
1049 conn_inspector.try_client_cell().unwrap().msg().cmd(),
1050 ChanCmd::CREATE2,
1051 );
1052 assert_eq!(
1053 conn_inspector.try_relay_cell().unwrap().msg().cmd(),
1054 ChanCmd::DESTROY,
1055 );
1056
1057 assert!(conn_inspector.try_client_cell().is_none());
1059 assert!(conn_inspector.try_relay_cell().is_none());
1060 }
1061
1062 let wait_fut =
1064 futures::future::join(client_chan.wait_for_close(), relay_chan.wait_for_close());
1065 drop((client_chan, relay_chan));
1066 let _ = wait_fut.await;
1067
1068 assert!(conn_inspector.try_client_cell().is_none());
1070 assert!(conn_inspector.try_relay_cell().is_none());
1071 });
1072 }
1073
1074 #[test]
1076 fn ntor_v3() {
1077 test_with_one_runtime!(|rt| async move {
1078 let mut conn_inspector = test_utils::ConnInspector::new();
1079
1080 let (client_chan, relay_chan, _circuit_stream_rx, mut target_builder) =
1081 test_utils::new_channel_pair_with_keys(&rt, &conn_inspector);
1082
1083 for relay_version in [4, 5, 6] {
1088 let pending_tunnel = test_utils::new_pending_tunnel(&rt, &client_chan).await;
1089
1090 let circ_params = CircParameters::default();
1091
1092 let protocols = format!("Relay=4-{relay_version}").parse().unwrap();
1093 let target = target_builder.protocols(protocols).build().unwrap();
1094
1095 let tunnel = pending_tunnel
1096 .create_firsthop(&target, circ_params)
1097 .await
1098 .unwrap();
1099
1100 let client_cell = conn_inspector.try_client_cell().unwrap().msg().clone();
1101 let relay_cell = conn_inspector.try_relay_cell().unwrap().msg().clone();
1102
1103 assert_eq!(client_cell.cmd(), ChanCmd::CREATE2);
1105 assert_eq!(relay_cell.cmd(), ChanCmd::CREATED2);
1106
1107 let AnyChanMsg::Create2(client_cell) = client_cell else {
1109 unreachable!("CREATE2 checked above");
1110 };
1111 assert_eq!(client_cell.handshake_type(), HandshakeType::NTOR_V3);
1112
1113 drop(tunnel);
1117
1118 assert_eq!(
1119 conn_inspector.client_cell().await.unwrap().msg().cmd(),
1120 ChanCmd::DESTROY,
1121 );
1122
1123 assert!(conn_inspector.try_client_cell().is_none());
1125 assert!(conn_inspector.try_relay_cell().is_none());
1126 }
1127
1128 let wait_fut =
1130 futures::future::join(client_chan.wait_for_close(), relay_chan.wait_for_close());
1131 drop((client_chan, relay_chan));
1132 let _ = wait_fut.await;
1133
1134 assert!(conn_inspector.try_client_cell().is_none());
1136 assert!(conn_inspector.try_relay_cell().is_none());
1137 });
1138 }
1139
1140 #[test]
1142 fn ntor_v3_fail() {
1143 test_with_one_runtime!(|rt| async move {
1144 let mut conn_inspector = test_utils::ConnInspector::new();
1145
1146 conn_inspector.set_client_cell_modifier(|cell: &mut AnyChanCell| {
1148 let circ_id = cell.circid();
1149 if let AnyChanMsg::Create2(msg) = cell.msg() {
1150 let mut new_body = msg.body().to_vec();
1151
1152 new_body[10] = !new_body[10];
1154
1155 let new_msg = Create2::new(msg.handshake_type(), new_body);
1157 *cell = AnyChanCell::new(circ_id, AnyChanMsg::Create2(new_msg));
1158 }
1159 });
1160
1161 let (client_chan, relay_chan, _circuit_stream_rx, mut target_builder) =
1162 test_utils::new_channel_pair_with_keys(&rt, &conn_inspector);
1163
1164 for relay_version in [4, 5, 6] {
1169 let pending_tunnel = test_utils::new_pending_tunnel(&rt, &client_chan).await;
1170
1171 let circ_params = CircParameters::default();
1172
1173 let protocols = format!("Relay=4-{relay_version}").parse().unwrap();
1174 let target = target_builder.protocols(protocols).build().unwrap();
1175
1176 assert!(matches!(
1179 pending_tunnel.create_firsthop(&target, circ_params).await,
1180 Err(crate::Error::CircRefused(_)),
1181 ));
1182
1183 assert_eq!(
1185 conn_inspector.try_client_cell().unwrap().msg().cmd(),
1186 ChanCmd::CREATE2,
1187 );
1188 assert_eq!(
1189 conn_inspector.try_relay_cell().unwrap().msg().cmd(),
1190 ChanCmd::DESTROY,
1191 );
1192
1193 assert!(conn_inspector.try_client_cell().is_none());
1195 assert!(conn_inspector.try_relay_cell().is_none());
1196 }
1197
1198 let wait_fut =
1200 futures::future::join(client_chan.wait_for_close(), relay_chan.wait_for_close());
1201 drop((client_chan, relay_chan));
1202 let _ = wait_fut.await;
1203
1204 assert!(conn_inspector.try_client_cell().is_none());
1206 assert!(conn_inspector.try_relay_cell().is_none());
1207 });
1208 }
1209
1210 #[test]
1212 fn create2_invalid_handshake_fail() {
1213 test_with_one_runtime!(|rt| async move {
1214 let mut conn_inspector = test_utils::ConnInspector::new();
1215
1216 conn_inspector.set_client_cell_modifier(|cell: &mut AnyChanCell| {
1218 let circ_id = cell.circid();
1219 if let AnyChanMsg::Create2(msg) = cell.msg() {
1220 let new_msg = tor_cell::chancell::msg::Create2::new(99.into(), msg.body());
1222 *cell = AnyChanCell::new(circ_id, AnyChanMsg::Create2(new_msg));
1223 }
1224 });
1225
1226 let (client_chan, relay_chan, _circuit_stream_rx, mut target_builder) =
1227 test_utils::new_channel_pair_with_keys(&rt, &conn_inspector);
1228
1229 for relay_version in [2, 6] {
1236 let pending_tunnel = test_utils::new_pending_tunnel(&rt, &client_chan).await;
1237
1238 let circ_params = CircParameters::default();
1239
1240 let protocols = format!("Relay=2-{relay_version}").parse().unwrap();
1241 let target = target_builder.protocols(protocols).build().unwrap();
1242
1243 assert!(matches!(
1246 pending_tunnel.create_firsthop(&target, circ_params).await,
1247 Err(crate::Error::CircRefused(_)),
1248 ));
1249
1250 assert_eq!(
1252 conn_inspector.try_client_cell().unwrap().msg().cmd(),
1253 ChanCmd::CREATE2,
1254 );
1255 assert_eq!(
1256 conn_inspector.try_relay_cell().unwrap().msg().cmd(),
1257 ChanCmd::DESTROY,
1258 );
1259
1260 assert!(conn_inspector.try_client_cell().is_none());
1262 assert!(conn_inspector.try_relay_cell().is_none());
1263 }
1264
1265 let wait_fut =
1267 futures::future::join(client_chan.wait_for_close(), relay_chan.wait_for_close());
1268 drop((client_chan, relay_chan));
1269 let _ = wait_fut.await;
1270
1271 assert!(conn_inspector.try_client_cell().is_none());
1273 assert!(conn_inspector.try_relay_cell().is_none());
1274 });
1275 }
1276}