channel padding: Send negotiation cells

This commit is contained in:
Ian Jackson 2022-08-02 12:48:39 +01:00
parent 0a1bffb047
commit 50ca64218e
6 changed files with 69 additions and 9 deletions

1
Cargo.lock generated
View File

@ -3476,6 +3476,7 @@ dependencies = [
"serde", "serde",
"thiserror", "thiserror",
"tor-basic-utils", "tor-basic-utils",
"tor-cell",
"tor-config", "tor-config",
"tor-error", "tor-error",
"tor-linkspec", "tor-linkspec",

View File

@ -25,6 +25,7 @@ rand = "0.8"
serde = { version = "1.0.103", features = ["derive"] } serde = { version = "1.0.103", features = ["derive"] }
thiserror = "1" thiserror = "1"
tor-basic-utils = { path = "../tor-basic-utils", version = "0.3.3" } tor-basic-utils = { path = "../tor-basic-utils", version = "0.3.3" }
tor-cell = { path = "../tor-cell", version = "0.5.0" }
tor-config = { path = "../tor-config", version = "0.5.0" } tor-config = { path = "../tor-config", version = "0.5.0" }
tor-error = { path = "../tor-error", version = "0.3.2" } tor-error = { path = "../tor-error", version = "0.3.2" }
tor-linkspec = { path = "../tor-linkspec", version = "0.4.0" } tor-linkspec = { path = "../tor-linkspec", version = "0.4.0" }

View File

@ -8,6 +8,7 @@ use crate::{ChannelConfig, Dormancy, Error, Result};
use std::collections::{hash_map, HashMap}; use std::collections::{hash_map, HashMap};
use std::result::Result as StdResult; use std::result::Result as StdResult;
use std::sync::Arc; use std::sync::Arc;
use tor_cell::chancell::msg::PaddingNegotiate;
use tor_config::PaddingLevel; use tor_config::PaddingLevel;
use tor_error::{internal, into_internal}; use tor_error::{internal, into_internal};
use tor_netdir::{params::CHANNEL_PADDING_TIMEOUT_UPPER_BOUND, NetDir}; use tor_netdir::{params::CHANNEL_PADDING_TIMEOUT_UPPER_BOUND, NetDir};
@ -337,8 +338,6 @@ impl<C: AbstractChannel> ChannelMap<C> {
netdir: tor_netdir::Result<Arc<NetDir>>, netdir: tor_netdir::Result<Arc<NetDir>>,
) -> StdResult<(), tor_error::Bug> { ) -> StdResult<(), tor_error::Bug> {
use ChannelState as CS; use ChannelState as CS;
// TODO when entering/leaving dormant mode, send CELL_PADDING_NEGOTIATE to peers
// TODO with reduced padding, send CELL_PADDING_NEGOTIATE
// TODO when we support operation as a relay, inter-relay channels ought // TODO when we support operation as a relay, inter-relay channels ought
// not to get padding. // not to get padding.
@ -423,16 +422,61 @@ fn parameterize(
dormancy: Dormancy, dormancy: Dormancy,
netdir: StdResult<&NetDirExtract, &()>, netdir: StdResult<&NetDirExtract, &()>,
) -> StdResult<Option<ChannelsParamsUpdates>, tor_error::Bug> { ) -> StdResult<Option<ChannelsParamsUpdates>, tor_error::Bug> {
let padding_parameters = padding_parameters(config.padding, netdir)?; // Everything in this calculation applies to *all* channels, disregarding
// channel usage. Usage is handled downstream, in the channel frontend.
// See the module doc in `crates/tor-proto/src/channel/padding.rs`.
let padding_of_level = |level| padding_parameters(level, netdir);
let padding_parameters = padding_of_level(config.padding)?;
let padding_default = padding_of_level(PaddingLevel::default())?;
let send_padding = (match dormancy { let send_padding = (match dormancy {
Dormancy::Active => true, Dormancy::Active => true,
Dormancy::Dormant => false, Dormancy::Dormant => false,
}) && padding_parameters != PaddingParameters::all_zeroes(); }) && padding_parameters != PaddingParameters::all_zeroes();
let recv_padding = match config.padding {
PaddingLevel::Reduced => false,
PaddingLevel::Normal => send_padding,
PaddingLevel::None => false,
};
// Whether the inbound padding approach we are to use, is the same as the default
// derived from the netdir (disregarding our config and dormancy).
//
// Ie, whether the parameters we want are precisely those that a peer would
// use by default (assuming they have the same view of the netdir as us).
let recv_equals_default = if padding_default == PaddingParameters::all_zeroes() {
// The netdir has padding disabled by setting the parameters to zero.
// That means our peers won't do padding unless we ask it to.
// Or to put it another way, our desired peer padding approach is the same as our
// peers' default iff we also think padding should be disabled.
!recv_padding
} else {
// Peers are going to do padding. That is the same approach as we want
// if we want to receive padding, with the same parameters.
recv_padding && padding_parameters == padding_default
};
let padding_negotiate = if recv_equals_default {
// Our padding approach is the same as peers' defaults. So the PADDING_NEGOTIATE
// message we need to send is the START(0,0). (The channel frontend elides an
// initial message of this form, - see crates/tor-proto/src/channel.rs::note_usage.)
//p
// If the netdir default is no padding, and we previously negotiated
// padding being enabled, and now want to disable it, we would send
// START(0,0) rather than STOP. That is OK (even, arguably, right).
PaddingNegotiate::start_default()
} else if !recv_padding {
PaddingNegotiate::stop()
} else {
padding_parameters.padding_negotiate_cell()?
};
let mut update = channels_params let mut update = channels_params
.start_update() .start_update()
.padding_enable(send_padding); .padding_enable(send_padding)
.padding_negotiate(padding_negotiate);
if send_padding { if send_padding {
update = update.padding_parameters(padding_parameters); update = update.padding_parameters(padding_parameters);
} }
@ -721,7 +765,8 @@ mod test {
"ChannelsParamsUpdates { padding_enable: None, \ "ChannelsParamsUpdates { padding_enable: None, \
padding_parameters: Some(Parameters { \ padding_parameters: Some(Parameters { \
low_ms: IntegerMilliseconds { value: 1500 }, \ low_ms: IntegerMilliseconds { value: 1500 }, \
high_ms: IntegerMilliseconds { value: 9500 } }) }" high_ms: IntegerMilliseconds { value: 9500 } }), \
padding_negotiate: None }"
); );
}); });
eprintln!(); eprintln!();

View File

@ -75,7 +75,7 @@ use crate::{Error, Result};
use std::pin::Pin; use std::pin::Pin;
use std::sync::{Mutex, MutexGuard}; use std::sync::{Mutex, MutexGuard};
use std::time::Duration; use std::time::Duration;
use tor_cell::chancell::{msg, ChanCell, CircId}; use tor_cell::chancell::{msg, msg::PaddingNegotiate, ChanCell, CircId};
use tor_error::internal; use tor_error::internal;
use tor_linkspec::{HasRelayIds, OwnedChanTarget}; use tor_linkspec::{HasRelayIds, OwnedChanTarget};
use tor_rtcompat::SleepProvider; use tor_rtcompat::SleepProvider;
@ -212,8 +212,6 @@ enum PaddingControlState {
/// (which is fine since this timer is not enabled). /// (which is fine since this timer is not enabled).
/// * We don't send any PADDING_NEGOTIATE cells. The peer is supposed to come to the /// * We don't send any PADDING_NEGOTIATE cells. The peer is supposed to come to the
/// same conclusions as us, based on channel usage: it should also not send padding. /// same conclusions as us, based on channel usage: it should also not send padding.
/// (Note: sending negotiation cells is not yet done at this point in the branch,
/// but it will be organised via `ChannelsParamsUpdates`.)
#[educe(Default)] #[educe(Default)]
UsageDoesNotImplyPadding { UsageDoesNotImplyPadding {
/// The last padding parameters (from reparameterize) /// The last padding parameters (from reparameterize)
@ -448,7 +446,13 @@ impl Channel {
// Well, apparently the channel usage *does* imply padding now, // Well, apparently the channel usage *does* imply padding now,
// so we need to (belatedly) enable the timer, // so we need to (belatedly) enable the timer,
// send the padding negotiation cell, etc. // send the padding negotiation cell, etc.
let params = params.clone(); let mut params = params.clone();
// Except, maybe the padding we would be requesting is precisely default,
// so we wouldn't actually want to send that cell.
if params.padding_negotiate == Some(PaddingNegotiate::start_default()) {
params.padding_negotiate = None;
}
match self.send_control(CtrlMsg::ConfigUpdate(Arc::new(params))) { match self.send_control(CtrlMsg::ConfigUpdate(Arc::new(params))) {
Ok(()) => {} Ok(()) => {}

View File

@ -2,6 +2,8 @@
use educe::Educe; use educe::Educe;
use tor_cell::chancell::msg::PaddingNegotiate;
use super::padding; use super::padding;
/// Generate most of the module: things which contain or process all params fields (or each one) /// Generate most of the module: things which contain or process all params fields (or each one)
@ -133,6 +135,9 @@ define_channels_params_and_automatic_impls! {
/// rather than the parameters changing, /// rather than the parameters changing,
/// so the padding timer always keeps parameters, even when disabled. /// so the padding timer always keeps parameters, even when disabled.
padding_parameters: padding::Parameters, padding_parameters: padding::Parameters,
/// Channel padding negotiation cell
padding_negotiate: PaddingNegotiate,
} }
/// Placeholder function for saying whether to enable channel padding /// Placeholder function for saying whether to enable channel padding

View File

@ -263,6 +263,7 @@ impl<S: SleepProvider> Reactor<S> {
// if one is added and we fail to handle it here. // if one is added and we fail to handle it here.
padding_enable, padding_enable,
padding_parameters, padding_parameters,
padding_negotiate,
} = &*updates; } = &*updates;
if let Some(parameters) = padding_parameters { if let Some(parameters) = padding_parameters {
self.padding_timer.as_mut().reconfigure(parameters); self.padding_timer.as_mut().reconfigure(parameters);
@ -274,6 +275,9 @@ impl<S: SleepProvider> Reactor<S> {
self.padding_timer.as_mut().disable(); self.padding_timer.as_mut().disable();
} }
} }
if let Some(padding_negotiate) = padding_negotiate {
self.special_outgoing.padding_negotiate = Some(padding_negotiate.clone());
}
} }
} }
Ok(()) Ok(())