#![allow(dead_code)]
use core::fmt;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
use std::str::FromStr;
use thiserror::Error;
use zerocopy::{BigEndian, FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned, U16};
use crate::packet::protocol::EtherProto;
use crate::packet::{HeaderParser, PacketHeader};
use std::ops::Deref;
const ETH_ALEN: usize = 6; const ETH_HLEN: usize = 14; const ETH_ZLEN: usize = 60; const ETH_DATA_LEN: usize = 1500; const ETH_FRAME_LEN: usize = 1514; const VLAN_TAG_LEN: usize = 4;
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
FromBytes,
IntoBytes,
Immutable,
KnownLayout,
Serialize,
Deserialize,
)]
#[serde(into = "String")]
#[serde(try_from = "String")]
pub struct EthAddr([u8; ETH_ALEN]);
impl Default for EthAddr {
fn default() -> Self {
EthAddr([0u8; ETH_ALEN])
}
}
impl Display for EthAddr {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
)
}
}
#[derive(Debug, Clone, Error)]
pub enum EtherError {
#[error("Invalid Ethernet address format")]
InvalidAddressFormat,
}
impl FromStr for EthAddr {
type Err = EtherError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let bytes: Vec<u8> = s
.split(':')
.map(|part| u8::from_str_radix(part, 16).map_err(|_| EtherError::InvalidAddressFormat))
.collect::<Result<Vec<u8>, _>>()?;
if bytes.len() != ETH_ALEN {
return Err(EtherError::InvalidAddressFormat);
}
let mut addr = [0u8; ETH_ALEN];
addr.copy_from_slice(&bytes);
Ok(EthAddr(addr))
}
}
impl From<EthAddr> for String {
#[inline]
fn from(addr: EthAddr) -> Self {
addr.to_string()
}
}
impl TryFrom<String> for EthAddr {
type Error = EtherError;
#[inline]
fn try_from(s: String) -> Result<Self, Self::Error> {
EthAddr::from_str(&s)
}
}
#[repr(C, packed)]
#[derive(FromBytes, IntoBytes, Unaligned, Immutable, KnownLayout, Debug, Clone, Copy)]
pub struct EtherHeader {
dest: EthAddr,
source: EthAddr,
proto: EtherProto,
}
impl EtherHeader {
pub fn dest(&self) -> &EthAddr {
&self.dest
}
pub fn source(&self) -> &EthAddr {
&self.source
}
pub fn protocol(&self) -> EtherProto {
self.proto
}
}
#[repr(C)]
#[derive(FromBytes, IntoBytes, Unaligned, Immutable, KnownLayout, Debug, Clone, Copy)]
struct EtherHeaderFixed(EtherHeader);
impl PacketHeader for EtherHeaderFixed {
const NAME: &'static str = "EtherHeaderFixed";
type InnerType = EtherProto;
#[inline]
fn inner_type(&self) -> Self::InnerType {
self.0.proto
}
}
impl HeaderParser for EtherHeaderFixed {
type Output<'a> = &'a EtherHeader;
#[inline]
fn into_view<'a>(header: &'a Self, _options: &'a [u8]) -> Self::Output<'a> {
&header.0
}
}
impl PacketHeader for EtherHeader {
const NAME: &'static str = "EtherHeader";
type InnerType = EtherProto;
#[inline]
fn inner_type(&self) -> Self::InnerType {
self.proto
}
}
impl HeaderParser for EtherHeader {
type Output<'a> = EtherHeaderVlan<'a>;
#[inline]
fn into_view<'a>(_: &'a Self, _: &'a [u8]) -> Self::Output<'a> {
unreachable!()
}
#[inline]
fn from_bytes<'a>(
buf: &'a [u8],
) -> Result<(Self::Output<'a>, &'a [u8]), super::PacketHeaderError> {
let (eth_header, mut rest) = EtherHeaderFixed::from_bytes(buf)?;
let mut ethernet_header = EtherHeaderVlan::Standard(eth_header);
while ethernet_header.inner_type() == EtherProto::VLAN_8021Q {
let (vlan_header, vlan_rest) = Ether8021qHeader::from_bytes(rest)?;
rest = vlan_rest;
ethernet_header = match ðernet_header {
EtherHeaderVlan::Standard(eth) => EtherHeaderVlan::VLAN8021Q(eth, vlan_header),
EtherHeaderVlan::VLAN8021Q(eth, vlan) => {
EtherHeaderVlan::VLAN8021QNested(eth, vlan, vlan_header)
}
EtherHeaderVlan::VLAN8021QNested(_, _, _) => {
return Err(super::PacketHeaderError::Other(
"More than two nested VLAN tags are not supported",
));
}
};
}
Ok((ethernet_header, rest))
}
}
#[repr(C, packed)]
#[derive(FromBytes, IntoBytes, Unaligned, Immutable, KnownLayout, Debug, Clone, Copy)]
pub struct Ether8021qHeader {
tci: U16<BigEndian>,
proto: EtherProto,
}
impl Ether8021qHeader {
pub fn vlan_id(&self) -> u16 {
self.tci.get() & 0x0FFF
}
pub fn vlan_pcp(&self) -> u8 {
((self.tci.get() >> 13) & 0x07) as u8
}
pub fn vlan_dei(&self) -> bool {
((self.tci.get() >> 12) & 0x01) != 0
}
}
impl Display for Ether8021qHeader {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"802.1Q vid={} pcp={} dei={} proto={}",
self.vlan_id(),
self.vlan_pcp(),
self.vlan_dei(),
self.proto
)
}
}
impl PacketHeader for Ether8021qHeader {
const NAME: &'static str = "Ether8021qHeader";
type InnerType = EtherProto;
#[inline]
fn inner_type(&self) -> Self::InnerType {
self.proto
}
}
impl HeaderParser for Ether8021qHeader {
type Output<'a> = &'a Ether8021qHeader;
#[inline]
fn into_view<'a>(header: &'a Self, _options: &'a [u8]) -> Self::Output<'a> {
header
}
}
#[derive(Debug, Clone)]
pub enum EtherHeaderVlan<'a> {
Standard(&'a EtherHeader),
VLAN8021Q(&'a EtherHeader, &'a Ether8021qHeader),
VLAN8021QNested(&'a EtherHeader, &'a Ether8021qHeader, &'a Ether8021qHeader),
}
impl Display for EtherHeaderVlan<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
EtherHeaderVlan::Standard(eth) => {
write!(
f,
"Ethernet {} -> {} proto={}",
eth.source, eth.dest, eth.proto
)
}
EtherHeaderVlan::VLAN8021Q(eth, vlan) => {
write!(
f,
"Ethernet {} -> {} proto={} [{}]",
eth.source, eth.dest, eth.proto, vlan
)
}
EtherHeaderVlan::VLAN8021QNested(eth, vlan1, vlan2) => {
write!(
f,
"Ethernet {} -> {} proto={} [{}] [{}]",
eth.source, eth.dest, eth.proto, vlan1, vlan2
)
}
}
}
}
impl Deref for EtherHeaderVlan<'_> {
type Target = EtherHeader;
fn deref(&self) -> &Self::Target {
match self {
EtherHeaderVlan::Standard(eth) => eth,
EtherHeaderVlan::VLAN8021Q(eth, _) => eth,
EtherHeaderVlan::VLAN8021QNested(eth, _, _) => eth,
}
}
}
impl<'a> EtherHeaderVlan<'a> {
pub fn dest(&self) -> &EthAddr {
match self {
EtherHeaderVlan::Standard(eth) => ð.dest,
EtherHeaderVlan::VLAN8021Q(eth, _) => ð.dest,
EtherHeaderVlan::VLAN8021QNested(eth, _, _) => ð.dest,
}
}
pub fn source(&self) -> &EthAddr {
match self {
EtherHeaderVlan::Standard(eth) => ð.source,
EtherHeaderVlan::VLAN8021Q(eth, _) => ð.source,
EtherHeaderVlan::VLAN8021QNested(eth, _, _) => ð.source,
}
}
pub fn inner_type(&self) -> EtherProto {
match self {
EtherHeaderVlan::Standard(eth) => eth.proto,
EtherHeaderVlan::VLAN8021Q(_, vlan) => vlan.proto,
EtherHeaderVlan::VLAN8021QNested(_, _, vlan) => vlan.proto,
}
}
}
impl PacketHeader for EtherHeaderVlan<'_> {
const NAME: &'static str = "EtherHeaderVlan";
type InnerType = EtherProto;
#[inline]
fn inner_type(&self) -> Self::InnerType {
self.inner_type()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ether_header_parse_ipv4() {
let packet_bytes: [u8; 14] = [
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x08, 0x00, ];
let (header, remaining) =
EtherHeader::from_bytes(&packet_bytes).expect("Failed to parse EtherHeader");
assert_eq!(header.proto, EtherProto::IPV4);
assert_eq!(header.dest.0, [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
assert_eq!(header.source.0, [0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c]);
assert_eq!(header.dest.to_string(), "01:02:03:04:05:06");
assert_eq!(header.source.to_string(), "07:08:09:0a:0b:0c");
assert_eq!(remaining.len(), 0);
}
#[test]
fn test_ether_header_parse_vlan() {
let packet_bytes: [u8; 18] = [
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x81, 0x00, 0x00, 0x2a, 0x08, 0x00, ];
let (eth_header_ext, remaining) =
EtherHeader::from_bytes(&packet_bytes).expect("Failed to parse EtherHeader");
assert_eq!(
eth_header_ext.dest().0,
[0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]
);
assert_eq!(
eth_header_ext.source().0,
[0x11, 0x22, 0x33, 0x44, 0x55, 0x66]
);
assert_eq!(eth_header_ext.dest().to_string(), "aa:bb:cc:dd:ee:ff");
assert_eq!(eth_header_ext.source().to_string(), "11:22:33:44:55:66");
assert_eq!(eth_header_ext.inner_type(), EtherProto::IPV4);
assert_eq!(remaining.len(), 0);
match eth_header_ext {
EtherHeaderVlan::VLAN8021Q(eth, vlan) => {
assert_eq!(eth.proto, EtherProto::VLAN_8021Q);
assert_eq!(vlan.vlan_id(), 42);
assert_eq!(vlan.vlan_pcp(), 0);
assert!(!vlan.vlan_dei());
assert_eq!(vlan.proto, EtherProto::IPV4);
let display_str = vlan.to_string();
assert!(display_str.contains("vid=42"));
assert!(display_str.contains("pcp=0"));
assert!(display_str.contains("dei=false"));
}
_ => panic!("Expected VLAN8021Q variant"),
}
}
}