cell: Move UDP to its own module and feature gate it
Related to #463 Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
parent
8cb012ed78
commit
8fd6541985
|
@ -11,6 +11,13 @@ keywords = ["tor", "arti", "protocol"]
|
|||
categories = ["parser-implementations", "network-programming"]
|
||||
repository = "https://gitlab.torproject.org/tpo/core/arti.git/"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
# Enable experimental UDP support.
|
||||
experimental-udp = []
|
||||
# Enable testing only API
|
||||
testing = [ "experimental-udp" ]
|
||||
|
||||
[dependencies]
|
||||
arrayref = "0.3"
|
||||
bitflags = "1"
|
||||
|
|
|
@ -10,6 +10,8 @@ use caret::caret_int;
|
|||
use rand::{CryptoRng, Rng};
|
||||
|
||||
pub mod msg;
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
pub mod udp;
|
||||
|
||||
caret_int! {
|
||||
/// A command that identifies the type of a relay cell
|
||||
|
@ -45,6 +47,8 @@ caret_int! {
|
|||
/// Reply to an EXTEND2 cell.
|
||||
EXTENDED2 = 15,
|
||||
|
||||
/// NOTE: UDP command are reserved but only used with experimental-udp feature
|
||||
|
||||
/// UDP: Start of a stream
|
||||
CONNECT_UDP = 16,
|
||||
/// UDP: Acknowledge a CONNECT_UDP. Stream is open.
|
||||
|
@ -99,10 +103,11 @@ impl RelayCmd {
|
|||
| RelayCmd::CONNECTED
|
||||
| RelayCmd::RESOLVE
|
||||
| RelayCmd::RESOLVED
|
||||
| RelayCmd::BEGIN_DIR
|
||||
| RelayCmd::CONNECT_UDP
|
||||
| RelayCmd::CONNECTED_UDP
|
||||
| RelayCmd::DATAGRAM => StreamIdReq::WantNonZero,
|
||||
| RelayCmd::BEGIN_DIR => StreamIdReq::WantNonZero,
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
RelayCmd::CONNECT_UDP | RelayCmd::CONNECTED_UDP | RelayCmd::DATAGRAM => {
|
||||
StreamIdReq::WantNonZero
|
||||
}
|
||||
RelayCmd::EXTEND
|
||||
| RelayCmd::EXTENDED
|
||||
| RelayCmd::TRUNCATE
|
||||
|
|
|
@ -9,8 +9,7 @@ use crate::chancell::CELL_DATA_LEN;
|
|||
use caret::caret_int;
|
||||
use educe::Educe;
|
||||
use std::fmt::Write;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
use std::str::FromStr;
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
use tor_bytes::{Error, Result};
|
||||
use tor_bytes::{Readable, Reader, Writeable, Writer};
|
||||
use tor_linkspec::LinkSpec;
|
||||
|
@ -18,6 +17,9 @@ use tor_llcrypto::pk::rsa::RsaIdentity;
|
|||
|
||||
use bitflags::bitflags;
|
||||
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
use super::udp;
|
||||
|
||||
/// A single parsed relay message, sent or received along a circuit
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
|
@ -53,11 +55,14 @@ pub enum RelayMsg {
|
|||
/// Start a directory stream
|
||||
BeginDir,
|
||||
/// Start a UDP stream.
|
||||
ConnectUdp(ConnectUdp),
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
ConnectUdp(udp::ConnectUdp),
|
||||
/// Successful response to a ConnectUdp message
|
||||
ConnectedUdp(ConnectedUdp),
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
ConnectedUdp(udp::ConnectedUdp),
|
||||
/// UDP stream data
|
||||
Datagram(Datagram),
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
Datagram(udp::Datagram),
|
||||
|
||||
/// An unrecognized command.
|
||||
Unrecognized(Unrecognized),
|
||||
|
@ -100,8 +105,11 @@ impl RelayMsg {
|
|||
Resolve(_) => RelayCmd::RESOLVE,
|
||||
Resolved(_) => RelayCmd::RESOLVED,
|
||||
BeginDir => RelayCmd::BEGIN_DIR,
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
ConnectUdp(_) => RelayCmd::CONNECT_UDP,
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
ConnectedUdp(_) => RelayCmd::CONNECTED_UDP,
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
Datagram(_) => RelayCmd::DATAGRAM,
|
||||
Unrecognized(u) => u.cmd(),
|
||||
}
|
||||
|
@ -124,9 +132,14 @@ impl RelayMsg {
|
|||
RelayCmd::RESOLVE => RelayMsg::Resolve(Resolve::decode_from_reader(r)?),
|
||||
RelayCmd::RESOLVED => RelayMsg::Resolved(Resolved::decode_from_reader(r)?),
|
||||
RelayCmd::BEGIN_DIR => RelayMsg::BeginDir,
|
||||
RelayCmd::CONNECT_UDP => RelayMsg::ConnectUdp(ConnectUdp::decode_from_reader(r)?),
|
||||
RelayCmd::CONNECTED_UDP => RelayMsg::ConnectedUdp(ConnectedUdp::decode_from_reader(r)?),
|
||||
RelayCmd::DATAGRAM => RelayMsg::Datagram(Datagram::decode_from_reader(r)?),
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
RelayCmd::CONNECT_UDP => RelayMsg::ConnectUdp(udp::ConnectUdp::decode_from_reader(r)?),
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
RelayCmd::CONNECTED_UDP => {
|
||||
RelayMsg::ConnectedUdp(udp::ConnectedUdp::decode_from_reader(r)?)
|
||||
}
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
RelayCmd::DATAGRAM => RelayMsg::Datagram(udp::Datagram::decode_from_reader(r)?),
|
||||
_ => RelayMsg::Unrecognized(Unrecognized::decode_with_cmd(c, r)?),
|
||||
})
|
||||
}
|
||||
|
@ -149,8 +162,11 @@ impl RelayMsg {
|
|||
Resolve(b) => b.encode_onto(w),
|
||||
Resolved(b) => b.encode_onto(w),
|
||||
BeginDir => (),
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
ConnectUdp(b) => b.encode_onto(w),
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
ConnectedUdp(b) => b.encode_onto(w),
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
Datagram(b) => b.encode_onto(w),
|
||||
Unrecognized(b) => b.encode_onto(w),
|
||||
}
|
||||
|
@ -1132,297 +1148,6 @@ impl Body for Resolved {
|
|||
}
|
||||
}
|
||||
|
||||
/// Address contained in a ConnectUdp and ConnectedUdp cell which can
|
||||
/// represent a hostname, IPv4 or IPv6.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
pub enum Address {
|
||||
/// Hostname
|
||||
Hostname(Vec<u8>),
|
||||
/// IP version 4 address
|
||||
Ipv4(Ipv4Addr),
|
||||
/// IP version 6 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. It must fit in a u8 minus the nul term byte.
|
||||
const MAX_HOSTNAME_LEN: usize = (u8::MAX - 1) as usize;
|
||||
|
||||
impl Address {
|
||||
/// Return true iff this is a Hostname.
|
||||
pub fn is_hostname(&self) -> bool {
|
||||
matches!(self, Address::Hostname(_))
|
||||
}
|
||||
|
||||
/// Return the cell ABI address type value.
|
||||
fn abi_addr_type(&self) -> u8 {
|
||||
match self {
|
||||
Address::Hostname(_) => T_HOSTNAME,
|
||||
Address::Ipv4(_) => T_IPV4,
|
||||
Address::Ipv6(_) => T_IPV6,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the cell ABI address length. Note that the Hostname has an extra byte added to its
|
||||
/// length due to the nulterm character needed for encoding.
|
||||
fn abi_addr_len(&self) -> u8 {
|
||||
match self {
|
||||
// Add nulterm byte to length. Length can't be above MAX_HOSTNAME_LEN.
|
||||
Address::Hostname(h) => (h.len() + 1).try_into().expect("Address hostname too long"),
|
||||
Address::Ipv4(_) => 4,
|
||||
Address::Ipv6(_) => 16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Readable for Address {
|
||||
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
|
||||
let addr_type = r.take_u8()?;
|
||||
let addr_len = r.take_u8()? as usize;
|
||||
|
||||
Ok(match addr_type {
|
||||
T_HOSTNAME => {
|
||||
let h = r.take_until(0)?;
|
||||
if h.len() != (addr_len - 1) {
|
||||
return Err(Error::BadMessage(
|
||||
"Address length doesn't match nulterm hostname",
|
||||
));
|
||||
}
|
||||
Self::Hostname(h.into())
|
||||
}
|
||||
T_IPV4 => Self::Ipv4(r.extract()?),
|
||||
T_IPV6 => Self::Ipv6(r.extract()?),
|
||||
_ => return Err(Error::BadMessage("Unknown address type")),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Writeable for Address {
|
||||
fn write_onto<B: Writer + ?Sized>(&self, w: &mut B) {
|
||||
// Address type.
|
||||
w.write_u8(self.abi_addr_type());
|
||||
// Address length.
|
||||
w.write_u8(self.abi_addr_len());
|
||||
|
||||
match self {
|
||||
Address::Hostname(h) => {
|
||||
w.write_all(&h[..]);
|
||||
w.write_zeros(1); // Nul terminating byte.
|
||||
}
|
||||
Address::Ipv4(ip) => w.write(ip),
|
||||
Address::Ipv6(ip) => w.write(ip),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Address {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
if s.is_empty() {
|
||||
return Err(Error::BadMessage("Empty address"));
|
||||
}
|
||||
if !s.is_ascii() {
|
||||
return Err(Error::BadMessage("Non-ascii address"));
|
||||
}
|
||||
|
||||
if let Ok(ipv4) = Ipv4Addr::from_str(s) {
|
||||
Ok(Self::Ipv4(ipv4))
|
||||
} else if let Ok(ipv6) = Ipv6Addr::from_str(s) {
|
||||
Ok(Self::Ipv6(ipv6))
|
||||
} else {
|
||||
if s.len() > MAX_HOSTNAME_LEN {
|
||||
return Err(Error::BadMessage("Hostname too long"));
|
||||
}
|
||||
let mut addr = s.to_string();
|
||||
addr.make_ascii_lowercase();
|
||||
Ok(Self::Hostname(addr.into_bytes()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IpAddr> for Address {
|
||||
fn from(ip: IpAddr) -> Self {
|
||||
match ip {
|
||||
IpAddr::V4(ip) => Address::Ipv4(ip),
|
||||
IpAddr::V6(ip) => Address::Ipv6(ip),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A ConnectUdp message creates a new UDP data stream.
|
||||
///
|
||||
/// Upon receiving a ConnectUdp message, a relay tries to connect to the given address with the UDP
|
||||
/// procotol if the xit policy permits.
|
||||
///
|
||||
/// If the exit decides to reject the message, or if the UDP connection fails, the exit should send
|
||||
/// an End message.
|
||||
///
|
||||
/// Clients should reject these messages.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ConnectUdp {
|
||||
/// Same as Begin flags.
|
||||
flags: BeginFlags,
|
||||
/// Address to connect to. Can be Hostname, IPv4 or IPv6.
|
||||
addr: Address,
|
||||
/// Target port
|
||||
port: u16,
|
||||
}
|
||||
|
||||
impl ConnectUdp {
|
||||
/// Construct a new ConnectUdp cell
|
||||
pub fn new<F>(addr: &str, port: u16, flags: F) -> crate::Result<Self>
|
||||
where
|
||||
F: Into<BeginFlags>,
|
||||
{
|
||||
Ok(Self {
|
||||
addr: Address::from_str(addr)?,
|
||||
port,
|
||||
flags: flags.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Body for ConnectUdp {
|
||||
fn into_message(self) -> RelayMsg {
|
||||
RelayMsg::ConnectUdp(self)
|
||||
}
|
||||
|
||||
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
|
||||
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<u8>) {
|
||||
w.write_u32(self.flags.bits());
|
||||
w.write(&self.addr);
|
||||
w.write_u16(self.port);
|
||||
}
|
||||
}
|
||||
|
||||
/// A ConnectedUdp cell sent in response to a ConnectUdp.
|
||||
#[derive(Debug, Clone)]
|
||||
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,
|
||||
/// The address that the stream is connected to.
|
||||
their_address: Address,
|
||||
}
|
||||
|
||||
impl ConnectedUdp {
|
||||
/// Construct a new ConnectedUdp cell.
|
||||
pub fn new(our: IpAddr, their: IpAddr) -> Result<Self> {
|
||||
Ok(Self {
|
||||
our_address: our.into(),
|
||||
their_address: their.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Body for ConnectedUdp {
|
||||
fn into_message(self) -> RelayMsg {
|
||||
RelayMsg::ConnectedUdp(self)
|
||||
}
|
||||
|
||||
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
|
||||
let our_address: Address = r.extract()?;
|
||||
if our_address.is_hostname() {
|
||||
return Err(Error::BadMessage("Our address is a Hostname"));
|
||||
}
|
||||
let their_address: Address = r.extract()?;
|
||||
if their_address.is_hostname() {
|
||||
return Err(Error::BadMessage("Their address is a Hostname"));
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
our_address,
|
||||
their_address,
|
||||
})
|
||||
}
|
||||
|
||||
fn encode_onto(self, w: &mut Vec<u8>) {
|
||||
w.write(&self.our_address);
|
||||
w.write(&self.their_address);
|
||||
}
|
||||
}
|
||||
|
||||
/// A Datagram message represents data sent along a UDP stream.
|
||||
///
|
||||
/// Upon receiving a Datagram message for a live stream, the client or
|
||||
/// exit sends that data onto the associated UDP connection.
|
||||
///
|
||||
/// These messages hold between 1 and [Datagram::MAXLEN] bytes of data each.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Datagram {
|
||||
/// Contents of the cell, to be sent on a specific stream
|
||||
body: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Datagram {
|
||||
/// The longest allowable body length for a single data cell.
|
||||
pub const MAXLEN: usize = CELL_DATA_LEN - 11;
|
||||
|
||||
/// Construct a new data cell.
|
||||
///
|
||||
/// Returns an error if `inp` is longer than [`Data::MAXLEN`] bytes.
|
||||
pub fn new(inp: &[u8]) -> crate::Result<Self> {
|
||||
if inp.len() > Data::MAXLEN {
|
||||
return Err(crate::Error::CantEncode);
|
||||
}
|
||||
Ok(Self::new_unchecked(inp.into()))
|
||||
}
|
||||
|
||||
/// Construct a new cell from a provided vector of bytes.
|
||||
///
|
||||
/// The vector _must_ have fewer than [`Data::MAXLEN`] bytes.
|
||||
fn new_unchecked(body: Vec<u8>) -> Self {
|
||||
Self { body }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Datagram> for Vec<u8> {
|
||||
fn from(data: Datagram) -> Vec<u8> {
|
||||
data.body
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Datagram {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.body[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl Body for Datagram {
|
||||
fn into_message(self) -> RelayMsg {
|
||||
RelayMsg::Datagram(self)
|
||||
}
|
||||
|
||||
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
|
||||
Ok(Datagram {
|
||||
body: r.take(r.remaining())?.into(),
|
||||
})
|
||||
}
|
||||
|
||||
fn encode_onto(mut self, w: &mut Vec<u8>) {
|
||||
w.append(&mut self.body);
|
||||
}
|
||||
}
|
||||
|
||||
/// A relay message that we didn't recognize
|
||||
///
|
||||
/// NOTE: Clients should generally reject these.
|
||||
|
|
|
@ -35,7 +35,7 @@ const MAX_HOSTNAME_LEN: usize = (u8::MAX - 1) as usize;
|
|||
|
||||
impl Address {
|
||||
/// Return true iff this is a Hostname.
|
||||
fn is_hostname(&self) -> bool {
|
||||
pub fn is_hostname(&self) -> bool {
|
||||
matches!(self, Address::Hostname(_))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
// Tests for encoding/decoding relay messages into relay cell bodies.
|
||||
|
||||
use tor_bytes::Error;
|
||||
use tor_cell::relaycell::{msg, msg::RelayMsg, RelayCell, RelayCmd, StreamId};
|
||||
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
use std::{
|
||||
net::{Ipv4Addr, Ipv6Addr},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use tor_bytes::Error;
|
||||
use tor_cell::relaycell::{msg, msg::Address, msg::RelayMsg, RelayCell, RelayCmd, StreamId};
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
use tor_cell::relaycell::udp::Address;
|
||||
|
||||
const CELL_BODY_LEN: usize = 509;
|
||||
|
||||
|
@ -120,6 +123,7 @@ fn test_streamid() {
|
|||
assert!(!RelayCmd::EXTEND2.accepts_streamid_val(two));
|
||||
}
|
||||
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
#[test]
|
||||
fn test_address() {
|
||||
// IPv4
|
||||
|
|
|
@ -8,10 +8,14 @@ use tor_cell::relaycell::{msg, RelayCmd};
|
|||
use tor_llcrypto::pk::rsa::RsaIdentity;
|
||||
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::str::FromStr;
|
||||
|
||||
use hex_literal::hex;
|
||||
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
use std::str::FromStr;
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
use tor_cell::relaycell::udp;
|
||||
|
||||
/// Decode `s`, a hexadecimal value that may have spaces in it.
|
||||
///
|
||||
/// Panic if the input is not valid hexadecimal
|
||||
|
@ -475,6 +479,7 @@ fn test_data() {
|
|||
assert_eq!(rest, &b[498..]);
|
||||
}
|
||||
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
#[test]
|
||||
fn test_connect_udp() {
|
||||
let cmd = RelayCmd::CONNECT_UDP;
|
||||
|
@ -485,7 +490,7 @@ fn test_connect_udp() {
|
|||
cmd,
|
||||
"00000000 01 0B
|
||||
7269736575702E6E657400 01BB",
|
||||
&msg::ConnectUdp::new("riseup.net", 443, 0).unwrap().into(),
|
||||
&udp::ConnectUdp::new("riseup.net", 443, 0).unwrap().into(),
|
||||
);
|
||||
|
||||
// Valid encoded message with flags. Generated by hand with python.
|
||||
|
@ -493,7 +498,7 @@ fn test_connect_udp() {
|
|||
cmd,
|
||||
"00000003 01 0F
|
||||
746F7270726F6A6563742E6F726700 0050",
|
||||
&msg::ConnectUdp::new("torproject.org", 80, 3)
|
||||
&udp::ConnectUdp::new("torproject.org", 80, 3)
|
||||
.unwrap()
|
||||
.into(),
|
||||
);
|
||||
|
@ -503,7 +508,7 @@ fn test_connect_udp() {
|
|||
cmd,
|
||||
"00000000 04 04
|
||||
01020304 0050",
|
||||
&msg::ConnectUdp::new("1.2.3.4", 80, 0).unwrap().into(),
|
||||
&udp::ConnectUdp::new("1.2.3.4", 80, 0).unwrap().into(),
|
||||
);
|
||||
|
||||
// Valid encoded message with IPv6
|
||||
|
@ -511,7 +516,7 @@ fn test_connect_udp() {
|
|||
cmd,
|
||||
"00000000 06 10
|
||||
26000001000200000000000000000004 0050",
|
||||
&msg::ConnectUdp::new("2600:1:2::4", 80, 0).unwrap().into(),
|
||||
&udp::ConnectUdp::new("2600:1:2::4", 80, 0).unwrap().into(),
|
||||
);
|
||||
|
||||
// Invalid length for hostname.
|
||||
|
@ -537,6 +542,7 @@ fn test_connect_udp() {
|
|||
msg_error(cmd, "00000000 01 00 18167251 01BB", BytesError::Truncated);
|
||||
}
|
||||
|
||||
#[cfg(feature = "experimental-udp")]
|
||||
#[test]
|
||||
fn test_connected_udp() {
|
||||
let cmd = RelayCmd::CONNECTED_UDP;
|
||||
|
@ -553,7 +559,7 @@ fn test_connected_udp() {
|
|||
cmd,
|
||||
"04 04 01020304
|
||||
04 04 05060708",
|
||||
&msg::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.
|
||||
|
@ -561,7 +567,7 @@ fn test_connected_udp() {
|
|||
cmd,
|
||||
"06 10 26000000000000000000000000000001
|
||||
06 10 27000000000000000000000000000001",
|
||||
&msg::ConnectedUdp::new(a_ipv6, b_ipv6).unwrap().into(),
|
||||
&udp::ConnectedUdp::new(a_ipv6, b_ipv6).unwrap().into(),
|
||||
);
|
||||
|
||||
// Length doesn't match hostname length.
|
||||
|
|
Loading…
Reference in New Issue