2016-12-14 09:59:47 +08:00
|
|
|
use core::fmt;
|
2016-12-14 08:11:45 +08:00
|
|
|
use byteorder::{ByteOrder, NetworkEndian};
|
|
|
|
|
|
|
|
use Error;
|
2016-12-20 21:54:11 +08:00
|
|
|
use super::{IpProtocol, IpAddress};
|
2016-12-14 08:11:45 +08:00
|
|
|
use super::ip::checksum;
|
|
|
|
|
|
|
|
/// A read/write wrapper around an User Datagram Protocol packet buffer.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Packet<T: AsRef<[u8]>> {
|
|
|
|
buffer: T
|
|
|
|
}
|
|
|
|
|
|
|
|
mod field {
|
2016-12-17 13:12:45 +08:00
|
|
|
#![allow(non_snake_case)]
|
|
|
|
|
2016-12-14 08:11:45 +08:00
|
|
|
use wire::field::*;
|
|
|
|
|
|
|
|
pub const SRC_PORT: Field = 0..2;
|
|
|
|
pub const DST_PORT: Field = 2..4;
|
|
|
|
pub const LENGTH: Field = 4..6;
|
|
|
|
pub const CHECKSUM: Field = 6..8;
|
2016-12-17 13:12:45 +08:00
|
|
|
|
|
|
|
pub fn PAYLOAD(length: u16) -> Field {
|
|
|
|
CHECKSUM.end..(length as usize)
|
|
|
|
}
|
2016-12-14 08:11:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: AsRef<[u8]>> Packet<T> {
|
Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.
This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
* `fn check_len(&self) -> Result<(), Error>`, purely a validator;
* `fn new(T) -> Self`, purely a wrapper;
* `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.
This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).
Fixes #17.
2017-06-24 17:15:22 +08:00
|
|
|
/// Imbue a raw octet buffer with UDP packet structure.
|
|
|
|
pub fn new(buffer: T) -> Packet<T> {
|
|
|
|
Packet { buffer }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Shorthand for a combination of [new] and [check_len].
|
|
|
|
///
|
|
|
|
/// [new]: #method.new
|
|
|
|
/// [check_len]: #method.check_len
|
|
|
|
pub fn new_checked(buffer: T) -> Result<Packet<T>, Error> {
|
|
|
|
let packet = Self::new(buffer);
|
2017-06-25 00:34:32 +08:00
|
|
|
packet.check_len()?;
|
Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.
This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
* `fn check_len(&self) -> Result<(), Error>`, purely a validator;
* `fn new(T) -> Self`, purely a wrapper;
* `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.
This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).
Fixes #17.
2017-06-24 17:15:22 +08:00
|
|
|
Ok(packet)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Ensure that no accessor method will panic if called.
|
|
|
|
/// Returns `Err(Error::Truncated)` if the buffer is too short.
|
2017-06-24 20:15:18 +08:00
|
|
|
/// Returns `Err(Error::Malformed)` if the length field has a value smaller
|
|
|
|
/// than the header length.
|
Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.
This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
* `fn check_len(&self) -> Result<(), Error>`, purely a validator;
* `fn new(T) -> Self`, purely a wrapper;
* `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.
This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).
Fixes #17.
2017-06-24 17:15:22 +08:00
|
|
|
///
|
2017-06-24 20:15:18 +08:00
|
|
|
/// The result of this check is invalidated by calling [set_len].
|
Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.
This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
* `fn check_len(&self) -> Result<(), Error>`, purely a validator;
* `fn new(T) -> Self`, purely a wrapper;
* `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.
This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).
Fixes #17.
2017-06-24 17:15:22 +08:00
|
|
|
///
|
2017-06-24 20:15:18 +08:00
|
|
|
/// [set_len]: #method.set_len
|
Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.
This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
* `fn check_len(&self) -> Result<(), Error>`, purely a validator;
* `fn new(T) -> Self`, purely a wrapper;
* `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.
This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).
Fixes #17.
2017-06-24 17:15:22 +08:00
|
|
|
pub fn check_len(&self) -> Result<(), Error> {
|
2017-06-24 20:15:18 +08:00
|
|
|
let buffer_len = self.buffer.as_ref().len();
|
|
|
|
if buffer_len < field::CHECKSUM.end {
|
2016-12-14 08:11:45 +08:00
|
|
|
Err(Error::Truncated)
|
|
|
|
} else {
|
2017-06-24 20:15:18 +08:00
|
|
|
let field_len = self.len() as usize;
|
|
|
|
if buffer_len < field_len {
|
2016-12-14 08:11:45 +08:00
|
|
|
Err(Error::Truncated)
|
2017-06-24 20:15:18 +08:00
|
|
|
} else if field_len < field::CHECKSUM.end {
|
|
|
|
Err(Error::Malformed)
|
2016-12-14 08:11:45 +08:00
|
|
|
} else {
|
Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.
This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
* `fn check_len(&self) -> Result<(), Error>`, purely a validator;
* `fn new(T) -> Self`, purely a wrapper;
* `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.
This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).
Fixes #17.
2017-06-24 17:15:22 +08:00
|
|
|
Ok(())
|
2016-12-14 08:11:45 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.
This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
* `fn check_len(&self) -> Result<(), Error>`, purely a validator;
* `fn new(T) -> Self`, purely a wrapper;
* `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.
This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).
Fixes #17.
2017-06-24 17:15:22 +08:00
|
|
|
/// Consume the packet, returning the underlying buffer.
|
2016-12-14 08:11:45 +08:00
|
|
|
pub fn into_inner(self) -> T {
|
|
|
|
self.buffer
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the source port field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-14 08:11:45 +08:00
|
|
|
pub fn src_port(&self) -> u16 {
|
|
|
|
let data = self.buffer.as_ref();
|
|
|
|
NetworkEndian::read_u16(&data[field::SRC_PORT])
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the destination port field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-14 08:11:45 +08:00
|
|
|
pub fn dst_port(&self) -> u16 {
|
|
|
|
let data = self.buffer.as_ref();
|
|
|
|
NetworkEndian::read_u16(&data[field::DST_PORT])
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the length field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-14 08:11:45 +08:00
|
|
|
pub fn len(&self) -> u16 {
|
|
|
|
let data = self.buffer.as_ref();
|
|
|
|
NetworkEndian::read_u16(&data[field::LENGTH])
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the checksum field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-14 08:11:45 +08:00
|
|
|
pub fn checksum(&self) -> u16 {
|
|
|
|
let data = self.buffer.as_ref();
|
|
|
|
NetworkEndian::read_u16(&data[field::CHECKSUM])
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Validate the packet checksum.
|
2016-12-14 09:59:47 +08:00
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
/// This function panics unless `src_addr` and `dst_addr` belong to the same family,
|
|
|
|
/// and that family is IPv4 or IPv6.
|
2017-06-24 23:26:15 +08:00
|
|
|
///
|
|
|
|
/// # Fuzzing
|
|
|
|
/// This function always returns `true` when fuzzing.
|
2016-12-20 21:54:11 +08:00
|
|
|
pub fn verify_checksum(&self, src_addr: &IpAddress, dst_addr: &IpAddress) -> bool {
|
2017-06-24 23:26:15 +08:00
|
|
|
if cfg!(fuzzing) { return true }
|
|
|
|
|
2016-12-14 08:11:45 +08:00
|
|
|
let data = self.buffer.as_ref();
|
2016-12-14 09:59:47 +08:00
|
|
|
checksum::combine(&[
|
2016-12-20 21:54:11 +08:00
|
|
|
checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Udp,
|
2016-12-14 09:59:47 +08:00
|
|
|
self.len() as u32),
|
|
|
|
checksum::data(&data[..self.len() as usize])
|
|
|
|
]) == !0
|
2016-12-14 08:11:45 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
|
|
|
|
/// Return a pointer to the payload.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-14 08:11:45 +08:00
|
|
|
pub fn payload(&self) -> &'a [u8] {
|
2016-12-17 13:12:45 +08:00
|
|
|
let length = self.len();
|
2016-12-14 08:11:45 +08:00
|
|
|
let data = self.buffer.as_ref();
|
2016-12-17 13:12:45 +08:00
|
|
|
&data[field::PAYLOAD(length)]
|
2016-12-14 08:11:45 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
|
|
|
|
/// Set the source port field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-14 08:11:45 +08:00
|
|
|
pub fn set_src_port(&mut self, value: u16) {
|
|
|
|
let mut data = self.buffer.as_mut();
|
|
|
|
NetworkEndian::write_u16(&mut data[field::SRC_PORT], value)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the destination port field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-14 08:11:45 +08:00
|
|
|
pub fn set_dst_port(&mut self, value: u16) {
|
|
|
|
let mut data = self.buffer.as_mut();
|
|
|
|
NetworkEndian::write_u16(&mut data[field::DST_PORT], value)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the length field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-14 08:11:45 +08:00
|
|
|
pub fn set_len(&mut self, value: u16) {
|
|
|
|
let mut data = self.buffer.as_mut();
|
|
|
|
NetworkEndian::write_u16(&mut data[field::LENGTH], value)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the checksum field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-14 08:11:45 +08:00
|
|
|
pub fn set_checksum(&mut self, value: u16) {
|
|
|
|
let mut data = self.buffer.as_mut();
|
|
|
|
NetworkEndian::write_u16(&mut data[field::CHECKSUM], value)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Compute and fill in the header checksum.
|
2016-12-14 09:59:47 +08:00
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
/// This function panics unless `src_addr` and `dst_addr` belong to the same family,
|
|
|
|
/// and that family is IPv4 or IPv6.
|
2016-12-20 21:54:11 +08:00
|
|
|
pub fn fill_checksum(&mut self, src_addr: &IpAddress, dst_addr: &IpAddress) {
|
2016-12-14 08:11:45 +08:00
|
|
|
self.set_checksum(0);
|
|
|
|
let checksum = {
|
|
|
|
let data = self.buffer.as_ref();
|
2016-12-14 09:59:47 +08:00
|
|
|
!checksum::combine(&[
|
2016-12-20 21:54:11 +08:00
|
|
|
checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Udp,
|
2016-12-14 09:59:47 +08:00
|
|
|
self.len() as u32),
|
|
|
|
checksum::data(&data[..self.len() as usize])
|
|
|
|
])
|
2016-12-14 08:11:45 +08:00
|
|
|
};
|
|
|
|
self.set_checksum(checksum)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Packet<&'a mut T> {
|
2016-12-19 05:42:44 +08:00
|
|
|
/// Return a mutable pointer to the payload.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-14 08:11:45 +08:00
|
|
|
pub fn payload_mut(&mut self) -> &mut [u8] {
|
2016-12-17 13:12:45 +08:00
|
|
|
let length = self.len();
|
2016-12-14 08:11:45 +08:00
|
|
|
let mut data = self.buffer.as_mut();
|
2016-12-17 13:12:45 +08:00
|
|
|
&mut data[field::PAYLOAD(length)]
|
2016-12-14 08:11:45 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-14 09:59:47 +08:00
|
|
|
/// A high-level representation of an User Datagram Protocol packet.
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
|
|
pub struct Repr<'a> {
|
|
|
|
pub src_port: u16,
|
|
|
|
pub dst_port: u16,
|
|
|
|
pub payload: &'a [u8]
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Repr<'a> {
|
|
|
|
/// Parse an User Datagram Protocol packet and return a high-level representation.
|
|
|
|
pub fn parse<T: ?Sized>(packet: &Packet<&'a T>,
|
2016-12-20 21:54:11 +08:00
|
|
|
src_addr: &IpAddress,
|
|
|
|
dst_addr: &IpAddress) -> Result<Repr<'a>, Error>
|
2016-12-14 09:59:47 +08:00
|
|
|
where T: AsRef<[u8]> {
|
|
|
|
// Destination port cannot be omitted (but source port can be).
|
|
|
|
if packet.dst_port() == 0 { return Err(Error::Malformed) }
|
|
|
|
// Valid checksum is expected...
|
|
|
|
if !packet.verify_checksum(src_addr, dst_addr) {
|
|
|
|
match (src_addr, dst_addr) {
|
2016-12-20 21:54:11 +08:00
|
|
|
(&IpAddress::Ipv4(_), &IpAddress::Ipv4(_))
|
2016-12-14 09:59:47 +08:00
|
|
|
if packet.checksum() != 0 => {
|
|
|
|
// ... except on UDP-over-IPv4, where it can be omitted.
|
|
|
|
return Err(Error::Checksum)
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
return Err(Error::Checksum)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Repr {
|
|
|
|
src_port: packet.src_port(),
|
|
|
|
dst_port: packet.dst_port(),
|
|
|
|
payload: packet.payload()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the length of a packet that will be emitted from this high-level representation.
|
2016-12-20 07:50:04 +08:00
|
|
|
pub fn buffer_len(&self) -> usize {
|
2016-12-17 13:12:45 +08:00
|
|
|
field::CHECKSUM.end + self.payload.len()
|
2016-12-14 09:59:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Emit a high-level representation into an User Datagram Protocol packet.
|
|
|
|
pub fn emit<T: ?Sized>(&self, packet: &mut Packet<&mut T>,
|
2016-12-20 21:54:11 +08:00
|
|
|
src_addr: &IpAddress,
|
|
|
|
dst_addr: &IpAddress)
|
2016-12-14 09:59:47 +08:00
|
|
|
where T: AsRef<[u8]> + AsMut<[u8]> {
|
|
|
|
packet.set_src_port(self.src_port);
|
|
|
|
packet.set_dst_port(self.dst_port);
|
2016-12-17 13:12:45 +08:00
|
|
|
packet.set_len((field::CHECKSUM.end + self.payload.len()) as u16);
|
2016-12-14 09:59:47 +08:00
|
|
|
packet.payload_mut().copy_from_slice(self.payload);
|
|
|
|
packet.fill_checksum(src_addr, dst_addr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
// Cannot use Repr::parse because we don't have the IP addresses.
|
|
|
|
write!(f, "UDP src={} dst={} len={}",
|
|
|
|
self.src_port(), self.dst_port(), self.payload().len())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> fmt::Display for Repr<'a> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "UDP src={} dst={} len={}",
|
|
|
|
self.src_port, self.dst_port, self.payload.len())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
use super::pretty_print::{PrettyPrint, PrettyIndent};
|
|
|
|
|
|
|
|
impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
|
|
|
|
fn pretty_print(buffer: &AsRef<[u8]>, f: &mut fmt::Formatter,
|
|
|
|
indent: &mut PrettyIndent) -> fmt::Result {
|
Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.
This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
* `fn check_len(&self) -> Result<(), Error>`, purely a validator;
* `fn new(T) -> Self`, purely a wrapper;
* `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.
This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).
Fixes #17.
2017-06-24 17:15:22 +08:00
|
|
|
match Packet::new_checked(buffer) {
|
2016-12-14 09:59:47 +08:00
|
|
|
Err(err) => write!(f, "{}({})\n", indent, err),
|
|
|
|
Ok(packet) => write!(f, "{}{}\n", indent, packet)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-14 08:11:45 +08:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2016-12-14 09:59:47 +08:00
|
|
|
use wire::Ipv4Address;
|
2016-12-14 08:11:45 +08:00
|
|
|
use super::*;
|
|
|
|
|
2016-12-14 09:59:47 +08:00
|
|
|
const SRC_ADDR: Ipv4Address = Ipv4Address([192, 168, 1, 1]);
|
|
|
|
const DST_ADDR: Ipv4Address = Ipv4Address([192, 168, 1, 2]);
|
|
|
|
|
2016-12-14 08:11:45 +08:00
|
|
|
static PACKET_BYTES: [u8; 12] =
|
|
|
|
[0xbf, 0x00, 0x00, 0x35,
|
2016-12-14 09:59:47 +08:00
|
|
|
0x00, 0x0c, 0x12, 0x4d,
|
2016-12-14 08:11:45 +08:00
|
|
|
0xaa, 0x00, 0x00, 0xff];
|
|
|
|
|
|
|
|
static PAYLOAD_BYTES: [u8; 4] =
|
|
|
|
[0xaa, 0x00, 0x00, 0xff];
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_deconstruct() {
|
Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.
This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
* `fn check_len(&self) -> Result<(), Error>`, purely a validator;
* `fn new(T) -> Self`, purely a wrapper;
* `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.
This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).
Fixes #17.
2017-06-24 17:15:22 +08:00
|
|
|
let packet = Packet::new(&PACKET_BYTES[..]);
|
2016-12-14 08:11:45 +08:00
|
|
|
assert_eq!(packet.src_port(), 48896);
|
|
|
|
assert_eq!(packet.dst_port(), 53);
|
|
|
|
assert_eq!(packet.len(), 12);
|
2016-12-14 09:59:47 +08:00
|
|
|
assert_eq!(packet.checksum(), 0x124d);
|
2016-12-14 08:11:45 +08:00
|
|
|
assert_eq!(packet.payload(), &PAYLOAD_BYTES[..]);
|
2016-12-14 09:59:47 +08:00
|
|
|
assert_eq!(packet.verify_checksum(&SRC_ADDR.into(), &DST_ADDR.into()), true);
|
2016-12-14 08:11:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_construct() {
|
|
|
|
let mut bytes = vec![0; 12];
|
Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.
This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
* `fn check_len(&self) -> Result<(), Error>`, purely a validator;
* `fn new(T) -> Self`, purely a wrapper;
* `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.
This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).
Fixes #17.
2017-06-24 17:15:22 +08:00
|
|
|
let mut packet = Packet::new(&mut bytes);
|
2016-12-14 08:11:45 +08:00
|
|
|
packet.set_src_port(48896);
|
|
|
|
packet.set_dst_port(53);
|
|
|
|
packet.set_len(12);
|
|
|
|
packet.set_checksum(0xffff);
|
|
|
|
packet.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]);
|
2016-12-14 09:59:47 +08:00
|
|
|
packet.fill_checksum(&SRC_ADDR.into(), &DST_ADDR.into());
|
|
|
|
assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]);
|
|
|
|
}
|
|
|
|
|
2017-06-24 20:15:18 +08:00
|
|
|
#[test]
|
|
|
|
fn test_impossible_len() {
|
|
|
|
let mut bytes = vec![0; 12];
|
|
|
|
let mut packet = Packet::new(&mut bytes);
|
|
|
|
packet.set_len(4);
|
|
|
|
assert_eq!(packet.check_len(), Err(Error::Malformed));
|
|
|
|
}
|
|
|
|
|
2016-12-14 09:59:47 +08:00
|
|
|
fn packet_repr() -> Repr<'static> {
|
|
|
|
Repr {
|
|
|
|
src_port: 48896,
|
|
|
|
dst_port: 53,
|
|
|
|
payload: &PAYLOAD_BYTES
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_parse() {
|
Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.
This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
* `fn check_len(&self) -> Result<(), Error>`, purely a validator;
* `fn new(T) -> Self`, purely a wrapper;
* `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.
This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).
Fixes #17.
2017-06-24 17:15:22 +08:00
|
|
|
let packet = Packet::new(&PACKET_BYTES[..]);
|
2016-12-14 09:59:47 +08:00
|
|
|
let repr = Repr::parse(&packet, &SRC_ADDR.into(), &DST_ADDR.into()).unwrap();
|
|
|
|
assert_eq!(repr, packet_repr());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_emit() {
|
2016-12-20 20:52:33 +08:00
|
|
|
let repr = packet_repr();
|
|
|
|
let mut bytes = vec![0; repr.buffer_len()];
|
Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.
This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
* `fn check_len(&self) -> Result<(), Error>`, purely a validator;
* `fn new(T) -> Self`, purely a wrapper;
* `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.
This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).
Fixes #17.
2017-06-24 17:15:22 +08:00
|
|
|
let mut packet = Packet::new(&mut bytes);
|
2016-12-20 20:52:33 +08:00
|
|
|
repr.emit(&mut packet, &SRC_ADDR.into(), &DST_ADDR.into());
|
2016-12-14 08:11:45 +08:00
|
|
|
assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]);
|
|
|
|
}
|
|
|
|
}
|