use std::net::{Ipv4Addr, Ipv6Addr};
use super::LayerKind;
#[derive(Debug, Clone, Copy)]
pub struct Ipv4Slice<'a> {
raw: &'a [u8],
header_len: usize,
}
impl<'a> Ipv4Slice<'a> {
pub(crate) fn new(raw: &'a [u8], header_len: usize) -> Self {
Self { raw, header_len }
}
pub fn version(&self) -> u8 {
(self.raw[0] >> 4) & 0x0F
}
pub fn ihl(&self) -> u8 {
self.raw[0] & 0x0F
}
pub fn dscp(&self) -> u8 {
(self.raw[1] >> 2) & 0x3F
}
pub fn ecn(&self) -> u8 {
self.raw[1] & 0x03
}
pub fn total_length(&self) -> u16 {
u16::from_be_bytes([self.raw[2], self.raw[3]])
}
pub fn identification(&self) -> u16 {
u16::from_be_bytes([self.raw[4], self.raw[5]])
}
pub fn df(&self) -> bool {
(self.raw[6] >> 6) & 0x01 == 1
}
pub fn mf(&self) -> bool {
(self.raw[6] >> 5) & 0x01 == 1
}
pub fn fragment_offset(&self) -> u16 {
u16::from_be_bytes([self.raw[6] & 0x1F, self.raw[7]])
}
pub fn ttl(&self) -> u8 {
self.raw[8]
}
pub fn protocol(&self) -> u8 {
self.raw[9]
}
pub fn checksum(&self) -> u16 {
u16::from_be_bytes([self.raw[10], self.raw[11]])
}
pub fn source(&self) -> Ipv4Addr {
Ipv4Addr::new(self.raw[12], self.raw[13], self.raw[14], self.raw[15])
}
pub fn destination(&self) -> Ipv4Addr {
Ipv4Addr::new(self.raw[16], self.raw[17], self.raw[18], self.raw[19])
}
pub fn header(&self) -> &'a [u8] {
&self.raw[..self.header_len]
}
pub fn payload(&self) -> &'a [u8] {
&self.raw[self.header_len..]
}
pub fn bytes(&self) -> &'a [u8] {
self.raw
}
pub fn kind(&self) -> LayerKind {
LayerKind::Ipv4
}
}
#[derive(Debug, Clone, Copy)]
pub struct Ipv6Slice<'a> {
raw: &'a [u8],
header_len: usize,
}
impl<'a> Ipv6Slice<'a> {
pub(crate) fn new(raw: &'a [u8], header_len: usize) -> Self {
Self { raw, header_len }
}
pub fn version(&self) -> u8 {
(self.raw[0] >> 4) & 0x0F
}
pub fn traffic_class(&self) -> u8 {
((self.raw[0] & 0x0F) << 4) | (self.raw[1] >> 4)
}
pub fn flow_label(&self) -> u32 {
((self.raw[1] as u32 & 0x0F) << 16) | ((self.raw[2] as u32) << 8) | self.raw[3] as u32
}
pub fn payload_length(&self) -> u16 {
u16::from_be_bytes([self.raw[4], self.raw[5]])
}
pub fn next_header(&self) -> u8 {
self.raw[6]
}
pub fn hop_limit(&self) -> u8 {
self.raw[7]
}
pub fn source(&self) -> Ipv6Addr {
let mut a = [0u8; 16];
a.copy_from_slice(&self.raw[8..24]);
Ipv6Addr::from(a)
}
pub fn destination(&self) -> Ipv6Addr {
let mut a = [0u8; 16];
a.copy_from_slice(&self.raw[24..40]);
Ipv6Addr::from(a)
}
pub fn header(&self) -> &'a [u8] {
&self.raw[..self.header_len]
}
pub fn payload(&self) -> &'a [u8] {
&self.raw[self.header_len..]
}
pub fn bytes(&self) -> &'a [u8] {
self.raw
}
pub fn kind(&self) -> LayerKind {
LayerKind::Ipv6
}
pub fn extensions(&self) -> Ipv6ExtensionWalk {
const MAX_DEPTH: u8 = 8;
let payload = self.payload();
let mut nh = self.next_header();
let mut offset = 0usize;
let mut chain_depth = 0u8;
let mut fragment_present = false;
let mut chain_too_deep = false;
let mut malformed = false;
loop {
if !is_extension_header(nh) {
break;
}
if chain_depth >= MAX_DEPTH {
chain_too_deep = true;
break;
}
if payload.len() < offset + 2 {
malformed = true;
break;
}
let hdr_next = payload[offset];
let ext_len_bytes = ext_header_len(nh, payload[offset + 1]);
if payload.len() < offset + ext_len_bytes {
malformed = true;
break;
}
if nh == 44 {
fragment_present = true;
}
nh = hdr_next;
offset += ext_len_bytes;
chain_depth += 1;
}
Ipv6ExtensionWalk {
upper_header: nh,
payload_offset: offset,
chain_depth,
fragment_present,
chain_too_deep,
malformed,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub struct Ipv6ExtensionWalk {
pub upper_header: u8,
pub payload_offset: usize,
pub chain_depth: u8,
pub fragment_present: bool,
pub chain_too_deep: bool,
pub malformed: bool,
}
fn is_extension_header(nh: u8) -> bool {
matches!(nh, 0 | 43 | 44 | 60 | 51 | 135 | 139 | 140)
}
fn ext_header_len(this_header: u8, hdr_ext_len: u8) -> usize {
match this_header {
44 => 8,
51 => (hdr_ext_len as usize + 2) * 4,
_ => 8 + (hdr_ext_len as usize) * 8,
}
}
#[derive(Debug, Clone, Copy)]
pub struct ArpSlice<'a> {
raw: &'a [u8],
}
impl<'a> ArpSlice<'a> {
pub(crate) fn new(raw: &'a [u8]) -> Self {
Self { raw }
}
pub fn htype(&self) -> u16 {
u16::from_be_bytes([self.raw[0], self.raw[1]])
}
pub fn ptype(&self) -> u16 {
u16::from_be_bytes([self.raw[2], self.raw[3]])
}
pub fn hlen(&self) -> u8 {
self.raw[4]
}
pub fn plen(&self) -> u8 {
self.raw[5]
}
pub fn oper(&self) -> u16 {
u16::from_be_bytes([self.raw[6], self.raw[7]])
}
pub fn sender_ha(&self) -> Option<[u8; 6]> {
if self.hlen() != 6 || self.raw.len() < 14 {
return None;
}
let mut o = [0u8; 6];
o.copy_from_slice(&self.raw[8..14]);
Some(o)
}
pub fn sender_pa(&self) -> Option<std::net::Ipv4Addr> {
if self.plen() != 4 || self.raw.len() < 18 {
return None;
}
Some(std::net::Ipv4Addr::new(
self.raw[14],
self.raw[15],
self.raw[16],
self.raw[17],
))
}
pub fn target_ha(&self) -> Option<[u8; 6]> {
if self.hlen() != 6 || self.raw.len() < 24 {
return None;
}
let mut o = [0u8; 6];
o.copy_from_slice(&self.raw[18..24]);
Some(o)
}
pub fn target_pa(&self) -> Option<std::net::Ipv4Addr> {
if self.plen() != 4 || self.raw.len() < 28 {
return None;
}
Some(std::net::Ipv4Addr::new(
self.raw[24],
self.raw[25],
self.raw[26],
self.raw[27],
))
}
pub fn header(&self) -> &'a [u8] {
&self.raw[..self.raw.len().min(28)]
}
pub fn bytes(&self) -> &'a [u8] {
self.raw
}
pub fn kind(&self) -> LayerKind {
LayerKind::Arp
}
}