packet_strata/packet/
arp.rs

1//! ARP (Address Resolution Protocol) packet parsing
2//!
3//! This module implements parsing for ARP packets as defined in RFC 826.
4//! ARP is used to map network layer addresses (like IPv4) to link layer addresses (like MAC).
5//!
6//! # ARP Header Format (for Ethernet/IPv4)
7//!
8//! ```text
9//!  0                   1                   2                   3
10//!  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
11//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12//! |         Hardware Type         |         Protocol Type         |
13//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
14//! |  HW Addr Len  | Proto Addr Len|          Operation            |
15//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16//! |                    Sender Hardware Address                    |
17//! +                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18//! |                               |    Sender Protocol Address    |
19//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20//! |    Sender Protocol Address    |                               |
21//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
22//! |                    Target Hardware Address                    |
23//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24//! |                    Target Protocol Address                    |
25//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26//! ```
27//!
28//! # Key characteristics
29//!
30//! - Fixed header size: 8 bytes (before variable-length addresses)
31//! - For Ethernet/IPv4: 28 bytes total (6+4+6+4 for addresses)
32//! - Hardware Type: 1 for Ethernet
33//! - Protocol Type: 0x0800 for IPv4
34//! - Operation: 1 (Request), 2 (Reply)
35//!
36//! # Examples
37//!
38//! ```no_run
39//! use packet_strata::packet::arp::{ArpHeader, ArpOperation};
40//! use packet_strata::packet::HeaderParser;
41//! use std::net::Ipv4Addr;
42//!
43//! # fn main() {
44//! # let packet_bytes: Vec<u8> = vec![]; // ARP packet data
45//! let (arp_header, remaining) = ArpHeader::from_bytes(&packet_bytes).unwrap();
46//!
47//! // Check if it's a request or reply
48//! match arp_header.operation() {
49//!     ArpOperation::REQUEST => println!("ARP Request"),
50//!     ArpOperation::REPLY => println!("ARP Reply"),
51//!     _ => println!("Other ARP operation"),
52//! }
53//!
54//! // For Ethernet/IPv4 ARP, access IP addresses
55//! if let Some(sender_ip) = arp_header.sender_ipv4() {
56//!     println!("Sender IP: {}", sender_ip);
57//! }
58//! # }
59//! ```
60
61use core::fmt;
62use std::fmt::{Display, Formatter};
63use std::net::Ipv4Addr;
64use std::ops::Deref;
65use zerocopy::byteorder::{BigEndian, U16};
66use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
67
68use crate::packet::ether::EthAddr;
69use crate::packet::{HeaderParser, PacketHeader};
70
71/// ARP Hardware Type
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, FromBytes, IntoBytes, Immutable, KnownLayout)]
73#[repr(transparent)]
74pub struct ArpHardwareType(pub U16<BigEndian>);
75
76impl ArpHardwareType {
77    pub const ETHERNET: ArpHardwareType = ArpHardwareType(U16::new(1)); // Ethernet (10Mb)
78    pub const EXPERIMENTAL_ETHERNET: ArpHardwareType = ArpHardwareType(U16::new(2)); // Experimental Ethernet (3Mb)
79    pub const AX25: ArpHardwareType = ArpHardwareType(U16::new(3)); // Amateur Radio AX.25
80    pub const PROTEON_TOKEN_RING: ArpHardwareType = ArpHardwareType(U16::new(4)); // Proteon ProNET Token Ring
81    pub const CHAOS: ArpHardwareType = ArpHardwareType(U16::new(5)); // Chaos
82    pub const IEEE802: ArpHardwareType = ArpHardwareType(U16::new(6)); // IEEE 802 Networks
83    pub const ARCNET: ArpHardwareType = ArpHardwareType(U16::new(7)); // ARCNET
84    pub const HYPERCHANNEL: ArpHardwareType = ArpHardwareType(U16::new(8)); // Hyperchannel
85    pub const LANSTAR: ArpHardwareType = ArpHardwareType(U16::new(9)); // Lanstar
86    pub const AUTONET: ArpHardwareType = ArpHardwareType(U16::new(10)); // Autonet Short Address
87    pub const LOCALTALK: ArpHardwareType = ArpHardwareType(U16::new(11)); // LocalTalk
88    pub const LOCALNET: ArpHardwareType = ArpHardwareType(U16::new(12)); // LocalNet (IBM PCNet or SYTEK LocalNET)
89    pub const ULTRA_LINK: ArpHardwareType = ArpHardwareType(U16::new(13)); // Ultra link
90    pub const SMDS: ArpHardwareType = ArpHardwareType(U16::new(14)); // SMDS
91    pub const FRAME_RELAY: ArpHardwareType = ArpHardwareType(U16::new(15)); // Frame Relay
92    pub const ATM: ArpHardwareType = ArpHardwareType(U16::new(16)); // Asynchronous Transmission Mode (ATM)
93    pub const HDLC: ArpHardwareType = ArpHardwareType(U16::new(17)); // HDLC
94    pub const FIBRE_CHANNEL: ArpHardwareType = ArpHardwareType(U16::new(18)); // Fibre Channel
95    pub const ATM_2: ArpHardwareType = ArpHardwareType(U16::new(19)); // Asynchronous Transmission Mode (ATM)
96    pub const SERIAL_LINE: ArpHardwareType = ArpHardwareType(U16::new(20)); // Serial Line
97
98    #[inline]
99    pub fn value(&self) -> u16 {
100        self.0.get()
101    }
102}
103
104impl Display for ArpHardwareType {
105    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
106        let name = match *self {
107            ArpHardwareType::ETHERNET => "ethernet",
108            ArpHardwareType::EXPERIMENTAL_ETHERNET => "exp-ethernet",
109            ArpHardwareType::AX25 => "ax25",
110            ArpHardwareType::PROTEON_TOKEN_RING => "token-ring",
111            ArpHardwareType::CHAOS => "chaos",
112            ArpHardwareType::IEEE802 => "ieee802",
113            ArpHardwareType::ARCNET => "arcnet",
114            ArpHardwareType::HYPERCHANNEL => "hyperchannel",
115            ArpHardwareType::LANSTAR => "lanstar",
116            ArpHardwareType::AUTONET => "autonet",
117            ArpHardwareType::LOCALTALK => "localtalk",
118            ArpHardwareType::LOCALNET => "localnet",
119            ArpHardwareType::ULTRA_LINK => "ultra-link",
120            ArpHardwareType::SMDS => "smds",
121            ArpHardwareType::FRAME_RELAY => "frame-relay",
122            ArpHardwareType::ATM => "atm",
123            ArpHardwareType::HDLC => "hdlc",
124            ArpHardwareType::FIBRE_CHANNEL => "fibre-channel",
125            ArpHardwareType::ATM_2 => "atm2",
126            ArpHardwareType::SERIAL_LINE => "serial-line",
127            _ => return write!(f, "unknown({})", self.value()),
128        };
129        write!(f, "{}", name)
130    }
131}
132
133/// ARP Protocol Type (typically matches EtherType for the protocol being resolved)
134#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, FromBytes, IntoBytes, Immutable, KnownLayout)]
135#[repr(transparent)]
136pub struct ArpProtocolType(pub U16<BigEndian>);
137
138impl ArpProtocolType {
139    pub const IPV4: ArpProtocolType = ArpProtocolType(U16::new(0x0800)); // IPv4
140
141    #[inline]
142    pub fn value(&self) -> u16 {
143        self.0.get()
144    }
145}
146
147impl Display for ArpProtocolType {
148    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
149        match *self {
150            ArpProtocolType::IPV4 => write!(f, "ipv4"),
151            _ => write!(f, "0x{:04x}", self.value()),
152        }
153    }
154}
155
156/// ARP Operation Code
157#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, FromBytes, IntoBytes, Immutable, KnownLayout)]
158#[repr(transparent)]
159pub struct ArpOperation(pub U16<BigEndian>);
160
161impl ArpOperation {
162    pub const REQUEST: ArpOperation = ArpOperation(U16::new(1)); // ARP request
163    pub const REPLY: ArpOperation = ArpOperation(U16::new(2)); // ARP reply
164    pub const RARP_REQUEST: ArpOperation = ArpOperation(U16::new(3)); // RARP request
165    pub const RARP_REPLY: ArpOperation = ArpOperation(U16::new(4)); // RARP reply
166    pub const DRARP_REQUEST: ArpOperation = ArpOperation(U16::new(5)); // DRARP request
167    pub const DRARP_REPLY: ArpOperation = ArpOperation(U16::new(6)); // DRARP reply
168    pub const DRARP_ERROR: ArpOperation = ArpOperation(U16::new(7)); // DRARP error
169    pub const INARP_REQUEST: ArpOperation = ArpOperation(U16::new(8)); // InARP request
170    pub const INARP_REPLY: ArpOperation = ArpOperation(U16::new(9)); // InARP reply
171    pub const ARP_NAK: ArpOperation = ArpOperation(U16::new(10)); // ARP NAK
172
173    #[inline]
174    pub fn value(&self) -> u16 {
175        self.0.get()
176    }
177}
178
179impl Display for ArpOperation {
180    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
181        let name = match *self {
182            ArpOperation::REQUEST => "request",
183            ArpOperation::REPLY => "reply",
184            ArpOperation::RARP_REQUEST => "rarp-request",
185            ArpOperation::RARP_REPLY => "rarp-reply",
186            ArpOperation::DRARP_REQUEST => "drarp-request",
187            ArpOperation::DRARP_REPLY => "drarp-reply",
188            ArpOperation::DRARP_ERROR => "drarp-error",
189            ArpOperation::INARP_REQUEST => "inarp-request",
190            ArpOperation::INARP_REPLY => "inarp-reply",
191            ArpOperation::ARP_NAK => "arp-nak",
192            _ => return write!(f, "unknown({})", self.value()),
193        };
194        write!(f, "{}", name)
195    }
196}
197
198/// ARP Header structure (RFC 826) - Fixed portion
199///
200/// This represents the fixed portion of an ARP packet. The actual hardware and
201/// protocol addresses follow this header and have variable lengths specified by
202/// `hlen` and `plen` fields.
203#[repr(C, packed)]
204#[derive(FromBytes, IntoBytes, Unaligned, Immutable, KnownLayout, Debug, Clone, Copy)]
205pub struct ArpHeader {
206    htype: ArpHardwareType, // Hardware type
207    ptype: ArpProtocolType, // Protocol type
208    hlen: u8,               // Hardware address length
209    plen: u8,               // Protocol address length
210    oper: ArpOperation,     // Operation code
211}
212
213impl ArpHeader {
214    /// Returns the hardware type
215    #[inline]
216    pub fn hardware_type(&self) -> ArpHardwareType {
217        self.htype
218    }
219
220    /// Returns the protocol type
221    #[inline]
222    pub fn protocol_type(&self) -> ArpProtocolType {
223        self.ptype
224    }
225
226    /// Returns the hardware address length in bytes
227    #[inline]
228    pub fn hardware_len(&self) -> u8 {
229        self.hlen
230    }
231
232    /// Returns the protocol address length in bytes
233    #[inline]
234    pub fn protocol_len(&self) -> u8 {
235        self.plen
236    }
237
238    /// Returns the ARP operation
239    #[inline]
240    pub fn operation(&self) -> ArpOperation {
241        self.oper
242    }
243
244    /// Returns the total size of addresses in the ARP packet
245    #[inline]
246    fn addresses_len(&self) -> usize {
247        // sender hw + sender proto + target hw + target proto
248        2 * (self.hlen as usize + self.plen as usize)
249    }
250
251    /// Validates the ARP header
252    #[inline]
253    fn is_valid(&self) -> bool {
254        // Most common case: Ethernet (hlen=6) and IPv4 (plen=4)
255        // But we accept other valid combinations
256        self.hlen > 0 && self.plen > 0
257    }
258
259    /// Check if this is Ethernet/IPv4 ARP
260    #[inline]
261    pub fn is_eth_ipv4(&self) -> bool {
262        self.htype == ArpHardwareType::ETHERNET
263            && self.ptype == ArpProtocolType::IPV4
264            && self.hlen == 6
265            && self.plen == 4
266    }
267}
268
269impl PacketHeader for ArpHeader {
270    const NAME: &'static str = "ArpHeader";
271    type InnerType = ();
272
273    #[inline]
274    fn inner_type(&self) -> Self::InnerType {}
275
276    #[inline]
277    fn total_len(&self, _buf: &[u8]) -> usize {
278        Self::FIXED_LEN + self.addresses_len()
279    }
280
281    #[inline]
282    fn is_valid(&self) -> bool {
283        self.is_valid()
284    }
285}
286
287impl HeaderParser for ArpHeader {
288    type Output<'a> = ArpHeaderFull<'a>;
289
290    #[inline]
291    fn into_view<'a>(header: &'a Self, addresses: &'a [u8]) -> Self::Output<'a> {
292        ArpHeaderFull { header, addresses }
293    }
294}
295
296/// ARP Header with addresses
297///
298/// This is the proxy object returned by the parser. It provides access to both
299/// the fixed header and the variable-length address fields.
300#[derive(Debug, Clone)]
301pub struct ArpHeaderFull<'a> {
302    pub header: &'a ArpHeader,
303    pub addresses: &'a [u8],
304}
305
306impl<'a> ArpHeaderFull<'a> {
307    /// Returns the hardware type
308    #[inline]
309    pub fn hardware_type(&self) -> ArpHardwareType {
310        self.header.hardware_type()
311    }
312
313    /// Returns the protocol type
314    #[inline]
315    pub fn protocol_type(&self) -> ArpProtocolType {
316        self.header.protocol_type()
317    }
318
319    /// Returns the hardware address length
320    #[inline]
321    pub fn hardware_len(&self) -> u8 {
322        self.header.hardware_len()
323    }
324
325    /// Returns the protocol address length
326    #[inline]
327    pub fn protocol_len(&self) -> u8 {
328        self.header.protocol_len()
329    }
330
331    /// Returns the ARP operation
332    #[inline]
333    pub fn operation(&self) -> ArpOperation {
334        self.header.operation()
335    }
336
337    /// Check if this is Ethernet/IPv4 ARP
338    #[inline]
339    pub fn is_eth_ipv4(&self) -> bool {
340        self.header.is_eth_ipv4()
341    }
342
343    /// Get sender hardware address (raw bytes)
344    #[inline]
345    pub fn sender_hw_addr_raw(&self) -> &[u8] {
346        let hlen = self.hardware_len() as usize;
347        &self.addresses[0..hlen]
348    }
349
350    /// Get sender protocol address (raw bytes)
351    #[inline]
352    pub fn sender_proto_addr_raw(&self) -> &[u8] {
353        let hlen = self.hardware_len() as usize;
354        let plen = self.protocol_len() as usize;
355        &self.addresses[hlen..hlen + plen]
356    }
357
358    /// Get target hardware address (raw bytes)
359    #[inline]
360    pub fn target_hw_addr_raw(&self) -> &[u8] {
361        let hlen = self.hardware_len() as usize;
362        let plen = self.protocol_len() as usize;
363        &self.addresses[hlen + plen..hlen + plen + hlen]
364    }
365
366    /// Get target protocol address (raw bytes)
367    #[inline]
368    pub fn target_proto_addr_raw(&self) -> &[u8] {
369        let hlen = self.hardware_len() as usize;
370        let plen = self.protocol_len() as usize;
371        &self.addresses[hlen + plen + hlen..]
372    }
373
374    /// For Ethernet/IPv4 ARP, get sender MAC address
375    #[inline]
376    pub fn sender_hw_addr(&self) -> Option<&EthAddr> {
377        if self.is_eth_ipv4() {
378            zerocopy::Ref::<_, EthAddr>::from_prefix(self.sender_hw_addr_raw())
379                .ok()
380                .map(|(r, _)| zerocopy::Ref::into_ref(r))
381        } else {
382            None
383        }
384    }
385
386    /// For Ethernet/IPv4 ARP, get sender IPv4 address as bytes
387    #[inline]
388    pub fn sender_proto_addr(&self) -> Option<[u8; 4]> {
389        if self.is_eth_ipv4() {
390            self.sender_proto_addr_raw().try_into().ok()
391        } else {
392            None
393        }
394    }
395
396    /// For Ethernet/IPv4 ARP, get sender IPv4 address
397    #[inline]
398    pub fn sender_ipv4(&self) -> Option<Ipv4Addr> {
399        self.sender_proto_addr().map(Ipv4Addr::from)
400    }
401
402    /// For Ethernet/IPv4 ARP, get target MAC address
403    #[inline]
404    pub fn target_hw_addr(&self) -> Option<&EthAddr> {
405        if self.is_eth_ipv4() {
406            zerocopy::Ref::<_, EthAddr>::from_prefix(self.target_hw_addr_raw())
407                .ok()
408                .map(|(r, _)| zerocopy::Ref::into_ref(r))
409        } else {
410            None
411        }
412    }
413
414    /// For Ethernet/IPv4 ARP, get target IPv4 address as bytes
415    #[inline]
416    pub fn target_proto_addr(&self) -> Option<[u8; 4]> {
417        if self.is_eth_ipv4() {
418            self.target_proto_addr_raw().try_into().ok()
419        } else {
420            None
421        }
422    }
423
424    /// For Ethernet/IPv4 ARP, get target IPv4 address
425    #[inline]
426    pub fn target_ipv4(&self) -> Option<Ipv4Addr> {
427        self.target_proto_addr().map(Ipv4Addr::from)
428    }
429}
430
431impl Deref for ArpHeaderFull<'_> {
432    type Target = ArpHeader;
433
434    #[inline]
435    fn deref(&self) -> &Self::Target {
436        self.header
437    }
438}
439
440impl Display for ArpHeaderFull<'_> {
441    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
442        if self.is_eth_ipv4() {
443            // Format for Ethernet/IPv4
444            if let (Some(sha), Some(spa), Some(tha), Some(tpa)) = (
445                self.sender_hw_addr(),
446                self.sender_ipv4(),
447                self.target_hw_addr(),
448                self.target_ipv4(),
449            ) {
450                write!(
451                    f,
452                    "ARP {} {} -> {} ({}): {} -> {}",
453                    self.operation(),
454                    sha,
455                    tha,
456                    if self.operation() == ArpOperation::REQUEST {
457                        "who-has"
458                    } else {
459                        "is-at"
460                    },
461                    spa,
462                    tpa
463                )
464            } else {
465                write!(f, "ARP {} (invalid)", self.operation())
466            }
467        } else {
468            // Generic format
469            write!(
470                f,
471                "ARP {} htype={} ptype={} hlen={} plen={}",
472                self.operation(),
473                self.hardware_type(),
474                self.protocol_type(),
475                self.hardware_len(),
476                self.protocol_len()
477            )
478        }
479    }
480}
481
482#[cfg(test)]
483mod tests {
484    use super::*;
485    use std::str::FromStr;
486
487    #[test]
488    fn test_arp_request_eth_ipv4() {
489        // ARP request: Who has 192.168.1.1? Tell 192.168.1.2
490        let packet = vec![
491            0x00, 0x01, // Hardware type: Ethernet (1)
492            0x08, 0x00, // Protocol type: IPv4 (0x0800)
493            0x06, // Hardware size: 6
494            0x04, // Protocol size: 4
495            0x00, 0x01, // Opcode: request (1)
496            0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, // Sender MAC address
497            192, 168, 1, 2, // Sender IP address
498            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Target MAC address (unknown)
499            192, 168, 1, 1, // Target IP address
500        ];
501
502        let (arp, remaining) = ArpHeader::from_bytes(&packet).expect("Failed to parse ARP");
503
504        assert_eq!(remaining.len(), 0);
505        assert_eq!(arp.hardware_type(), ArpHardwareType::ETHERNET);
506        assert_eq!(arp.protocol_type(), ArpProtocolType::IPV4);
507        assert_eq!(arp.hardware_len(), 6);
508        assert_eq!(arp.protocol_len(), 4);
509        assert_eq!(arp.operation(), ArpOperation::REQUEST);
510        assert!(arp.is_eth_ipv4());
511
512        // Check Ethernet/IPv4 specific accessors
513        assert_eq!(
514            arp.sender_hw_addr().unwrap().to_string(),
515            "aa:bb:cc:dd:ee:ff"
516        );
517        assert_eq!(arp.sender_proto_addr().unwrap(), [192, 168, 1, 2]);
518        assert_eq!(arp.sender_ipv4().unwrap(), Ipv4Addr::new(192, 168, 1, 2));
519
520        assert_eq!(
521            arp.target_hw_addr().unwrap().to_string(),
522            "00:00:00:00:00:00"
523        );
524        assert_eq!(arp.target_proto_addr().unwrap(), [192, 168, 1, 1]);
525        assert_eq!(arp.target_ipv4().unwrap(), Ipv4Addr::new(192, 168, 1, 1));
526    }
527
528    #[test]
529    fn test_arp_reply_eth_ipv4() {
530        // ARP reply: 192.168.1.1 is at 11:22:33:44:55:66
531        let packet = vec![
532            0x00, 0x01, // Hardware type: Ethernet (1)
533            0x08, 0x00, // Protocol type: IPv4 (0x0800)
534            0x06, // Hardware size: 6
535            0x04, // Protocol size: 4
536            0x00, 0x02, // Opcode: reply (2)
537            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, // Sender MAC address
538            192, 168, 1, 1, // Sender IP address
539            0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, // Target MAC address
540            192, 168, 1, 2, // Target IP address
541        ];
542
543        let (arp, remaining) = ArpHeader::from_bytes(&packet).expect("Failed to parse ARP reply");
544
545        assert_eq!(remaining.len(), 0);
546        assert_eq!(arp.operation(), ArpOperation::REPLY);
547        assert!(arp.is_eth_ipv4());
548
549        assert_eq!(
550            arp.sender_hw_addr().unwrap().to_string(),
551            "11:22:33:44:55:66"
552        );
553        assert_eq!(arp.sender_proto_addr().unwrap(), [192, 168, 1, 1]);
554    }
555
556    #[test]
557    fn test_arp_packet_too_short() {
558        let short_packet = vec![0x00, 0x01, 0x08, 0x00]; // Only 4 bytes
559
560        let result = ArpHeader::from_bytes(&short_packet);
561        assert!(result.is_err());
562    }
563
564    #[test]
565    fn test_arp_invalid_lengths() {
566        // Invalid hardware/protocol lengths (both zero)
567        let packet = vec![
568            0x00, 0x01, // Hardware type: Ethernet
569            0x08, 0x00, // Protocol type: IPv4
570            0x00, // Hardware size: 0 (invalid)
571            0x00, // Protocol size: 0 (invalid)
572            0x00, 0x01, // Opcode: request
573        ];
574
575        let result = ArpHeader::from_bytes(&packet);
576        assert!(result.is_err());
577    }
578
579    #[test]
580    fn test_arp_display() {
581        let packet = vec![
582            0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
583            192, 168, 1, 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 192, 168, 1, 1,
584        ];
585
586        let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
587        let display_str = format!("{}", arp);
588
589        assert!(display_str.contains("request"));
590        assert!(display_str.contains("aa:bb:cc:dd:ee:ff"));
591    }
592
593    #[test]
594    fn test_arp_operation_display() {
595        assert_eq!(format!("{}", ArpOperation::REQUEST), "request");
596        assert_eq!(format!("{}", ArpOperation::REPLY), "reply");
597        assert_eq!(format!("{}", ArpOperation::RARP_REQUEST), "rarp-request");
598        assert_eq!(format!("{}", ArpOperation::RARP_REPLY), "rarp-reply");
599        assert_eq!(format!("{}", ArpOperation::ARP_NAK), "arp-nak");
600    }
601
602    #[test]
603    fn test_arp_hardware_type_display() {
604        assert_eq!(format!("{}", ArpHardwareType::ETHERNET), "ethernet");
605        assert_eq!(format!("{}", ArpHardwareType::IEEE802), "ieee802");
606        assert_eq!(format!("{}", ArpHardwareType::FRAME_RELAY), "frame-relay");
607        assert_eq!(
608            format!("{}", ArpHardwareType(U16::new(9999))),
609            "unknown(9999)"
610        );
611    }
612
613    #[test]
614    fn test_arp_protocol_type_display() {
615        assert_eq!(format!("{}", ArpProtocolType::IPV4), "ipv4");
616        assert_eq!(format!("{}", ArpProtocolType(U16::new(0x1234))), "0x1234");
617    }
618
619    #[test]
620    fn test_arp_with_payload() {
621        let mut packet = vec![
622            0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
623            192, 168, 1, 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 192, 168, 1, 1,
624        ];
625
626        // Add some extra payload bytes (padding or other data)
627        packet.extend_from_slice(b"extra data");
628
629        let (arp, remaining) = ArpHeader::from_bytes(&packet).unwrap();
630
631        assert_eq!(arp.operation(), ArpOperation::REQUEST);
632        assert_eq!(remaining, b"extra data");
633    }
634
635    #[test]
636    fn test_arp_rarp_request() {
637        let packet = vec![
638            0x00, 0x01, // Hardware type: Ethernet
639            0x08, 0x00, // Protocol type: IPv4
640            0x06, // Hardware size: 6
641            0x04, // Protocol size: 4
642            0x00, 0x03, // Opcode: RARP request (3)
643            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, // Sender MAC
644            0, 0, 0, 0, // Sender IP (unknown)
645            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // Target MAC (broadcast)
646            0, 0, 0, 0, // Target IP (unknown)
647        ];
648
649        let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
650        assert_eq!(arp.operation(), ArpOperation::RARP_REQUEST);
651    }
652
653    #[test]
654    fn test_arp_gratuitous() {
655        // Gratuitous ARP: sender IP == target IP
656        let packet = vec![
657            0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
658            192, 168, 1, 100, // Sender IP
659            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // Target MAC (broadcast)
660            192, 168, 1, 100, // Target IP (same as sender)
661        ];
662
663        let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
664
665        // In gratuitous ARP, sender and target IPs are the same
666        assert_eq!(arp.sender_ipv4().unwrap(), Ipv4Addr::new(192, 168, 1, 100));
667        assert_eq!(arp.sender_ipv4().unwrap(), arp.target_ipv4().unwrap());
668        assert_eq!(arp.operation(), ArpOperation::REQUEST);
669    }
670
671    #[test]
672    fn test_arp_probe() {
673        // ARP Probe: sender IP is 0.0.0.0
674        let packet = vec![
675            0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0,
676            0, 0, 0, // Sender IP (0.0.0.0 in probe)
677            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Target MAC (unknown)
678            192, 168, 1, 100, // Target IP (IP being probed)
679        ];
680
681        let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
682
683        assert_eq!(arp.sender_ipv4().unwrap(), Ipv4Addr::new(0, 0, 0, 0));
684        assert_eq!(arp.target_ipv4().unwrap(), Ipv4Addr::new(192, 168, 1, 100));
685    }
686
687    #[test]
688    fn test_arp_real_world_request() {
689        // Real-world ARP request captured from network
690        // Who has 10.0.0.1? Tell 10.0.0.2
691        let packet = vec![
692            0x00, 0x01, // Ethernet
693            0x08, 0x00, // IPv4
694            0x06, 0x04, // hlen=6, plen=4
695            0x00, 0x01, // Request
696            0x08, 0x00, 0x27, 0x12, 0x34, 0x56, // Sender MAC
697            10, 0, 0, 2, // Sender IP: 10.0.0.2
698            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Target MAC: unknown
699            10, 0, 0, 1, // Target IP: 10.0.0.1
700        ];
701
702        let (arp, remaining) = ArpHeader::from_bytes(&packet).unwrap();
703
704        assert_eq!(remaining.len(), 0);
705        assert_eq!(arp.sender_ipv4().unwrap(), Ipv4Addr::new(10, 0, 0, 2));
706        assert_eq!(arp.target_ipv4().unwrap(), Ipv4Addr::new(10, 0, 0, 1));
707        assert_eq!(
708            arp.sender_hw_addr().unwrap(),
709            &EthAddr::from_str("08:00:27:12:34:56").unwrap()
710        );
711    }
712
713    #[test]
714    fn test_arp_real_world_reply() {
715        // Real-world ARP reply
716        // 10.0.0.1 is at 52:54:00:12:34:56
717        let packet = vec![
718            0x00, 0x01, // Ethernet
719            0x08, 0x00, // IPv4
720            0x06, 0x04, // hlen=6, plen=4
721            0x00, 0x02, // Reply
722            0x52, 0x54, 0x00, 0x12, 0x34, 0x56, // Sender MAC: 52:54:00:12:34:56
723            10, 0, 0, 1, // Sender IP: 10.0.0.1
724            0x08, 0x00, 0x27, 0x12, 0x34, 0x56, // Target MAC
725            10, 0, 0, 2, // Target IP: 10.0.0.2
726        ];
727
728        let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
729
730        assert_eq!(arp.operation(), ArpOperation::REPLY);
731        assert_eq!(
732            arp.sender_hw_addr().unwrap(),
733            &EthAddr::from_str("52:54:00:12:34:56").unwrap()
734        );
735        assert_eq!(arp.sender_ipv4().unwrap(), Ipv4Addr::new(10, 0, 0, 1));
736    }
737
738    #[test]
739    fn test_arp_from_bytes_multiple_packets() {
740        // Test parsing multiple different ARP packets
741        let test_cases = vec![
742            (
743                vec![
744                    0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
745                    0xff, 192, 168, 1, 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 192, 168, 1, 1,
746                ],
747                ArpOperation::REQUEST,
748            ),
749            (
750                vec![
751                    0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x11, 0x22, 0x33, 0x44, 0x55,
752                    0x66, 192, 168, 1, 1, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 192, 168, 1, 2,
753                ],
754                ArpOperation::REPLY,
755            ),
756        ];
757
758        for (packet, expected_op) in test_cases {
759            let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
760            assert_eq!(arp.operation(), expected_op);
761            assert!(arp.is_eth_ipv4());
762        }
763    }
764
765    #[test]
766    fn test_arp_size_constants() {
767        assert_eq!(
768            std::mem::size_of::<ArpHeader>(),
769            8,
770            "ARP fixed header should be 8 bytes"
771        );
772        assert_eq!(ArpHeader::FIXED_LEN, 8);
773    }
774
775    #[test]
776    fn test_arp_packet_boundary_conditions() {
777        // Test exact size packet
778        let packet = vec![
779            0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
780            192, 168, 1, 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 192, 168, 1, 1,
781        ];
782
783        assert_eq!(packet.len(), 28);
784        let (arp, remaining) = ArpHeader::from_bytes(&packet).unwrap();
785        assert_eq!(remaining.len(), 0);
786        assert!(arp.is_eth_ipv4());
787    }
788
789    #[test]
790    fn test_arp_generic_parsing() {
791        // Test with non-standard hardware/protocol lengths
792        let mut packet = vec![
793            0x00, 0x01, // Hardware type: Ethernet
794            0x08, 0x00, // Protocol type: IPv4
795            0x08, // Hardware size: 8 (non-standard, not 6)
796            0x04, // Protocol size: 4
797            0x00, 0x01, // Opcode: request
798        ];
799
800        // Add sender hw (8 bytes), sender proto (4 bytes), target hw (8 bytes), target proto (4 bytes)
801        packet.extend_from_slice(&[0xAA; 8]); // sender hw
802        packet.extend_from_slice(&[192, 168, 1, 2]); // sender proto
803        packet.extend_from_slice(&[0xBB; 8]); // target hw
804        packet.extend_from_slice(&[192, 168, 1, 1]); // target proto
805
806        let (arp, remaining) = ArpHeader::from_bytes(&packet).unwrap();
807
808        assert_eq!(remaining.len(), 0);
809        assert_eq!(arp.hardware_len(), 8);
810        assert_eq!(arp.protocol_len(), 4);
811        assert_eq!(arp.operation(), ArpOperation::REQUEST);
812
813        // This should NOT be eth_ipv4 because hlen is 8, not 6
814        assert!(!arp.is_eth_ipv4());
815
816        // Check raw address accessors
817        assert_eq!(arp.sender_hw_addr_raw().len(), 8);
818        assert_eq!(arp.sender_proto_addr_raw(), &[192, 168, 1, 2]);
819        assert_eq!(arp.target_hw_addr_raw().len(), 8);
820        assert_eq!(arp.target_proto_addr_raw(), &[192, 168, 1, 1]);
821    }
822
823    #[test]
824    fn test_arp_deref() {
825        let packet = vec![
826            0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
827            192, 168, 1, 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 192, 168, 1, 1,
828        ];
829
830        let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
831
832        // Test that Deref works
833        assert_eq!(arp.hardware_type(), ArpHardwareType::ETHERNET);
834        assert_eq!(arp.protocol_type(), ArpProtocolType::IPV4);
835    }
836
837    #[test]
838    fn test_arp_zerocopy_parsing() {
839        // Test that zerocopy parsing works correctly for addresses
840        let packet = vec![
841            0x00, 0x01, // Hardware type: Ethernet
842            0x08, 0x00, // Protocol type: IPv4
843            0x06, 0x04, // hlen=6, plen=4
844            0x00, 0x01, // Request
845            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, // Sender MAC
846            10, 20, 30, 40, // Sender IP
847            0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, // Target MAC
848            50, 60, 70, 80, // Target IP
849        ];
850
851        let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
852
853        // Test raw address accessors
854        assert_eq!(
855            arp.sender_hw_addr_raw(),
856            &[0x11, 0x22, 0x33, 0x44, 0x55, 0x66]
857        );
858        assert_eq!(arp.sender_proto_addr_raw(), &[10, 20, 30, 40]);
859        assert_eq!(
860            arp.target_hw_addr_raw(),
861            &[0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]
862        );
863        assert_eq!(arp.target_proto_addr_raw(), &[50, 60, 70, 80]);
864
865        // Test typed accessors using zerocopy
866        assert!(arp.sender_hw_addr().is_some());
867        assert_eq!(
868            arp.sender_hw_addr().unwrap().to_string(),
869            "11:22:33:44:55:66"
870        );
871
872        assert!(arp.target_hw_addr().is_some());
873        assert_eq!(
874            arp.target_hw_addr().unwrap().to_string(),
875            "aa:bb:cc:dd:ee:ff"
876        );
877
878        // Test IPv4 address parsing
879        assert_eq!(arp.sender_proto_addr().unwrap(), [10, 20, 30, 40]);
880        assert_eq!(arp.target_proto_addr().unwrap(), [50, 60, 70, 80]);
881
882        // Test IPv4 as Ipv4Addr
883        assert_eq!(arp.sender_ipv4().unwrap(), Ipv4Addr::new(10, 20, 30, 40));
884        assert_eq!(arp.target_ipv4().unwrap(), Ipv4Addr::new(50, 60, 70, 80));
885    }
886
887    #[test]
888    fn test_arp_non_eth_ipv4_returns_none() {
889        // Test with non-standard hardware length (7 instead of 6)
890        let mut packet = vec![
891            0x00, 0x01, // Hardware type: Ethernet
892            0x08, 0x00, // Protocol type: IPv4
893            0x07, // Hardware size: 7 (non-standard!)
894            0x04, // Protocol size: 4
895            0x00, 0x01, // Opcode: request
896        ];
897
898        // Add addresses: sender hw (7), sender proto (4), target hw (7), target proto (4)
899        packet.extend_from_slice(&[0xAA; 7]); // sender hw
900        packet.extend_from_slice(&[192, 168, 1, 2]); // sender proto
901        packet.extend_from_slice(&[0xBB; 7]); // target hw
902        packet.extend_from_slice(&[192, 168, 1, 1]); // target proto
903
904        let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
905
906        // Should NOT be recognized as eth_ipv4 due to hlen=7
907        assert!(!arp.is_eth_ipv4());
908
909        // Typed accessors should return None
910        assert!(arp.sender_hw_addr().is_none());
911        assert!(arp.target_hw_addr().is_none());
912        assert!(arp.sender_proto_addr().is_none());
913        assert!(arp.target_proto_addr().is_none());
914        assert!(arp.sender_ipv4().is_none());
915        assert!(arp.target_ipv4().is_none());
916
917        // But raw accessors should still work
918        assert_eq!(arp.sender_hw_addr_raw().len(), 7);
919        assert_eq!(arp.sender_proto_addr_raw(), &[192, 168, 1, 2]);
920    }
921
922    #[test]
923    fn test_arp_ipv4addr_parsing() {
924        // Test using Ipv4Addr::parse like IPv4 module does
925        let packet = vec![
926            0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
927            192, 168, 1, 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 192, 168, 1, 1,
928        ];
929
930        let (arp, _) = ArpHeader::from_bytes(&packet).unwrap();
931
932        // Test using parse
933        assert_eq!(
934            arp.sender_ipv4().unwrap(),
935            "192.168.1.2".parse::<Ipv4Addr>().unwrap()
936        );
937        assert_eq!(
938            arp.target_ipv4().unwrap(),
939            "192.168.1.1".parse::<Ipv4Addr>().unwrap()
940        );
941
942        // Test Display implementation works
943        let sender_ip = arp.sender_ipv4().unwrap();
944        assert_eq!(sender_ip.to_string(), "192.168.1.2");
945
946        let target_ip = arp.target_ipv4().unwrap();
947        assert_eq!(target_ip.to_string(), "192.168.1.1");
948    }
949}