udp: New AddressPort used in cells

Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
David Goulet 2022-06-07 11:45:22 -04:00
parent a591bf353a
commit 3da4b95434
2 changed files with 71 additions and 42 deletions

View File

@ -10,8 +10,55 @@ use std::str::FromStr;
use tor_bytes::{Error, Result}; use tor_bytes::{Error, Result};
use tor_bytes::{Readable, Reader, Writeable, Writer}; 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 /// 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<Self> {
Ok(Self {
addr: r.extract()?,
port: r.take_u16()?,
})
}
}
impl Writeable for AddressPort {
fn write_onto<B: Writer + ?Sized>(&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<Self> {
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)] #[derive(Clone, Debug, Eq, PartialEq)]
#[non_exhaustive] #[non_exhaustive]
pub enum Address { pub enum Address {
@ -23,16 +70,6 @@ pub enum Address {
Ipv6(Ipv6Addr), 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 { impl Address {
/// Return true iff this is a Hostname. /// Return true iff this is a Hostname.
pub fn is_hostname(&self) -> bool { pub fn is_hostname(&self) -> bool {
@ -147,9 +184,7 @@ pub struct ConnectUdp {
/// Same as Begin flags. /// Same as Begin flags.
flags: msg::BeginFlags, flags: msg::BeginFlags,
/// Address to connect to. Can be Hostname, IPv4 or IPv6. /// Address to connect to. Can be Hostname, IPv4 or IPv6.
addr: Address, addr: AddressPort,
/// Target port
port: u16,
} }
impl ConnectUdp { impl ConnectUdp {
@ -159,8 +194,7 @@ impl ConnectUdp {
F: Into<msg::BeginFlags>, F: Into<msg::BeginFlags>,
{ {
Ok(Self { Ok(Self {
addr: Address::from_str(addr)?, addr: (addr, port).try_into()?,
port,
flags: flags.into(), flags: flags.into(),
}) })
} }
@ -174,19 +208,16 @@ impl msg::Body for ConnectUdp {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> { fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let flags = r.take_u32()?; let flags = r.take_u32()?;
let addr = r.extract()?; let addr = r.extract()?;
let port = r.take_u16()?;
Ok(Self { Ok(Self {
flags: flags.into(), flags: flags.into(),
addr, addr,
port,
}) })
} }
fn encode_onto(self, w: &mut Vec<u8>) { fn encode_onto(self, w: &mut Vec<u8>) {
w.write_u32(self.flags.bits()); w.write_u32(self.flags.bits());
w.write(&self.addr); w.write(&self.addr);
w.write_u16(self.port);
} }
} }
@ -195,17 +226,17 @@ impl msg::Body for ConnectUdp {
pub struct ConnectedUdp { pub struct ConnectedUdp {
/// The address that the relay has bound locally of a ConnectUdp. Note /// The address that the relay has bound locally of a ConnectUdp. Note
/// that this might not be the relay address from the descriptor. /// 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. /// The address that the stream is connected to.
their_address: Address, their_address: AddressPort,
} }
impl ConnectedUdp { impl ConnectedUdp {
/// Construct a new ConnectedUdp cell. /// Construct a new ConnectedUdp cell.
pub fn new(our: IpAddr, their: IpAddr) -> Result<Self> { pub fn new(our_address: AddressPort, their_address: AddressPort) -> Result<Self> {
Ok(Self { Ok(Self {
our_address: our.into(), our_address,
their_address: their.into(), their_address,
}) })
} }
} }
@ -216,12 +247,12 @@ impl msg::Body for ConnectedUdp {
} }
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> { fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let our_address: Address = r.extract()?; let our_address: AddressPort = r.extract()?;
if our_address.is_hostname() { if our_address.addr.is_hostname() {
return Err(Error::BadMessage("Our address is a Hostname")); return Err(Error::BadMessage("Our address is a Hostname"));
} }
let their_address: Address = r.extract()?; let their_address: AddressPort = r.extract()?;
if their_address.is_hostname() { if their_address.addr.is_hostname() {
return Err(Error::BadMessage("Their address is a Hostname")); return Err(Error::BadMessage("Their address is a Hostname"));
} }

View File

@ -11,8 +11,6 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use hex_literal::hex; use hex_literal::hex;
#[cfg(feature = "experimental-udp")]
use std::str::FromStr;
#[cfg(feature = "experimental-udp")] #[cfg(feature = "experimental-udp")]
use tor_cell::relaycell::udp; use tor_cell::relaycell::udp;
@ -576,40 +574,40 @@ fn test_connected_udp() {
let cmd = RelayCmd::CONNECTED_UDP; let cmd = RelayCmd::CONNECTED_UDP;
assert_eq!(Into::<u8>::into(cmd), 17_u8); assert_eq!(Into::<u8>::into(cmd), 17_u8);
let a_ipv4 = IpAddr::from_str("1.2.3.4").unwrap(); let a_ipv4 = ("1.2.3.4", 80).try_into().unwrap();
let b_ipv4 = IpAddr::from_str("5.6.7.8").unwrap(); let b_ipv4 = ("5.6.7.8", 80).try_into().unwrap();
let a_ipv6 = IpAddr::from_str("2600::1").unwrap(); let a_ipv6 = ("2600::1", 80).try_into().unwrap();
let b_ipv6 = IpAddr::from_str("2700::1").unwrap(); let b_ipv6 = ("2700::1", 80).try_into().unwrap();
// Valid encoded message. Generated by hand with python. // Valid encoded message. Generated by hand with python.
msg( msg(
cmd, cmd,
"04 04 01020304 "04 04 01020304 0050
04 04 05060708", 04 04 05060708 0050",
&udp::ConnectedUdp::new(a_ipv4, b_ipv4).unwrap().into(), &udp::ConnectedUdp::new(a_ipv4, b_ipv4).unwrap().into(),
); );
// Valid encoded message. Generated by hand with python. // Valid encoded message. Generated by hand with python.
msg( msg(
cmd, cmd,
"06 10 26000000000000000000000000000001 "06 10 26000000000000000000000000000001 0050
06 10 27000000000000000000000000000001", 06 10 27000000000000000000000000000001 0050",
&udp::ConnectedUdp::new(a_ipv6, b_ipv6).unwrap().into(), &udp::ConnectedUdp::new(a_ipv6, b_ipv6).unwrap().into(),
); );
// Invalid our_address // Invalid our_address
msg_error( msg_error(
cmd, cmd,
"01 04 01020304 "01 04 01020304 0050
04 04 05060708", 04 04 05060708 0050",
BytesError::BadMessage("Our address is a Hostname"), BytesError::BadMessage("Our address is a Hostname"),
); );
// Invalid their_address // Invalid their_address
msg_error( msg_error(
cmd, cmd,
"04 04 01020304 "04 04 01020304 0050
01 04 05060708", 01 04 05060708 0050",
BytesError::BadMessage("Their address is a Hostname"), BytesError::BadMessage("Their address is a Hostname"),
); );
} }