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::{CircuitRxSender, HandshakeSubprotocols, UniqId};
12use crate::client::circuit::padding::PaddingController;
13use crate::crypto::binding::CircuitBinding;
14use crate::crypto::cell::CryptInit as _;
15use crate::crypto::cell::{InboundRelayLayer, OutboundRelayLayer, RelayLayer, tor1};
16use crate::crypto::handshake::RelayHandshakeError;
17use crate::crypto::handshake::ServerHandshake as _;
18use crate::crypto::handshake::fast::CreateFastServer;
19use crate::crypto::handshake::ntor::{NtorSecretKey, NtorServer};
20use crate::memquota::SpecificAccount as _;
21use crate::memquota::{ChannelAccount, CircuitAccount};
22use crate::relay::channel_provider::ChannelProvider;
23use crate::relay::reactor::Reactor;
24use crate::relay::{IncomingStreamRequestFilter, RelayCirc};
25use crate::stream::IncomingStream;
26use futures::channel::mpsc;
27use futures::{SinkExt, Stream};
28use smallvec::SmallVec;
29use std::sync::{Arc, RwLock, Weak};
30use tor_cell::chancell::ChanMsg as _;
31use tor_cell::chancell::CircId;
32use tor_cell::chancell::msg::{
33 CreateFast, Created2, CreatedFast, Destroy, DestroyReason, HandshakeType,
34};
35use tor_cell::relaycell::RelayCmd;
36use tor_error::{ErrorKind, HasKind, debug_report, internal, into_internal, warn_report};
37use tor_linkspec::OwnedChanTarget;
38use tor_llcrypto::cipher::aes::Aes128Ctr;
39use tor_llcrypto::d::Sha1;
40use tor_llcrypto::pk::ed25519::Ed25519Identity;
41use tor_llcrypto::pk::rsa::RsaIdentity;
42use tor_memquota::mq_queue::ChannelSpec as _;
43use tor_memquota::mq_queue::MpscSpec;
44use tor_relay_crypto::pk::{RelayNtorKeypair, RelayNtorKeys};
45use tor_rtcompat::SpawnExt as _;
46use tor_rtcompat::{DynTimeProvider, Runtime};
47use tracing::trace;
48
49#[derive(derive_more::Debug)]
51pub struct CreateRequestHandler {
52 chan_provider: Weak<dyn ChannelProvider<BuildSpec = OwnedChanTarget> + Send + Sync>,
54 circ_net_params: RwLock<CircNetParameters>,
56 #[debug(skip)]
58 ntor_keys: RwLock<RelayNtorKeys>,
59 #[debug(skip)]
69 incoming_filter_factory: Box<dyn IncomingStreamRequestFilterFactory + Send + Sync>,
70 allowed_stream_cmds: SmallVec<[RelayCmd; 3]>,
78 #[debug(skip)]
91 circuit_stream_tx: mpsc::Sender<Box<dyn Stream<Item = IncomingStream> + Send + Sync + Unpin>>,
92}
93
94impl CreateRequestHandler {
95 pub fn new(
98 chan_provider: Weak<dyn ChannelProvider<BuildSpec = OwnedChanTarget> + Send + Sync>,
99 circ_net_params: CircNetParameters,
100 ntor_keys: RelayNtorKeys,
101 incoming_filter_factory: Box<dyn IncomingStreamRequestFilterFactory + Send + Sync>,
102 allowed_stream_cmds: &[RelayCmd],
103 ) -> (Self, CircuitIncomingStreamReceiver) {
104 const CIRC_STREAM_BUF_SIZE: usize = 1024;
110
111 #[allow(clippy::disallowed_methods)]
115 let (stream_tx, stream_rx) = mpsc::channel(CIRC_STREAM_BUF_SIZE);
116
117 let handler = Self {
118 chan_provider,
119 circ_net_params: RwLock::new(circ_net_params),
120 ntor_keys: RwLock::new(ntor_keys),
121 incoming_filter_factory,
122 allowed_stream_cmds: allowed_stream_cmds.into(),
123 circuit_stream_tx: stream_tx,
124 };
125
126 let circuit_stream_rx = CircuitIncomingStreamReceiver {
127 circuit_stream_rx: stream_rx,
128 };
129
130 (handler, circuit_stream_rx)
131 }
132
133 pub fn update_params(&self, circ_net_params: CircNetParameters) {
135 *self.circ_net_params.write().expect("rwlock poisoned") = circ_net_params;
136 }
137
138 pub fn update_ntor_keys(&self, ntor_keys: RelayNtorKeys) {
142 *self.ntor_keys.write().expect("rwlock poisoned") = ntor_keys;
143 }
144
145 #[allow(clippy::too_many_arguments)]
153 pub(crate) fn handle_create<R: Runtime>(
154 &self,
155 runtime: &R,
156 channel: &Arc<Channel>,
157 our_ed25519_id: &Ed25519Identity,
158 our_rsa_id: &RsaIdentity,
159 circ_id: CircId,
160 msg: &CreateRequest,
161 memquota: &ChannelAccount,
162 circ_unique_id: UniqId,
163 ) -> Result<(CreateResponse, RelayCircComponents), Destroy> {
164 let result = self.handle_create_inner(
165 runtime,
166 channel,
167 our_ed25519_id,
168 our_rsa_id,
169 circ_id,
170 msg,
171 memquota,
172 circ_unique_id,
173 );
174
175 match result {
176 Ok(x) => Ok(x),
177 Err(e) => {
178 let cmd = msg.cmd();
180 debug_report!(&e, %cmd, "Failed to handle circuit create request");
181
182 Err(Destroy::new(DestroyReason::NONE))
186 }
187 }
188 }
189
190 #[allow(clippy::too_many_arguments)]
192 fn handle_create_inner<R: Runtime>(
193 &self,
194 runtime: &R,
195 channel: &Arc<Channel>,
196 our_ed25519_id: &Ed25519Identity,
197 our_rsa_id: &RsaIdentity,
198 circ_id: CircId,
199 msg: &CreateRequest,
200 memquota: &ChannelAccount,
201 circ_unique_id: UniqId,
202 ) -> Result<(CreateResponse, RelayCircComponents), HandleCreateError> {
203 let handshake_components = match msg {
205 CreateRequest::CreateFast(msg) => self.handle_create_fast(msg)?,
206 CreateRequest::Create2(msg) => match msg.handshake_type() {
207 HandshakeType::NTOR_V3 => self.handle_create2_ntorv3(msg.body(), our_ed25519_id)?,
208 HandshakeType::NTOR => self.handle_create2_ntor(msg.body(), our_rsa_id)?,
209 x @ HandshakeType::TAP | x => {
210 return Err(HandleCreateError::Create2HandshakeType(x));
211 }
212 },
213 };
214
215 let memquota = CircuitAccount::new(memquota)?;
216
217 let time_provider = DynTimeProvider::new(runtime.clone());
223 let account = memquota.as_raw_account();
224 let (sender, receiver) =
225 MpscSpec::new(10_000_000).new_mq(time_provider.clone(), account)?;
226 let (sender, receiver) = crate::circuit::circ_sender::channel(sender, receiver);
227
228 let (padding_ctrl, padding_stream) =
230 crate::client::circuit::padding::new_padding(DynTimeProvider::new(runtime.clone()));
231
232 let Some(chan_provider) = self.chan_provider.upgrade() else {
234 return Err(internal!("Unable to upgrade weak `ChannelProvider`").into());
235 };
236
237 let incoming_filter = self.incoming_filter_factory.current_filter();
244
245 let (reactor, circ, incoming_streams) = Reactor::new(
247 runtime.clone(),
248 channel,
249 circ_id,
250 circ_unique_id,
251 receiver,
252 handshake_components.crypto_in,
253 handshake_components.crypto_out,
254 &handshake_components.hop_settings,
255 chan_provider,
256 padding_ctrl.clone(),
257 padding_stream,
258 incoming_filter,
259 &self.allowed_stream_cmds,
260 &memquota,
261 )
262 .map_err(into_internal!("Failed to start circuit reactor"))?;
263
264 let mut circuit_stream_tx = self.circuit_stream_tx.clone();
265 let () = runtime.spawn(async move {
267 if let Err(e) = circuit_stream_tx.send(Box::new(incoming_streams)).await {
268 warn_report!(e, "IncomingStream handler disappeared?!");
269 drop(reactor);
276 } else {
277 match reactor.run().await {
280 Ok(()) => {}
281 Err(e) => {
282 debug_report!(e, "Relay circuit reactor exited with an error");
283 }
284 }
285 }
286 })?;
287
288 Ok((
289 handshake_components.response,
290 RelayCircComponents {
291 circ,
292 sender,
293 padding_ctrl,
294 },
295 ))
296 }
297
298 fn handle_create_fast(
300 &self,
301 msg: &CreateFast,
302 ) -> Result<CompletedHandshakeComponents, HandleCreateError> {
303 let (keygen, handshake_msg) = CreateFastServer::server(
305 &mut rand::rng(),
306 &mut |_: &()| Some(()),
309 &[()],
311 msg.handshake(),
312 )?;
313
314 let circ_net_params = self
315 .circ_net_params
316 .read()
317 .expect("rwlock poisoned")
318 .clone();
319
320 let subprotos = HandshakeSubprotocols::default();
322
323 let hop_settings = HopSettings::from_handshake_params(
324 circ_net_params,
325 AlgorithmDiscriminants::FixedWindow,
327 subprotos,
328 )?;
329
330 let crypt = tor1::CryptStatePair::<Aes128Ctr, Sha1>::construct(keygen)
331 .map_err(into_internal!("Circuit crypt state construction failed"))?;
332
333 let (crypto_out, crypto_in, _binding) = split_relay_layer(crypt);
334
335 let response = CreatedFast::new(handshake_msg);
336 let response = CreateResponse::CreatedFast(response);
337
338 trace!("Completed CREATE_FAST handshake");
339
340 Ok(CompletedHandshakeComponents {
341 response,
342 hop_settings,
343 crypto_out,
344 crypto_in,
345 })
346 }
347
348 fn handle_create2_ntor(
350 &self,
351 msg_body: &[u8],
352 our_rsa_id: &RsaIdentity,
353 ) -> Result<CompletedHandshakeComponents, HandleCreateError> {
354 let ntor_keys = self.ntor_keys(|k| {
355 NtorSecretKey::new(k.secret().clone(), *k.public().inner(), *our_rsa_id)
356 });
357
358 let (keygen, handshake_msg) = NtorServer::server(
360 &mut rand::rng(),
361 &mut |_: &()| Some(()),
364 ntor_keys.as_ref(),
365 msg_body,
366 )?;
367
368 let circ_net_params = self
369 .circ_net_params
370 .read()
371 .expect("rwlock poisoned")
372 .clone();
373
374 let subprotos = HandshakeSubprotocols::default();
376
377 let hop_settings = HopSettings::from_handshake_params(
378 circ_net_params,
379 AlgorithmDiscriminants::FixedWindow,
381 subprotos,
382 )?;
383
384 let crypt = tor1::CryptStatePair::<Aes128Ctr, Sha1>::construct(keygen)
385 .map_err(into_internal!("Circuit crypt state construction failed"))?;
386
387 let (crypto_out, crypto_in, _binding) = split_relay_layer(crypt);
388
389 let response = Created2::new(handshake_msg);
390 let response = CreateResponse::Created2(response);
391
392 trace!("Completed ntor handshake");
393
394 Ok(CompletedHandshakeComponents {
395 response,
396 hop_settings,
397 crypto_out,
398 crypto_in,
399 })
400 }
401
402 fn handle_create2_ntorv3(
404 &self,
405 _msg_body: &[u8],
406 _our_ed25519_id: &Ed25519Identity,
407 ) -> Result<CompletedHandshakeComponents, HandleCreateError> {
408 Err(HandleCreateError::Create2HandshakeType(
409 HandshakeType::NTOR_V3,
410 ))
411 }
412
413 fn ntor_keys<T>(&self, map: impl FnMut(&RelayNtorKeypair) -> T) -> impl AsRef<[T]> {
421 let ntor_keys = self.ntor_keys.read().expect("rwlock poisoned");
422 let ntor_keys = [Some(ntor_keys.latest()), ntor_keys.previous()];
423 ntor_keys
424 .into_iter()
425 .flatten()
426 .map(map)
427 .collect::<SmallVec<[T; 2]>>()
428 }
429}
430
431pub struct CircuitIncomingStreamReceiver {
447 circuit_stream_rx: mpsc::Receiver<<Self as Stream>::Item>,
452}
453
454impl Stream for CircuitIncomingStreamReceiver {
455 type Item = Box<dyn Stream<Item = IncomingStream> + Send + Sync + Unpin>;
459
460 fn poll_next(
461 mut self: std::pin::Pin<&mut Self>,
462 cx: &mut std::task::Context<'_>,
463 ) -> std::task::Poll<Option<Self::Item>> {
464 use futures::StreamExt as _;
465
466 self.circuit_stream_rx.poll_next_unpin(cx)
467 }
468}
469
470fn split_relay_layer<F, B>(
472 crypt: impl RelayLayer<F, B>,
473) -> (
474 Box<dyn OutboundRelayLayer + Send>,
475 Box<dyn InboundRelayLayer + Send>,
476 CircuitBinding,
477)
478where
479 F: OutboundRelayLayer + Send + 'static,
480 B: InboundRelayLayer + Send + 'static,
481{
482 let (crypto_out, crypto_in, binding) = crypt.split_relay_layer();
483 let (crypto_out, crypto_in) = (Box::new(crypto_out), Box::new(crypto_in));
484
485 (crypto_out, crypto_in, binding)
486}
487
488#[derive(Debug, thiserror::Error)]
490enum HandleCreateError {
491 #[error("Circuit relay handshake failed")]
493 Handshake(#[from] RelayHandshakeError),
494 #[error("Failed to process the circuit relay handshake parameters")]
496 HandshakeParameters(#[from] HandshakeParamsError),
497 #[error("Unsupported handshake type {0}")]
499 Create2HandshakeType(HandshakeType),
500 #[error("Memquota error")]
502 Memquota(#[from] tor_memquota::Error),
503 #[error("Runtime task spawn error")]
505 Spawn(#[from] futures::task::SpawnError),
506 #[error("Internal error")]
511 Internal(#[from] tor_error::Bug),
512}
513
514impl HasKind for HandleCreateError {
515 fn kind(&self) -> ErrorKind {
516 match self {
517 Self::Handshake(e) => e.kind(),
518 Self::HandshakeParameters(e) => e.kind(),
519 Self::Create2HandshakeType(_) => ErrorKind::NotImplemented,
520 Self::Memquota(e) => e.kind(),
521 Self::Spawn(e) => e.kind(),
522 Self::Internal(_) => ErrorKind::Internal,
523 }
524 }
525}
526
527struct CompletedHandshakeComponents {
529 response: CreateResponse,
531 hop_settings: HopSettings,
533 crypto_out: Box<dyn OutboundRelayLayer + Send>,
535 crypto_in: Box<dyn InboundRelayLayer + Send>,
537}
538
539pub(crate) struct RelayCircComponents {
541 pub(crate) circ: Arc<RelayCirc>,
543 pub(crate) sender: CircuitRxSender,
545 pub(crate) padding_ctrl: PaddingController,
547}
548
549#[derive(Debug, Clone)]
551#[allow(clippy::exhaustive_structs)]
552pub struct CongestionControlNetParams {
553 pub fixed_window: FixedWindowParams,
555
556 pub vegas_exit: VegasParams,
561
562 pub cwnd: CongestionWindowParams,
564
565 pub rtt: RoundTripEstimatorParams,
567
568 pub flow_ctrl: FlowCtrlParameters,
570}
571
572impl CongestionControlNetParams {
573 #[cfg(test)]
574 pub(crate) fn defaults_for_tests() -> Self {
576 Self {
577 fixed_window: FixedWindowParams::defaults_for_tests(),
578 vegas_exit: VegasParams::defaults_for_tests(),
579 cwnd: CongestionWindowParams::defaults_for_tests(),
580 rtt: RoundTripEstimatorParams::defaults_for_tests(),
581 flow_ctrl: FlowCtrlParameters::defaults_for_tests(),
582 }
583 }
584}
585
586#[derive(Debug, Clone)]
594#[allow(clippy::exhaustive_structs)]
595pub struct CircNetParameters {
596 pub cc: CongestionControlNetParams,
598}
599
600pub trait IncomingStreamRequestFilterFactory {
606 fn current_filter(&self) -> Box<dyn IncomingStreamRequestFilter>;
609}
610
611impl<F> IncomingStreamRequestFilterFactory for F
612where
613 F: Fn() -> Box<dyn IncomingStreamRequestFilter>,
614{
615 fn current_filter(&self) -> Box<dyn IncomingStreamRequestFilter> {
616 (self)()
617 }
618}
619
620#[cfg(test)]
621mod test {
622 #![allow(clippy::bool_assert_comparison)]
624 #![allow(clippy::clone_on_copy)]
625 #![allow(clippy::dbg_macro)]
626 #![allow(clippy::mixed_attributes_style)]
627 #![allow(clippy::print_stderr)]
628 #![allow(clippy::print_stdout)]
629 #![allow(clippy::single_char_pattern)]
630 #![allow(clippy::unwrap_used)]
631 #![allow(clippy::unchecked_time_subtraction)]
632 #![allow(clippy::useless_vec)]
633 #![allow(clippy::needless_pass_by_value)]
634 #![allow(clippy::string_slice)] use tor_cell::chancell::{ChanCmd, ChanMsg as _};
638 use tor_rtcompat::test_with_one_runtime;
639
640 use crate::channel::test_utils;
641 use crate::circuit::CircParameters;
642
643 #[test]
644 fn create_fast() {
645 test_with_one_runtime!(|rt| async move {
646 let mut conn_inspector = test_utils::ConnInspector::new();
647
648 let (client_chan, _relay_chan, _circuit_stream_rx, _target_builder) =
649 test_utils::new_channel_pair_with_keys(&rt, &conn_inspector);
650
651 let pending_tunnel = test_utils::new_pending_tunnel(&rt, &client_chan).await;
652
653 let circ_params = CircParameters::default();
654
655 let tunnel = pending_tunnel
656 .create_firsthop_fast(circ_params)
657 .await
658 .unwrap();
659
660 assert_eq!(
661 conn_inspector.try_client_cell().unwrap().msg().cmd(),
662 ChanCmd::CREATE_FAST,
663 );
664 assert_eq!(
665 conn_inspector.try_relay_cell().unwrap().msg().cmd(),
666 ChanCmd::CREATED_FAST,
667 );
668
669 drop(tunnel);
670
671 assert_eq!(
672 conn_inspector.client_cell().await.unwrap().msg().cmd(),
673 ChanCmd::DESTROY,
674 );
675 assert_eq!(
678 conn_inspector.relay_cell().await.unwrap().msg().cmd(),
679 ChanCmd::DESTROY,
680 );
681 });
682 }
683
684 #[test]
685 fn tap() {
686 test_with_one_runtime!(|rt| async move {
687 let mut conn_inspector = test_utils::ConnInspector::new();
688
689 let (client_chan, _relay_chan, _circuit_stream_rx, mut target_builder) =
690 test_utils::new_channel_pair_with_keys(&rt, &conn_inspector);
691
692 let pending_tunnel = test_utils::new_pending_tunnel(&rt, &client_chan).await;
693
694 let circ_params = CircParameters::default();
695
696 let protocols = "Relay=1".parse().unwrap();
699 let target = target_builder.protocols(protocols).build().unwrap();
700
701 let _tunnel = pending_tunnel
705 .create_firsthop(&target, circ_params)
706 .await
707 .unwrap();
708
709 assert_eq!(
711 conn_inspector.try_client_cell().unwrap().msg().cmd(),
712 ChanCmd::CREATE2,
713 );
714 assert_eq!(
715 conn_inspector.try_relay_cell().unwrap().msg().cmd(),
716 ChanCmd::CREATED2,
717 );
718 });
719 }
720
721 #[test]
722 fn ntor() {
723 test_with_one_runtime!(|rt| async move {
724 let mut conn_inspector = test_utils::ConnInspector::new();
725
726 let (client_chan, _relay_chan, _circuit_stream_rx, mut target_builder) =
727 test_utils::new_channel_pair_with_keys(&rt, &conn_inspector);
728
729 for relay_version in [2, 3] {
733 let pending_tunnel = test_utils::new_pending_tunnel(&rt, &client_chan).await;
734
735 let circ_params = CircParameters::default();
736
737 let protocols = format!("Relay=2-{relay_version}").parse().unwrap();
738 let target = target_builder.protocols(protocols).build().unwrap();
739
740 let tunnel = pending_tunnel
741 .create_firsthop(&target, circ_params)
742 .await
743 .unwrap();
744
745 assert_eq!(
746 conn_inspector.try_client_cell().unwrap().msg().cmd(),
747 ChanCmd::CREATE2,
748 );
749 assert_eq!(
750 conn_inspector.try_relay_cell().unwrap().msg().cmd(),
751 ChanCmd::CREATED2,
752 );
753
754 drop(tunnel);
755
756 assert_eq!(
757 conn_inspector.client_cell().await.unwrap().msg().cmd(),
758 ChanCmd::DESTROY,
759 );
760 assert_eq!(
763 conn_inspector.relay_cell().await.unwrap().msg().cmd(),
764 ChanCmd::DESTROY,
765 );
766 }
767 });
768 }
769
770 }