use std::net::IpAddr;
use bitfield_struct::bitfield;
use either::Either;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
use crate::packet::{Ipv4, Ipv6};
#[bitfield(u8)]
#[derive(FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable, PartialEq, Eq)]
pub struct IpvxVersion {
#[bits(4)]
pub _unknown: u8,
#[bits(4)]
pub version: u8,
}
#[repr(C, packed)]
#[derive(FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable)]
pub struct Ip {
pub header: IpvxVersion,
pub rest: [u8],
}
impl Ip {
fn as_v4_or_v6(&self) -> Option<Either<&Ipv4, &Ipv6>> {
let b = self.as_bytes();
match self.header.version() {
4 => Ipv4::<[u8]>::ref_from_bytes(b).ok().map(Either::Left),
6 => Ipv6::<[u8]>::ref_from_bytes(b).ok().map(Either::Right),
_ => None,
}
}
pub fn source(&self) -> Option<IpAddr> {
Some(match self.as_v4_or_v6()? {
Either::Left(ipv4) => ipv4.header.source().into(),
Either::Right(ipv6) => ipv6.header.source().into(),
})
}
pub fn destination(&self) -> Option<IpAddr> {
Some(match self.as_v4_or_v6()? {
Either::Left(ipv4) => ipv4.header.destination().into(),
Either::Right(ipv6) => ipv6.header.destination().into(),
})
}
}