proto: major refactor to channel cells

The protocol is now based around a message-oriented scheme intended
to use futures_codec, which in turn uses BytesMut.  The transition
to BytesMut is incomplete, and we're not nearly so zero-copy as
intended.  We should think about that.
This commit is contained in:
Nick Mathewson 2020-09-06 16:00:14 -04:00
parent 8db525dab4
commit e749e2bc27
8 changed files with 832 additions and 758 deletions

View File

@ -25,6 +25,8 @@ zeroize = "1.1.0"
subtle = "2.2.3"
stream-cipher = "0.7.1"
sha2 = "0.9.1"
futures_codec = "*"
bytes = "*"
[dev-dependencies]
hex-literal = "0.3.1"

163
tor-proto/src/chancell.rs Normal file
View File

@ -0,0 +1,163 @@
//! Messages sent over Tor channels
//!
//! A 'channel' is a direct connection between a tor client and a
//! relay, or between two relays. Current channels all use TLS.
//!
//! This module implements the "cell" type, which is the encoding for
//! data sent over a channel. It also encodes and decodes various
//! channel messages, which are the types of data conveyed over a
//! channel.
#![allow(missing_docs)]
pub mod codec;
pub mod msg;
use bytes;
use caret::caret_int;
/// The amount of data sent in a fixed-length cell.
///
/// Historically, this was set at 509 bytes so that cells would be
/// 512 bytes long once commands and circuit IDs were added. But now
/// circuit IDs are longer, so cells are 514 bytes.
pub const CELL_DATA_LEN: usize = 509;
/// Channel-local identifier for a circuit.
///
/// A circuit ID can be 2 or 4 bytes long; on modern versions of the Tor
/// protocol, it's 4 bytes long.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct CircID(u32);
impl From<u32> for CircID {
fn from(item: u32) -> Self {
Self(item)
}
}
impl Into<u32> for CircID {
fn into(self) -> u32 {
self.0
}
}
caret_int! {
/// A ChanCmd is the type of a channel cell. The value of the ChanCmd
/// indicates the meaning of the cell, and (possibly) its length.
pub struct ChanCmd(u8) {
/// A fixed-length cell that will be dropped.
PADDING = 0,
/// Create a new circuit (obsolete format)
CREATE = 1,
/// Finish circuit-creation handshake (obsolete format)
CREATED = 2,
/// Relay cell, transmitted over a circuit.
RELAY = 3,
/// Destroy a circuit
DESTROY = 4,
/// Create a new circuit (no public-key)
CREATE_FAST = 5,
/// Finish a circuit-creation handshake (no public-key)
CREATED_FAST = 6,
// note gap in numbering: 7 is grouped with the variable-length cells
/// Finish a channel handshake with time and address information
NETINFO = 8,
/// Relay cellm transmitted over a circuit. Limited.
RELAY_EARLY = 9,
/// Create a new circuit (current format)
CREATE2 = 10,
/// Finish a circuit-creation handshake (current format)
CREATED2 = 11,
/// Adjust channel-padding settings
PADDING_NEGOTIATE = 12,
/// Variable-length cell, despite its number: negotiate versions
VERSIONS = 7,
/// Variable-length channel-padding cell
VPADDING = 128,
/// Provide additional certificates beyond those given in the TLS
/// handshake
CERTS = 129,
/// Challenge material used in relay-to-relay handshake.
AUTH_CHALLENGE = 130,
/// Response material used in relay-to-relay handshake.
AUTHENTICATE = 131,
/// Indicates client permission to use relay. Not currently used.
AUTHORIZE = 132,
}
}
impl ChanCmd {
/// Return true if this cell uses the variable-length format.
pub fn is_var_cell(self) -> bool {
// Version 1 of the channel protocol had no variable-length
// cells, but that's obsolete. In version 2, only the VERSIONS
// cell was variable-length.
self == ChanCmd::VERSIONS || self.0 >= 128u8
}
pub fn is_recognized(self) -> bool {
match self {
ChanCmd::PADDING
| ChanCmd::NETINFO
| ChanCmd::PADDING_NEGOTIATE
| ChanCmd::VERSIONS
| ChanCmd::VPADDING
| ChanCmd::CERTS
| ChanCmd::AUTH_CHALLENGE
| ChanCmd::AUTHENTICATE
| ChanCmd::CREATE
| ChanCmd::CREATED
| ChanCmd::RELAY
| ChanCmd::DESTROY
| ChanCmd::CREATE_FAST
| ChanCmd::CREATED_FAST
| ChanCmd::RELAY_EARLY
| ChanCmd::CREATE2
| ChanCmd::CREATED2 => true,
_ => false,
}
}
pub fn allows_circid(self) -> bool {
match self {
ChanCmd::PADDING
| ChanCmd::NETINFO
| ChanCmd::PADDING_NEGOTIATE
| ChanCmd::VERSIONS
| ChanCmd::VPADDING
| ChanCmd::CERTS
| ChanCmd::AUTH_CHALLENGE
| ChanCmd::AUTHENTICATE => false,
ChanCmd::CREATE
| ChanCmd::CREATED
| ChanCmd::RELAY
| ChanCmd::DESTROY
| ChanCmd::CREATE_FAST
| ChanCmd::CREATED_FAST
| ChanCmd::RELAY_EARLY
| ChanCmd::CREATE2
| ChanCmd::CREATED2 => true,
_ => true,
}
}
}
/// A single cell extracted from, or encodeable onto, a channel.
#[derive(Clone, Debug)]
pub struct ChanCell {
circ: CircID,
cmd: ChanCmd,
body: bytes::Bytes,
}
impl ChanCell {
/// Return the cell's circuit ID.
pub fn get_circid(&self) -> CircID {
self.circ
}
/// Return the cell's channel ID
pub fn get_cmd(&self) -> ChanCmd {
self.cmd
}
/// Return the body of this cell.
pub fn get_body(&self) -> &bytes::Bytes {
&self.body
}
}

View File

@ -0,0 +1,99 @@
use crate::chancell::{
msg::{ChanMsg, ChannelMessage},
ChanCmd, CircID,
};
use crate::crypto::cell::CELL_BODY_LEN;
use arrayref::{array_mut_ref, array_ref};
use bytes;
use futures_codec;
use tor_bytes::{self, Reader, Writer};
// XXXX make a crate-level error type
pub enum Error {
Io(std::io::Error),
Bytes(tor_bytes::Error),
Misc(),
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Error {
Error::Io(e)
}
}
impl From<tor_bytes::Error> for Error {
fn from(e: tor_bytes::Error) -> Error {
Error::Bytes(e)
}
}
// Note: only link versions 3 and higher are supported. Versions cell
// is not supported via coder/decoder ,since it always uses a two-byte
// circuit-ID.
pub struct ChannelCodec {
link_version: u16,
}
impl futures_codec::Encoder for ChannelCodec {
type Item = (CircID, ChannelMessage);
type Error = Error;
fn encode(&mut self, item: Self::Item, dst: &mut bytes::BytesMut) -> Result<(), Self::Error> {
let (circid, msg) = item;
let cmd = msg.get_cmd();
dst.write_u32(circid.into());
dst.write_u8(cmd.into());
// now write the cell body and handle the length.
if cmd.is_var_cell() {
let pos = dst.len(); // always 5?
dst.write_u16(0);
msg.write_body_onto(dst);
let len = dst.len() - pos - 2;
if len > std::u16::MAX as usize {
return Err(Error::Misc());
}
// go back and set the length.
*(array_mut_ref![&mut dst[pos..pos + 2], 0, 2]) = (len as u16).to_be_bytes();
} else {
let pos = dst.len(); // Always 5?
msg.write_body_onto(dst);
let len = dst.len() - pos;
if len > CELL_BODY_LEN {
return Err(Error::Misc());
}
// pad to end of fixed-length cell
dst.write_zeros(CELL_BODY_LEN - len);
}
Ok(())
}
}
impl futures_codec::Decoder for ChannelCodec {
type Item = (CircID, ChannelMessage);
type Error = Error;
fn decode(&mut self, src: &mut bytes::BytesMut) -> Result<Option<Self::Item>, Self::Error> {
if src.len() < 7 {
// Smallest possible command: varcell with len 0
return Ok(None);
}
let cmd: ChanCmd = src[4].into();
let varcell = cmd.is_var_cell();
let cell_len: usize = if varcell {
let msg_len = u16::from_be_bytes(*array_ref![&src[5..7], 0, 2]);
msg_len as usize + 7
} else {
514
};
if src.len() < cell_len {
return Ok(None);
}
let cell = src.split_to(cell_len).freeze();
let mut r = Reader::from_bytes(&cell);
let circid = r.take_u32()?.into();
r.advance(if varcell { 1 } else { 3 })?;
let msg = r.extract()?;
Ok(Some((circid, msg)))
}
}

View File

@ -0,0 +1,566 @@
/// A channel message is a decoded channel cell.
use crate::crypto::cell::{RawCellBody, CELL_BODY_LEN};
use tor_bytes::{Error, Readable, Reader, Result, Writer};
use super::ChanCmd;
use std::net::{IpAddr, Ipv4Addr};
pub trait ChanMsg: Readable {
fn as_message(self) -> ChannelMessage;
fn write_body_onto<W: Writer + ?Sized>(&self, w: &mut W);
}
#[non_exhaustive]
#[derive(Clone, Debug)]
pub enum ChannelMessage {
Padding(Padding),
VPadding(VPadding),
Create(Create),
CreateFast(CreateFast),
Create2(Create2),
Created(Created),
CreatedFast(CreatedFast),
Created2(Created2),
Relay(Relay),
RelayEarly(Relay),
Destroy(Destroy),
Netinfo(Netinfo),
Versions(Versions),
PaddingNegotiate(PaddingNegotiate),
Certs(Certs),
AuthChallenge(AuthChallenge),
Authenticate(Authenticate),
Authorize(Authorize),
Unrecognized(Unrecognized),
}
impl ChannelMessage {
pub fn get_cmd(&self) -> ChanCmd {
use ChannelMessage::*;
match self {
Padding(_) => ChanCmd::PADDING,
VPadding(_) => ChanCmd::VPADDING,
Create(_) => ChanCmd::CREATE,
CreateFast(_) => ChanCmd::CREATE_FAST,
Create2(_) => ChanCmd::CREATE2,
Created(_) => ChanCmd::CREATED,
CreatedFast(_) => ChanCmd::CREATED_FAST,
Created2(_) => ChanCmd::CREATED2,
Relay(_) => ChanCmd::RELAY,
RelayEarly(_) => ChanCmd::RELAY_EARLY,
Destroy(_) => ChanCmd::DESTROY,
Netinfo(_) => ChanCmd::NETINFO,
Versions(_) => ChanCmd::VERSIONS,
PaddingNegotiate(_) => ChanCmd::PADDING_NEGOTIATE,
Certs(_) => ChanCmd::CERTS,
AuthChallenge(_) => ChanCmd::AUTH_CHALLENGE,
Authenticate(_) => ChanCmd::AUTHENTICATE,
Authorize(_) => ChanCmd::AUTHORIZE,
Unrecognized(c) => c.get_cmd(),
}
}
}
impl ChanMsg for ChannelMessage {
fn as_message(self) -> Self {
self
}
fn write_body_onto<W: Writer + ?Sized>(&self, w: &mut W) {
use ChannelMessage::*;
match self {
Padding(b) => b.write_body_onto(w),
VPadding(b) => b.write_body_onto(w),
Create(b) => b.write_body_onto(w),
CreateFast(b) => b.write_body_onto(w),
Create2(b) => b.write_body_onto(w),
Created(b) => b.write_body_onto(w),
CreatedFast(b) => b.write_body_onto(w),
Created2(b) => b.write_body_onto(w),
Relay(b) => b.write_body_onto(w),
RelayEarly(b) => b.write_body_onto(w),
Destroy(b) => b.write_body_onto(w),
Netinfo(b) => b.write_body_onto(w),
Versions(b) => b.write_body_onto(w),
PaddingNegotiate(b) => b.write_body_onto(w),
Certs(b) => b.write_body_onto(w),
AuthChallenge(b) => b.write_body_onto(w),
Authenticate(b) => b.write_body_onto(w),
Authorize(b) => b.write_body_onto(w),
Unrecognized(b) => b.write_body_onto(w),
}
}
}
impl Readable for ChannelMessage {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let cmd = r.take_u8()?.into();
use ChannelMessage::*;
Ok(match cmd {
ChanCmd::PADDING => Padding(r.extract()?),
ChanCmd::VPADDING => VPadding(r.extract()?),
ChanCmd::CREATE => Create(r.extract()?),
ChanCmd::CREATE_FAST => CreateFast(r.extract()?),
ChanCmd::CREATE2 => Create2(r.extract()?),
ChanCmd::CREATED => Created(r.extract()?),
ChanCmd::CREATED_FAST => CreatedFast(r.extract()?),
ChanCmd::CREATED2 => Created2(r.extract()?),
ChanCmd::RELAY => Relay(r.extract()?),
ChanCmd::RELAY_EARLY => RelayEarly(r.extract()?),
ChanCmd::DESTROY => Destroy(r.extract()?),
ChanCmd::NETINFO => Netinfo(r.extract()?),
ChanCmd::VERSIONS => Versions(r.extract()?),
ChanCmd::PADDING_NEGOTIATE => PaddingNegotiate(r.extract()?),
ChanCmd::CERTS => Certs(r.extract()?),
ChanCmd::AUTH_CHALLENGE => AuthChallenge(r.extract()?),
ChanCmd::AUTHENTICATE => Authenticate(r.extract()?),
ChanCmd::AUTHORIZE => Authorize(r.extract()?),
_ => Unrecognized(unrecognized_with_cmd(cmd, r)?),
})
}
}
#[derive(Clone, Debug)]
pub struct Padding {}
impl ChanMsg for Padding {
fn as_message(self) -> ChannelMessage {
ChannelMessage::Padding(self)
}
fn write_body_onto<W: Writer + ?Sized>(&self, _w: &mut W) {}
}
impl Readable for Padding {
fn take_from(_r: &mut Reader<'_>) -> Result<Self> {
Ok(Padding {})
}
}
#[derive(Clone, Debug)]
pub struct VPadding {
len: u16,
}
impl ChanMsg for VPadding {
fn as_message(self) -> ChannelMessage {
ChannelMessage::VPadding(self)
}
fn write_body_onto<W: Writer + ?Sized>(&self, w: &mut W) {
w.write_zeros(self.len as usize);
}
}
impl Readable for VPadding {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
if r.remaining() > std::u16::MAX as usize {
return Err(Error::BadMessage("XX"));
}
Ok(VPadding {
len: r.remaining() as u16,
})
}
}
macro_rules! fixed_len {
{
$name:ident , $cmd:ident, $len:ident
} => {
#[derive(Clone,Debug)]
pub struct $name {
handshake: Vec<u8>
}
impl ChanMsg for $name {
fn as_message(self) -> ChannelMessage {
ChannelMessage::$name(self)
}
fn write_body_onto<W: Writer + ?Sized>(&self, w: &mut W) {
w.write_all(&self.handshake[..])
}
}
impl Readable for $name {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
Ok($name {
handshake: r.take($len)?.into(),
})
}
}
}
}
// XXXX MOVE THESE
pub const TAP_C_HANDSHAKE_LEN: usize = 128 * 2 + 42;
pub const TAP_S_HANDSHAKE_LEN: usize = 128 + 20;
const FAST_C_HANDSHAKE_LEN: usize = 20;
const FAST_S_HANDSHAKE_LEN: usize = 20 * 2;
fixed_len! { Create, CREATE, TAP_C_HANDSHAKE_LEN }
fixed_len! { Created, CREATED, TAP_S_HANDSHAKE_LEN }
fixed_len! { CreateFast, CREATE_FAST, FAST_C_HANDSHAKE_LEN }
fixed_len! { CreatedFast, CREATED_FAST, FAST_S_HANDSHAKE_LEN }
#[derive(Clone, Debug)]
pub struct Create2 {
handshake_type: u16,
handshake: Vec<u8>,
}
impl ChanMsg for Create2 {
fn as_message(self) -> ChannelMessage {
ChannelMessage::Create2(self)
}
fn write_body_onto<W: Writer + ?Sized>(&self, w: &mut W) {
w.write_u16(self.handshake_type);
assert!(self.handshake.len() <= std::u16::MAX as usize);
w.write_u16(self.handshake.len() as u16);
w.write_all(&self.handshake[..]);
}
}
impl Readable for Create2 {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let handshake_type = r.take_u16()?;
let hlen = r.take_u16()?;
let handshake = r.take(hlen as usize)?.into();
Ok(Create2 {
handshake_type,
handshake,
})
}
}
#[derive(Clone, Debug)]
pub struct Created2 {
handshake: Vec<u8>,
}
impl ChanMsg for Created2 {
fn as_message(self) -> ChannelMessage {
ChannelMessage::Created2(self)
}
fn write_body_onto<W: Writer + ?Sized>(&self, w: &mut W) {
assert!(self.handshake.len() <= std::u16::MAX as usize);
w.write_u16(self.handshake.len() as u16);
w.write_all(&self.handshake[..]);
}
}
impl Readable for Created2 {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let hlen = r.take_u16()?;
let handshake = r.take(hlen as usize)?.into();
Ok(Created2 { handshake })
}
}
#[derive(Clone)]
pub struct Relay {
body: Box<RawCellBody>,
}
impl std::fmt::Debug for Relay {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Relay").finish()
}
}
impl ChanMsg for Relay {
fn as_message(self) -> ChannelMessage {
ChannelMessage::Relay(self)
}
fn write_body_onto<W: Writer + ?Sized>(&self, w: &mut W) {
w.write_all(&self.body[..])
}
}
impl Readable for Relay {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let mut body = Box::new([0u8; CELL_BODY_LEN]);
(&mut body[..]).copy_from_slice(r.take(CELL_BODY_LEN)?);
Ok(Relay { body })
}
}
#[derive(Clone, Debug)]
pub struct Destroy {}
impl ChanMsg for Destroy {
fn as_message(self) -> ChannelMessage {
ChannelMessage::Destroy(self)
}
fn write_body_onto<W: Writer + ?Sized>(&self, _w: &mut W) {}
}
impl Readable for Destroy {
fn take_from(_r: &mut Reader<'_>) -> Result<Self> {
Ok(Destroy {})
}
}
#[derive(Clone, Debug)]
pub struct Netinfo {
timestamp: u32,
their_addr: IpAddr,
my_addr: Vec<IpAddr>,
}
fn enc_one_netinfo_addr<W: Writer + ?Sized>(w: &mut W, addr: &IpAddr) {
match addr {
IpAddr::V4(ipv4) => {
w.write_u8(0x04); // type.
w.write_u8(4); // length.
w.write_all(&ipv4.octets()[..]);
}
IpAddr::V6(ipv6) => {
w.write_u8(0x06); // type.
w.write_u8(16); // length.
w.write_all(&ipv6.octets()[..]);
}
}
}
fn take_one_netinfo_addr(r: &mut Reader<'_>) -> Result<Option<IpAddr>> {
let atype = r.take_u8()?;
let alen = r.take_u8()?;
let abody = r.take(alen as usize)?;
match (atype, alen) {
(0x04, 4) => {
let bytes = [abody[0], abody[1], abody[2], abody[3]];
Ok(Some(IpAddr::V4(bytes.into())))
}
(0x06, 16) => {
// XXXX is there a better way?
let mut bytes = [0u8; 16];
(&mut bytes[..]).copy_from_slice(abody);
Ok(Some(IpAddr::V6(bytes.into())))
}
(0x04, _) => Err(Error::BadMessage("XX")),
(0x06, _) => Err(Error::BadMessage("XX")),
(_, _) => Ok(None),
}
}
impl ChanMsg for Netinfo {
fn as_message(self) -> ChannelMessage {
ChannelMessage::Netinfo(self)
}
fn write_body_onto<W: Writer + ?Sized>(&self, w: &mut W) {
w.write_u32(self.timestamp);
enc_one_netinfo_addr(w, &self.their_addr);
w.write_u8(self.my_addr.len() as u8); // XXXX overflow?
for addr in self.my_addr.iter() {
enc_one_netinfo_addr(w, &addr);
}
}
}
impl Readable for Netinfo {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let timestamp = r.take_u32()?;
let their_addr = take_one_netinfo_addr(r)?.unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED));
let mut my_addr = Vec::new();
let my_n_addrs = r.take_u8()?;
for _ in 0..my_n_addrs {
if let Some(a) = take_one_netinfo_addr(r)? {
my_addr.push(a);
}
}
Ok(Netinfo {
timestamp,
their_addr,
my_addr,
})
}
}
#[derive(Clone, Debug)]
pub struct Versions {
versions: Vec<u16>,
}
impl ChanMsg for Versions {
fn as_message(self) -> ChannelMessage {
ChannelMessage::Versions(self)
}
fn write_body_onto<W: Writer + ?Sized>(&self, w: &mut W) {
for v in self.versions.iter() {
w.write_u16(*v);
}
}
}
impl Readable for Versions {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let mut versions = Vec::new();
while r.remaining() > 0 {
versions.push(r.take_u16()?);
}
Ok(Versions { versions })
}
}
#[derive(Clone, Debug)]
pub struct PaddingNegotiate {
command: u8,
ito_low_ms: u16,
ito_high_ms: u16,
}
impl ChanMsg for PaddingNegotiate {
fn as_message(self) -> ChannelMessage {
ChannelMessage::PaddingNegotiate(self)
}
fn write_body_onto<W: Writer + ?Sized>(&self, w: &mut W) {
w.write_u8(0); // version
w.write_u8(self.command);
w.write_u16(self.ito_low_ms);
w.write_u16(self.ito_high_ms);
}
}
impl Readable for PaddingNegotiate {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let v = r.take_u8()?;
if v != 0 {
return Err(Error::BadMessage("XX"));
}
let command = r.take_u8()?;
let ito_low_ms = r.take_u16()?;
let ito_high_ms = r.take_u16()?;
Ok(PaddingNegotiate {
command,
ito_low_ms,
ito_high_ms,
})
}
}
#[derive(Clone, Debug)]
struct TorCert {
certtype: u8,
cert: Vec<u8>,
}
fn enc_one_tor_cert<W: Writer + ?Sized>(w: &mut W, c: &TorCert) {
w.write_u8(c.certtype);
w.write_u16(c.cert.len() as u16); // XXXX overflow?
w.write_all(&c.cert[..]);
}
fn take_one_tor_cert(r: &mut Reader<'_>) -> Result<TorCert> {
let certtype = r.take_u8()?;
let certlen = r.take_u16()?;
let cert = r.take(certlen as usize)?;
Ok(TorCert {
certtype,
cert: cert.into(),
})
}
#[derive(Clone, Debug)]
pub struct Certs {
certs: Vec<TorCert>,
}
impl ChanMsg for Certs {
fn as_message(self) -> ChannelMessage {
ChannelMessage::Certs(self)
}
fn write_body_onto<W: Writer + ?Sized>(&self, w: &mut W) {
w.write_u8(self.certs.len() as u8); //XXXXX overflow?
for c in self.certs.iter() {
enc_one_tor_cert(w, &c)
}
}
}
impl Readable for Certs {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let n = r.take_u8()?;
let mut certs = Vec::new();
for _ in 0..n {
certs.push(take_one_tor_cert(r)?);
}
Ok(Certs { certs })
}
}
#[derive(Clone, Debug)]
pub struct AuthChallenge {
challenge: Vec<u8>,
methods: Vec<u16>,
}
const CHALLENGE_LEN: usize = 32;
impl ChanMsg for AuthChallenge {
fn as_message(self) -> ChannelMessage {
ChannelMessage::AuthChallenge(self)
}
fn write_body_onto<W: Writer + ?Sized>(&self, w: &mut W) {
w.write_all(&self.challenge[..]);
w.write_u16(self.methods.len() as u16); // XXXXX overflow
for m in self.methods.iter() {
w.write_u16(*m);
}
}
}
impl Readable for AuthChallenge {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let challenge = r.take(CHALLENGE_LEN)?.into();
let n_methods = r.take_u16()?;
let mut methods = Vec::new();
for _ in 0..n_methods {
methods.push(r.take_u16()?);
}
Ok(AuthChallenge { challenge, methods })
}
}
#[derive(Clone, Debug)]
pub struct Authenticate {
authtype: u16,
auth: Vec<u8>,
}
impl ChanMsg for Authenticate {
fn as_message(self) -> ChannelMessage {
ChannelMessage::Authenticate(self)
}
fn write_body_onto<W: Writer + ?Sized>(&self, w: &mut W) {
w.write_u16(self.authtype);
w.write_u16(self.auth.len() as u16); // XXXX overflow
w.write_all(&self.auth[..]);
}
}
impl Readable for Authenticate {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let authtype = r.take_u16()?;
let authlen = r.take_u16()?;
let auth = r.take(authlen as usize)?.into();
Ok(Authenticate { authtype, auth })
}
}
#[derive(Clone, Debug)]
pub struct Authorize {
content: Vec<u8>,
}
impl ChanMsg for Authorize {
fn as_message(self) -> ChannelMessage {
ChannelMessage::Authorize(self)
}
fn write_body_onto<W: Writer + ?Sized>(&self, w: &mut W) {
w.write_all(&self.content[..])
}
}
impl Readable for Authorize {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
Ok(Authorize {
content: r.take(r.remaining())?.into(),
})
}
}
#[derive(Clone, Debug)]
pub struct Unrecognized {
cmd: ChanCmd,
content: Vec<u8>,
}
fn unrecognized_with_cmd(cmd: ChanCmd, r: &mut Reader<'_>) -> Result<Unrecognized> {
let mut u = Unrecognized::take_from(r)?;
u.cmd = cmd;
Ok(u)
}
impl Unrecognized {
fn get_cmd(&self) -> ChanCmd {
self.cmd
}
}
impl ChanMsg for Unrecognized {
fn as_message(self) -> ChannelMessage {
ChannelMessage::Unrecognized(self)
}
fn write_body_onto<W: Writer + ?Sized>(&self, w: &mut W) {
w.write_all(&self.content[..])
}
}
impl Readable for Unrecognized {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
Ok(Unrecognized {
cmd: 0.into(),
content: r.take(r.remaining())?.into(),
})
}
}

View File

@ -23,6 +23,7 @@
#![allow(dead_code)]
#![deny(missing_docs)]
pub mod chancell;
mod crypto;
pub mod proto;
mod util;

View File

@ -11,38 +11,9 @@
#![allow(missing_docs)]
use caret::caret_int;
use tor_bytes::{Error, Reader, Result, Writer};
pub mod cellmsg;
pub mod relaymsg;
pub const CELL_DATA_LEN: usize = 509;
caret_int! {
pub struct ChanCmd(u8) {
PADDING = 0,
CREATE = 1,
CREATED = 2,
RELAY = 3,
DESTROY = 4,
CREATE_FAST = 5,
CREATED_FAST = 6,
// note gap.
NETINFO = 8,
RELAY_EARLY = 9,
CREATE2 = 10,
CREATED2 = 11,
PADDING_NEGOTIATE = 12,
VERSIONS = 7,
VPADDING = 128,
CERTS = 129,
AUTH_CHALLENGE = 130,
AUTHENTICATE = 131,
AUTHORIZE = 132,
}
}
caret_int! {
pub struct StreamCmd(u8) {
BEGIN = 1,
@ -74,28 +45,6 @@ caret_int! {
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct CircID(u32);
impl From<u32> for CircID {
fn from(item: u32) -> Self {
Self(item)
}
}
#[derive(Clone)]
pub struct ChanCell {
circ: CircID,
cmd: ChanCmd,
body: Vec<u8>,
}
pub struct CellRef<'a> {
pub circ: CircID,
pub cmd: ChanCmd,
pub body: &'a [u8],
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct StreamID(u16);
@ -104,121 +53,3 @@ pub struct RelayCellRef<'a> {
pub cmd: StreamCmd,
pub body: &'a [u8],
}
pub struct ChannelProto {
link_version: u16,
relay_early_count: Option<u8>,
}
impl ChanCmd {
pub fn is_var_cell(self) -> bool {
self == ChanCmd::VERSIONS || self.0 >= 128u8
}
}
impl ChannelProto {
fn circ_id_len(&self) -> usize {
if self.link_version >= 4 {
4
} else {
2
}
}
pub fn get_cell<'a>(&self, bc: &mut Reader<'a>) -> Result<CellRef<'a>> {
let circ = if self.circ_id_len() == 4 {
CircID(bc.take_u32()?)
} else {
CircID(bc.take_u16()? as u32)
};
let cmd = ChanCmd(bc.take_u8()?);
let body_len = if cmd.is_var_cell() {
bc.take_u16()? as usize
} else {
CELL_DATA_LEN
};
let body = bc.take(body_len)?;
Ok(CellRef { circ, cmd, body })
}
pub fn enc_cell<'a, W: Writer>(&self, w: &mut W, cell: &CellRef<'a>) -> Result<()> {
if self.circ_id_len() == 4 {
w.write_u32(cell.circ.0);
} else {
if cell.circ.0 > std::u16::MAX as u32 {
return Err(Error::BadMessage("XX"));
}
w.write_u16(cell.circ.0 as u16);
}
w.write_u8(cell.cmd.0);
if cell.cmd.is_var_cell() {
if cell.body.len() > std::u16::MAX as usize {
return Err(Error::BadMessage("XX"));
}
w.write_u16(cell.body.len() as u16);
w.write_all(cell.body);
} else {
if cell.body.len() > CELL_DATA_LEN {
return Err(Error::BadMessage("XX"));
}
w.write_all(cell.body);
w.write_zeros(CELL_DATA_LEN - cell.body.len());
}
Ok(())
}
}
impl<'a> CellRef<'a> {
fn to_cell(&self) -> ChanCell {
ChanCell {
circ: self.circ,
cmd: self.cmd,
body: self.body.into(),
}
}
fn reader(&self) -> Reader<'_> {
Reader::from_slice(&self.body[..])
}
}
impl ChanCell {
pub fn as_ref(&self) -> CellRef<'_> {
CellRef {
circ: self.circ,
cmd: self.cmd,
body: self.get_body(),
}
}
}
pub trait CellData: Sized {
fn get_circid(&self) -> CircID;
fn get_cmd(&self) -> ChanCmd;
fn get_body(&self) -> &[u8];
}
impl CellData for ChanCell {
fn get_circid(&self) -> CircID {
self.circ
}
fn get_cmd(&self) -> ChanCmd {
self.cmd
}
fn get_body(&self) -> &[u8] {
&self.body[..]
}
}
impl<'a> CellData for CellRef<'a> {
fn get_circid(&self) -> CircID {
self.circ
}
fn get_cmd(&self) -> ChanCmd {
self.cmd
}
fn get_body(&self) -> &[u8] {
self.body
}
}

View File

@ -1,588 +0,0 @@
use crate::crypto::cell::{RawCellBody, CELL_BODY_LEN};
use tor_bytes::{Error, Reader, Result, Writer};
use super::{CellData, CellRef, ChanCell, ChanCmd, CircID};
use std::net::{IpAddr, Ipv4Addr};
pub struct ChannelCell {
circid: CircID,
body: ChannelCellBody,
}
impl ChannelCell {
fn get_circid(&self) -> CircID {
self.circid
}
fn get_cmd(&self) -> ChanCmd {
self.body.get_cmd()
}
fn encode(self) -> ChanCell {
let cmd = self.get_cmd();
let circ = self.get_circid();
let body = self.body.encode();
ChanCell { cmd, circ, body }
}
fn decode(c: ChanCell) -> Result<Self> {
let circid = c.get_circid();
let cmd = c.get_cmd();
let body = ChannelCellBody::decode(cmd, c.body)?;
Ok(ChannelCell { circid, body })
}
fn decode_ref(c: &CellRef<'_>) -> Result<Self> {
let circid = c.get_circid();
let cmd = c.get_cmd();
let mut r = Reader::from_slice(c.body);
let body = ChannelCellBody::decode_from_reader(cmd, &mut r)?;
Ok(ChannelCell { circid, body })
}
}
#[non_exhaustive]
pub enum ChannelCellBody {
Padding(PaddingBody),
VPadding(VPaddingBody),
Create(CreateBody),
CreateFast(CreateFastBody),
Create2(Create2Body),
Created(CreatedBody),
CreatedFast(CreatedFastBody),
Created2(Created2Body),
Relay(RelayBody),
RelayEarly(RelayBody),
Destroy(DestroyBody),
Netinfo(NetinfoBody),
Versions(VersionsBody),
PaddingNegotiate(PaddingNegotiateBody),
Certs(CertsBody),
AuthChallenge(AuthChallengeBody),
Authenticate(AuthenticateBody),
Authorize(AuthorizeBody),
Unrecognized(ChanCmd, UnrecognizedBody),
}
impl ChannelCellBody {
pub fn get_cmd(&self) -> ChanCmd {
use ChannelCellBody::*;
match self {
Padding(_) => ChanCmd::PADDING,
VPadding(_) => ChanCmd::VPADDING,
Create(_) => ChanCmd::CREATE,
CreateFast(_) => ChanCmd::CREATE_FAST,
Create2(_) => ChanCmd::CREATE2,
Created(_) => ChanCmd::CREATED,
CreatedFast(_) => ChanCmd::CREATED_FAST,
Created2(_) => ChanCmd::CREATED2,
Relay(_) => ChanCmd::RELAY,
RelayEarly(_) => ChanCmd::RELAY_EARLY,
Destroy(_) => ChanCmd::DESTROY,
Netinfo(_) => ChanCmd::NETINFO,
Versions(_) => ChanCmd::VERSIONS,
PaddingNegotiate(_) => ChanCmd::PADDING_NEGOTIATE,
Certs(_) => ChanCmd::CERTS,
AuthChallenge(_) => ChanCmd::AUTH_CHALLENGE,
Authenticate(_) => ChanCmd::AUTHENTICATE,
Authorize(_) => ChanCmd::AUTHORIZE,
Unrecognized(c, _) => *c,
}
}
fn encode(self) -> Vec<u8> {
use ChannelCellBody::*;
match self {
Padding(b) => b.encode(),
VPadding(b) => b.encode(),
Create(b) => b.encode(),
CreateFast(b) => b.encode(),
Create2(b) => b.encode(),
Created(b) => b.encode(),
CreatedFast(b) => b.encode(),
Created2(b) => b.encode(),
Relay(b) => b.encode(),
RelayEarly(b) => b.encode(),
Destroy(b) => b.encode(),
Netinfo(b) => b.encode(),
Versions(b) => b.encode(),
PaddingNegotiate(b) => b.encode(),
Certs(b) => b.encode(),
AuthChallenge(b) => b.encode(),
Authenticate(b) => b.encode(),
Authorize(b) => b.encode(),
Unrecognized(_, b) => b.encode(),
}
}
fn decode(cmd: ChanCmd, b: Vec<u8>) -> Result<Self> {
use ChannelCellBody::*;
Ok(match cmd {
ChanCmd::PADDING => Padding(PaddingBody::decode(b)?),
ChanCmd::VPADDING => VPadding(VPaddingBody::decode(b)?),
ChanCmd::CREATE => Create(CreateBody::decode(b)?),
ChanCmd::CREATE_FAST => CreateFast(CreateFastBody::decode(b)?),
ChanCmd::CREATE2 => Create2(Create2Body::decode(b)?),
ChanCmd::CREATED => Created(CreatedBody::decode(b)?),
ChanCmd::CREATED_FAST => CreatedFast(CreatedFastBody::decode(b)?),
ChanCmd::CREATED2 => Created2(Created2Body::decode(b)?),
ChanCmd::RELAY => Relay(RelayBody::decode(b)?),
ChanCmd::RELAY_EARLY => RelayEarly(RelayBody::decode(b)?),
ChanCmd::DESTROY => Destroy(DestroyBody::decode(b)?),
ChanCmd::NETINFO => Netinfo(NetinfoBody::decode(b)?),
ChanCmd::VERSIONS => Versions(VersionsBody::decode(b)?),
ChanCmd::PADDING_NEGOTIATE => PaddingNegotiate(PaddingNegotiateBody::decode(b)?),
ChanCmd::CERTS => Certs(CertsBody::decode(b)?),
ChanCmd::AUTH_CHALLENGE => AuthChallenge(AuthChallengeBody::decode(b)?),
ChanCmd::AUTHENTICATE => Authenticate(AuthenticateBody::decode(b)?),
ChanCmd::AUTHORIZE => Authorize(AuthorizeBody::decode(b)?),
_ => Unrecognized(cmd, UnrecognizedBody::decode(b)?),
})
}
fn decode_from_reader(cmd: ChanCmd, r: &mut Reader<'_>) -> Result<Self> {
use ChannelCellBody::*;
Ok(match cmd {
ChanCmd::PADDING => Padding(PaddingBody::decode_from_reader(r)?),
ChanCmd::VPADDING => VPadding(VPaddingBody::decode_from_reader(r)?),
ChanCmd::CREATE => Create(CreateBody::decode_from_reader(r)?),
ChanCmd::CREATE_FAST => CreateFast(CreateFastBody::decode_from_reader(r)?),
ChanCmd::CREATE2 => Create2(Create2Body::decode_from_reader(r)?),
ChanCmd::CREATED => Created(CreatedBody::decode_from_reader(r)?),
ChanCmd::CREATED_FAST => CreatedFast(CreatedFastBody::decode_from_reader(r)?),
ChanCmd::CREATED2 => Created2(Created2Body::decode_from_reader(r)?),
ChanCmd::RELAY => Relay(RelayBody::decode_from_reader(r)?),
ChanCmd::RELAY_EARLY => RelayEarly(RelayBody::decode_from_reader(r)?),
ChanCmd::DESTROY => Destroy(DestroyBody::decode_from_reader(r)?),
ChanCmd::NETINFO => Netinfo(NetinfoBody::decode_from_reader(r)?),
ChanCmd::VERSIONS => Versions(VersionsBody::decode_from_reader(r)?),
ChanCmd::PADDING_NEGOTIATE => {
PaddingNegotiate(PaddingNegotiateBody::decode_from_reader(r)?)
}
ChanCmd::CERTS => Certs(CertsBody::decode_from_reader(r)?),
ChanCmd::AUTH_CHALLENGE => AuthChallenge(AuthChallengeBody::decode_from_reader(r)?),
ChanCmd::AUTHENTICATE => Authenticate(AuthenticateBody::decode_from_reader(r)?),
ChanCmd::AUTHORIZE => Authorize(AuthorizeBody::decode_from_reader(r)?),
_ => Unrecognized(cmd, UnrecognizedBody::decode_from_reader(r)?),
})
}
}
trait Body: Sized {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self>;
fn decode(body: Vec<u8>) -> Result<Self> {
let mut reader = Reader::from_slice(&body[..]);
Self::decode_from_reader(&mut reader)
}
fn encode(self) -> Vec<u8>;
}
pub struct PaddingBody {}
impl Body for PaddingBody {
fn decode_from_reader(_r: &mut Reader<'_>) -> Result<Self> {
Ok(PaddingBody {})
}
fn encode(self) -> Vec<u8> {
Vec::new()
}
}
pub struct VPaddingBody {
len: u16,
}
impl Body for VPaddingBody {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
if r.remaining() > std::u16::MAX as usize {
return Err(Error::BadMessage("XX"));
}
Ok(VPaddingBody {
len: r.remaining() as u16,
}) // XXXX overflow?
}
fn encode(self) -> Vec<u8> {
let mut res = Vec::new();
res.resize(self.len as usize, 0);
res
}
}
// XXXX MOVE THESE
pub const TAP_C_HANDSHAKE_LEN: usize = 128 * 2 + 42;
pub const TAP_S_HANDSHAKE_LEN: usize = 128 + 20;
const FAST_C_HANDSHAKE_LEN: usize = 20;
const FAST_S_HANDSHAKE_LEN: usize = 20 * 2;
pub struct CreateBody {
handshake: Vec<u8>,
}
impl Body for CreateBody {
fn encode(self) -> Vec<u8> {
self.handshake
}
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
Ok(CreateBody {
handshake: r.take(TAP_C_HANDSHAKE_LEN)?.into(),
})
}
}
pub struct CreateFastBody {
handshake: Vec<u8>,
}
impl Body for CreateFastBody {
fn encode(self) -> Vec<u8> {
self.handshake
}
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
Ok(CreateFastBody {
handshake: r.take(FAST_C_HANDSHAKE_LEN)?.into(),
})
}
}
pub struct Create2Body {
handshake_type: u16,
handshake: Vec<u8>,
}
impl Body for Create2Body {
fn encode(mut self) -> Vec<u8> {
let mut body = Vec::new();
body.write_u16(self.handshake_type);
body.write_u16(self.handshake.len() as u16); // XXXX overflow?
body.append(&mut self.handshake);
body
}
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let handshake_type = r.take_u16()?;
let hlen = r.take_u16()?;
let handshake = r.take(hlen as usize)?.into();
Ok(Create2Body {
handshake_type,
handshake,
})
}
}
pub struct CreatedBody {
handshake: Vec<u8>,
}
impl Body for CreatedBody {
fn encode(self) -> Vec<u8> {
self.handshake
}
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
Ok(CreatedBody {
handshake: r.take(TAP_S_HANDSHAKE_LEN)?.into(),
})
}
}
pub struct CreatedFastBody {
handshake: Vec<u8>,
}
impl Body for CreatedFastBody {
fn encode(self) -> Vec<u8> {
self.handshake
}
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
Ok(CreatedFastBody {
handshake: r.take(FAST_S_HANDSHAKE_LEN)?.into(),
})
}
}
pub struct Created2Body {
handshake: Vec<u8>,
}
impl Body for Created2Body {
fn encode(mut self) -> Vec<u8> {
let mut body = Vec::new();
body.write_u16(self.handshake.len() as u16); // XXX overflow?
body.append(&mut self.handshake);
body
}
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let hlen = r.take_u16()?;
let handshake = r.take(hlen as usize)?.into();
Ok(Created2Body { handshake })
}
}
pub struct RelayBody {
body: Box<RawCellBody>,
}
impl Body for RelayBody {
fn encode(self) -> Vec<u8> {
// Avoids copy.
(self.body as Box<[_]>).into_vec()
}
fn decode(body: Vec<u8>) -> Result<Self> {
if body.len() != CELL_BODY_LEN {
return Err(Error::BadMessage("XX"));
}
// Once rust has const generics this should be doable safely. XXXX
// Till then, I'll avoid the unsafe.
/*
let boxed_slice = body.into_boxed_slice();
let boxed_array = unsafe {
Box::from_raw(Box::into_raw(boxed_slice) as *mut RawCellBody)
};
*/
let mut boxed_array = Box::new([0u8; CELL_BODY_LEN]);
(&mut boxed_array[..]).copy_from_slice(&body[..]);
Ok(RelayBody { body: boxed_array })
}
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
Self::decode(r.take(CELL_BODY_LEN)?.into())
}
}
pub struct DestroyBody {}
impl Body for DestroyBody {
fn encode(self) -> Vec<u8> {
Vec::new()
}
fn decode_from_reader(_r: &mut Reader<'_>) -> Result<Self> {
Ok(DestroyBody {})
}
}
pub struct NetinfoBody {
timestamp: u32,
their_addr: IpAddr,
my_addr: Vec<IpAddr>,
}
fn enc_one_netinfo_addr(w: &mut Vec<u8>, addr: &IpAddr) {
match addr {
IpAddr::V4(ipv4) => {
w.write_u8(0x04); // type.
w.write_u8(4); // length.
w.write_all(&ipv4.octets()[..]);
}
IpAddr::V6(ipv6) => {
w.write_u8(0x06); // type.
w.write_u8(16); // length.
w.write_all(&ipv6.octets()[..]);
}
}
}
fn take_one_netinfo_addr(r: &mut Reader<'_>) -> Result<Option<IpAddr>> {
let atype = r.take_u8()?;
let alen = r.take_u8()?;
let abody = r.take(alen as usize)?;
match (atype, alen) {
(0x04, 4) => {
let bytes = [abody[0], abody[1], abody[2], abody[3]];
Ok(Some(IpAddr::V4(bytes.into())))
}
(0x06, 16) => {
// XXXX is there a better way?
let mut bytes = [0u8; 16];
(&mut bytes[..]).copy_from_slice(abody);
Ok(Some(IpAddr::V6(bytes.into())))
}
(0x04, _) => Err(Error::BadMessage("XX")),
(0x06, _) => Err(Error::BadMessage("XX")),
(_, _) => Ok(None),
}
}
impl Body for NetinfoBody {
fn encode(self) -> Vec<u8> {
let mut body = Vec::new();
body.write_u32(self.timestamp);
enc_one_netinfo_addr(&mut body, &self.their_addr);
body.write_u8(self.my_addr.len() as u8); // XXXX overflow?
for addr in self.my_addr {
enc_one_netinfo_addr(&mut body, &addr);
}
body
}
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let timestamp = r.take_u32()?;
let their_addr = take_one_netinfo_addr(r)?.unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED));
let mut my_addr = Vec::new();
let my_n_addrs = r.take_u8()?;
for _ in 0..my_n_addrs {
if let Some(a) = take_one_netinfo_addr(r)? {
my_addr.push(a);
}
}
Ok(NetinfoBody {
timestamp,
their_addr,
my_addr,
})
}
}
pub struct VersionsBody {
versions: Vec<u16>,
}
impl Body for VersionsBody {
fn encode(self) -> Vec<u8> {
let mut body = Vec::new();
for v in self.versions {
body.write_u16(v);
}
body
}
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let mut versions = Vec::new();
while r.remaining() > 0 {
versions.push(r.take_u16()?);
}
Ok(VersionsBody { versions })
}
}
pub struct PaddingNegotiateBody {
command: u8,
ito_low_ms: u16,
ito_high_ms: u16,
}
impl Body for PaddingNegotiateBody {
fn encode(self) -> Vec<u8> {
let mut body = Vec::new();
body.write_u8(0); // version
body.write_u8(self.command);
body.write_u16(self.ito_low_ms);
body.write_u16(self.ito_high_ms);
body
}
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let v = r.take_u8()?;
if v != 0 {
return Err(Error::BadMessage("XX"));
}
let command = r.take_u8()?;
let ito_low_ms = r.take_u16()?;
let ito_high_ms = r.take_u16()?;
Ok(PaddingNegotiateBody {
command,
ito_low_ms,
ito_high_ms,
})
}
}
struct TorCert {
certtype: u8,
cert: Vec<u8>,
}
fn enc_one_tor_cert(w: &mut Vec<u8>, c: &TorCert) {
w.write_u8(c.certtype);
w.write_u16(c.cert.len() as u16); // XXXX overflow?
w.write_all(&c.cert[..]);
}
fn take_one_tor_cert(r: &mut Reader<'_>) -> Result<TorCert> {
let certtype = r.take_u8()?;
let certlen = r.take_u16()?;
let cert = r.take(certlen as usize)?;
Ok(TorCert {
certtype,
cert: cert.into(),
})
}
pub struct CertsBody {
certs: Vec<TorCert>,
}
impl Body for CertsBody {
fn encode(self) -> Vec<u8> {
// XXXX overflow.
let mut w = Vec::new();
w.write_u8(self.certs.len() as u8); //XXXXX overflow?
for c in self.certs {
enc_one_tor_cert(&mut w, &c)
}
w
}
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let n = r.take_u8()?;
let mut certs = Vec::new();
for _ in 0..n {
certs.push(take_one_tor_cert(r)?);
}
Ok(CertsBody { certs })
}
}
pub struct AuthChallengeBody {
challenge: Vec<u8>,
methods: Vec<u16>,
}
const CHALLENGE_LEN: usize = 32;
impl Body for AuthChallengeBody {
fn encode(self) -> Vec<u8> {
let mut body = Vec::new();
body.write_all(&self.challenge[..]);
body.write_u16(self.methods.len() as u16); // XXXXX overflow
for m in self.methods {
body.write_u16(m);
}
body
}
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let challenge = r.take(CHALLENGE_LEN)?.into();
let n_methods = r.take_u16()?;
let mut methods = Vec::new();
for _ in 0..n_methods {
methods.push(r.take_u16()?);
}
Ok(AuthChallengeBody { challenge, methods })
}
}
pub struct AuthenticateBody {
authtype: u16,
auth: Vec<u8>,
}
impl Body for AuthenticateBody {
fn encode(self) -> Vec<u8> {
let mut body = Vec::new();
body.write_u16(self.authtype);
body.write_u16(self.auth.len() as u16); // XXXX overflow
body.write_all(&self.auth[..]);
body
}
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let authtype = r.take_u16()?;
let authlen = r.take_u16()?;
let auth = r.take(authlen as usize)?.into();
Ok(AuthenticateBody { authtype, auth })
}
}
pub struct AuthorizeBody {
content: Vec<u8>,
}
impl Body for AuthorizeBody {
fn encode(self) -> Vec<u8> {
self.content
}
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
Ok(AuthorizeBody {
content: r.take(r.remaining())?.into(),
})
}
}
pub struct UnrecognizedBody {
content: Vec<u8>,
}
impl Body for UnrecognizedBody {
fn encode(self) -> Vec<u8> {
self.content
}
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
Ok(UnrecognizedBody {
content: r.take(r.remaining())?.into(),
})
}
}

View File

@ -1,6 +1,6 @@
use super::cellmsg::{TAP_C_HANDSHAKE_LEN, TAP_S_HANDSHAKE_LEN};
use super::StreamCmd;
use super::StreamID;
use crate::chancell::msg::{TAP_C_HANDSHAKE_LEN, TAP_S_HANDSHAKE_LEN};
use std::net::{IpAddr, Ipv4Addr};
use tor_bytes::{Error, Result};
use tor_bytes::{Readable, Reader, Writeable, Writer};