Simple functions to send and receive relay cells.

This commit is contained in:
Nick Mathewson 2020-09-12 16:25:10 -04:00
parent 3e342a69ae
commit d1039dda9b
5 changed files with 77 additions and 3 deletions

5
TODO
View File

@ -10,16 +10,17 @@ MILESTONE 0: Build a circuit and use it -- minimum to share inside tor
o Pick random relays o Pick random relays
o Construct a one-hop circuit with CREATE_FAST o Construct a one-hop circuit with CREATE_FAST
o Construct a one-hop circuit with ntor o Construct a one-hop circuit with ntor
- Build relay cells o Build relay cells
- Construct a multihop circuit. - Construct a multihop circuit.
- Open a stream - Open a stream
- Make a request, get a response (no sendmes yet) - Make a request, get a response (no sendmes yet)
MILESTONE 1: Refactoring on above -- minimum to share outside tor MILESTONE 1: Refactoring on above -- minimum to share outside tor
- Stop parameterizing all APIs on TLS type. - Stop parameterizing all APIs on TLS type.
- Less copying, esp around Box<RawCellBody>. Consider bytes crate.
- Is this "reactor" business a sensible design? Is there a better one? - Is this "reactor" business a sensible design? Is there a better one?
- Combine "create circuit" and "first hop"? - Combine "create circuit" and "first hop"?
- Improve testing, - Improve testing
- Improve documentation - Improve documentation
- More types of circent for clarity. - More types of circent for clarity.
- Make sure readme is right - Make sure readme is right

View File

@ -357,8 +357,22 @@ impl Readable for Created2 {
/// XXXX. /// XXXX.
#[derive(Clone)] #[derive(Clone)]
pub struct Relay { pub struct Relay {
// XXXX either this shouldn't be boxed, or RelayCellBody should be boxed!
body: Box<RawCellBody>, body: Box<RawCellBody>,
} }
impl Relay {
/// Construct a Relay message from its body.
pub fn from_raw(body: RawCellBody) -> Self {
Relay {
body: Box::new(body),
}
}
/// Consume this Relay message and return a RelayCellBody for
/// encryption/decryption.
pub fn into_relay_cell(self) -> crate::crypto::cell::RelayCellBody {
(*self.body).into()
}
}
impl std::fmt::Debug for Relay { impl std::fmt::Debug for Relay {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Relay").finish() f.debug_struct("Relay").finish()

View File

@ -1,19 +1,21 @@
//! Multi-hop paths over the Tor network. //! Multi-hop paths over the Tor network.
use crate::chancell::{ use crate::chancell::{
self,
msg::{self, ChanMsg}, msg::{self, ChanMsg},
ChanCell, CircID, ChanCell, CircID,
}; };
use crate::channel::Channel; use crate::channel::Channel;
use crate::crypto::cell::{ClientLayer, CryptInit}; use crate::crypto::cell::{ClientLayer, CryptInit};
use crate::crypto::handshake::{ClientHandshake, KeyGenerator}; use crate::crypto::handshake::{ClientHandshake, KeyGenerator};
use crate::relaycell::msg::RelayCell;
use crate::{Error, Result}; use crate::{Error, Result};
use futures::channel::mpsc; use futures::channel::mpsc;
use futures::io::{AsyncRead, AsyncWrite}; use futures::io::{AsyncRead, AsyncWrite};
use futures::stream::StreamExt; use futures::stream::StreamExt;
use rand::{CryptoRng, Rng}; use rand::{thread_rng, CryptoRng, Rng};
use crate::crypto::cell::ClientCrypt; use crate::crypto::cell::ClientCrypt;
@ -65,6 +67,53 @@ where
self.input.next().await.ok_or(Error::CircuitClosed) self.input.next().await.ok_or(Error::CircuitClosed)
} }
/// Encode the message `msg`, encrypt it, and send it to the 'hop'th hop.
///
/// TODO: This is not a good long-term API. It should become private
/// if we keep it.
///
/// TODO: use HopNum
pub async fn send_relay_cell(&mut self, hop: u8, early: bool, cell: RelayCell) -> Result<()> {
assert!((hop as usize) < self.crypto.n_layers());
let mut body = cell.encode(&mut thread_rng())?;
self.crypto.encrypt(&mut body, hop)?;
let msg = chancell::msg::Relay::from_raw(body.into());
let msg = if early {
ChanMsg::RelayEarly(msg)
} else {
ChanMsg::Relay(msg)
};
self.send_msg(msg).await?;
Ok(())
}
/// Receive a message from the circuit, decrypt it, and return it as a
/// RelayCell.
///
/// TODO: This is not a good long-term API. It should become private
/// if we keep it.
///
/// TODO: use HopNum
pub async fn recv_relay_cell(&mut self) -> Result<(u8, RelayCell)> {
let chanmsg = self.read_msg().await?;
let body = match chanmsg {
ChanMsg::Relay(r) => r,
_ => {
return Err(Error::ChanProto(format!(
"{} cell received on circuit",
chanmsg.get_cmd()
)))
}
};
// Decrypt, if possible.
let mut cell = body.into_relay_cell();
let hopnum = self.crypto.decrypt(&mut cell)?;
let msg = RelayCell::decode(cell)?;
Ok((hopnum, msg))
}
/// Helper: create the first hop of a circuit. /// Helper: create the first hop of a circuit.
/// ///
/// This is parameterized not just on the RNG, but a wrapper object to /// This is parameterized not just on the RNG, but a wrapper object to

View File

@ -124,6 +124,8 @@ impl ClientCrypt {
} }
/// Return the number of layers configured on this ClientCrypt. /// Return the number of layers configured on this ClientCrypt.
///
/// TODO: use HopNum
pub fn n_layers(&self) -> usize { pub fn n_layers(&self) -> usize {
self.layers.len() self.layers.len()
} }

View File

@ -73,6 +73,14 @@ impl RelayCell {
/// ///
/// Requires that the cryptographic checks on the message have already been /// Requires that the cryptographic checks on the message have already been
/// performed /// performed
pub fn decode(body: RelayCellBody) -> Result<Self> {
let mut reader = Reader::from_slice(body.as_ref());
RelayCell::decode_from_reader(&mut reader)
}
/// Parse a RELAY or RELAY_EARLY cell body into a RelayCell from a reader.
///
/// Requires that the cryptographic checks on the message have already been
/// performed
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> { fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let cmd = r.take_u8()?.into(); let cmd = r.take_u8()?.into();
r.advance(2)?; // "recognized" r.advance(2)?; // "recognized"