1pub(crate) mod circhop;
4pub(super) mod extender;
5
6use crate::channel::Channel;
7use crate::circuit::cell_sender::CircuitCellSender;
8use crate::circuit::celltypes::CreateResponse;
9use crate::circuit::circhop::{HopSettings, ReactorStreamComponents};
10use crate::circuit::create::{Create2Wrap, CreateFastWrap, CreateHandshakeWrap};
11use crate::circuit::padding::CircPaddingDisposition;
12use crate::circuit::{CircuitRxReceiver, UniqId};
13use crate::client::circuit::handshake::{BoxedClientLayer, HandshakeRole};
14use crate::client::circuit::padding::{
15 self, PaddingController, PaddingEventStream, QueuedCellPaddingInfo,
16};
17use crate::client::circuit::{ClientCircChanMsg, MutableState, path};
18use crate::client::reactor::MetaCellDisposition;
19use crate::congestion::CongestionSignals;
20use crate::congestion::sendme;
21use crate::crypto::binding::CircuitBinding;
22use crate::crypto::cell::{
23 HopNum, InboundClientCrypt, InboundClientLayer, OutboundClientCrypt, OutboundClientLayer,
24 RelayCellBody,
25};
26use crate::crypto::handshake::fast::CreateFastClient;
27use crate::crypto::handshake::ntor::{NtorClient, NtorPublicKey};
28use crate::crypto::handshake::ntor_v3::{NtorV3Client, NtorV3PublicKey};
29use crate::crypto::handshake::{ClientHandshake, KeyGenerator};
30use crate::memquota::{CircuitAccount, SpecificAccount as _, StreamAccount};
31use crate::stream::cmdcheck::{AnyCmdChecker, StreamStatus};
32use crate::stream::msg_streamid;
33use crate::streammap;
34use crate::tunnel::TunnelScopedCircId;
35use crate::util::err::ReactorError;
36use crate::util::timeout::TimeoutEstimator;
37use crate::{ClockSkew, Error, Result};
38
39use tor_async_utils::{SinkTrySend as _, SinkTrySendError as _};
40use tor_cell::chancell::msg::{AnyChanMsg, HandshakeType, Relay};
41use tor_cell::chancell::{AnyChanCell, ChanCmd, CircId};
42use tor_cell::chancell::{BoxedCellBody, ChanMsg};
43use tor_cell::relaycell::msg::{AnyRelayMsg, End, Sendme, SendmeTag, Truncated};
44use tor_cell::relaycell::{
45 AnyRelayMsgOuter, RelayCellDecoderResult, RelayCellFormat, RelayCmd, StreamId, UnparsedRelayMsg,
46};
47use tor_error::{Bug, internal};
48use tor_linkspec::RelayIds;
49use tor_llcrypto::pk;
50use web_time_compat::{Duration, Instant, SystemTime};
51
52use futures::SinkExt as _;
53use oneshot_fused_workaround as oneshot;
54use tor_rtcompat::{DynTimeProvider, SleepProvider as _};
55use tracing::{debug, instrument, trace, warn};
56
57use super::{
58 CellHandlers, CircuitHandshake, CloseStreamBehavior, ReactorResultChannel, SendRelayCell,
59};
60
61use crate::conflux::msghandler::ConfluxStatus;
62
63use std::borrow::Borrow;
64use std::pin::Pin;
65use std::result::Result as StdResult;
66use std::sync::Arc;
67
68use extender::HandshakeAuxDataHandler;
69
70#[cfg(feature = "hs-service")]
71use {
72 crate::circuit::CircHopSyncView,
73 crate::stream::{InboundDataCmdChecker, IncomingStreamRequest},
74 tor_cell::relaycell::msg::Begin,
75};
76
77#[cfg(feature = "conflux")]
78use {
79 crate::conflux::msghandler::{ConfluxAction, ConfluxCmd, ConfluxMsgHandler, OooRelayMsg},
80 crate::tunnel::TunnelId,
81};
82
83#[cfg(not(feature = "flowctl-cc"))]
84use crate::stream::STREAM_READER_BUFFER;
85
86pub(super) use circhop::{CircHop, CircHopList};
87
88pub(crate) struct Circuit {
93 runtime: DynTimeProvider,
95 channel: Arc<Channel>,
97 pub(super) chan_sender: CircuitCellSender,
102 pub(super) input: CircuitRxReceiver,
107 crypto_in: InboundClientCrypt,
111 crypto_out: OutboundClientCrypt,
113 pub(super) hops: CircHopList,
115 mutable: Arc<MutableState>,
118 channel_id: CircId,
120 unique_id: TunnelScopedCircId,
122 #[cfg(feature = "conflux")]
127 conflux_handler: Option<ConfluxMsgHandler>,
128 padding_ctrl: PaddingController,
130 pub(super) padding_event_stream: PaddingEventStream,
138 #[cfg(feature = "circ-padding")]
140 padding_block: Option<padding::StartBlocking>,
141 timeouts: Arc<dyn TimeoutEstimator>,
145 #[allow(dead_code)] memquota: CircuitAccount,
148}
149
150#[derive(Debug, derive_more::From)]
158pub(super) enum CircuitCmd {
159 Send(SendRelayCell),
161 HandleSendMe {
163 hop: HopNum,
165 sendme: Sendme,
167 },
168 CloseStream {
170 hop: HopNum,
172 sid: StreamId,
174 behav: CloseStreamBehavior,
176 reason: streammap::TerminateReason,
178 },
179 #[cfg(feature = "conflux")]
181 Conflux(ConfluxCmd),
182 CleanShutdown,
184 #[cfg(feature = "conflux")]
186 Enqueue(OooRelayMsg),
187}
188
189macro_rules! unsupported_client_cell {
196 ($msg:expr) => {{
197 unsupported_client_cell!(@ $msg, "")
198 }};
199
200 ($msg:expr, $hopnum:expr) => {{
201 let hop: HopNum = $hopnum;
202 let hop_display = format!(" from hop {}", hop.display());
203 unsupported_client_cell!(@ $msg, hop_display)
204 }};
205
206 (@ $msg:expr, $hopnum_display:expr) => {
207 Err(crate::Error::CircProto(format!(
208 "Unexpected {} cell{} on client circuit",
209 $msg.cmd(),
210 $hopnum_display,
211 )))
212 };
213}
214
215pub(super) use unsupported_client_cell;
216
217impl Circuit {
218 #[allow(clippy::too_many_arguments)]
220 pub(super) fn new(
221 runtime: DynTimeProvider,
222 channel: Arc<Channel>,
223 channel_id: CircId,
224 unique_id: TunnelScopedCircId,
225 input: CircuitRxReceiver,
226 memquota: CircuitAccount,
227 mutable: Arc<MutableState>,
228 padding_ctrl: PaddingController,
229 padding_event_stream: PaddingEventStream,
230 timeouts: Arc<dyn TimeoutEstimator>,
231 ) -> Self {
232 let chan_sender = CircuitCellSender::from_channel_sender(channel.sender());
233
234 let crypto_out = OutboundClientCrypt::new();
235 Circuit {
236 runtime,
237 channel,
238 chan_sender,
239 input,
240 crypto_in: InboundClientCrypt::new(),
241 hops: CircHopList::default(),
242 unique_id,
243 channel_id,
244 crypto_out,
245 mutable,
246 #[cfg(feature = "conflux")]
247 conflux_handler: None,
248 padding_ctrl,
249 padding_event_stream,
250 #[cfg(feature = "circ-padding")]
251 padding_block: None,
252 timeouts,
253 memquota,
254 }
255 }
256
257 pub(super) fn unique_id(&self) -> UniqId {
259 self.unique_id.unique_id()
260 }
261
262 pub(super) fn mutable(&self) -> &Arc<MutableState> {
264 &self.mutable
265 }
266
267 #[cfg(feature = "conflux")]
272 pub(super) fn add_to_conflux_tunnel(
273 &mut self,
274 tunnel_id: TunnelId,
275 conflux_handler: ConfluxMsgHandler,
276 ) {
277 self.unique_id = TunnelScopedCircId::new(tunnel_id, self.unique_id.unique_id());
278 self.conflux_handler = Some(conflux_handler);
279 }
280
281 #[cfg(feature = "conflux")]
286 pub(super) async fn begin_conflux_link(
287 &mut self,
288 hop: HopNum,
289 cell: AnyRelayMsgOuter,
290 runtime: &tor_rtcompat::DynTimeProvider,
291 ) -> Result<()> {
292 use tor_rtcompat::SleepProvider as _;
293
294 if self.conflux_handler.is_none() {
295 return Err(internal!(
296 "tried to send LINK cell before installing a ConfluxMsgHandler?!"
297 )
298 .into());
299 }
300
301 let cell = SendRelayCell {
302 hop: Some(hop),
303 early: false,
304 cell,
305 };
306 self.send_relay_cell(cell).await?;
307
308 let Some(conflux_handler) = self.conflux_handler.as_mut() else {
309 return Err(internal!("ConfluxMsgHandler disappeared?!").into());
310 };
311
312 Ok(conflux_handler.note_link_sent(runtime.wallclock())?)
313 }
314
315 pub(super) fn conflux_hs_timeout(&self) -> Option<SystemTime> {
319 cfg_if::cfg_if! {
320 if #[cfg(feature = "conflux")] {
321 self.conflux_handler.as_ref().map(|handler| handler.handshake_timeout())?
322 } else {
323 None
324 }
325 }
326 }
327
328 #[cfg(test)]
330 pub(super) fn handle_add_fake_hop(
331 &mut self,
332 format: RelayCellFormat,
333 fwd_lasthop: bool,
334 rev_lasthop: bool,
335 dummy_peer_id: path::HopDetail,
336 params: &crate::client::circuit::CircParameters,
340 done: ReactorResultChannel<()>,
341 ) {
342 use tor_protover::{Protocols, named};
343
344 use crate::client::circuit::test::DummyCrypto;
345
346 assert!(matches!(format, RelayCellFormat::V0));
347 let _ = format; let fwd = Box::new(DummyCrypto::new(fwd_lasthop));
350 let rev = Box::new(DummyCrypto::new(rev_lasthop));
351 let binding = None;
352
353 let settings = HopSettings::from_params_and_caps(
354 crate::circuit::circhop::HopNegotiationType::Full,
356 params,
357 &[named::FLOWCTRL_CC].into_iter().collect::<Protocols>(),
358 )
359 .expect("Can't construct HopSettings");
360 self.add_hop(dummy_peer_id, fwd, rev, binding, &settings)
361 .expect("could not add hop to circuit");
362 let _ = done.send(Ok(()));
363 }
364
365 fn encode_relay_cell(
369 crypto_out: &mut OutboundClientCrypt,
370 relay_format: RelayCellFormat,
371 hop: HopNum,
372 early: bool,
373 msg: AnyRelayMsgOuter,
374 ) -> Result<(AnyChanMsg, SendmeTag)> {
375 let mut body: RelayCellBody = msg
376 .encode(relay_format, &mut rand::rng())
377 .map_err(|e| Error::from_cell_enc(e, "relay cell body"))?
378 .into();
379 let cmd = if early {
380 ChanCmd::RELAY_EARLY
381 } else {
382 ChanCmd::RELAY
383 };
384 let tag = crypto_out.encrypt(cmd, &mut body, hop)?;
385 let msg = Relay::from(BoxedCellBody::from(body));
386 let msg = if early {
387 AnyChanMsg::RelayEarly(msg.into())
388 } else {
389 AnyChanMsg::Relay(msg)
390 };
391
392 Ok((msg, tag))
393 }
394
395 #[instrument(level = "trace", skip_all)]
406 pub(super) async fn send_relay_cell(&mut self, msg: SendRelayCell) -> Result<()> {
407 self.send_relay_cell_inner(msg, None).await
408 }
409
410 #[instrument(level = "trace", skip_all)]
416 async fn send_relay_cell_inner(
417 &mut self,
418 msg: SendRelayCell,
419 padding_info: Option<QueuedCellPaddingInfo>,
420 ) -> Result<()> {
421 let SendRelayCell {
422 hop,
423 early,
424 cell: msg,
425 } = msg;
426
427 let is_conflux_link = msg.cmd() == RelayCmd::CONFLUX_LINK;
428 if !is_conflux_link && self.is_conflux_pending() {
429 return Err(internal!("tried to send cell on unlinked circuit").into());
432 }
433
434 trace!(circ_id = %self.unique_id, cell = ?msg, "sending relay cell");
435
436 let runtime = self.runtime.clone();
438 let c_t_w = sendme::cmd_counts_towards_windows(msg.cmd());
439 let stream_id = msg.stream_id();
440 let hop = hop.expect("missing hop in client SendRelayCell?!");
441 let circhop = self.hops.get_mut(hop).ok_or(Error::NoSuchHop)?;
442
443 circhop.decrement_outbound_cell_limit()?;
448
449 if c_t_w {
451 if let Some(stream_id) = stream_id {
452 circhop.about_to_send(stream_id, msg.msg())?;
453 }
454 }
455
456 let relay_cmd = msg.cmd();
460
461 let (msg, tag) = Self::encode_relay_cell(
464 &mut self.crypto_out,
465 circhop.relay_cell_format(),
466 hop,
467 early,
468 msg,
469 )?;
470 if c_t_w {
473 circhop.ccontrol().note_data_sent(&runtime, &tag)?;
474 }
475
476 let padding_info = padding_info.or_else(|| self.padding_ctrl.queued_data(hop));
478
479 self.send_msg(msg, padding_info).await?;
480
481 #[cfg(feature = "conflux")]
482 if let Some(conflux) = self.conflux_handler.as_mut() {
483 conflux.note_cell_sent(relay_cmd);
484 }
485
486 Ok(())
487 }
488
489 pub(super) fn handle_cell(
502 &mut self,
503 handlers: &mut CellHandlers,
504 leg: UniqId,
505 cell: ClientCircChanMsg,
506 ) -> Result<Vec<CircuitCmd>> {
507 trace!(circ_id = %self.unique_id, cell = ?cell, "handling cell");
508 use ClientCircChanMsg::*;
509 match cell {
510 Relay(r) => self.handle_relay_cell(handlers, leg, r),
511 Destroy(d) => {
512 let reason = d.reason();
513 debug!(
514 circ_id = %self.unique_id,
515 "Received DESTROY cell. Reason: {} [{}]",
516 reason.human_str(),
517 reason
518 );
519
520 self.handle_destroy_cell().map(|c| vec![c])
521 }
522 }
523 }
524
525 fn decode_relay_cell(
528 &mut self,
529 cell: Relay,
530 ) -> Result<(HopNum, SendmeTag, RelayCellDecoderResult)> {
531 let cmd = cell.cmd();
533 let mut body = cell.into_relay_body().into();
534
535 let (hopnum, tag) = self.crypto_in.decrypt(cmd, &mut body)?;
538
539 let decode_res = self
541 .hop_mut(hopnum)
542 .ok_or_else(|| {
543 Error::from(internal!(
544 "Trying to decode cell from nonexistent hop {:?}",
545 hopnum
546 ))
547 })?
548 .decode(body.into())?;
549
550 Ok((hopnum, tag, decode_res))
551 }
552
553 fn handle_relay_cell(
555 &mut self,
556 handlers: &mut CellHandlers,
557 leg: UniqId,
558 cell: Relay,
559 ) -> Result<Vec<CircuitCmd>> {
560 let (hopnum, tag, decode_res) = self.decode_relay_cell(cell)?;
561
562 if decode_res.is_padding() {
563 self.padding_ctrl.decrypted_padding(hopnum)?;
564 } else {
565 self.padding_ctrl.decrypted_data(hopnum);
566 }
567
568 self.hop_mut(hopnum)
570 .ok_or_else(|| internal!("nonexistent hop {:?}", hopnum))?
571 .decrement_inbound_cell_limit()?;
572
573 let c_t_w = decode_res.cmds().any(sendme::cmd_counts_towards_windows);
574
575 let send_circ_sendme = if c_t_w {
578 self.hop_mut(hopnum)
579 .ok_or_else(|| Error::CircProto("Sendme from nonexistent hop".into()))?
580 .ccontrol()
581 .note_data_received()?
582 } else {
583 false
584 };
585
586 let mut circ_cmds = vec![];
587 if send_circ_sendme {
589 let sendme = Sendme::from(tag);
594 let cell = AnyRelayMsgOuter::new(None, sendme.into());
595 circ_cmds.push(CircuitCmd::Send(SendRelayCell {
596 hop: Some(hopnum),
597 early: false,
598 cell,
599 }));
600
601 self.hop_mut(hopnum)
603 .ok_or_else(|| {
604 Error::from(internal!(
605 "Trying to send SENDME to nonexistent hop {:?}",
606 hopnum
607 ))
608 })?
609 .ccontrol()
610 .note_sendme_sent()?;
611 }
612
613 let (mut msgs, incomplete) = decode_res.into_parts();
614 while let Some(msg) = msgs.next() {
615 let msg_status = self.handle_relay_msg(handlers, hopnum, leg, c_t_w, msg)?;
616
617 match msg_status {
618 None => continue,
619 Some(msg @ CircuitCmd::CleanShutdown) => {
620 for m in msgs {
621 debug!(
622 "{id}: Ignoring relay msg received after triggering shutdown: {m:?}",
623 id = self.unique_id
624 );
625 }
626 if let Some(incomplete) = incomplete {
627 debug!(
628 "{id}: Ignoring partial relay msg received after triggering shutdown: {:?}",
629 incomplete,
630 id = self.unique_id,
631 );
632 }
633 circ_cmds.push(msg);
634 return Ok(circ_cmds);
635 }
636 Some(msg) => {
637 circ_cmds.push(msg);
638 }
639 }
640 }
641
642 Ok(circ_cmds)
643 }
644
645 fn handle_relay_msg(
647 &mut self,
648 handlers: &mut CellHandlers,
649 hopnum: HopNum,
650 leg: UniqId,
651 cell_counts_toward_windows: bool,
652 msg: UnparsedRelayMsg,
653 ) -> Result<Option<CircuitCmd>> {
654 let streamid = msg_streamid(&msg)?;
657
658 let Some(streamid) = streamid else {
661 return self.handle_meta_cell(handlers, hopnum, msg);
662 };
663
664 #[cfg(feature = "conflux")]
665 let msg = if let Some(conflux) = self.conflux_handler.as_mut() {
666 match conflux.action_for_msg(hopnum, cell_counts_toward_windows, streamid, msg)? {
667 ConfluxAction::Deliver(msg) => {
668 msg
675 }
676 ConfluxAction::Enqueue(msg) => {
677 return Ok(Some(CircuitCmd::Enqueue(msg)));
679 }
680 }
681 } else {
682 msg
685 };
686
687 self.handle_in_order_relay_msg(
688 handlers,
689 hopnum,
690 leg,
691 cell_counts_toward_windows,
692 streamid,
693 msg,
694 )
695 }
696
697 pub(super) fn handle_in_order_relay_msg(
699 &mut self,
700 handlers: &mut CellHandlers,
701 hopnum: HopNum,
702 leg: UniqId,
703 cell_counts_toward_windows: bool,
704 streamid: StreamId,
705 msg: UnparsedRelayMsg,
706 ) -> Result<Option<CircuitCmd>> {
707 let now = self.runtime.now();
708
709 #[cfg(feature = "conflux")]
710 if let Some(conflux) = self.conflux_handler.as_mut() {
711 conflux.inc_last_seq_delivered(&msg);
712 }
713
714 let path = self.mutable.path();
715
716 let nonexistent_hop_err = || Error::CircProto("Cell from nonexistent hop!".into());
717 let hop = self.hop_mut(hopnum).ok_or_else(nonexistent_hop_err)?;
718
719 let hop_detail = path
720 .iter()
721 .nth(usize::from(hopnum))
722 .ok_or_else(nonexistent_hop_err)?;
723
724 let res = hop.handle_msg(hop_detail, cell_counts_toward_windows, streamid, msg, now)?;
727
728 if let Some(msg) = res {
731 cfg_if::cfg_if! {
732 if #[cfg(feature = "hs-service")] {
733 return self.handle_incoming_stream_request(handlers, msg, streamid, hopnum, leg);
734 } else {
735 return Err(internal!("incoming stream not rejected, but hs-service feature is disabled?!").into());
736 }
737 }
738 }
739
740 if let Some(cell) = hop.maybe_send_xoff(streamid)? {
742 let cell = AnyRelayMsgOuter::new(Some(streamid), cell.into());
743 let cell = SendRelayCell {
744 hop: Some(hopnum),
745 early: false,
746 cell,
747 };
748 return Ok(Some(CircuitCmd::Send(cell)));
749 }
750
751 Ok(None)
752 }
753
754 #[cfg(feature = "conflux")]
762 fn handle_conflux_msg(
763 &mut self,
764 hop: HopNum,
765 msg: UnparsedRelayMsg,
766 ) -> Result<Option<ConfluxCmd>> {
767 let Some(conflux_handler) = self.conflux_handler.as_mut() else {
768 return Err(Error::CircProto(format!(
771 "Received {} cell from hop {} on non-conflux client circuit?!",
772 msg.cmd(),
773 hop.display(),
774 )));
775 };
776
777 Ok(conflux_handler.handle_conflux_msg(msg, hop))
778 }
779
780 #[cfg(feature = "conflux")]
784 pub(super) fn last_seq_sent(&self) -> Result<u64> {
785 let handler = self
786 .conflux_handler
787 .as_ref()
788 .ok_or_else(|| internal!("tried to get last_seq_sent of non-conflux circ"))?;
789
790 Ok(handler.last_seq_sent())
791 }
792
793 #[cfg(feature = "conflux")]
797 pub(super) fn set_last_seq_sent(&mut self, n: u64) -> Result<()> {
798 let handler = self
799 .conflux_handler
800 .as_mut()
801 .ok_or_else(|| internal!("tried to get last_seq_sent of non-conflux circ"))?;
802
803 handler.set_last_seq_sent(n);
804 Ok(())
805 }
806
807 #[cfg(feature = "conflux")]
811 pub(super) fn last_seq_recv(&self) -> Result<u64> {
812 let handler = self
813 .conflux_handler
814 .as_ref()
815 .ok_or_else(|| internal!("tried to get last_seq_recv of non-conflux circ"))?;
816
817 Ok(handler.last_seq_recv())
818 }
819
820 #[cfg(feature = "hs-service")]
824 fn handle_incoming_stream_request(
825 &mut self,
826 handlers: &mut CellHandlers,
827 msg: UnparsedRelayMsg,
828 stream_id: StreamId,
829 hop_num: HopNum,
830 leg: UniqId,
831 ) -> Result<Option<CircuitCmd>> {
832 use tor_cell::relaycell::msg::EndReason;
833 use tor_error::into_internal;
834 use tor_log_ratelim::log_ratelim;
835
836 use crate::stream::incoming::StreamReqInfo;
837
838 let Some(handler) = handlers.incoming_stream_req_handler.as_mut() else {
841 return Err(Error::CircProto(
842 "Cannot handle BEGIN cells on this circuit".into(),
843 ));
844 };
845
846 let expected_hop_num = handler
848 .hop_num
849 .ok_or_else(|| internal!("Handler HopNum is None in client impl?!"))?;
850
851 if hop_num != expected_hop_num {
852 return Err(Error::CircProto(format!(
853 "Expecting incoming streams from {}, but received {} cell from unexpected hop {}",
854 expected_hop_num.display(),
855 msg.cmd(),
856 hop_num.display()
857 )));
858 }
859
860 let message_closes_stream = handler.cmd_checker.check_msg(&msg)? == StreamStatus::Closed;
861
862 let hop = self.hops.get_mut(hop_num).ok_or(Error::CircuitClosed)?;
870
871 if message_closes_stream {
872 hop.ending_msg_received(stream_id)?;
873
874 return Ok(None);
875 }
876
877 let begin = msg
878 .decode::<Begin>()
879 .map_err(|e| Error::from_bytes_err(e, "Invalid Begin message"))?
880 .into_msg();
881
882 let req = IncomingStreamRequest::Begin(begin);
883
884 {
885 use crate::stream::IncomingStreamRequestDisposition::*;
886
887 let ctx = crate::stream::IncomingStreamRequestContext { request: &req };
888 let view = CircHopSyncView::new(hop.outbound());
894
895 match handler.filter.as_mut().disposition(&ctx, &view)? {
896 Accept => {}
897 CloseCircuit => return Ok(Some(CircuitCmd::CleanShutdown)),
898 RejectRequest(end) => {
899 let end_msg = AnyRelayMsgOuter::new(Some(stream_id), end.into());
900 let cell = SendRelayCell {
901 hop: Some(hop_num),
902 early: false,
903 cell: end_msg,
904 };
905 return Ok(Some(CircuitCmd::Send(cell)));
906 }
907 }
908 }
909
910 let hop = self.hops.get_mut(hop_num).ok_or(Error::CircuitClosed)?;
913 let relay_cell_format = hop.relay_cell_format();
914
915 let memquota = StreamAccount::new(&self.memquota)?;
916
917 let cmd_checker = InboundDataCmdChecker::new_connected();
918 let stream_components = hop.add_ent_with_id(
919 self.chan_sender.time_provider(),
920 stream_id,
921 cmd_checker,
922 &memquota,
923 )?;
924
925 let outcome = Pin::new(&mut handler.incoming_sender).try_send(StreamReqInfo {
926 req,
927 stream_id,
928 hop: Some((leg, hop_num).into()),
929 stream_components,
930 memquota,
931 relay_cell_format,
932 });
933
934 log_ratelim!("Delivering message to incoming stream handler"; outcome);
935
936 if let Err(e) = outcome {
937 if e.is_full() {
938 let end_msg = AnyRelayMsgOuter::new(
942 Some(stream_id),
943 End::new_with_reason(EndReason::RESOURCELIMIT).into(),
944 );
945
946 let cell = SendRelayCell {
947 hop: Some(hop_num),
948 early: false,
949 cell: end_msg,
950 };
951 return Ok(Some(CircuitCmd::Send(cell)));
952 } else if e.is_disconnected() {
953 debug!(
965 circ_id = %self.unique_id,
966 "Incoming stream request receiver dropped",
967 );
968 return Err(Error::CircuitClosed);
970 } else {
971 return Err(Error::from((into_internal!(
975 "try_send failed unexpectedly"
976 ))(e)));
977 }
978 }
979
980 Ok(None)
981 }
982
983 #[allow(clippy::unnecessary_wraps)]
985 fn handle_destroy_cell(&mut self) -> Result<CircuitCmd> {
986 Ok(CircuitCmd::CleanShutdown)
988 }
989
990 pub(super) async fn handle_create(
992 &mut self,
993 recv_created: oneshot::Receiver<CreateResponse>,
994 handshake: CircuitHandshake,
995 settings: HopSettings,
996 done: ReactorResultChannel<()>,
997 ) -> StdResult<(), ReactorError> {
998 let ret = match handshake {
999 CircuitHandshake::CreateFast => self.create_firsthop_fast(recv_created, settings).await,
1000 CircuitHandshake::Ntor {
1001 public_key,
1002 ed_identity,
1003 } => {
1004 self.create_firsthop_ntor(recv_created, ed_identity, public_key, settings)
1005 .await
1006 }
1007 CircuitHandshake::NtorV3 { public_key } => {
1008 self.create_firsthop_ntor_v3(recv_created, public_key, settings)
1009 .await
1010 }
1011 };
1012 let _ = done.send(ret); self.chan_sender.flush().await?;
1017
1018 Ok(())
1019 }
1020
1021 async fn create_impl<H, W, M>(
1027 &mut self,
1028 recvcreated: oneshot::Receiver<CreateResponse>,
1029 wrap: &W,
1030 key: &H::KeyType,
1031 mut settings: HopSettings,
1032 msg: &M,
1033 ) -> Result<()>
1034 where
1035 H: ClientHandshake + HandshakeAuxDataHandler,
1036 W: CreateHandshakeWrap,
1037 H::KeyGen: KeyGenerator,
1038 M: Borrow<H::ClientAuxData>,
1039 {
1040 let (state, msg) = H::client1(&mut rand::rng(), key, msg)?;
1045 let create_cell = wrap.to_chanmsg(msg);
1046 trace!(
1047 circ_id = %self.unique_id,
1048 create = %create_cell.cmd(),
1049 "Extending to hop 1",
1050 );
1051 self.send_msg(create_cell, None).await?;
1052
1053 let reply = recvcreated
1054 .await
1055 .map_err(|_| Error::CircProto("Circuit closed while waiting".into()))?;
1056
1057 let relay_handshake = wrap.decode_chanmsg(reply)?;
1058 let (server_msg, keygen) = H::client2(state, relay_handshake)?;
1059
1060 H::handle_server_aux_data(&mut settings, &server_msg)?;
1061
1062 let BoxedClientLayer { fwd, back, binding } = settings
1063 .relay_crypt_protocol()
1064 .construct_client_layers(HandshakeRole::Initiator, keygen)?;
1065
1066 trace!(circ_id = %self.unique_id, "Handshake complete; circuit created.");
1067
1068 let peer_id = self.channel.target().clone();
1069
1070 self.add_hop(
1071 path::HopDetail::Relay(peer_id),
1072 fwd,
1073 back,
1074 binding,
1075 &settings,
1076 )?;
1077 Ok(())
1078 }
1079
1080 async fn create_firsthop_fast(
1087 &mut self,
1088 recvcreated: oneshot::Receiver<CreateResponse>,
1089 settings: HopSettings,
1090 ) -> Result<()> {
1091 let wrap = CreateFastWrap;
1093 self.create_impl::<CreateFastClient, _, _>(recvcreated, &wrap, &(), settings, &())
1094 .await
1095 }
1096
1097 async fn create_firsthop_ntor(
1102 &mut self,
1103 recvcreated: oneshot::Receiver<CreateResponse>,
1104 ed_identity: pk::ed25519::Ed25519Identity,
1105 pubkey: NtorPublicKey,
1106 settings: HopSettings,
1107 ) -> Result<()> {
1108 let target = RelayIds::builder()
1110 .ed_identity(ed_identity)
1111 .rsa_identity(pubkey.id)
1112 .build()
1113 .expect("Unable to build RelayIds");
1114 self.channel.check_match(&target)?;
1115
1116 let wrap = Create2Wrap {
1117 handshake_type: HandshakeType::NTOR,
1118 };
1119 self.create_impl::<NtorClient, _, _>(recvcreated, &wrap, &pubkey, settings, &())
1120 .await
1121 }
1122
1123 async fn create_firsthop_ntor_v3(
1128 &mut self,
1129 recvcreated: oneshot::Receiver<CreateResponse>,
1130 pubkey: NtorV3PublicKey,
1131 settings: HopSettings,
1132 ) -> Result<()> {
1133 let target = RelayIds::builder()
1135 .ed_identity(pubkey.id)
1136 .build()
1137 .expect("Unable to build RelayIds");
1138 self.channel.check_match(&target)?;
1139
1140 let client_extensions = settings.circuit_request_extensions()?;
1142 let wrap = Create2Wrap {
1143 handshake_type: HandshakeType::NTOR_V3,
1144 };
1145
1146 self.create_impl::<NtorV3Client, _, _>(
1147 recvcreated,
1148 &wrap,
1149 &pubkey,
1150 settings,
1151 &client_extensions,
1152 )
1153 .await
1154 }
1155
1156 pub(super) fn add_hop(
1160 &mut self,
1161 peer_id: path::HopDetail,
1162 fwd: Box<dyn OutboundClientLayer + 'static + Send>,
1163 rev: Box<dyn InboundClientLayer + 'static + Send>,
1164 binding: Option<CircuitBinding>,
1165 settings: &HopSettings,
1166 ) -> StdResult<(), Bug> {
1167 let hop_num = self.hops.len();
1168 debug_assert_eq!(hop_num, usize::from(self.num_hops()));
1169
1170 if hop_num == usize::from(u8::MAX) {
1174 return Err(internal!(
1175 "cannot add more hops to a circuit with `u8::MAX` hops"
1176 ));
1177 }
1178
1179 let hop_num = (hop_num as u8).into();
1180
1181 let hop = CircHop::new(self.unique_id, hop_num, settings);
1182 self.hops.push(hop);
1183 self.crypto_in.add_layer(rev);
1184 self.crypto_out.add_layer(fwd);
1185 self.mutable.add_hop(peer_id, binding);
1186
1187 Ok(())
1188 }
1189
1190 #[allow(clippy::cognitive_complexity)]
1206 fn handle_meta_cell(
1207 &mut self,
1208 handlers: &mut CellHandlers,
1209 hopnum: HopNum,
1210 msg: UnparsedRelayMsg,
1211 ) -> Result<Option<CircuitCmd>> {
1212 if msg.cmd() == RelayCmd::SENDME {
1222 let sendme = msg
1223 .decode::<Sendme>()
1224 .map_err(|e| Error::from_bytes_err(e, "sendme message"))?
1225 .into_msg();
1226
1227 return Ok(Some(CircuitCmd::HandleSendMe {
1228 hop: hopnum,
1229 sendme,
1230 }));
1231 }
1232 if msg.cmd() == RelayCmd::TRUNCATED {
1233 let truncated = msg
1234 .decode::<Truncated>()
1235 .map_err(|e| Error::from_bytes_err(e, "truncated message"))?
1236 .into_msg();
1237 let reason = truncated.reason();
1238 debug!(
1239 circ_id = %self.unique_id,
1240 "Truncated from hop {}. Reason: {} [{}]",
1241 hopnum.display(),
1242 reason.human_str(),
1243 reason
1244 );
1245
1246 return Ok(Some(CircuitCmd::CleanShutdown));
1247 }
1248
1249 if msg.cmd() == RelayCmd::DROP {
1250 cfg_if::cfg_if! {
1251 if #[cfg(feature = "circ-padding")] {
1252 return Ok(None);
1253 } else {
1254 use crate::util::err::ExcessPadding;
1255 return Err(Error::ExcessPadding(ExcessPadding::NoPaddingNegotiated, hopnum));
1256 }
1257 }
1258 }
1259
1260 trace!(circ_id = %self.unique_id, cell = ?msg, "Received meta-cell");
1261
1262 #[cfg(feature = "conflux")]
1263 if matches!(
1264 msg.cmd(),
1265 RelayCmd::CONFLUX_LINK
1266 | RelayCmd::CONFLUX_LINKED
1267 | RelayCmd::CONFLUX_LINKED_ACK
1268 | RelayCmd::CONFLUX_SWITCH
1269 ) {
1270 let cmd = self.handle_conflux_msg(hopnum, msg)?;
1271 return Ok(cmd.map(CircuitCmd::from));
1272 }
1273
1274 if self.is_conflux_pending() {
1275 warn!(
1276 circ_id = %self.unique_id,
1277 "received unexpected cell {msg:?} on unlinked conflux circuit",
1278 );
1279 return Err(Error::CircProto(
1280 "Received unexpected cell on unlinked circuit".into(),
1281 ));
1282 }
1283
1284 if let Some(mut handler) = handlers.meta_handler.take() {
1292 if handler.expected_hop() == (self.unique_id(), hopnum).into() {
1294 let ret = handler.handle_msg(msg, self);
1296 trace!(
1297 circ_id = %self.unique_id,
1298 result = ?ret,
1299 "meta handler completed",
1300 );
1301 match ret {
1302 #[cfg(feature = "send-control-msg")]
1303 Ok(MetaCellDisposition::Consumed) => {
1304 handlers.meta_handler = Some(handler);
1305 Ok(None)
1306 }
1307 Ok(MetaCellDisposition::ConversationFinished) => Ok(None),
1308 #[cfg(feature = "send-control-msg")]
1309 Ok(MetaCellDisposition::CloseCirc) => Ok(Some(CircuitCmd::CleanShutdown)),
1310 Err(e) => Err(e),
1311 }
1312 } else {
1313 handlers.meta_handler = Some(handler);
1316
1317 unsupported_client_cell!(msg, hopnum)
1318 }
1319 } else {
1320 unsupported_client_cell!(msg)
1323 }
1324 }
1325
1326 #[instrument(level = "trace", skip_all)]
1328 pub(super) fn handle_sendme(
1329 &mut self,
1330 hopnum: HopNum,
1331 msg: Sendme,
1332 signals: CongestionSignals,
1333 ) -> Result<Option<CircuitCmd>> {
1334 let runtime = self.runtime.clone();
1336
1337 let hop = self
1340 .hop_mut(hopnum)
1341 .ok_or_else(|| Error::CircProto(format!("Couldn't find hop {}", hopnum.display())))?;
1342
1343 let tag = msg.into_sendme_tag().ok_or_else(||
1344 Error::CircProto("missing tag on circuit sendme".into()))?;
1347 hop.ccontrol()
1349 .note_sendme_received(&runtime, tag, signals)?;
1350 Ok(None)
1351 }
1352
1353 #[instrument(level = "trace", skip_all)]
1368 async fn send_msg(
1369 &mut self,
1370 msg: AnyChanMsg,
1371 info: Option<QueuedCellPaddingInfo>,
1372 ) -> Result<()> {
1373 let cell = AnyChanCell::new(Some(self.channel_id), msg);
1374 Pin::new(&mut self.chan_sender)
1376 .send_unbounded((cell, info))
1377 .await?;
1378 Ok(())
1379 }
1380
1381 pub(super) fn remove_expired_halfstreams(&mut self, now: Instant) {
1383 self.hops.remove_expired_halfstreams(now);
1384 }
1385
1386 pub(super) fn hop(&self, hopnum: HopNum) -> Option<&CircHop> {
1388 self.hops.hop(hopnum)
1389 }
1390
1391 pub(super) fn hop_mut(&mut self, hopnum: HopNum) -> Option<&mut CircHop> {
1393 self.hops.get_mut(hopnum)
1394 }
1395
1396 #[allow(clippy::too_many_arguments)]
1399 pub(super) fn begin_stream(
1400 &mut self,
1401 hop_num: HopNum,
1402 message: AnyRelayMsg,
1403 time_prov: &DynTimeProvider,
1404 cmd_checker: AnyCmdChecker,
1405 memquota: &StreamAccount,
1406 ) -> Result<(SendRelayCell, StreamId, ReactorStreamComponents)> {
1407 let Some(hop) = self.hop_mut(hop_num) else {
1408 return Err(internal!(
1409 "{}: Attempting to send a BEGIN cell to an unknown hop {hop_num:?}",
1410 self.unique_id,
1411 )
1412 .into());
1413 };
1414
1415 hop.begin_stream(message, time_prov, cmd_checker, memquota)
1416 }
1417
1418 #[instrument(level = "trace", skip_all)]
1420 pub(super) async fn close_stream(
1421 &mut self,
1422 hop_num: HopNum,
1423 sid: StreamId,
1424 behav: CloseStreamBehavior,
1425 reason: streammap::TerminateReason,
1426 expiry: Instant,
1427 ) -> Result<()> {
1428 if let Some(hop) = self.hop_mut(hop_num) {
1429 let res = hop.close_stream(sid, behav, reason, expiry)?;
1430 if let Some(cell) = res {
1431 self.send_relay_cell(cell).await?;
1432 }
1433 }
1434 Ok(())
1435 }
1436
1437 pub(super) fn has_streams(&self) -> bool {
1443 self.hops.has_streams()
1444 }
1445
1446 pub(super) fn num_hops(&self) -> u8 {
1448 self.hops
1453 .len()
1454 .try_into()
1455 .expect("`hops.len()` has more than `u8::MAX` hops")
1456 }
1457
1458 pub(super) fn has_hops(&self) -> bool {
1460 !self.hops.is_empty()
1461 }
1462
1463 pub(super) fn last_hop_num(&self) -> Option<HopNum> {
1467 let num_hops = self.num_hops();
1468 if num_hops == 0 {
1469 return None;
1471 }
1472 Some(HopNum::from(num_hops - 1))
1473 }
1474
1475 pub(super) fn path(&self) -> Arc<path::Path> {
1479 self.mutable.path()
1480 }
1481
1482 pub(super) fn clock_skew(&self) -> ClockSkew {
1485 self.channel.clock_skew()
1486 }
1487
1488 pub(super) fn uses_stream_sendme(&self, hop: HopNum) -> Option<bool> {
1492 let hop = self.hop(hop)?;
1493 Some(hop.ccontrol().uses_stream_sendme())
1494 }
1495
1496 pub(super) fn is_conflux_pending(&self) -> bool {
1498 let Some(status) = self.conflux_status() else {
1499 return false;
1500 };
1501
1502 status != ConfluxStatus::Linked
1503 }
1504
1505 pub(super) fn conflux_status(&self) -> Option<ConfluxStatus> {
1509 cfg_if::cfg_if! {
1510 if #[cfg(feature = "conflux")] {
1511 self.conflux_handler
1512 .as_ref()
1513 .map(|handler| handler.status())
1514 } else {
1515 None
1516 }
1517 }
1518 }
1519
1520 #[cfg(feature = "conflux")]
1522 pub(super) fn init_rtt(&self) -> Option<Duration> {
1523 self.conflux_handler
1524 .as_ref()
1525 .map(|handler| handler.init_rtt())?
1526 }
1527
1528 #[cfg(feature = "circ-padding-manual")]
1534 pub(super) fn set_padding_at_hop(
1535 &self,
1536 hop: HopNum,
1537 padder: Option<padding::CircuitPadder>,
1538 ) -> Result<()> {
1539 if self.hop(hop).is_none() {
1540 return Err(Error::NoSuchHop);
1541 }
1542 self.padding_ctrl.install_padder_padding_at_hop(hop, padder);
1543 Ok(())
1544 }
1545
1546 #[cfg(feature = "circ-padding")]
1555 fn padding_disposition(&self, send_padding: &padding::SendPadding) -> CircPaddingDisposition {
1556 crate::circuit::padding::padding_disposition(
1557 send_padding,
1558 &self.chan_sender,
1559 self.padding_block.as_ref(),
1560 )
1561 }
1562
1563 #[cfg(feature = "circ-padding")]
1565 pub(super) async fn send_padding(&mut self, send_padding: padding::SendPadding) -> Result<()> {
1566 use CircPaddingDisposition::*;
1567
1568 let target_hop = send_padding.hop;
1569
1570 match self.padding_disposition(&send_padding) {
1571 QueuePaddingNormally => {
1572 let queue_info = self.padding_ctrl.queued_padding(target_hop, send_padding);
1573 self.queue_padding_cell_for_hop(target_hop, queue_info)
1574 .await?;
1575 }
1576 QueuePaddingAndBypass => {
1577 let queue_info = self.padding_ctrl.queued_padding(target_hop, send_padding);
1578 self.queue_padding_cell_for_hop(target_hop, queue_info)
1579 .await?;
1580 }
1581 TreatQueuedCellAsPadding => {
1582 self.padding_ctrl
1583 .replaceable_padding_already_queued(target_hop, send_padding);
1584 }
1585 }
1586 Ok(())
1587 }
1588
1589 #[cfg(feature = "circ-padding")]
1593 async fn queue_padding_cell_for_hop(
1594 &mut self,
1595 target_hop: HopNum,
1596 queue_info: Option<QueuedCellPaddingInfo>,
1597 ) -> Result<()> {
1598 use tor_cell::relaycell::msg::Drop as DropMsg;
1599 let msg = SendRelayCell {
1600 hop: Some(target_hop),
1601 early: false,
1603 cell: AnyRelayMsgOuter::new(None, DropMsg::default().into()),
1604 };
1605 self.send_relay_cell_inner(msg, queue_info).await
1606 }
1607
1608 #[cfg(feature = "circ-padding")]
1611 pub(super) fn start_blocking_for_padding(&mut self, block: padding::StartBlocking) {
1612 self.chan_sender.start_blocking();
1613 self.padding_block = Some(block);
1614 }
1615
1616 #[cfg(feature = "circ-padding")]
1618 pub(super) fn stop_blocking_for_padding(&mut self) {
1619 self.chan_sender.stop_blocking();
1620 self.padding_block = None;
1621 }
1622
1623 pub(super) fn estimate_cbt(&self, length: usize) -> Duration {
1625 self.timeouts.circuit_build_timeout(length)
1626 }
1627}
1628
1629impl Drop for Circuit {
1630 fn drop(&mut self) {
1631 let _ = self.channel.close_circuit(self.channel_id);
1632 }
1633}