From 3da4b9543484629fe9f39c4bef503760faef0543 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 7 Jun 2022 11:45:22 -0400 Subject: [PATCH] udp: New AddressPort used in cells Signed-off-by: David Goulet --- crates/tor-cell/src/relaycell/udp.rs | 87 +++++++++++++++-------- crates/tor-cell/tests/testvec_relaymsg.rs | 26 ++++--- 2 files changed, 71 insertions(+), 42 deletions(-) diff --git a/crates/tor-cell/src/relaycell/udp.rs b/crates/tor-cell/src/relaycell/udp.rs index 7e4bc7b6f..ba7375fd3 100644 --- a/crates/tor-cell/src/relaycell/udp.rs +++ b/crates/tor-cell/src/relaycell/udp.rs @@ -10,8 +10,55 @@ use std::str::FromStr; use tor_bytes::{Error, Result}; use tor_bytes::{Readable, Reader, Writeable, Writer}; +/// Indicates the payload is a hostname. +const T_HOSTNAME: u8 = 0x01; +/// Indicates the payload is an IPv4. +const T_IPV4: u8 = 0x04; +/// Indicates the payload is an IPv6. +const T_IPV6: u8 = 0x06; + +/// Maximum length of an Address::Hostname set at 255. +const MAX_HOSTNAME_LEN: usize = u8::MAX as usize; + /// Address contained in a ConnectUdp and ConnectedUdp cell which can -/// represent a hostname, IPv4 or IPv6. +/// represent a hostname, IPv4 or IPv6 along a port number. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AddressPort { + /// Address. + addr: Address, + /// Port. + port: u16, +} + +impl Readable for AddressPort { + fn take_from(r: &mut Reader<'_>) -> Result { + Ok(Self { + addr: r.extract()?, + port: r.take_u16()?, + }) + } +} + +impl Writeable for AddressPort { + fn write_onto(&self, w: &mut B) { + w.write(&self.addr); + w.write_u16(self.port); + } +} + +impl TryFrom<(&str, u16)> for AddressPort { + type Error = Error; + + fn try_from(value: (&str, u16)) -> Result { + let addr = Address::from_str(value.0)?; + Ok(Self { + addr, + port: value.1, + }) + } +} + +/// Address representing either a hostname, IPv4 or IPv6. #[derive(Clone, Debug, Eq, PartialEq)] #[non_exhaustive] pub enum Address { @@ -23,16 +70,6 @@ pub enum Address { Ipv6(Ipv6Addr), } -/// Indicates the payload is a hostname. -const T_HOSTNAME: u8 = 0x01; -/// Indicates the payload is an IPv4. -const T_IPV4: u8 = 0x04; -/// Indicates the payload is an IPv6. -const T_IPV6: u8 = 0x06; - -/// Maximum length of an Address::Hostname set at 255. -const MAX_HOSTNAME_LEN: usize = u8::MAX as usize; - impl Address { /// Return true iff this is a Hostname. pub fn is_hostname(&self) -> bool { @@ -147,9 +184,7 @@ pub struct ConnectUdp { /// Same as Begin flags. flags: msg::BeginFlags, /// Address to connect to. Can be Hostname, IPv4 or IPv6. - addr: Address, - /// Target port - port: u16, + addr: AddressPort, } impl ConnectUdp { @@ -159,8 +194,7 @@ impl ConnectUdp { F: Into, { Ok(Self { - addr: Address::from_str(addr)?, - port, + addr: (addr, port).try_into()?, flags: flags.into(), }) } @@ -174,19 +208,16 @@ impl msg::Body for ConnectUdp { fn decode_from_reader(r: &mut Reader<'_>) -> Result { let flags = r.take_u32()?; let addr = r.extract()?; - let port = r.take_u16()?; Ok(Self { flags: flags.into(), addr, - port, }) } fn encode_onto(self, w: &mut Vec) { w.write_u32(self.flags.bits()); w.write(&self.addr); - w.write_u16(self.port); } } @@ -195,17 +226,17 @@ impl msg::Body for ConnectUdp { pub struct ConnectedUdp { /// The address that the relay has bound locally of a ConnectUdp. Note /// that this might not be the relay address from the descriptor. - our_address: Address, + our_address: AddressPort, /// The address that the stream is connected to. - their_address: Address, + their_address: AddressPort, } impl ConnectedUdp { /// Construct a new ConnectedUdp cell. - pub fn new(our: IpAddr, their: IpAddr) -> Result { + pub fn new(our_address: AddressPort, their_address: AddressPort) -> Result { Ok(Self { - our_address: our.into(), - their_address: their.into(), + our_address, + their_address, }) } } @@ -216,12 +247,12 @@ impl msg::Body for ConnectedUdp { } fn decode_from_reader(r: &mut Reader<'_>) -> Result { - let our_address: Address = r.extract()?; - if our_address.is_hostname() { + let our_address: AddressPort = r.extract()?; + if our_address.addr.is_hostname() { return Err(Error::BadMessage("Our address is a Hostname")); } - let their_address: Address = r.extract()?; - if their_address.is_hostname() { + let their_address: AddressPort = r.extract()?; + if their_address.addr.is_hostname() { return Err(Error::BadMessage("Their address is a Hostname")); } diff --git a/crates/tor-cell/tests/testvec_relaymsg.rs b/crates/tor-cell/tests/testvec_relaymsg.rs index 04152637b..d1dd9e862 100644 --- a/crates/tor-cell/tests/testvec_relaymsg.rs +++ b/crates/tor-cell/tests/testvec_relaymsg.rs @@ -11,8 +11,6 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use hex_literal::hex; -#[cfg(feature = "experimental-udp")] -use std::str::FromStr; #[cfg(feature = "experimental-udp")] use tor_cell::relaycell::udp; @@ -576,40 +574,40 @@ fn test_connected_udp() { let cmd = RelayCmd::CONNECTED_UDP; assert_eq!(Into::::into(cmd), 17_u8); - let a_ipv4 = IpAddr::from_str("1.2.3.4").unwrap(); - let b_ipv4 = IpAddr::from_str("5.6.7.8").unwrap(); + let a_ipv4 = ("1.2.3.4", 80).try_into().unwrap(); + let b_ipv4 = ("5.6.7.8", 80).try_into().unwrap(); - let a_ipv6 = IpAddr::from_str("2600::1").unwrap(); - let b_ipv6 = IpAddr::from_str("2700::1").unwrap(); + let a_ipv6 = ("2600::1", 80).try_into().unwrap(); + let b_ipv6 = ("2700::1", 80).try_into().unwrap(); // Valid encoded message. Generated by hand with python. msg( cmd, - "04 04 01020304 - 04 04 05060708", + "04 04 01020304 0050 + 04 04 05060708 0050", &udp::ConnectedUdp::new(a_ipv4, b_ipv4).unwrap().into(), ); // Valid encoded message. Generated by hand with python. msg( cmd, - "06 10 26000000000000000000000000000001 - 06 10 27000000000000000000000000000001", + "06 10 26000000000000000000000000000001 0050 + 06 10 27000000000000000000000000000001 0050", &udp::ConnectedUdp::new(a_ipv6, b_ipv6).unwrap().into(), ); // Invalid our_address msg_error( cmd, - "01 04 01020304 - 04 04 05060708", + "01 04 01020304 0050 + 04 04 05060708 0050", BytesError::BadMessage("Our address is a Hostname"), ); // Invalid their_address msg_error( cmd, - "04 04 01020304 - 01 04 05060708", + "04 04 01020304 0050 + 01 04 05060708 0050", BytesError::BadMessage("Their address is a Hostname"), ); }