pub mod arp;
pub mod checksum;
mod ethernet;
pub mod icmp;
pub mod ip;
mod tcp;
pub mod types;
mod udp;
pub use self::ethernet::*;
pub use self::tcp::*;
pub use self::udp::*;
use crate::Mbuf;
use anyhow::{Context, Result};
use std::fmt;
use std::marker::PhantomData;
use std::ops::Deref;
#[derive(Clone, Debug)]
pub struct Internal(());
#[allow(clippy::len_without_is_empty)]
pub trait Packet {
type Envelope: Packet;
fn envelope(&self) -> &Self::Envelope;
fn envelope_mut(&mut self) -> &mut Self::Envelope;
#[inline]
fn mbuf(&self) -> &Mbuf {
self.envelope().mbuf()
}
#[inline]
fn mbuf_mut(&mut self) -> &mut Mbuf {
self.envelope_mut().mbuf_mut()
}
fn offset(&self) -> usize;
fn header_len(&self) -> usize;
#[inline]
fn payload_offset(&self) -> usize {
self.offset() + self.header_len()
}
#[inline]
fn len(&self) -> usize {
self.mbuf().data_len() - self.offset()
}
#[inline]
fn payload_len(&self) -> usize {
self.len() - self.header_len()
}
unsafe fn clone(&self, internal: Internal) -> Self;
fn try_parse(envelope: Self::Envelope, internal: Internal) -> Result<Self>
where
Self: Sized;
#[inline]
fn parse<T: Packet<Envelope = Self>>(self) -> Result<T>
where
Self: Sized,
{
T::try_parse(self, Internal(()))
}
#[inline]
fn peek<T: Packet<Envelope = Self>>(&self) -> Result<Immutable<'_, T>>
where
Self: Sized,
{
let clone = unsafe { self.clone(Internal(())) };
clone.parse::<T>().map(Immutable::new)
}
fn try_push(envelope: Self::Envelope, internal: Internal) -> Result<Self>
where
Self: Sized;
#[inline]
fn push<T: Packet<Envelope = Self>>(self) -> Result<T>
where
Self: Sized,
{
T::try_push(self, Internal(()))
}
fn deparse(self) -> Self::Envelope
where
Self: Sized;
#[inline]
fn remove(mut self) -> Result<Self::Envelope>
where
Self: Sized,
{
let offset = self.offset();
let len = self.header_len();
self.mbuf_mut()
.shrink(offset, len)
.context("failed to remove packet header.")?;
Ok(self.deparse())
}
#[inline]
fn remove_payload(&mut self) -> Result<()> {
let offset = self.payload_offset();
let len = self.payload_len();
self.mbuf_mut()
.shrink(offset, len)
.context("failed to remove packet payload.")?;
Ok(())
}
#[inline]
fn reset(self) -> Mbuf
where
Self: Sized,
{
self.deparse().reset()
}
#[inline]
fn reconcile(&mut self) {}
#[inline]
fn reconcile_all(&mut self) {
self.reconcile();
self.envelope_mut().reconcile_all();
}
}
pub struct Immutable<'a, T> {
value: T,
phantom: PhantomData<&'a T>,
}
impl<T: fmt::Debug> fmt::Debug for Immutable<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.value.fmt(f)
}
}
impl<T> Immutable<'_, T> {
pub fn new(value: T) -> Self {
Immutable {
value,
phantom: PhantomData,
}
}
}
impl<T> Deref for Immutable<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::net::MacAddr;
use crate::packets::ip::v4::Ipv4;
use crate::testils::byte_arrays::IPV4_UDP_PACKET;
#[capsule::test]
fn parse_and_reset_packet() {
let packet = Mbuf::from_bytes(&IPV4_UDP_PACKET).unwrap();
let len = packet.data_len();
let ethernet = packet.parse::<Ethernet>().unwrap();
let ipv4 = ethernet.parse::<Ipv4>().unwrap();
let udp = ipv4.parse::<Udp4>().unwrap();
let reset = udp.reset();
assert_eq!(len, reset.data_len());
}
#[capsule::test]
fn peek_packet() {
let packet = Mbuf::from_bytes(&IPV4_UDP_PACKET).unwrap();
let ethernet = packet.peek::<Ethernet>().unwrap();
assert_eq!(MacAddr::new(0, 0, 0, 0, 0, 2), ethernet.src());
let v4 = ethernet.peek::<Ipv4>().unwrap();
assert_eq!(255, v4.ttl());
let udp = v4.peek::<Udp4>().unwrap();
assert_eq!(39376, udp.src_port());
}
#[capsule::test]
fn peek_back_via_envelope() {
let packet = Mbuf::from_bytes(&IPV4_UDP_PACKET).unwrap();
let ethernet = packet.parse::<Ethernet>().unwrap();
let v4 = ethernet.parse::<Ipv4>().unwrap();
let udp = v4.parse::<Udp4>().unwrap();
let mut v4_2 = udp.deparse();
v4_2.set_ttl(25);
let udp_2 = v4_2.parse::<Udp4>().unwrap();
let v4_4 = udp_2.envelope();
assert_eq!(v4_4.ttl(), 25);
}
#[capsule::test]
fn remove_header_and_payload() {
let packet = Mbuf::from_bytes(&IPV4_UDP_PACKET).unwrap();
let ethernet = packet.parse::<Ethernet>().unwrap();
let v4 = ethernet.parse::<Ipv4>().unwrap();
let mut udp = v4.parse::<Udp4>().unwrap();
assert!(udp.payload_len() > 0);
let _ = udp.remove_payload();
assert_eq!(0, udp.payload_len());
let v4 = udp.remove().unwrap();
assert_eq!(0, v4.payload_len());
}
#[test]
#[cfg(feature = "compile_failure")]
fn cannot_mutate_packet_while_peeking_into_payload() {
let packet = Mbuf::from_bytes(&IPV4_UDP_PACKET).unwrap();
let mut ethernet = packet.parse::<Ethernet>().unwrap();
let ipv4 = ethernet.peek::<Ipv4>().unwrap();
ethernet.set_src(MacAddr::UNSPECIFIED);
assert!(ipv4.payload_len() > 0);
}
#[test]
#[cfg(feature = "compile_failure")]
fn cannot_mutate_immutable_packet() {
let packet = Mbuf::from_bytes(&IPV4_UDP_PACKET).unwrap();
let ethernet = packet.peek::<Ethernet>().unwrap();
ethernet.set_src(MacAddr::UNSPECIFIED);
}
}