use core::fmt;
use std::fmt::{Display, Formatter};
use std::net::Ipv4Addr;
use std::ops::Deref;
use zerocopy::byteorder::{BigEndian, U16};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
use crate::packet::ether::EthAddr;
use crate::packet::{HeaderParser, PacketHeader};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, FromBytes, IntoBytes, Immutable, KnownLayout)]
#[repr(transparent)]
pub struct ArpHardwareType(pub U16<BigEndian>);
impl ArpHardwareType {
pub const ETHERNET: ArpHardwareType = ArpHardwareType(U16::new(1)); pub const EXPERIMENTAL_ETHERNET: ArpHardwareType = ArpHardwareType(U16::new(2)); pub const AX25: ArpHardwareType = ArpHardwareType(U16::new(3)); pub const PROTEON_TOKEN_RING: ArpHardwareType = ArpHardwareType(U16::new(4)); pub const CHAOS: ArpHardwareType = ArpHardwareType(U16::new(5)); pub const IEEE802: ArpHardwareType = ArpHardwareType(U16::new(6)); pub const ARCNET: ArpHardwareType = ArpHardwareType(U16::new(7)); pub const HYPERCHANNEL: ArpHardwareType = ArpHardwareType(U16::new(8)); pub const LANSTAR: ArpHardwareType = ArpHardwareType(U16::new(9)); pub const AUTONET: ArpHardwareType = ArpHardwareType(U16::new(10)); pub const LOCALTALK: ArpHardwareType = ArpHardwareType(U16::new(11)); pub const LOCALNET: ArpHardwareType = ArpHardwareType(U16::new(12)); pub const ULTRA_LINK: ArpHardwareType = ArpHardwareType(U16::new(13)); pub const SMDS: ArpHardwareType = ArpHardwareType(U16::new(14)); pub const FRAME_RELAY: ArpHardwareType = ArpHardwareType(U16::new(15)); pub const ATM: ArpHardwareType = ArpHardwareType(U16::new(16)); pub const HDLC: ArpHardwareType = ArpHardwareType(U16::new(17)); pub const FIBRE_CHANNEL: ArpHardwareType = ArpHardwareType(U16::new(18)); pub const ATM_2: ArpHardwareType = ArpHardwareType(U16::new(19)); pub const SERIAL_LINE: ArpHardwareType = ArpHardwareType(U16::new(20));
#[inline]
pub fn value(&self) -> u16 {
self.0.get()
}
}
impl Display for ArpHardwareType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let name = match *self {
ArpHardwareType::ETHERNET => "ethernet",
ArpHardwareType::EXPERIMENTAL_ETHERNET => "exp-ethernet",
ArpHardwareType::AX25 => "ax25",
ArpHardwareType::PROTEON_TOKEN_RING => "token-ring",
ArpHardwareType::CHAOS => "chaos",
ArpHardwareType::IEEE802 => "ieee802",
ArpHardwareType::ARCNET => "arcnet",
ArpHardwareType::HYPERCHANNEL => "hyperchannel",
ArpHardwareType::LANSTAR => "lanstar",
ArpHardwareType::AUTONET => "autonet",
ArpHardwareType::LOCALTALK => "localtalk",
ArpHardwareType::LOCALNET => "localnet",
ArpHardwareType::ULTRA_LINK => "ultra-link",
ArpHardwareType::SMDS => "smds",
ArpHardwareType::FRAME_RELAY => "frame-relay",
ArpHardwareType::ATM => "atm",
ArpHardwareType::HDLC => "hdlc",
ArpHardwareType::FIBRE_CHANNEL => "fibre-channel",
ArpHardwareType::ATM_2 => "atm2",
ArpHardwareType::SERIAL_LINE => "serial-line",
_ => return write!(f, "unknown({})", self.value()),
};
write!(f, "{}", name)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, FromBytes, IntoBytes, Immutable, KnownLayout)]
#[repr(transparent)]
pub struct ArpProtocolType(pub U16<BigEndian>);
impl ArpProtocolType {
pub const IPV4: ArpProtocolType = ArpProtocolType(U16::new(0x0800));
#[inline]
pub fn value(&self) -> u16 {
self.0.get()
}
}
impl Display for ArpProtocolType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match *self {
ArpProtocolType::IPV4 => write!(f, "ipv4"),
_ => write!(f, "0x{:04x}", self.value()),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, FromBytes, IntoBytes, Immutable, KnownLayout)]
#[repr(transparent)]
pub struct ArpOperation(pub U16<BigEndian>);
impl ArpOperation {
pub const REQUEST: ArpOperation = ArpOperation(U16::new(1)); pub const REPLY: ArpOperation = ArpOperation(U16::new(2)); pub const RARP_REQUEST: ArpOperation = ArpOperation(U16::new(3)); pub const RARP_REPLY: ArpOperation = ArpOperation(U16::new(4)); pub const DRARP_REQUEST: ArpOperation = ArpOperation(U16::new(5)); pub const DRARP_REPLY: ArpOperation = ArpOperation(U16::new(6)); pub const DRARP_ERROR: ArpOperation = ArpOperation(U16::new(7)); pub const INARP_REQUEST: ArpOperation = ArpOperation(U16::new(8)); pub const INARP_REPLY: ArpOperation = ArpOperation(U16::new(9)); pub const ARP_NAK: ArpOperation = ArpOperation(U16::new(10));
#[inline]
pub fn value(&self) -> u16 {
self.0.get()
}
}
impl Display for ArpOperation {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let name = match *self {
ArpOperation::REQUEST => "request",
ArpOperation::REPLY => "reply",
ArpOperation::RARP_REQUEST => "rarp-request",
ArpOperation::RARP_REPLY => "rarp-reply",
ArpOperation::DRARP_REQUEST => "drarp-request",
ArpOperation::DRARP_REPLY => "drarp-reply",
ArpOperation::DRARP_ERROR => "drarp-error",
ArpOperation::INARP_REQUEST => "inarp-request",
ArpOperation::INARP_REPLY => "inarp-reply",
ArpOperation::ARP_NAK => "arp-nak",
_ => return write!(f, "unknown({})", self.value()),
};
write!(f, "{}", name)
}
}
#[repr(C, packed)]
#[derive(FromBytes, IntoBytes, Unaligned, Immutable, KnownLayout, Debug, Clone, Copy)]
pub struct ArpHeader {
htype: ArpHardwareType, ptype: ArpProtocolType, hlen: u8, plen: u8, oper: ArpOperation, }
impl ArpHeader {
#[inline]
pub fn hardware_type(&self) -> ArpHardwareType {
self.htype
}
#[inline]
pub fn protocol_type(&self) -> ArpProtocolType {
self.ptype
}
#[inline]
pub fn hardware_len(&self) -> u8 {
self.hlen
}
#[inline]
pub fn protocol_len(&self) -> u8 {
self.plen
}
#[inline]
pub fn operation(&self) -> ArpOperation {
self.oper
}
#[inline]
fn addresses_len(&self) -> usize {
2 * (self.hlen as usize + self.plen as usize)
}
#[inline]
fn is_valid(&self) -> bool {
self.hlen > 0 && self.plen > 0
}
#[inline]
pub fn is_eth_ipv4(&self) -> bool {
self.htype == ArpHardwareType::ETHERNET
&& self.ptype == ArpProtocolType::IPV4
&& self.hlen == 6
&& self.plen == 4
}
}
impl PacketHeader for ArpHeader {
const NAME: &'static str = "ArpHeader";
type InnerType = ();
#[inline]
fn inner_type(&self) -> Self::InnerType {}
#[inline]
fn total_len(&self, _buf: &[u8]) -> usize {
Self::FIXED_LEN + self.addresses_len()
}
#[inline]
fn is_valid(&self) -> bool {
self.is_valid()
}
}
impl HeaderParser for ArpHeader {
type Output<'a> = ArpHeaderFull<'a>;
#[inline]
fn into_view<'a>(header: &'a Self, addresses: &'a [u8]) -> Self::Output<'a> {
ArpHeaderFull { header, addresses }
}
}
#[derive(Debug, Clone)]
pub struct ArpHeaderFull<'a> {
pub header: &'a ArpHeader,
pub addresses: &'a [u8],
}
impl<'a> ArpHeaderFull<'a> {
#[inline]
pub fn hardware_type(&self) -> ArpHardwareType {
self.header.hardware_type()
}
#[inline]
pub fn protocol_type(&self) -> ArpProtocolType {
self.header.protocol_type()
}
#[inline]
pub fn hardware_len(&self) -> u8 {
self.header.hardware_len()
}
#[inline]
pub fn protocol_len(&self) -> u8 {
self.header.protocol_len()
}
#[inline]
pub fn operation(&self) -> ArpOperation {
self.header.operation()
}
#[inline]
pub fn is_eth_ipv4(&self) -> bool {
self.header.is_eth_ipv4()
}
#[inline]
pub fn sender_hw_addr_raw(&self) -> &[u8] {
let hlen = self.hardware_len() as usize;
&self.addresses[0..hlen]
}
#[inline]
pub fn sender_proto_addr_raw(&self) -> &[u8] {
let hlen = self.hardware_len() as usize;
let plen = self.protocol_len() as usize;
&self.addresses[hlen..hlen + plen]
}
#[inline]
pub fn target_hw_addr_raw(&self) -> &[u8] {
let hlen = self.hardware_len() as usize;
let plen = self.protocol_len() as usize;
&self.addresses[hlen + plen..hlen + plen + hlen]
}
#[inline]
pub fn target_proto_addr_raw(&self) -> &[u8] {
let hlen = self.hardware_len() as usize;
let plen = self.protocol_len() as usize;
&self.addresses[hlen + plen + hlen..]
}
#[inline]
pub fn sender_hw_addr(&self) -> Option<&EthAddr> {
if self.is_eth_ipv4() {
zerocopy::Ref::<_, EthAddr>::from_prefix(self.sender_hw_addr_raw())
.ok()
.map(|(r, _)| zerocopy::Ref::into_ref(r))
} else {
None
}
}
#[inline]
pub fn sender_proto_addr(&self) -> Option<[u8; 4]> {
if self.is_eth_ipv4() {
self.sender_proto_addr_raw().try_into().ok()
} else {
None
}
}
#[inline]
pub fn sender_ipv4(&self) -> Option<Ipv4Addr> {
self.sender_proto_addr().map(Ipv4Addr::from)
}
#[inline]
pub fn target_hw_addr(&self) -> Option<&EthAddr> {
if self.is_eth_ipv4() {
zerocopy::Ref::<_, EthAddr>::from_prefix(self.target_hw_addr_raw())
.ok()
.map(|(r, _)| zerocopy::Ref::into_ref(r))
} else {
None
}
}
#[inline]
pub fn target_proto_addr(&self) -> Option<[u8; 4]> {
if self.is_eth_ipv4() {
self.target_proto_addr_raw().try_into().ok()
} else {
None
}
}
#[inline]
pub fn target_ipv4(&self) -> Option<Ipv4Addr> {
self.target_proto_addr().map(Ipv4Addr::from)
}
}
impl Deref for ArpHeaderFull<'_> {
type Target = ArpHeader;
#[inline]
fn deref(&self) -> &Self::Target {
self.header
}
}
impl Display for ArpHeaderFull<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if self.is_eth_ipv4() {
if let (Some(sha), Some(spa), Some(tha), Some(tpa)) = (
self.sender_hw_addr(),
self.sender_ipv4(),
self.target_hw_addr(),
self.target_ipv4(),
) {
write!(
f,
"ARP {} {} -> {} ({}): {} -> {}",
self.operation(),
sha,
tha,
if self.operation() == ArpOperation::REQUEST {
"who-has"
} else {
"is-at"
},
spa,
tpa
)
} else {
write!(f, "ARP {} (invalid)", self.operation())
}
} else {
write!(
f,
"ARP {} htype={} ptype={} hlen={} plen={}",
self.operation(),
self.hardware_type(),
self.protocol_type(),
self.hardware_len(),
self.protocol_len()
)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test]
fn test_arp_request_eth_ipv4() {
let packet = vec![
0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 192, 168, 1, 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 192, 168, 1, 1, ];
let (arp, remaining) = ArpHeader::from_bytes(&packet).expect("Failed to parse ARP");
assert_eq!(remaining.len(), 0);
assert_eq!(arp.hardware_type(), ArpHardwareType::ETHERNET);
assert_eq!(arp.protocol_type(), ArpProtocolType::IPV4);
assert_eq!(arp.hardware_len(), 6);
assert_eq!(arp.protocol_len(), 4);
assert_eq!(arp.operation(), ArpOperation::REQUEST);
assert!(arp.is_eth_ipv4());
assert_eq!(
arp.sender_hw_addr().unwrap().to_string(),
"aa:bb:cc:dd:ee:ff"
);
assert_eq!(arp.sender_proto_addr().unwrap(), [192, 168, 1, 2]);
assert_eq!(arp.sender_ipv4().unwrap(), Ipv4Addr::new(192, 168, 1, 2));
assert_eq!(
arp.target_hw_addr().unwrap().to_string(),
"00:00:00:00:00:00"
);
assert_eq!(arp.target_proto_addr().unwrap(), [192, 168, 1, 1]);
assert_eq!(arp.target_ipv4().unwrap(), Ipv4Addr::new(192, 168, 1, 1));
}
#[test]
fn test_arp_reply_eth_ipv4() {
let packet = vec![
0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 192, 168, 1, 1, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 192, 168, 1, 2, ];
let (arp, remaining) = ArpHeader::from_bytes(&packet).expect("Failed to parse ARP reply");
assert_eq!(remaining.len(), 0);
assert_eq!(arp.operation(), ArpOperation::REPLY);
assert!(arp.is_eth_ipv4());
assert_eq!(
arp.sender_hw_addr().unwrap().to_string(),
"11:22:33:44:55:66"
);
assert_eq!(arp.sender_proto_addr().unwrap(), [192, 168, 1, 1]);
}
#[test]
fn test_arp_packet_too_short() {
let short_packet = vec![0x00, 0x01, 0x08, 0x00];
let result = ArpHeader::from_bytes(&short_packet);
assert!(result.is_err());
}
#[test]
fn test_arp_invalid_lengths() {
let packet = vec![
0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, ];
let result = ArpHeader::from_bytes(&packet);
assert!(result.is_err());
}
#[test]
fn test_arp_display() {
let packet = vec![
0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
192, 168, 1, 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 192, 168, 1, 1,
];
let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
let display_str = format!("{}", arp);
assert!(display_str.contains("request"));
assert!(display_str.contains("aa:bb:cc:dd:ee:ff"));
}
#[test]
fn test_arp_operation_display() {
assert_eq!(format!("{}", ArpOperation::REQUEST), "request");
assert_eq!(format!("{}", ArpOperation::REPLY), "reply");
assert_eq!(format!("{}", ArpOperation::RARP_REQUEST), "rarp-request");
assert_eq!(format!("{}", ArpOperation::RARP_REPLY), "rarp-reply");
assert_eq!(format!("{}", ArpOperation::ARP_NAK), "arp-nak");
}
#[test]
fn test_arp_hardware_type_display() {
assert_eq!(format!("{}", ArpHardwareType::ETHERNET), "ethernet");
assert_eq!(format!("{}", ArpHardwareType::IEEE802), "ieee802");
assert_eq!(format!("{}", ArpHardwareType::FRAME_RELAY), "frame-relay");
assert_eq!(
format!("{}", ArpHardwareType(U16::new(9999))),
"unknown(9999)"
);
}
#[test]
fn test_arp_protocol_type_display() {
assert_eq!(format!("{}", ArpProtocolType::IPV4), "ipv4");
assert_eq!(format!("{}", ArpProtocolType(U16::new(0x1234))), "0x1234");
}
#[test]
fn test_arp_with_payload() {
let mut packet = vec![
0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
192, 168, 1, 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 192, 168, 1, 1,
];
packet.extend_from_slice(b"extra data");
let (arp, remaining) = ArpHeader::from_bytes(&packet).unwrap();
assert_eq!(arp.operation(), ArpOperation::REQUEST);
assert_eq!(remaining, b"extra data");
}
#[test]
fn test_arp_rarp_request() {
let packet = vec![
0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x03, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, ];
let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
assert_eq!(arp.operation(), ArpOperation::RARP_REQUEST);
}
#[test]
fn test_arp_gratuitous() {
let packet = vec![
0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
192, 168, 1, 100, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 192, 168, 1, 100, ];
let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
assert_eq!(arp.sender_ipv4().unwrap(), Ipv4Addr::new(192, 168, 1, 100));
assert_eq!(arp.sender_ipv4().unwrap(), arp.target_ipv4().unwrap());
assert_eq!(arp.operation(), ArpOperation::REQUEST);
}
#[test]
fn test_arp_probe() {
let packet = vec![
0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0,
0, 0, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 192, 168, 1, 100, ];
let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
assert_eq!(arp.sender_ipv4().unwrap(), Ipv4Addr::new(0, 0, 0, 0));
assert_eq!(arp.target_ipv4().unwrap(), Ipv4Addr::new(192, 168, 1, 100));
}
#[test]
fn test_arp_real_world_request() {
let packet = vec![
0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x08, 0x00, 0x27, 0x12, 0x34, 0x56, 10, 0, 0, 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 10, 0, 0, 1, ];
let (arp, remaining) = ArpHeader::from_bytes(&packet).unwrap();
assert_eq!(remaining.len(), 0);
assert_eq!(arp.sender_ipv4().unwrap(), Ipv4Addr::new(10, 0, 0, 2));
assert_eq!(arp.target_ipv4().unwrap(), Ipv4Addr::new(10, 0, 0, 1));
assert_eq!(
arp.sender_hw_addr().unwrap(),
&EthAddr::from_str("08:00:27:12:34:56").unwrap()
);
}
#[test]
fn test_arp_real_world_reply() {
let packet = vec![
0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x52, 0x54, 0x00, 0x12, 0x34, 0x56, 10, 0, 0, 1, 0x08, 0x00, 0x27, 0x12, 0x34, 0x56, 10, 0, 0, 2, ];
let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
assert_eq!(arp.operation(), ArpOperation::REPLY);
assert_eq!(
arp.sender_hw_addr().unwrap(),
&EthAddr::from_str("52:54:00:12:34:56").unwrap()
);
assert_eq!(arp.sender_ipv4().unwrap(), Ipv4Addr::new(10, 0, 0, 1));
}
#[test]
fn test_arp_from_bytes_multiple_packets() {
let test_cases = vec![
(
vec![
0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
0xff, 192, 168, 1, 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 192, 168, 1, 1,
],
ArpOperation::REQUEST,
),
(
vec![
0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x11, 0x22, 0x33, 0x44, 0x55,
0x66, 192, 168, 1, 1, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 192, 168, 1, 2,
],
ArpOperation::REPLY,
),
];
for (packet, expected_op) in test_cases {
let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
assert_eq!(arp.operation(), expected_op);
assert!(arp.is_eth_ipv4());
}
}
#[test]
fn test_arp_size_constants() {
assert_eq!(
std::mem::size_of::<ArpHeader>(),
8,
"ARP fixed header should be 8 bytes"
);
assert_eq!(ArpHeader::FIXED_LEN, 8);
}
#[test]
fn test_arp_packet_boundary_conditions() {
let packet = vec![
0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
192, 168, 1, 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 192, 168, 1, 1,
];
assert_eq!(packet.len(), 28);
let (arp, remaining) = ArpHeader::from_bytes(&packet).unwrap();
assert_eq!(remaining.len(), 0);
assert!(arp.is_eth_ipv4());
}
#[test]
fn test_arp_generic_parsing() {
let mut packet = vec![
0x00, 0x01, 0x08, 0x00, 0x08, 0x04, 0x00, 0x01, ];
packet.extend_from_slice(&[0xAA; 8]); packet.extend_from_slice(&[192, 168, 1, 2]); packet.extend_from_slice(&[0xBB; 8]); packet.extend_from_slice(&[192, 168, 1, 1]);
let (arp, remaining) = ArpHeader::from_bytes(&packet).unwrap();
assert_eq!(remaining.len(), 0);
assert_eq!(arp.hardware_len(), 8);
assert_eq!(arp.protocol_len(), 4);
assert_eq!(arp.operation(), ArpOperation::REQUEST);
assert!(!arp.is_eth_ipv4());
assert_eq!(arp.sender_hw_addr_raw().len(), 8);
assert_eq!(arp.sender_proto_addr_raw(), &[192, 168, 1, 2]);
assert_eq!(arp.target_hw_addr_raw().len(), 8);
assert_eq!(arp.target_proto_addr_raw(), &[192, 168, 1, 1]);
}
#[test]
fn test_arp_deref() {
let packet = vec![
0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
192, 168, 1, 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 192, 168, 1, 1,
];
let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
assert_eq!(arp.hardware_type(), ArpHardwareType::ETHERNET);
assert_eq!(arp.protocol_type(), ArpProtocolType::IPV4);
}
#[test]
fn test_arp_zerocopy_parsing() {
let packet = vec![
0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 10, 20, 30, 40, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 50, 60, 70, 80, ];
let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
assert_eq!(
arp.sender_hw_addr_raw(),
&[0x11, 0x22, 0x33, 0x44, 0x55, 0x66]
);
assert_eq!(arp.sender_proto_addr_raw(), &[10, 20, 30, 40]);
assert_eq!(
arp.target_hw_addr_raw(),
&[0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]
);
assert_eq!(arp.target_proto_addr_raw(), &[50, 60, 70, 80]);
assert!(arp.sender_hw_addr().is_some());
assert_eq!(
arp.sender_hw_addr().unwrap().to_string(),
"11:22:33:44:55:66"
);
assert!(arp.target_hw_addr().is_some());
assert_eq!(
arp.target_hw_addr().unwrap().to_string(),
"aa:bb:cc:dd:ee:ff"
);
assert_eq!(arp.sender_proto_addr().unwrap(), [10, 20, 30, 40]);
assert_eq!(arp.target_proto_addr().unwrap(), [50, 60, 70, 80]);
assert_eq!(arp.sender_ipv4().unwrap(), Ipv4Addr::new(10, 20, 30, 40));
assert_eq!(arp.target_ipv4().unwrap(), Ipv4Addr::new(50, 60, 70, 80));
}
#[test]
fn test_arp_non_eth_ipv4_returns_none() {
let mut packet = vec![
0x00, 0x01, 0x08, 0x00, 0x07, 0x04, 0x00, 0x01, ];
packet.extend_from_slice(&[0xAA; 7]); packet.extend_from_slice(&[192, 168, 1, 2]); packet.extend_from_slice(&[0xBB; 7]); packet.extend_from_slice(&[192, 168, 1, 1]);
let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
assert!(!arp.is_eth_ipv4());
assert!(arp.sender_hw_addr().is_none());
assert!(arp.target_hw_addr().is_none());
assert!(arp.sender_proto_addr().is_none());
assert!(arp.target_proto_addr().is_none());
assert!(arp.sender_ipv4().is_none());
assert!(arp.target_ipv4().is_none());
assert_eq!(arp.sender_hw_addr_raw().len(), 7);
assert_eq!(arp.sender_proto_addr_raw(), &[192, 168, 1, 2]);
}
#[test]
fn test_arp_ipv4addr_parsing() {
let packet = vec![
0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
192, 168, 1, 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 192, 168, 1, 1,
];
let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
assert_eq!(
arp.sender_ipv4().unwrap(),
"192.168.1.2".parse::<Ipv4Addr>().unwrap()
);
assert_eq!(
arp.target_ipv4().unwrap(),
"192.168.1.1".parse::<Ipv4Addr>().unwrap()
);
let sender_ip = arp.sender_ipv4().unwrap();
assert_eq!(sender_ip.to_string(), "192.168.1.2");
let target_ip = arp.target_ipv4().unwrap();
assert_eq!(target_ip.to_string(), "192.168.1.1");
}
}