use crate::*;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum IpHeadersSlice<'a> {
Ipv4(Ipv4HeaderSlice<'a>, Ipv4ExtensionsSlice<'a>),
Ipv6(Ipv6HeaderSlice<'a>, Ipv6ExtensionsSlice<'a>),
}
impl<'a> IpHeadersSlice<'a> {
#[inline]
pub fn is_ipv4(&self) -> bool {
matches!(self, IpHeadersSlice::Ipv4(_, _))
}
#[inline]
pub fn is_ipv6(&self) -> bool {
matches!(self, IpHeadersSlice::Ipv6(_, _))
}
#[inline]
pub fn ipv4(&self) -> Option<Ipv4HeaderSlice<'a>> {
if let IpHeadersSlice::Ipv4(v, _) = self {
Some(*v)
} else {
None
}
}
#[inline]
pub fn ipv4_exts(&self) -> Option<Ipv4ExtensionsSlice<'a>> {
if let IpHeadersSlice::Ipv4(_, v) = self {
Some(*v)
} else {
None
}
}
#[inline]
pub fn ipv6(&self) -> Option<Ipv6HeaderSlice<'a>> {
if let IpHeadersSlice::Ipv6(v, _) = self {
Some(*v)
} else {
None
}
}
#[inline]
pub fn ipv6_exts(&self) -> Option<&Ipv6ExtensionsSlice<'a>> {
if let IpHeadersSlice::Ipv6(_, v) = self {
Some(v)
} else {
None
}
}
#[inline]
pub fn slice(&self) -> &'a [u8] {
match self {
IpHeadersSlice::Ipv4(v, _) => v.slice(),
IpHeadersSlice::Ipv6(v, _) => v.slice(),
}
}
#[inline]
pub fn source_addr(&self) -> core::net::IpAddr {
match self {
IpHeadersSlice::Ipv4(v, _) => v.source_addr().into(),
IpHeadersSlice::Ipv6(v, _) => v.source_addr().into(),
}
}
#[inline]
pub fn destination_addr(&self) -> core::net::IpAddr {
match self {
IpHeadersSlice::Ipv4(v, _) => v.destination_addr().into(),
IpHeadersSlice::Ipv6(v, _) => v.destination_addr().into(),
}
}
#[inline]
pub fn next_header(&self) -> IpNumber {
match self {
IpHeadersSlice::Ipv4(v, _) => v.protocol(),
IpHeadersSlice::Ipv6(v, _) => v.next_header(),
}
}
#[inline]
pub fn payload_ip_number(&self) -> IpNumber {
match self {
IpHeadersSlice::Ipv4(v, exts) => {
exts.auth.map(|a| a.next_header()).unwrap_or(v.protocol())
}
IpHeadersSlice::Ipv6(v, exts) => {
let (_, payload_ip_number, _, _) =
Ipv6Extensions::from_slice_lax(v.next_header(), exts.slice());
payload_ip_number
}
}
}
#[inline]
pub fn version(&self) -> u8 {
match self {
IpHeadersSlice::Ipv4(v, _) => v.version(),
IpHeadersSlice::Ipv6(v, _) => v.version(),
}
}
#[inline]
pub fn header_len(&self) -> usize {
match self {
IpHeadersSlice::Ipv4(v, exts) => {
v.slice().len() + exts.auth.map(|v| v.slice().len()).unwrap_or(0)
}
IpHeadersSlice::Ipv6(v, exts) => v.slice().len() + exts.slice().len(),
}
}
#[inline]
pub fn try_to_header(&self) -> Result<IpHeaders, err::ipv6_exts::HeaderSliceError> {
match self {
IpHeadersSlice::Ipv4(v, exts) => Ok(IpHeaders::Ipv4(v.to_header(), exts.to_header())),
IpHeadersSlice::Ipv6(v, exts) => {
let (exts, _, _) = Ipv6Extensions::from_slice(v.next_header(), exts.slice())?;
Ok(IpHeaders::Ipv6(v.to_header(), exts))
}
}
}
}
impl<'a> From<Ipv4HeaderSlice<'a>> for IpHeadersSlice<'a> {
#[inline]
fn from(value: Ipv4HeaderSlice<'a>) -> Self {
Self::Ipv4(value, Default::default())
}
}
impl<'a> From<Ipv6HeaderSlice<'a>> for IpHeadersSlice<'a> {
#[inline]
fn from(value: Ipv6HeaderSlice<'a>) -> Self {
Self::Ipv6(value, Default::default())
}
}
impl<'a> From<(Ipv4HeaderSlice<'a>, Ipv4ExtensionsSlice<'a>)> for IpHeadersSlice<'a> {
#[inline]
fn from(value: (Ipv4HeaderSlice<'a>, Ipv4ExtensionsSlice<'a>)) -> Self {
Self::Ipv4(value.0, value.1)
}
}
impl<'a> From<(Ipv6HeaderSlice<'a>, Ipv6ExtensionsSlice<'a>)> for IpHeadersSlice<'a> {
#[inline]
fn from(value: (Ipv6HeaderSlice<'a>, Ipv6ExtensionsSlice<'a>)) -> Self {
Self::Ipv6(value.0, value.1)
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec::Vec;
use core::net::{IpAddr, Ipv4Addr, Ipv6Addr};
#[test]
fn is_ipv4_ipv6_and_accessors() {
{
let h = Ipv4Header {
protocol: ip_number::AUTH,
source: [1, 2, 3, 4],
destination: [5, 6, 7, 8],
..Default::default()
};
let header_bytes = h.to_bytes();
let auth = IpAuthHeader::new(ip_number::UDP, 7, 9, &[1, 2, 3, 4]).unwrap();
let auth_bytes = auth.to_bytes();
let exts = Ipv4ExtensionsSlice::from_slice(ip_number::AUTH, &auth_bytes)
.unwrap()
.0;
let s = IpHeadersSlice::Ipv4(Ipv4HeaderSlice::from_slice(&header_bytes).unwrap(), exts);
assert!(s.is_ipv4());
assert_eq!(false, s.is_ipv6());
assert!(s.ipv4().is_some());
assert!(s.ipv6().is_none());
assert!(s.ipv4_exts().is_some());
assert!(s.ipv6_exts().is_none());
assert_eq!(s.slice(), header_bytes.as_slice());
assert_eq!(
s.ipv4_exts().unwrap().auth.unwrap().slice(),
auth_bytes.as_slice()
);
assert_eq!(s.next_header(), ip_number::AUTH);
assert_eq!(s.payload_ip_number(), ip_number::UDP);
assert_eq!(s.version(), 4);
assert_eq!(s.header_len(), Ipv4Header::MIN_LEN + auth.header_len());
assert_eq!(s.source_addr(), IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4)));
assert_eq!(s.destination_addr(), IpAddr::V4(Ipv4Addr::new(5, 6, 7, 8)));
}
{
let h = Ipv6Header {
next_header: ip_number::IPV6_FRAG,
source: [1; 16],
destination: [2; 16],
..Default::default()
};
let header_bytes = h.to_bytes();
let fragment = Ipv6FragmentHeader::new(ip_number::TCP, IpFragOffset::ZERO, false, 1234);
let mut ext_bytes = Vec::new();
ext_bytes.extend_from_slice(&fragment.to_bytes());
let exts = Ipv6ExtensionsSlice::from_slice(ip_number::IPV6_FRAG, &ext_bytes)
.unwrap()
.0;
let s = IpHeadersSlice::Ipv6(
Ipv6HeaderSlice::from_slice(&header_bytes).unwrap(),
exts.clone(),
);
assert_eq!(false, s.is_ipv4());
assert!(s.is_ipv6());
assert!(s.ipv4().is_none());
assert!(s.ipv6().is_some());
assert!(s.ipv4_exts().is_none());
assert_eq!(s.ipv6_exts(), Some(&exts));
assert_eq!(s.slice(), &header_bytes[..]);
assert_eq!(s.ipv6_exts().unwrap().slice(), &ext_bytes[..]);
assert_eq!(s.next_header(), ip_number::IPV6_FRAG);
assert_eq!(s.payload_ip_number(), ip_number::TCP);
assert_eq!(s.version(), 6);
assert_eq!(s.header_len(), Ipv6Header::LEN + ext_bytes.len());
assert_eq!(s.source_addr(), IpAddr::V6(Ipv6Addr::from([1; 16])));
assert_eq!(s.destination_addr(), IpAddr::V6(Ipv6Addr::from([2; 16])));
}
}
#[test]
fn try_to_header() {
{
let h = Ipv4Header {
protocol: ip_number::AUTH,
source: [1, 2, 3, 4],
destination: [5, 6, 7, 8],
..Default::default()
};
let header_bytes = h.to_bytes();
let auth = IpAuthHeader::new(ip_number::UDP, 7, 9, &[1, 2, 3, 4]).unwrap();
let auth_bytes = auth.to_bytes();
let exts = Ipv4ExtensionsSlice::from_slice(ip_number::AUTH, &auth_bytes)
.unwrap()
.0;
let s = IpHeadersSlice::Ipv4(Ipv4HeaderSlice::from_slice(&header_bytes).unwrap(), exts);
assert_eq!(
s.try_to_header().unwrap(),
IpHeaders::Ipv4(h, Ipv4Extensions { auth: Some(auth) })
);
}
{
let h = Ipv6Header {
next_header: ip_number::IPV6_FRAG,
source: [1; 16],
destination: [2; 16],
..Default::default()
};
let header_bytes = h.to_bytes();
let fragment = Ipv6FragmentHeader::new(ip_number::TCP, IpFragOffset::ZERO, false, 1234);
let mut ext_bytes = Vec::new();
ext_bytes.extend_from_slice(&fragment.to_bytes());
let exts = Ipv6ExtensionsSlice::from_slice(ip_number::IPV6_FRAG, &ext_bytes)
.unwrap()
.0;
let s = IpHeadersSlice::Ipv6(Ipv6HeaderSlice::from_slice(&header_bytes).unwrap(), exts);
assert_eq!(
s.try_to_header().unwrap(),
IpHeaders::Ipv6(
h,
Ipv6Extensions {
fragment: Some(fragment),
..Default::default()
}
)
);
}
{
let h = Ipv6Header {
next_header: ip_number::IPV6_HOP_BY_HOP,
..Default::default()
};
let header_bytes = h.to_bytes();
let s = IpHeadersSlice::Ipv6(
Ipv6HeaderSlice::from_slice(&header_bytes).unwrap(),
Ipv6ExtensionsSlice::default(),
);
assert!(s.try_to_header().is_err());
}
}
}