tor-proto: Use UnparsedRelayCell to start deferring cell processing.

In general, we want to avoid parsing these cells until we are
fairly sure that they are something we would accept.
This commit is contained in:
Nick Mathewson 2023-02-13 14:50:26 -05:00
parent e4bc7ef57b
commit 0765243f5e
2 changed files with 45 additions and 24 deletions

View File

@ -16,7 +16,7 @@ use std::marker::PhantomData;
use std::pin::Pin;
use tor_cell::chancell::msg::{AnyChanMsg, Relay};
use tor_cell::relaycell::msg::{AnyRelayMsg, End, Sendme};
use tor_cell::relaycell::{AnyRelayCell, RelayCmd, RelayMsg, StreamId};
use tor_cell::relaycell::{AnyRelayCell, RelayCmd, RelayMsg, StreamId, UnparsedRelayCell};
use futures::channel::{mpsc, oneshot};
use futures::Sink;
@ -822,7 +822,13 @@ impl Reactor {
}
/// Handle a RELAY cell on this circuit with stream ID 0.
fn handle_meta_cell(&mut self, hopnum: HopNum, msg: AnyRelayMsg) -> Result<CellStatus> {
fn handle_meta_cell(&mut self, hopnum: HopNum, msg: UnparsedRelayCell) -> Result<CellStatus> {
// XXXX: Defer this even further.
let (_, msg) = msg
.decode::<AnyRelayMsg>()
.map_err(|e| Error::from_bytes_err(e, "relay meta cell"))?
.into_streamid_and_msg();
// SENDME cells and TRUNCATED get handled internally by the circuit.
if let AnyRelayMsg::Sendme(s) = msg {
return self.handle_sendme(hopnum, s);
@ -976,7 +982,7 @@ impl Reactor {
early: bool,
cell: AnyRelayCell,
) -> Result<()> {
let c_t_w = sendme::cell_counts_towards_windows(&cell);
let c_t_w = sendme::cmd_counts_towards_windows(cell.cmd());
let stream_id = cell.stream_id();
// Check whether the hop send window is empty, if this cell counts towards windows.
// NOTE(eta): It is imperative this happens *before* calling encrypt() below, otherwise
@ -1241,9 +1247,8 @@ impl Reactor {
tag_copy.copy_from_slice(tag);
tag_copy
};
// Decode the cell.
let msg = AnyRelayCell::decode(body.into())
.map_err(|e| Error::from_bytes_err(e, "relay cell"))?;
// Put the cell into a format where we can make sense of it.
let msg = UnparsedRelayCell::from_body(body.into());
let c_t_w = sendme::cell_counts_towards_windows(&msg);
@ -1277,12 +1282,11 @@ impl Reactor {
.put();
}
// Break the message apart into its streamID and message.
let (streamid, msg) = msg.into_streamid_and_msg();
// If this cell wants/refuses to have a Stream ID, does it
// have/not have one?
if !msg.cmd().accepts_streamid_val(streamid) {
let cmd = msg.cmd();
let streamid = msg.stream_id();
if !cmd.accepts_streamid_val(streamid) {
return Err(Error::CircProto(format!(
"Invalid stream ID {} for relay command {}",
sv(streamid),
@ -1309,6 +1313,12 @@ impl Reactor {
}) => {
// The stream for this message exists, and is open.
// XXXX: Defer this decoding even further.
let (_, msg) = msg
.decode::<AnyRelayMsg>()
.map_err(|e| Error::from_bytes_err(e, "relay stream cell"))?
.into_streamid_and_msg();
if let AnyRelayMsg::Sendme(_) = msg {
// We need to handle sendmes here, not in the stream's
// recv() method, or else we'd never notice them if the
@ -1354,6 +1364,12 @@ impl Reactor {
Some(StreamEnt::EndSent(halfstream)) => {
// We sent an end but maybe the other side hasn't heard.
// XXXX: Defer this decoding even further.
let (_, msg) = msg
.decode::<AnyRelayMsg>()
.map_err(|e| Error::from_bytes_err(e, "relay half-stream cell"))?
.into_streamid_and_msg();
if matches!(msg, AnyRelayMsg::End(_)) {
hop.map.end_received(streamid)?;
} else {
@ -1361,7 +1377,7 @@ impl Reactor {
}
}
_ => {
// No stream wants this message.
// No stream wants this message, or ever did.
return Err(Error::CircProto(
"Cell received on nonexistent stream!?".into(),
));

View File

@ -12,8 +12,8 @@
use std::collections::VecDeque;
use tor_cell::relaycell::msg::AnyRelayMsg;
use tor_cell::relaycell::AnyRelayCell;
use tor_cell::relaycell::{msg::AnyRelayMsg, UnparsedRelayCell};
use tor_cell::relaycell::{RelayCmd, RelayMsg};
use tor_error::internal;
use crate::{Error, Result};
@ -267,14 +267,19 @@ impl<P: WindowParams> RecvWindow<P> {
}
}
/// Return true if this message is counted by flow-control windows.
pub(crate) fn msg_counts_towards_windows(msg: &AnyRelayMsg) -> bool {
matches!(msg, AnyRelayMsg::Data(_))
/// Return true if this message type is counted by flow-control windows.
pub(crate) fn cmd_counts_towards_windows(cmd: RelayCmd) -> bool {
cmd == RelayCmd::DATA
}
/// Return true if this message is counted by flow-control windows.
pub(crate) fn cell_counts_towards_windows(cell: &AnyRelayCell) -> bool {
msg_counts_towards_windows(cell.msg())
pub(crate) fn msg_counts_towards_windows(msg: &AnyRelayMsg) -> bool {
cmd_counts_towards_windows(msg.cmd())
}
/// Return true if this message is counted by flow-control windows.
pub(crate) fn cell_counts_towards_windows(cell: &UnparsedRelayCell) -> bool {
cmd_counts_towards_windows(cell.cmd())
}
#[cfg(test)]
@ -290,24 +295,24 @@ mod test {
#![allow(clippy::unchecked_duration_subtraction)]
//! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
use super::*;
use tor_basic_utils::test_rng::testing_rng;
use tor_cell::relaycell::{msg, AnyRelayCell};
#[test]
fn what_counts() {
let mut rng = testing_rng();
let m = msg::Begin::new("www.torproject.org", 443, 0)
.unwrap()
.into();
assert!(!msg_counts_towards_windows(&m));
assert!(!cell_counts_towards_windows(&AnyRelayCell::new(
77.into(),
m
assert!(!cell_counts_towards_windows(&UnparsedRelayCell::from_body(
AnyRelayCell::new(77.into(), m).encode(&mut rng).unwrap()
)));
let m = msg::Data::new(&b"Education is not a prerequisite to political control-political control is the cause of popular education."[..]).unwrap().into(); // Du Bois
assert!(msg_counts_towards_windows(&m));
assert!(cell_counts_towards_windows(&AnyRelayCell::new(
128.into(),
m
assert!(cell_counts_towards_windows(&UnparsedRelayCell::from_body(
AnyRelayCell::new(128.into(), m).encode(&mut rng).unwrap()
)));
}