2016-12-10 18:40:46 +08:00
|
|
|
use byteorder::{ByteOrder, NetworkEndian};
|
2021-06-27 15:31:59 +08:00
|
|
|
use core::fmt;
|
2017-07-27 21:51:02 +08:00
|
|
|
|
2020-12-27 07:11:30 +08:00
|
|
|
use crate::{Error, Result};
|
2016-12-10 18:40:46 +08:00
|
|
|
|
2016-12-20 21:54:11 +08:00
|
|
|
pub use super::EthernetProtocol as Protocol;
|
2016-12-10 18:40:46 +08:00
|
|
|
|
|
|
|
enum_with_unknown! {
|
2016-12-20 21:54:11 +08:00
|
|
|
/// ARP hardware type.
|
|
|
|
pub enum Hardware(u16) {
|
2016-12-10 18:40:46 +08:00
|
|
|
Ethernet = 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum_with_unknown! {
|
|
|
|
/// ARP operation type.
|
|
|
|
pub enum Operation(u16) {
|
|
|
|
Request = 1,
|
|
|
|
Reply = 2
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-13 01:26:06 +08:00
|
|
|
/// A read/write wrapper around an Address Resolution Protocol packet buffer.
|
2018-02-05 19:42:05 +08:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
2021-04-01 07:30:47 +08:00
|
|
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
2016-12-12 15:19:53 +08:00
|
|
|
pub struct Packet<T: AsRef<[u8]>> {
|
2021-06-27 15:31:59 +08:00
|
|
|
buffer: T,
|
2016-12-12 15:19:53 +08:00
|
|
|
}
|
2016-12-10 18:40:46 +08:00
|
|
|
|
|
|
|
mod field {
|
|
|
|
#![allow(non_snake_case)]
|
|
|
|
|
2020-12-27 07:11:30 +08:00
|
|
|
use crate::wire::field::*;
|
2016-12-10 18:40:46 +08:00
|
|
|
|
|
|
|
pub const HTYPE: Field = 0..2;
|
|
|
|
pub const PTYPE: Field = 2..4;
|
2021-06-27 15:31:59 +08:00
|
|
|
pub const HLEN: usize = 4;
|
|
|
|
pub const PLEN: usize = 5;
|
|
|
|
pub const OPER: Field = 6..8;
|
2016-12-10 18:40:46 +08:00
|
|
|
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-11 08:50:34 +08:00
|
|
|
pub fn SHA(hardware_len: u8, _protocol_len: u8) -> Field {
|
2016-12-10 18:40:46 +08:00
|
|
|
let start = OPER.end;
|
2016-12-11 08:50:34 +08:00
|
|
|
start..(start + hardware_len as usize)
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-11 08:50:34 +08:00
|
|
|
pub fn SPA(hardware_len: u8, protocol_len: u8) -> Field {
|
|
|
|
let start = SHA(hardware_len, protocol_len).end;
|
|
|
|
start..(start + protocol_len as usize)
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-11 08:50:34 +08:00
|
|
|
pub fn THA(hardware_len: u8, protocol_len: u8) -> Field {
|
|
|
|
let start = SPA(hardware_len, protocol_len).end;
|
|
|
|
start..(start + hardware_len as usize)
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-11 08:50:34 +08:00
|
|
|
pub fn TPA(hardware_len: u8, protocol_len: u8) -> Field {
|
|
|
|
let start = THA(hardware_len, protocol_len).end;
|
|
|
|
start..(start + protocol_len as usize)
|
2016-12-10 18:40:46 +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 ARP 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.
|
|
|
|
///
|
|
|
|
/// The result of this check is invalidated by calling [set_hardware_len] or
|
|
|
|
/// [set_protocol_len].
|
|
|
|
///
|
|
|
|
/// [set_hardware_len]: #method.set_hardware_len
|
|
|
|
/// [set_protocol_len]: #method.set_protocol_len
|
2021-01-11 06:16:08 +08:00
|
|
|
#[allow(clippy::if_same_then_else)]
|
2017-07-27 21:51:02 +08:00
|
|
|
pub fn check_len(&self) -> 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
|
|
|
let len = self.buffer.as_ref().len();
|
2016-12-10 18:40:46 +08:00
|
|
|
if len < field::OPER.end {
|
2016-12-12 15:19:53 +08:00
|
|
|
Err(Error::Truncated)
|
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
|
|
|
} else if len < field::TPA(self.hardware_len(), self.protocol_len()).end {
|
|
|
|
Err(Error::Truncated)
|
2016-12-10 18:40:46 +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-10 18:40:46 +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-10 18:40:46 +08:00
|
|
|
pub fn into_inner(self) -> T {
|
2016-12-12 15:19:53 +08:00
|
|
|
self.buffer
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the hardware type field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-20 21:54:11 +08:00
|
|
|
pub fn hardware_type(&self) -> Hardware {
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_ref();
|
|
|
|
let raw = NetworkEndian::read_u16(&data[field::HTYPE]);
|
2016-12-20 21:54:11 +08:00
|
|
|
Hardware::from(raw)
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the protocol type field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-20 21:54:11 +08:00
|
|
|
pub fn protocol_type(&self) -> Protocol {
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_ref();
|
|
|
|
let raw = NetworkEndian::read_u16(&data[field::PTYPE]);
|
2016-12-20 21:54:11 +08:00
|
|
|
Protocol::from(raw)
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the hardware length field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-11 08:50:34 +08:00
|
|
|
pub fn hardware_len(&self) -> u8 {
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_ref();
|
|
|
|
data[field::HLEN]
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the protocol length field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-11 08:50:34 +08:00
|
|
|
pub fn protocol_len(&self) -> u8 {
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_ref();
|
|
|
|
data[field::PLEN]
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the operation field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-10 18:40:46 +08:00
|
|
|
pub fn operation(&self) -> Operation {
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_ref();
|
|
|
|
let raw = NetworkEndian::read_u16(&data[field::OPER]);
|
2016-12-10 18:40:46 +08:00
|
|
|
Operation::from(raw)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the source hardware address field.
|
|
|
|
pub fn source_hardware_addr(&self) -> &[u8] {
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_ref();
|
|
|
|
&data[field::SHA(self.hardware_len(), self.protocol_len())]
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the source protocol address field.
|
|
|
|
pub fn source_protocol_addr(&self) -> &[u8] {
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_ref();
|
|
|
|
&data[field::SPA(self.hardware_len(), self.protocol_len())]
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the target hardware address field.
|
|
|
|
pub fn target_hardware_addr(&self) -> &[u8] {
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_ref();
|
|
|
|
&data[field::THA(self.hardware_len(), self.protocol_len())]
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the target protocol address field.
|
|
|
|
pub fn target_protocol_addr(&self) -> &[u8] {
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_ref();
|
|
|
|
&data[field::TPA(self.hardware_len(), self.protocol_len())]
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
|
|
|
|
/// Set the hardware type field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-20 21:54:11 +08:00
|
|
|
pub fn set_hardware_type(&mut self, value: Hardware) {
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_mut();
|
|
|
|
NetworkEndian::write_u16(&mut data[field::HTYPE], value.into())
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the protocol type field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-20 21:54:11 +08:00
|
|
|
pub fn set_protocol_type(&mut self, value: Protocol) {
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_mut();
|
|
|
|
NetworkEndian::write_u16(&mut data[field::PTYPE], value.into())
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the hardware length field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-11 08:50:34 +08:00
|
|
|
pub fn set_hardware_len(&mut self, value: u8) {
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_mut();
|
|
|
|
data[field::HLEN] = value
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the protocol length field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-11 08:50:34 +08:00
|
|
|
pub fn set_protocol_len(&mut self, value: u8) {
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_mut();
|
|
|
|
data[field::PLEN] = value
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the operation field.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-10 18:40:46 +08:00
|
|
|
pub fn set_operation(&mut self, value: Operation) {
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_mut();
|
|
|
|
NetworkEndian::write_u16(&mut data[field::OPER], value.into())
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the source hardware address field.
|
|
|
|
///
|
|
|
|
/// # Panics
|
2016-12-11 08:50:34 +08:00
|
|
|
/// The function panics if `value` is not `self.hardware_len()` long.
|
2016-12-10 18:40:46 +08:00
|
|
|
pub fn set_source_hardware_addr(&mut self, value: &[u8]) {
|
2016-12-11 08:50:34 +08:00
|
|
|
let (hardware_len, protocol_len) = (self.hardware_len(), self.protocol_len());
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_mut();
|
|
|
|
data[field::SHA(hardware_len, protocol_len)].copy_from_slice(value)
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the source protocol address field.
|
|
|
|
///
|
|
|
|
/// # Panics
|
2016-12-11 08:50:34 +08:00
|
|
|
/// The function panics if `value` is not `self.protocol_len()` long.
|
2016-12-10 18:40:46 +08:00
|
|
|
pub fn set_source_protocol_addr(&mut self, value: &[u8]) {
|
2016-12-11 08:50:34 +08:00
|
|
|
let (hardware_len, protocol_len) = (self.hardware_len(), self.protocol_len());
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_mut();
|
|
|
|
data[field::SPA(hardware_len, protocol_len)].copy_from_slice(value)
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the target hardware address field.
|
|
|
|
///
|
|
|
|
/// # Panics
|
2016-12-11 08:50:34 +08:00
|
|
|
/// The function panics if `value` is not `self.hardware_len()` long.
|
2016-12-10 18:40:46 +08:00
|
|
|
pub fn set_target_hardware_addr(&mut self, value: &[u8]) {
|
2016-12-11 08:50:34 +08:00
|
|
|
let (hardware_len, protocol_len) = (self.hardware_len(), self.protocol_len());
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_mut();
|
|
|
|
data[field::THA(hardware_len, protocol_len)].copy_from_slice(value)
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the target protocol address field.
|
|
|
|
///
|
|
|
|
/// # Panics
|
2016-12-11 08:50:34 +08:00
|
|
|
/// The function panics if `value` is not `self.protocol_len()` long.
|
2016-12-10 18:40:46 +08:00
|
|
|
pub fn set_target_protocol_addr(&mut self, value: &[u8]) {
|
2016-12-11 08:50:34 +08:00
|
|
|
let (hardware_len, protocol_len) = (self.hardware_len(), self.protocol_len());
|
2016-12-12 15:19:53 +08:00
|
|
|
let data = self.buffer.as_mut();
|
|
|
|
data[field::TPA(hardware_len, protocol_len)].copy_from_slice(value)
|
2016-12-10 18:40:46 +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()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-27 07:11:30 +08:00
|
|
|
use crate::wire::{EthernetAddress, Ipv4Address};
|
2016-12-10 21:13:13 +08:00
|
|
|
|
2016-12-10 19:16:51 +08:00
|
|
|
/// A high-level representation of an Address Resolution Protocol packet.
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
2021-04-01 07:30:47 +08:00
|
|
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
2021-01-09 07:55:28 +08:00
|
|
|
#[non_exhaustive]
|
2016-12-10 19:16:51 +08:00
|
|
|
pub enum Repr {
|
|
|
|
/// An Ethernet and IPv4 Address Resolution Protocol packet.
|
|
|
|
EthernetIpv4 {
|
|
|
|
operation: Operation,
|
2016-12-10 21:13:13 +08:00
|
|
|
source_hardware_addr: EthernetAddress,
|
|
|
|
source_protocol_addr: Ipv4Address,
|
|
|
|
target_hardware_addr: EthernetAddress,
|
2021-06-27 15:31:59 +08:00
|
|
|
target_protocol_addr: Ipv4Address,
|
2016-12-10 19:16:51 +08:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Repr {
|
2016-12-13 04:01:38 +08:00
|
|
|
/// Parse an Address Resolution Protocol packet and return a high-level representation,
|
2017-07-27 21:51:02 +08:00
|
|
|
/// or return `Err(Error::Unrecognized)` if the packet is not recognized.
|
|
|
|
pub fn parse<T: AsRef<[u8]>>(packet: &Packet<T>) -> Result<Repr> {
|
2021-06-27 15:31:59 +08:00
|
|
|
match (
|
|
|
|
packet.hardware_type(),
|
|
|
|
packet.protocol_type(),
|
|
|
|
packet.hardware_len(),
|
|
|
|
packet.protocol_len(),
|
|
|
|
) {
|
|
|
|
(Hardware::Ethernet, Protocol::Ipv4, 6, 4) => Ok(Repr::EthernetIpv4 {
|
|
|
|
operation: packet.operation(),
|
|
|
|
source_hardware_addr: EthernetAddress::from_bytes(packet.source_hardware_addr()),
|
|
|
|
source_protocol_addr: Ipv4Address::from_bytes(packet.source_protocol_addr()),
|
|
|
|
target_hardware_addr: EthernetAddress::from_bytes(packet.target_hardware_addr()),
|
|
|
|
target_protocol_addr: Ipv4Address::from_bytes(packet.target_protocol_addr()),
|
|
|
|
}),
|
|
|
|
_ => Err(Error::Unrecognized),
|
2016-12-10 19:16:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-20 07:50:04 +08:00
|
|
|
/// Return the length of a packet that will be emitted from this high-level representation.
|
|
|
|
pub fn buffer_len(&self) -> usize {
|
2020-12-26 16:28:05 +08:00
|
|
|
match *self {
|
|
|
|
Repr::EthernetIpv4 { .. } => field::TPA(6, 4).end,
|
2016-12-20 07:50:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-13 04:01:38 +08:00
|
|
|
/// Emit a high-level representation into an Address Resolution Protocol packet.
|
2016-12-10 19:16:51 +08:00
|
|
|
pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>) {
|
2020-12-26 16:28:05 +08:00
|
|
|
match *self {
|
|
|
|
Repr::EthernetIpv4 {
|
2016-12-10 19:16:51 +08:00
|
|
|
operation,
|
2021-06-27 15:31:59 +08:00
|
|
|
source_hardware_addr,
|
|
|
|
source_protocol_addr,
|
|
|
|
target_hardware_addr,
|
|
|
|
target_protocol_addr,
|
2016-12-10 19:16:51 +08:00
|
|
|
} => {
|
2016-12-20 21:54:11 +08:00
|
|
|
packet.set_hardware_type(Hardware::Ethernet);
|
|
|
|
packet.set_protocol_type(Protocol::Ipv4);
|
2016-12-11 08:50:34 +08:00
|
|
|
packet.set_hardware_len(6);
|
|
|
|
packet.set_protocol_len(4);
|
2016-12-10 19:16:51 +08:00
|
|
|
packet.set_operation(operation);
|
|
|
|
packet.set_source_hardware_addr(source_hardware_addr.as_bytes());
|
|
|
|
packet.set_source_protocol_addr(source_protocol_addr.as_bytes());
|
|
|
|
packet.set_target_hardware_addr(target_hardware_addr.as_bytes());
|
|
|
|
packet.set_target_protocol_addr(target_protocol_addr.as_bytes());
|
2021-06-27 15:31:59 +08:00
|
|
|
}
|
2016-12-10 19:16:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-11 07:15:56 +08:00
|
|
|
impl<T: AsRef<[u8]>> fmt::Display for Packet<T> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match Repr::parse(self) {
|
|
|
|
Ok(repr) => write!(f, "{}", repr),
|
|
|
|
_ => {
|
2017-06-25 00:34:32 +08:00
|
|
|
write!(f, "ARP (unrecognized)")?;
|
2021-06-27 15:31:59 +08:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
" htype={:?} ptype={:?} hlen={:?} plen={:?} op={:?}",
|
|
|
|
self.hardware_type(),
|
|
|
|
self.protocol_type(),
|
|
|
|
self.hardware_len(),
|
|
|
|
self.protocol_len(),
|
|
|
|
self.operation()
|
|
|
|
)?;
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
" sha={:?} spa={:?} tha={:?} tpa={:?}",
|
|
|
|
self.source_hardware_addr(),
|
|
|
|
self.source_protocol_addr(),
|
|
|
|
self.target_hardware_addr(),
|
|
|
|
self.target_protocol_addr()
|
|
|
|
)?;
|
2016-12-11 07:15:56 +08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-11 00:25:43 +08:00
|
|
|
impl fmt::Display for Repr {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2020-12-26 16:28:05 +08:00
|
|
|
match *self {
|
|
|
|
Repr::EthernetIpv4 {
|
2016-12-11 00:25:43 +08:00
|
|
|
operation,
|
2021-06-27 15:31:59 +08:00
|
|
|
source_hardware_addr,
|
|
|
|
source_protocol_addr,
|
|
|
|
target_hardware_addr,
|
|
|
|
target_protocol_addr,
|
2016-12-11 00:25:43 +08:00
|
|
|
} => {
|
2021-06-27 15:31:59 +08:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"ARP type=Ethernet+IPv4 src={}/{} tgt={}/{} op={:?}",
|
|
|
|
source_hardware_addr,
|
|
|
|
source_protocol_addr,
|
|
|
|
target_hardware_addr,
|
|
|
|
target_protocol_addr,
|
|
|
|
operation
|
|
|
|
)
|
|
|
|
}
|
2016-12-11 00:25:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-27 15:31:59 +08:00
|
|
|
use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
|
2016-12-11 07:15:56 +08:00
|
|
|
|
2016-12-12 20:30:35 +08:00
|
|
|
impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
|
2021-06-27 15:31:59 +08:00
|
|
|
fn pretty_print(
|
|
|
|
buffer: &dyn 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) {
|
2017-12-17 05:42:19 +08:00
|
|
|
Err(err) => write!(f, "{}({})", indent, err),
|
2021-06-27 15:31:59 +08:00
|
|
|
Ok(packet) => write!(f, "{}{}", indent, packet),
|
2016-12-11 07:15:56 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-10 18:40:46 +08:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
|
2021-06-27 15:31:59 +08:00
|
|
|
static PACKET_BYTES: [u8; 28] = [
|
|
|
|
0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x21,
|
|
|
|
0x22, 0x23, 0x24, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x41, 0x42, 0x43, 0x44,
|
|
|
|
];
|
2016-12-10 18:40:46 +08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_deconstruct() {
|
2018-07-11 08:22:43 +08:00
|
|
|
let packet = Packet::new_unchecked(&PACKET_BYTES[..]);
|
2016-12-20 21:54:11 +08:00
|
|
|
assert_eq!(packet.hardware_type(), Hardware::Ethernet);
|
|
|
|
assert_eq!(packet.protocol_type(), Protocol::Ipv4);
|
2016-12-11 08:50:34 +08:00
|
|
|
assert_eq!(packet.hardware_len(), 6);
|
|
|
|
assert_eq!(packet.protocol_len(), 4);
|
2016-12-10 18:40:46 +08:00
|
|
|
assert_eq!(packet.operation(), Operation::Request);
|
2021-06-27 15:31:59 +08:00
|
|
|
assert_eq!(
|
|
|
|
packet.source_hardware_addr(),
|
|
|
|
&[0x11, 0x12, 0x13, 0x14, 0x15, 0x16]
|
|
|
|
);
|
2016-12-10 18:40:46 +08:00
|
|
|
assert_eq!(packet.source_protocol_addr(), &[0x21, 0x22, 0x23, 0x24]);
|
2021-06-27 15:31:59 +08:00
|
|
|
assert_eq!(
|
|
|
|
packet.target_hardware_addr(),
|
|
|
|
&[0x31, 0x32, 0x33, 0x34, 0x35, 0x36]
|
|
|
|
);
|
2016-12-10 18:40:46 +08:00
|
|
|
assert_eq!(packet.target_protocol_addr(), &[0x41, 0x42, 0x43, 0x44]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_construct() {
|
2017-06-26 11:44:36 +08:00
|
|
|
let mut bytes = vec![0xa5; 28];
|
2018-07-11 08:22:43 +08:00
|
|
|
let mut packet = Packet::new_unchecked(&mut bytes);
|
2016-12-20 21:54:11 +08:00
|
|
|
packet.set_hardware_type(Hardware::Ethernet);
|
|
|
|
packet.set_protocol_type(Protocol::Ipv4);
|
2016-12-11 08:50:34 +08:00
|
|
|
packet.set_hardware_len(6);
|
|
|
|
packet.set_protocol_len(4);
|
2016-12-10 18:40:46 +08:00
|
|
|
packet.set_operation(Operation::Request);
|
|
|
|
packet.set_source_hardware_addr(&[0x11, 0x12, 0x13, 0x14, 0x15, 0x16]);
|
|
|
|
packet.set_source_protocol_addr(&[0x21, 0x22, 0x23, 0x24]);
|
|
|
|
packet.set_target_hardware_addr(&[0x31, 0x32, 0x33, 0x34, 0x35, 0x36]);
|
|
|
|
packet.set_target_protocol_addr(&[0x41, 0x42, 0x43, 0x44]);
|
|
|
|
assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]);
|
|
|
|
}
|
2016-12-10 19:16:51 +08:00
|
|
|
|
|
|
|
fn packet_repr() -> Repr {
|
|
|
|
Repr::EthernetIpv4 {
|
|
|
|
operation: Operation::Request,
|
2021-06-27 15:31:59 +08:00
|
|
|
source_hardware_addr: EthernetAddress::from_bytes(&[
|
|
|
|
0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
|
|
|
]),
|
|
|
|
source_protocol_addr: Ipv4Address::from_bytes(&[0x21, 0x22, 0x23, 0x24]),
|
|
|
|
target_hardware_addr: EthernetAddress::from_bytes(&[
|
|
|
|
0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
|
|
|
|
]),
|
|
|
|
target_protocol_addr: Ipv4Address::from_bytes(&[0x41, 0x42, 0x43, 0x44]),
|
2016-12-10 19:16:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_parse() {
|
2018-07-11 08:22:43 +08:00
|
|
|
let packet = Packet::new_unchecked(&PACKET_BYTES[..]);
|
2016-12-10 19:16:51 +08:00
|
|
|
let repr = Repr::parse(&packet).unwrap();
|
|
|
|
assert_eq!(repr, packet_repr());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_emit() {
|
2017-06-26 11:44:36 +08:00
|
|
|
let mut bytes = vec![0xa5; 28];
|
2018-07-11 08:22:43 +08:00
|
|
|
let mut packet = Packet::new_unchecked(&mut bytes);
|
2016-12-10 19:16:51 +08:00
|
|
|
packet_repr().emit(&mut packet);
|
|
|
|
assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]);
|
|
|
|
}
|
2016-12-10 18:40:46 +08:00
|
|
|
}
|