Skip to main content

tor_proto/circuit/
padding.rs

1//! Circuit padding
2//!
3// TODO(DEDUP): we should eventually move client::circuit::padding here
4
5#[cfg(feature = "circ-padding")]
6use {crate::circuit::cell_sender::CircuitCellSender, crate::client::circuit::padding};
7
8/// A possible way to handle a request to send padding.
9#[derive(Copy, Clone, Debug)]
10pub(crate) enum CircPaddingDisposition {
11    /// Enqueue the padding normally.
12    QueuePaddingNormally,
13    /// Enqueue the padding, and allow one cell of data on our outbound queue
14    /// to bypass the current block.
15    QueuePaddingAndBypass,
16    /// Do not take any actual padding action:
17    /// existing data on our outbound queue will count as padding.
18    TreatQueuedCellAsPadding,
19}
20
21/// Determine how exactly to handle a request to handle padding.
22///
23/// This is fairly complicated; see the maybenot documentation for more information.
24///
25// TODO(relay): relays use the same logic as clients here. Is that okay,
26// or do they need to handle SendPadding differently??
27#[cfg(feature = "circ-padding")]
28pub(crate) fn padding_disposition(
29    send_padding: &padding::SendPadding,
30    chan_sender: &CircuitCellSender,
31    padding_block: Option<&padding::StartBlocking>,
32) -> CircPaddingDisposition {
33    use CircPaddingDisposition::*;
34    use padding::Bypass::*;
35    use padding::Replace::*;
36
37    // If true, and we are trying to send Replaceable padding,
38    // we should let any data in the queue count as the queued padding instead,
39    // if it is queued for our target hop (or any subsequent hop).
40    //
41    // TODO circpad: In addition to letting currently-queued data count as padding,
42    // maybenot also permits us to send currently pending data from our streams
43    // (or from our next hop, if we're a relay).  We don't have that implemented yet.
44    //
45    // TODO circpad: This will usually be false, since we try not to queue data
46    // when there isn't space to write it.  If we someday add internal per-circuit
47    // Buffers to chan_sender, this test is more likely to trigger.
48    let have_queued_cell_for_hop = chan_sender.have_queued_cell_for_hop_or_later(send_padding.hop);
49
50    match padding_block {
51        Some(blocking) if blocking.is_bypassable => {
52            match (
53                send_padding.may_replace_with_data(),
54                send_padding.may_bypass_block(),
55            ) {
56                (NotReplaceable, DoNotBypass) => QueuePaddingNormally,
57                (NotReplaceable, BypassBlocking) => QueuePaddingAndBypass,
58                (Replaceable, DoNotBypass) => {
59                    if have_queued_cell_for_hop {
60                        TreatQueuedCellAsPadding
61                    } else {
62                        QueuePaddingNormally
63                    }
64                }
65                (Replaceable, BypassBlocking) => {
66                    if have_queued_cell_for_hop {
67                        TreatQueuedCellAsPadding
68                    } else {
69                        QueuePaddingAndBypass
70                    }
71                }
72            }
73        }
74        Some(_) | None => match send_padding.may_replace_with_data() {
75            Replaceable => {
76                if have_queued_cell_for_hop {
77                    TreatQueuedCellAsPadding
78                } else {
79                    QueuePaddingNormally
80                }
81            }
82            NotReplaceable => QueuePaddingNormally,
83        },
84    }
85}