2016-12-14 09:59:47 +08:00
|
|
|
use core::fmt;
|
2016-12-14 08:11:45 +08:00
|
|
|
use byteorder::{ByteOrder, NetworkEndian};
|
|
|
|
|
2020-12-27 07:11:30 +08:00
|
|
|
use crate::{Error, Result};
|
|
|
|
use crate::phy::ChecksumCapabilities;
|
|
|
|
use crate::wire::{IpProtocol, IpAddress};
|
|
|
|
use crate::wire::ip::checksum;
|
2016-12-14 08:11:45 +08:00
|
|
|
|
|
|
|
/// A read/write wrapper around an User Datagram Protocol packet buffer.
|
2018-02-05 19:42:05 +08:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
2016-12-14 08:11:45 +08:00
|
|
|
pub struct Packet<T: AsRef<[u8]>> {
|
|
|
|
buffer: T
|
|
|
|
}
|
|
|
|
|
|
|
|
mod field {
|
2016-12-17 13:12:45 +08:00
|
|
|
#![allow(non_snake_case)]
|
|
|
|
|
2020-12-27 07:11:30 +08:00
|
|
|
use crate::wire::field::*;
|
2016-12-14 08:11:45 +08:00
|
|
|
|
|
|
|
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.
|
2018-07-11 08:22:43 +08:00
|
|
|
pub fn new_unchecked(buffer: T) -> 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
|
|
|
Packet { buffer }
|
|
|
|
}
|
|
|
|
|
2018-07-11 08:22:43 +08:00
|
|
|
/// Shorthand for a combination of [new_unchecked] and [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
|
|
|
///
|
2018-07-11 08:22:43 +08:00
|
|
|
/// [new_unchecked]: #method.new_unchecked
|
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
|
|
|
/// [check_len]: #method.check_len
|
2017-07-27 21:51:02 +08:00
|
|
|
pub fn new_checked(buffer: T) -> Result<Packet<T>> {
|
2018-07-11 08:22:43 +08:00
|
|
|
let packet = Self::new_unchecked(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
|
2017-07-27 21:51:02 +08:00
|
|
|
pub fn check_len(&self) -> Result<()> {
|
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) {
|
2017-09-25 08:55:54 +08:00
|
|
|
let data = self.buffer.as_mut();
|
2016-12-14 08:11:45 +08:00
|
|
|
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) {
|
2017-09-25 08:55:54 +08:00
|
|
|
let data = self.buffer.as_mut();
|
2016-12-14 08:11:45 +08:00
|
|
|
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) {
|
2017-09-25 08:55:54 +08:00
|
|
|
let data = self.buffer.as_mut();
|
2016-12-14 08:11:45 +08:00
|
|
|
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) {
|
2017-09-25 08:55:54 +08:00
|
|
|
let data = self.buffer.as_mut();
|
2016-12-14 08:11:45 +08:00
|
|
|
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
|
|
|
};
|
2017-06-27 00:57:21 +08:00
|
|
|
// UDP checksum value of 0 means no checksum; if the checksum really is zero,
|
|
|
|
// use all-ones, which indicates that the remote end must verify the checksum.
|
|
|
|
// Arithmetically, RFC 1071 checksums of all-zeroes and all-ones behave identically,
|
|
|
|
// so no action is necessary on the remote end.
|
|
|
|
self.set_checksum(if checksum == 0 { 0xffff } else { checksum })
|
2016-12-14 08:11:45 +08:00
|
|
|
}
|
|
|
|
|
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();
|
2017-09-25 08:55:54 +08:00
|
|
|
let 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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-08 16:54:50 +08:00
|
|
|
impl<T: AsRef<[u8]>> AsRef<[u8]> for Packet<T> {
|
|
|
|
fn as_ref(&self) -> &[u8] {
|
|
|
|
self.buffer.as_ref()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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.
|
2017-10-03 05:51:43 +08:00
|
|
|
pub fn parse<T>(packet: &Packet<&'a T>, src_addr: &IpAddress, dst_addr: &IpAddress,
|
|
|
|
checksum_caps: &ChecksumCapabilities) -> Result<Repr<'a>>
|
|
|
|
where T: AsRef<[u8]> + ?Sized {
|
2016-12-14 09:59:47 +08:00
|
|
|
// Destination port cannot be omitted (but source port can be).
|
|
|
|
if packet.dst_port() == 0 { return Err(Error::Malformed) }
|
|
|
|
// Valid checksum is expected...
|
2018-05-28 08:32:50 +08:00
|
|
|
if checksum_caps.udp.rx() && !packet.verify_checksum(src_addr, dst_addr) {
|
2016-12-14 09:59:47 +08:00
|
|
|
match (src_addr, dst_addr) {
|
2019-04-25 04:22:54 +08:00
|
|
|
// ... except on UDP-over-IPv4, where it can be omitted.
|
2017-12-24 21:28:59 +08:00
|
|
|
#[cfg(feature = "proto-ipv4")]
|
2016-12-20 21:54:11 +08:00
|
|
|
(&IpAddress::Ipv4(_), &IpAddress::Ipv4(_))
|
2019-04-25 04:22:54 +08:00
|
|
|
if packet.checksum() == 0 => (),
|
2016-12-14 09:59:47 +08:00
|
|
|
_ => {
|
|
|
|
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,
|
2017-10-02 18:47:51 +08:00
|
|
|
dst_addr: &IpAddress,
|
|
|
|
checksum_caps: &ChecksumCapabilities)
|
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);
|
2017-10-02 18:47:51 +08:00
|
|
|
|
2018-05-28 08:32:50 +08:00
|
|
|
if checksum_caps.udp.tx() {
|
2017-10-02 18:47:51 +08:00
|
|
|
packet.fill_checksum(src_addr, dst_addr)
|
|
|
|
} else {
|
2018-01-27 01:28:52 +08:00
|
|
|
// make sure we get a consistently zeroed checksum,
|
|
|
|
// since implementations might rely on it
|
2017-10-02 18:47:51 +08:00
|
|
|
packet.set_checksum(0);
|
|
|
|
}
|
2016-12-14 09:59:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-27 07:11:30 +08:00
|
|
|
use crate::wire::pretty_print::{PrettyPrint, PrettyIndent};
|
2016-12-14 09:59:47 +08:00
|
|
|
|
|
|
|
impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
|
2019-06-22 16:19:39 +08:00
|
|
|
fn pretty_print(buffer: &dyn AsRef<[u8]>, f: &mut fmt::Formatter,
|
2016-12-14 09:59:47 +08:00
|
|
|
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) {
|
2017-12-17 05:42:19 +08:00
|
|
|
Err(err) => write!(f, "{}({})", indent, err),
|
|
|
|
Ok(packet) => write!(f, "{}{}", indent, packet)
|
2016-12-14 09:59:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-14 08:11:45 +08:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2017-12-24 21:28:59 +08:00
|
|
|
#[cfg(feature = "proto-ipv4")]
|
2020-12-27 07:11:30 +08:00
|
|
|
use crate::wire::Ipv4Address;
|
2016-12-14 08:11:45 +08:00
|
|
|
use super::*;
|
|
|
|
|
2017-12-24 21:28:59 +08:00
|
|
|
#[cfg(feature = "proto-ipv4")]
|
2016-12-14 09:59:47 +08:00
|
|
|
const SRC_ADDR: Ipv4Address = Ipv4Address([192, 168, 1, 1]);
|
2017-12-24 21:28:59 +08:00
|
|
|
#[cfg(feature = "proto-ipv4")]
|
2016-12-14 09:59:47 +08:00
|
|
|
const DST_ADDR: Ipv4Address = Ipv4Address([192, 168, 1, 2]);
|
|
|
|
|
2017-12-24 21:28:59 +08:00
|
|
|
#[cfg(feature = "proto-ipv4")]
|
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];
|
|
|
|
|
2019-04-25 04:22:54 +08:00
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
|
static NO_CHECKSUM_PACKET: [u8; 12] =
|
|
|
|
[0xbf, 0x00, 0x00, 0x35,
|
|
|
|
0x00, 0x0c, 0x00, 0x00,
|
|
|
|
0xaa, 0x00, 0x00, 0xff];
|
|
|
|
|
2017-12-24 21:28:59 +08:00
|
|
|
#[cfg(feature = "proto-ipv4")]
|
2016-12-14 08:11:45 +08:00
|
|
|
static PAYLOAD_BYTES: [u8; 4] =
|
|
|
|
[0xaa, 0x00, 0x00, 0xff];
|
|
|
|
|
|
|
|
#[test]
|
2017-12-24 21:28:59 +08:00
|
|
|
#[cfg(feature = "proto-ipv4")]
|
2016-12-14 08:11:45 +08:00
|
|
|
fn test_deconstruct() {
|
2018-07-11 08:22:43 +08:00
|
|
|
let packet = Packet::new_unchecked(&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]
|
2017-12-24 21:28:59 +08:00
|
|
|
#[cfg(feature = "proto-ipv4")]
|
2016-12-14 08:11:45 +08:00
|
|
|
fn test_construct() {
|
2017-06-26 11:44:36 +08:00
|
|
|
let mut bytes = vec![0xa5; 12];
|
2018-07-11 08:22:43 +08:00
|
|
|
let mut packet = Packet::new_unchecked(&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];
|
2018-07-11 08:22:43 +08:00
|
|
|
let mut packet = Packet::new_unchecked(&mut bytes);
|
2017-06-24 20:15:18 +08:00
|
|
|
packet.set_len(4);
|
|
|
|
assert_eq!(packet.check_len(), Err(Error::Malformed));
|
|
|
|
}
|
|
|
|
|
2017-06-27 00:57:21 +08:00
|
|
|
#[test]
|
2017-12-24 21:28:59 +08:00
|
|
|
#[cfg(feature = "proto-ipv4")]
|
2017-06-27 00:57:21 +08:00
|
|
|
fn test_zero_checksum() {
|
|
|
|
let mut bytes = vec![0; 8];
|
2018-07-11 08:22:43 +08:00
|
|
|
let mut packet = Packet::new_unchecked(&mut bytes);
|
2017-06-27 00:57:21 +08:00
|
|
|
packet.set_src_port(1);
|
|
|
|
packet.set_dst_port(31881);
|
|
|
|
packet.set_len(8);
|
|
|
|
packet.fill_checksum(&SRC_ADDR.into(), &DST_ADDR.into());
|
|
|
|
assert_eq!(packet.checksum(), 0xffff);
|
|
|
|
}
|
|
|
|
|
2017-12-24 21:28:59 +08:00
|
|
|
#[cfg(feature = "proto-ipv4")]
|
2016-12-14 09:59:47 +08:00
|
|
|
fn packet_repr() -> Repr<'static> {
|
|
|
|
Repr {
|
|
|
|
src_port: 48896,
|
|
|
|
dst_port: 53,
|
|
|
|
payload: &PAYLOAD_BYTES
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2017-12-24 21:28:59 +08:00
|
|
|
#[cfg(feature = "proto-ipv4")]
|
2016-12-14 09:59:47 +08:00
|
|
|
fn test_parse() {
|
2018-07-11 08:22:43 +08:00
|
|
|
let packet = Packet::new_unchecked(&PACKET_BYTES[..]);
|
|
|
|
let repr = Repr::parse(&packet, &SRC_ADDR.into(), &DST_ADDR.into(),
|
|
|
|
&ChecksumCapabilities::default()).unwrap();
|
2016-12-14 09:59:47 +08:00
|
|
|
assert_eq!(repr, packet_repr());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2017-12-24 21:28:59 +08:00
|
|
|
#[cfg(feature = "proto-ipv4")]
|
2016-12-14 09:59:47 +08:00
|
|
|
fn test_emit() {
|
2016-12-20 20:52:33 +08:00
|
|
|
let repr = packet_repr();
|
2017-06-26 11:44:36 +08:00
|
|
|
let mut bytes = vec![0xa5; repr.buffer_len()];
|
2018-07-11 08:22:43 +08:00
|
|
|
let mut packet = Packet::new_unchecked(&mut bytes);
|
|
|
|
repr.emit(&mut packet, &SRC_ADDR.into(), &DST_ADDR.into(),
|
|
|
|
&ChecksumCapabilities::default());
|
2016-12-14 08:11:45 +08:00
|
|
|
assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]);
|
|
|
|
}
|
2019-04-25 04:22:54 +08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
|
fn test_checksum_omitted() {
|
|
|
|
let packet = Packet::new_unchecked(&NO_CHECKSUM_PACKET[..]);
|
|
|
|
let repr = Repr::parse(&packet, &SRC_ADDR.into(), &DST_ADDR.into(),
|
|
|
|
&ChecksumCapabilities::default()).unwrap();
|
|
|
|
assert_eq!(repr, packet_repr());
|
|
|
|
}
|
2016-12-14 08:11:45 +08:00
|
|
|
}
|