Skip to main content

stackforge_core/layer/
arp.rs

1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
2
3use crate::layer::field::{Field, FieldDesc, FieldError, FieldType, FieldValue, MacAddress};
4use crate::layer::{Layer, LayerIndex, LayerKind};
5
6pub const ARP_HEADER_LEN: usize = 28;
7pub const ARP_FIXED_HEADER_LEN: usize = 8;
8
9/// Hardware types (RFC 826, IANA assignments).
10pub mod hardware_type {
11    pub const ETHERNET: u16 = 1;
12    pub const EXPERIMENTAL_ETHERNET: u16 = 2;
13    pub const AX25: u16 = 3;
14    pub const PRONET_TOKEN_RING: u16 = 4;
15    pub const CHAOS: u16 = 5;
16    pub const IEEE802: u16 = 6;
17    pub const ARCNET: u16 = 7;
18    pub const HYPERCHANNEL: u16 = 8;
19    pub const LANSTAR: u16 = 9;
20    pub const AUTONET: u16 = 10;
21    pub const LOCALTALK: u16 = 11;
22    pub const LOCALNET: u16 = 12;
23    pub const ULTRA_LINK: u16 = 13;
24    pub const SMDS: u16 = 14;
25    pub const FRAME_RELAY: u16 = 15;
26    pub const ATM: u16 = 16;
27    pub const HDLC: u16 = 17;
28    pub const FIBRE_CHANNEL: u16 = 18;
29    pub const ATM_2: u16 = 19;
30    pub const SERIAL_LINE: u16 = 20;
31    pub const ATM_3: u16 = 21;
32
33    pub fn name(t: u16) -> &'static str {
34        match t {
35            ETHERNET => "Ethernet (10Mb)",
36            EXPERIMENTAL_ETHERNET => "Experimental Ethernet (3Mb)",
37            AX25 => "AX.25",
38            PRONET_TOKEN_RING => "Proteon ProNET Token Ring",
39            CHAOS => "Chaos",
40            IEEE802 => "IEEE 802 Networks",
41            ARCNET => "ARCNET",
42            HYPERCHANNEL => "Hyperchannel",
43            LANSTAR => "Lanstar",
44            AUTONET => "Autonet Short Address",
45            LOCALTALK => "LocalTalk",
46            LOCALNET => "LocalNet",
47            ULTRA_LINK => "Ultra link",
48            SMDS => "SMDS",
49            FRAME_RELAY => "Frame relay",
50            ATM | ATM_2 | ATM_3 => "ATM",
51            HDLC => "HDLC",
52            FIBRE_CHANNEL => "Fibre Channel",
53            SERIAL_LINE => "Serial Line",
54            _ => "Unknown",
55        }
56    }
57
58    #[inline]
59    pub const fn is_ethernet_like(t: u16) -> bool {
60        matches!(t, ETHERNET | EXPERIMENTAL_ETHERNET | IEEE802)
61    }
62}
63
64/// Protocol types (EtherType values).
65pub mod protocol_type {
66    pub const IPV4: u16 = 0x0800;
67    pub const IPV6: u16 = 0x86DD;
68    pub const ARP: u16 = 0x0806;
69
70    #[inline]
71    pub const fn is_ipv4(t: u16) -> bool {
72        t == IPV4
73    }
74    #[inline]
75    pub const fn is_ipv6(t: u16) -> bool {
76        t == IPV6
77    }
78}
79
80/// ARP operation codes.
81pub mod opcode {
82    pub const REQUEST: u16 = 1;
83    pub const REPLY: u16 = 2;
84    pub const RARP_REQUEST: u16 = 3;
85    pub const RARP_REPLY: u16 = 4;
86    pub const DRARP_REQUEST: u16 = 5;
87    pub const DRARP_REPLY: u16 = 6;
88    pub const DRARP_ERROR: u16 = 7;
89    pub const INARP_REQUEST: u16 = 8;
90    pub const INARP_REPLY: u16 = 9;
91
92    pub fn name(op: u16) -> &'static str {
93        match op {
94            REQUEST => "who-has",
95            REPLY => "is-at",
96            RARP_REQUEST => "RARP-req",
97            RARP_REPLY => "RARP-rep",
98            DRARP_REQUEST => "Dyn-RARP-req",
99            DRARP_REPLY => "Dyn-RARP-rep",
100            DRARP_ERROR => "Dyn-RARP-err",
101            INARP_REQUEST => "InARP-req",
102            INARP_REPLY => "InARP-rep",
103            _ => "unknown",
104        }
105    }
106
107    pub fn from_name(name: &str) -> Option<u16> {
108        match name.to_lowercase().as_str() {
109            "who-has" | "request" | "1" => Some(REQUEST),
110            "is-at" | "reply" | "2" => Some(REPLY),
111            "rarp-req" | "3" => Some(RARP_REQUEST),
112            "rarp-rep" | "4" => Some(RARP_REPLY),
113            "dyn-rarp-req" | "5" => Some(DRARP_REQUEST),
114            "dyn-rarp-rep" | "6" => Some(DRARP_REPLY),
115            "dyn-rarp-err" | "7" => Some(DRARP_ERROR),
116            "inarp-req" | "8" => Some(INARP_REQUEST),
117            "inarp-rep" | "9" => Some(INARP_REPLY),
118            _ => None,
119        }
120    }
121
122    #[inline]
123    pub const fn is_request(op: u16) -> bool {
124        op % 2 == 1
125    }
126    #[inline]
127    pub const fn is_reply(op: u16) -> bool {
128        op % 2 == 0 && op > 0
129    }
130    #[inline]
131    pub const fn reply_for(request_op: u16) -> u16 {
132        request_op + 1
133    }
134}
135
136/// Field offsets within ARP fixed header.
137pub mod offsets {
138    pub const HWTYPE: usize = 0;
139    pub const PTYPE: usize = 2;
140    pub const HWLEN: usize = 4;
141    pub const PLEN: usize = 5;
142    pub const OP: usize = 6;
143    pub const VAR_START: usize = 8;
144}
145
146pub static FIXED_FIELDS: &[FieldDesc] = &[
147    FieldDesc::new("hwtype", offsets::HWTYPE, 2, FieldType::U16),
148    FieldDesc::new("ptype", offsets::PTYPE, 2, FieldType::U16),
149    FieldDesc::new("hwlen", offsets::HWLEN, 1, FieldType::U8),
150    FieldDesc::new("plen", offsets::PLEN, 1, FieldType::U8),
151    FieldDesc::new("op", offsets::OP, 2, FieldType::U16),
152];
153
154/// Hardware address (variable length).
155#[derive(Debug, Clone, PartialEq, Eq)]
156pub enum HardwareAddr {
157    Mac(MacAddress),
158    Raw(Vec<u8>),
159}
160
161impl HardwareAddr {
162    pub fn from_bytes(bytes: &[u8]) -> Self {
163        if bytes.len() == 6 {
164            Self::Mac(MacAddress::new([
165                bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5],
166            ]))
167        } else {
168            Self::Raw(bytes.to_vec())
169        }
170    }
171
172    pub fn as_mac(&self) -> Option<MacAddress> {
173        match self {
174            Self::Mac(mac) => Some(*mac),
175            Self::Raw(bytes) if bytes.len() == 6 => Some(MacAddress::new([
176                bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5],
177            ])),
178            _ => None,
179        }
180    }
181
182    pub fn as_bytes(&self) -> &[u8] {
183        match self {
184            Self::Mac(mac) => mac.as_bytes(),
185            Self::Raw(bytes) => bytes,
186        }
187    }
188
189    pub fn len(&self) -> usize {
190        match self {
191            Self::Mac(_) => 6,
192            Self::Raw(bytes) => bytes.len(),
193        }
194    }
195
196    pub fn is_empty(&self) -> bool {
197        self.len() == 0
198    }
199    pub fn is_zero(&self) -> bool {
200        self.as_bytes().iter().all(|&b| b == 0)
201    }
202    pub fn is_broadcast(&self) -> bool {
203        self.as_bytes().iter().all(|&b| b == 0xff)
204    }
205}
206
207impl std::fmt::Display for HardwareAddr {
208    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209        match self {
210            Self::Mac(mac) => write!(f, "{}", mac),
211            Self::Raw(bytes) => {
212                for (i, b) in bytes.iter().enumerate() {
213                    if i > 0 {
214                        write!(f, ":")?;
215                    }
216                    write!(f, "{:02x}", b)?;
217                }
218                Ok(())
219            }
220        }
221    }
222}
223
224impl From<MacAddress> for HardwareAddr {
225    fn from(mac: MacAddress) -> Self {
226        Self::Mac(mac)
227    }
228}
229
230impl From<Vec<u8>> for HardwareAddr {
231    fn from(bytes: Vec<u8>) -> Self {
232        Self::from_bytes(&bytes)
233    }
234}
235
236/// Protocol address (variable length).
237#[derive(Debug, Clone, PartialEq, Eq)]
238pub enum ProtocolAddr {
239    Ipv4(Ipv4Addr),
240    Ipv6(Ipv6Addr),
241    Raw(Vec<u8>),
242}
243
244impl ProtocolAddr {
245    pub fn from_bytes(bytes: &[u8], ptype: u16) -> Self {
246        match (bytes.len(), ptype) {
247            (4, protocol_type::IPV4) | (4, _) => {
248                Self::Ipv4(Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3]))
249            }
250            (16, protocol_type::IPV6) => {
251                let mut arr = [0u8; 16];
252                arr.copy_from_slice(bytes);
253                Self::Ipv6(Ipv6Addr::from(arr))
254            }
255            _ => Self::Raw(bytes.to_vec()),
256        }
257    }
258
259    pub fn as_ipv4(&self) -> Option<Ipv4Addr> {
260        match self {
261            Self::Ipv4(ip) => Some(*ip),
262            Self::Raw(bytes) if bytes.len() == 4 => {
263                Some(Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3]))
264            }
265            _ => None,
266        }
267    }
268
269    pub fn as_ipv6(&self) -> Option<Ipv6Addr> {
270        match self {
271            Self::Ipv6(ip) => Some(*ip),
272            Self::Raw(bytes) if bytes.len() == 16 => {
273                let mut arr = [0u8; 16];
274                arr.copy_from_slice(bytes);
275                Some(Ipv6Addr::from(arr))
276            }
277            _ => None,
278        }
279    }
280
281    pub fn as_bytes(&self) -> Vec<u8> {
282        match self {
283            Self::Ipv4(ip) => ip.octets().to_vec(),
284            Self::Ipv6(ip) => ip.octets().to_vec(),
285            Self::Raw(bytes) => bytes.clone(),
286        }
287    }
288
289    pub fn len(&self) -> usize {
290        match self {
291            Self::Ipv4(_) => 4,
292            Self::Ipv6(_) => 16,
293            Self::Raw(bytes) => bytes.len(),
294        }
295    }
296
297    pub fn is_empty(&self) -> bool {
298        self.len() == 0
299    }
300}
301
302impl std::fmt::Display for ProtocolAddr {
303    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304        match self {
305            Self::Ipv4(ip) => write!(f, "{}", ip),
306            Self::Ipv6(ip) => write!(f, "{}", ip),
307            Self::Raw(bytes) => {
308                write!(f, "0x")?;
309                for b in bytes {
310                    write!(f, "{:02x}", b)?;
311                }
312                Ok(())
313            }
314        }
315    }
316}
317
318impl From<Ipv4Addr> for ProtocolAddr {
319    fn from(ip: Ipv4Addr) -> Self {
320        Self::Ipv4(ip)
321    }
322}
323impl From<Ipv6Addr> for ProtocolAddr {
324    fn from(ip: Ipv6Addr) -> Self {
325        Self::Ipv6(ip)
326    }
327}
328impl From<Vec<u8>> for ProtocolAddr {
329    fn from(bytes: Vec<u8>) -> Self {
330        Self::Raw(bytes)
331    }
332}
333
334/// Routing information for ARP layer
335#[derive(Debug, Clone)]
336pub struct ArpRoute {
337    /// Outgoing interface name
338    pub interface: Option<String>,
339    /// Source IP to use
340    pub source_ip: Option<String>,
341    /// Gateway IP if needed
342    pub gateway: Option<String>,
343}
344
345impl Default for ArpRoute {
346    fn default() -> Self {
347        Self {
348            interface: None,
349            source_ip: None,
350            gateway: None,
351        }
352    }
353}
354
355/// A view into an ARP packet.
356#[derive(Debug, Clone)]
357pub struct ArpLayer {
358    pub index: LayerIndex,
359}
360
361impl ArpLayer {
362    #[inline]
363    pub const fn new(start: usize, end: usize) -> Self {
364        Self {
365            index: LayerIndex::new(LayerKind::Arp, start, end),
366        }
367    }
368
369    #[inline]
370    pub const fn at_offset(offset: usize) -> Self {
371        Self::new(offset, offset + ARP_HEADER_LEN)
372    }
373
374    pub fn at_offset_dynamic(buf: &[u8], offset: usize) -> Result<Self, FieldError> {
375        Self::validate(buf, offset)?;
376        let hwlen = buf[offset + offsets::HWLEN] as usize;
377        let plen = buf[offset + offsets::PLEN] as usize;
378        let total_len = ARP_FIXED_HEADER_LEN + 2 * hwlen + 2 * plen;
379        Ok(Self::new(offset, offset + total_len))
380    }
381
382    pub fn validate(buf: &[u8], offset: usize) -> Result<(), FieldError> {
383        if buf.len() < offset + ARP_FIXED_HEADER_LEN {
384            return Err(FieldError::BufferTooShort {
385                offset,
386                need: ARP_FIXED_HEADER_LEN,
387                have: buf.len().saturating_sub(offset),
388            });
389        }
390        let hwlen = buf[offset + offsets::HWLEN] as usize;
391        let plen = buf[offset + offsets::PLEN] as usize;
392        let total_len = ARP_FIXED_HEADER_LEN + 2 * hwlen + 2 * plen;
393        if buf.len() < offset + total_len {
394            return Err(FieldError::BufferTooShort {
395                offset,
396                need: total_len,
397                have: buf.len().saturating_sub(offset),
398            });
399        }
400        Ok(())
401    }
402
403    pub fn calculate_len(&self, buf: &[u8]) -> usize {
404        let hwlen = self.hwlen(buf).unwrap_or(6) as usize;
405        let plen = self.plen(buf).unwrap_or(4) as usize;
406        ARP_FIXED_HEADER_LEN + 2 * hwlen + 2 * plen
407    }
408
409    // ========== Fixed Header Field Readers ==========
410    #[inline]
411    pub fn hwtype(&self, buf: &[u8]) -> Result<u16, FieldError> {
412        u16::read(buf, self.index.start + offsets::HWTYPE)
413    }
414
415    #[inline]
416    pub fn ptype(&self, buf: &[u8]) -> Result<u16, FieldError> {
417        u16::read(buf, self.index.start + offsets::PTYPE)
418    }
419
420    #[inline]
421    pub fn hwlen(&self, buf: &[u8]) -> Result<u8, FieldError> {
422        u8::read(buf, self.index.start + offsets::HWLEN)
423    }
424
425    #[inline]
426    pub fn plen(&self, buf: &[u8]) -> Result<u8, FieldError> {
427        u8::read(buf, self.index.start + offsets::PLEN)
428    }
429
430    #[inline]
431    pub fn op(&self, buf: &[u8]) -> Result<u16, FieldError> {
432        u16::read(buf, self.index.start + offsets::OP)
433    }
434
435    // ========== Fixed Header Field Writers ==========
436    #[inline]
437    pub fn set_hwtype(&self, buf: &mut [u8], val: u16) -> Result<(), FieldError> {
438        val.write(buf, self.index.start + offsets::HWTYPE)
439    }
440
441    #[inline]
442    pub fn set_ptype(&self, buf: &mut [u8], val: u16) -> Result<(), FieldError> {
443        val.write(buf, self.index.start + offsets::PTYPE)
444    }
445
446    #[inline]
447    pub fn set_hwlen(&self, buf: &mut [u8], val: u8) -> Result<(), FieldError> {
448        val.write(buf, self.index.start + offsets::HWLEN)
449    }
450
451    #[inline]
452    pub fn set_plen(&self, buf: &mut [u8], val: u8) -> Result<(), FieldError> {
453        val.write(buf, self.index.start + offsets::PLEN)
454    }
455
456    #[inline]
457    pub fn set_op(&self, buf: &mut [u8], val: u16) -> Result<(), FieldError> {
458        val.write(buf, self.index.start + offsets::OP)
459    }
460
461    // ========== Variable Address Offset Calculations ==========
462    #[inline]
463    fn hwsrc_offset(&self) -> usize {
464        self.index.start + offsets::VAR_START
465    }
466
467    fn psrc_offset(&self, buf: &[u8]) -> Result<usize, FieldError> {
468        Ok(self.hwsrc_offset() + self.hwlen(buf)? as usize)
469    }
470
471    fn hwdst_offset(&self, buf: &[u8]) -> Result<usize, FieldError> {
472        let hwlen = self.hwlen(buf)? as usize;
473        let plen = self.plen(buf)? as usize;
474        Ok(self.hwsrc_offset() + hwlen + plen)
475    }
476
477    fn pdst_offset(&self, buf: &[u8]) -> Result<usize, FieldError> {
478        let hwlen = self.hwlen(buf)? as usize;
479        let plen = self.plen(buf)? as usize;
480        Ok(self.hwsrc_offset() + 2 * hwlen + plen)
481    }
482
483    // ========== Variable Address Readers ==========
484    pub fn hwsrc_raw(&self, buf: &[u8]) -> Result<HardwareAddr, FieldError> {
485        let hwlen = self.hwlen(buf)? as usize;
486        let offset = self.hwsrc_offset();
487        if buf.len() < offset + hwlen {
488            return Err(FieldError::BufferTooShort {
489                offset,
490                need: hwlen,
491                have: buf.len().saturating_sub(offset),
492            });
493        }
494        Ok(HardwareAddr::from_bytes(&buf[offset..offset + hwlen]))
495    }
496
497    pub fn hwsrc(&self, buf: &[u8]) -> Result<MacAddress, FieldError> {
498        let hwlen = self.hwlen(buf)?;
499        if hwlen != 6 {
500            return Err(FieldError::BufferTooShort {
501                offset: self.hwsrc_offset(),
502                need: 6,
503                have: hwlen as usize,
504            });
505        }
506        MacAddress::read(buf, self.hwsrc_offset())
507    }
508
509    pub fn psrc_raw(&self, buf: &[u8]) -> Result<ProtocolAddr, FieldError> {
510        let plen = self.plen(buf)? as usize;
511        let ptype = self.ptype(buf)?;
512        let offset = self.psrc_offset(buf)?;
513        if buf.len() < offset + plen {
514            return Err(FieldError::BufferTooShort {
515                offset,
516                need: plen,
517                have: buf.len().saturating_sub(offset),
518            });
519        }
520        Ok(ProtocolAddr::from_bytes(&buf[offset..offset + plen], ptype))
521    }
522
523    pub fn psrc(&self, buf: &[u8]) -> Result<Ipv4Addr, FieldError> {
524        Ipv4Addr::read(buf, self.psrc_offset(buf)?)
525    }
526
527    pub fn psrc_v6(&self, buf: &[u8]) -> Result<Ipv6Addr, FieldError> {
528        Ipv6Addr::read(buf, self.psrc_offset(buf)?)
529    }
530
531    pub fn hwdst_raw(&self, buf: &[u8]) -> Result<HardwareAddr, FieldError> {
532        let hwlen = self.hwlen(buf)? as usize;
533        let offset = self.hwdst_offset(buf)?;
534        if buf.len() < offset + hwlen {
535            return Err(FieldError::BufferTooShort {
536                offset,
537                need: hwlen,
538                have: buf.len().saturating_sub(offset),
539            });
540        }
541        Ok(HardwareAddr::from_bytes(&buf[offset..offset + hwlen]))
542    }
543
544    pub fn hwdst(&self, buf: &[u8]) -> Result<MacAddress, FieldError> {
545        MacAddress::read(buf, self.hwdst_offset(buf)?)
546    }
547
548    pub fn pdst_raw(&self, buf: &[u8]) -> Result<ProtocolAddr, FieldError> {
549        let plen = self.plen(buf)? as usize;
550        let ptype = self.ptype(buf)?;
551        let offset = self.pdst_offset(buf)?;
552        if buf.len() < offset + plen {
553            return Err(FieldError::BufferTooShort {
554                offset,
555                need: plen,
556                have: buf.len().saturating_sub(offset),
557            });
558        }
559        Ok(ProtocolAddr::from_bytes(&buf[offset..offset + plen], ptype))
560    }
561
562    pub fn pdst(&self, buf: &[u8]) -> Result<Ipv4Addr, FieldError> {
563        Ipv4Addr::read(buf, self.pdst_offset(buf)?)
564    }
565
566    pub fn pdst_v6(&self, buf: &[u8]) -> Result<Ipv6Addr, FieldError> {
567        Ipv6Addr::read(buf, self.pdst_offset(buf)?)
568    }
569
570    // ========== Variable Address Writers ==========
571    pub fn set_hwsrc(&self, buf: &mut [u8], mac: MacAddress) -> Result<(), FieldError> {
572        mac.write(buf, self.hwsrc_offset())
573    }
574
575    pub fn set_hwsrc_raw(&self, buf: &mut [u8], addr: &HardwareAddr) -> Result<(), FieldError> {
576        let offset = self.hwsrc_offset();
577        let bytes = addr.as_bytes();
578        if buf.len() < offset + bytes.len() {
579            return Err(FieldError::BufferTooShort {
580                offset,
581                need: bytes.len(),
582                have: buf.len().saturating_sub(offset),
583            });
584        }
585        buf[offset..offset + bytes.len()].copy_from_slice(bytes);
586        Ok(())
587    }
588
589    pub fn set_psrc(&self, buf: &mut [u8], ip: Ipv4Addr) -> Result<(), FieldError> {
590        ip.write(buf, self.psrc_offset(buf)?)
591    }
592
593    pub fn set_psrc_v6(&self, buf: &mut [u8], ip: Ipv6Addr) -> Result<(), FieldError> {
594        ip.write(buf, self.psrc_offset(buf)?)
595    }
596
597    pub fn set_psrc_raw(&self, buf: &mut [u8], addr: &ProtocolAddr) -> Result<(), FieldError> {
598        let offset = self.psrc_offset(buf)?;
599        let bytes = addr.as_bytes();
600        if buf.len() < offset + bytes.len() {
601            return Err(FieldError::BufferTooShort {
602                offset,
603                need: bytes.len(),
604                have: buf.len().saturating_sub(offset),
605            });
606        }
607        buf[offset..offset + bytes.len()].copy_from_slice(&bytes);
608        Ok(())
609    }
610
611    pub fn set_hwdst(&self, buf: &mut [u8], mac: MacAddress) -> Result<(), FieldError> {
612        mac.write(buf, self.hwdst_offset(buf)?)
613    }
614
615    pub fn set_hwdst_raw(&self, buf: &mut [u8], addr: &HardwareAddr) -> Result<(), FieldError> {
616        let offset = self.hwdst_offset(buf)?;
617        let bytes = addr.as_bytes();
618        if buf.len() < offset + bytes.len() {
619            return Err(FieldError::BufferTooShort {
620                offset,
621                need: bytes.len(),
622                have: buf.len().saturating_sub(offset),
623            });
624        }
625        buf[offset..offset + bytes.len()].copy_from_slice(bytes);
626        Ok(())
627    }
628
629    pub fn set_pdst(&self, buf: &mut [u8], ip: Ipv4Addr) -> Result<(), FieldError> {
630        ip.write(buf, self.pdst_offset(buf)?)
631    }
632
633    pub fn set_pdst_v6(&self, buf: &mut [u8], ip: Ipv6Addr) -> Result<(), FieldError> {
634        ip.write(buf, self.pdst_offset(buf)?)
635    }
636
637    pub fn set_pdst_raw(&self, buf: &mut [u8], addr: &ProtocolAddr) -> Result<(), FieldError> {
638        let offset = self.pdst_offset(buf)?;
639        let bytes = addr.as_bytes();
640        if buf.len() < offset + bytes.len() {
641            return Err(FieldError::BufferTooShort {
642                offset,
643                need: bytes.len(),
644                have: buf.len().saturating_sub(offset),
645            });
646        }
647        buf[offset..offset + bytes.len()].copy_from_slice(&bytes);
648        Ok(())
649    }
650
651    // ========== Dynamic Field Access ==========
652    pub fn get_field(&self, buf: &[u8], name: &str) -> Option<Result<FieldValue, FieldError>> {
653        match name {
654            "hwtype" => Some(self.hwtype(buf).map(FieldValue::U16)),
655            "ptype" => Some(self.ptype(buf).map(FieldValue::U16)),
656            "hwlen" => Some(self.hwlen(buf).map(FieldValue::U8)),
657            "plen" => Some(self.plen(buf).map(FieldValue::U8)),
658            "op" => Some(self.op(buf).map(FieldValue::U16)),
659            "hwsrc" => Some(self.hwsrc(buf).map(FieldValue::Mac)),
660            "psrc" => Some(self.psrc(buf).map(FieldValue::Ipv4)),
661            "hwdst" => Some(self.hwdst(buf).map(FieldValue::Mac)),
662            "pdst" => Some(self.pdst(buf).map(FieldValue::Ipv4)),
663            _ => None,
664        }
665    }
666
667    pub fn set_field(
668        &self,
669        buf: &mut [u8],
670        name: &str,
671        value: FieldValue,
672    ) -> Option<Result<(), FieldError>> {
673        match (name, value) {
674            ("hwtype", FieldValue::U16(v)) => Some(self.set_hwtype(buf, v)),
675            ("ptype", FieldValue::U16(v)) => Some(self.set_ptype(buf, v)),
676            ("hwlen", FieldValue::U8(v)) => Some(self.set_hwlen(buf, v)),
677            ("plen", FieldValue::U8(v)) => Some(self.set_plen(buf, v)),
678            ("op", FieldValue::U16(v)) => Some(self.set_op(buf, v)),
679            ("hwsrc", FieldValue::Mac(v)) => Some(self.set_hwsrc(buf, v)),
680            ("psrc", FieldValue::Ipv4(v)) => Some(self.set_psrc(buf, v)),
681            ("psrc", FieldValue::Ipv6(v)) => Some(self.set_psrc_v6(buf, v)),
682            ("hwdst", FieldValue::Mac(v)) => Some(self.set_hwdst(buf, v)),
683            ("pdst", FieldValue::Ipv4(v)) => Some(self.set_pdst(buf, v)),
684            ("pdst", FieldValue::Ipv6(v)) => Some(self.set_pdst_v6(buf, v)),
685            _ => None,
686        }
687    }
688
689    pub fn field_names() -> &'static [&'static str] {
690        &[
691            "hwtype", "ptype", "hwlen", "plen", "op", "hwsrc", "psrc", "hwdst", "pdst",
692        ]
693    }
694
695    #[inline]
696    pub fn is_request(&self, buf: &[u8]) -> bool {
697        self.op(buf).map(opcode::is_request).unwrap_or(false)
698    }
699
700    #[inline]
701    pub fn is_reply(&self, buf: &[u8]) -> bool {
702        self.op(buf).map(opcode::is_reply).unwrap_or(false)
703    }
704
705    #[inline]
706    pub fn is_who_has(&self, buf: &[u8]) -> bool {
707        self.op(buf)
708            .map(|op| op == opcode::REQUEST)
709            .unwrap_or(false)
710    }
711
712    #[inline]
713    pub fn is_is_at(&self, buf: &[u8]) -> bool {
714        self.op(buf).map(|op| op == opcode::REPLY).unwrap_or(false)
715    }
716
717    /// Compute hash for packet matching.
718    pub fn hashret(&self, buf: &[u8]) -> Vec<u8> {
719        let hwtype = self.hwtype(buf).unwrap_or(0);
720        let ptype = self.ptype(buf).unwrap_or(0);
721        let op = self.op(buf).unwrap_or(0);
722        let op_group = (op + 1) / 2;
723
724        let mut result = Vec::with_capacity(6);
725        result.extend_from_slice(&hwtype.to_be_bytes());
726        result.extend_from_slice(&ptype.to_be_bytes());
727        result.extend_from_slice(&op_group.to_be_bytes());
728        result
729    }
730
731    /// Check if this packet answers another (for sr() matching).
732    pub fn answers(&self, buf: &[u8], other: &ArpLayer, other_buf: &[u8]) -> bool {
733        let self_op = match self.op(buf) {
734            Ok(op) => op,
735            Err(_) => return false,
736        };
737        let other_op = match other.op(other_buf) {
738            Ok(op) => op,
739            Err(_) => return false,
740        };
741
742        if self_op != other_op + 1 {
743            return false;
744        }
745
746        let self_psrc = match self.psrc_raw(buf) {
747            Ok(addr) => addr.as_bytes(),
748            Err(_) => return false,
749        };
750        let other_pdst = match other.pdst_raw(other_buf) {
751            Ok(addr) => addr.as_bytes(),
752            Err(_) => return false,
753        };
754
755        let cmp_len = self_psrc.len().min(other_pdst.len());
756        self_psrc[..cmp_len] == other_pdst[..cmp_len]
757    }
758
759    /// Extract padding: ARP has no payload, remaining bytes are padding.
760    pub fn extract_padding<'a>(&self, buf: &'a [u8]) -> (&'a [u8], &'a [u8]) {
761        let end = self.index.end.min(buf.len());
762        (&[], &buf[end..])
763    }
764
765    /// Get routing information for this ARP packet.
766    pub fn route(&self, buf: &[u8]) -> ArpRoute {
767        let pdst_ip = match self.pdst_raw(buf) {
768            Ok(ProtocolAddr::Ipv4(ip)) => IpAddr::V4(ip),
769            Ok(ProtocolAddr::Ipv6(ip)) => IpAddr::V6(ip),
770            _ => return ArpRoute::default(),
771        };
772
773        let interfaces = pnet_datalink::interfaces();
774
775        for iface in &interfaces {
776            if !iface.is_up() || iface.is_loopback() {
777                continue;
778            }
779
780            for ip_net in &iface.ips {
781                if ip_net.contains(pdst_ip) {
782                    return ArpRoute {
783                        interface: Some(iface.name.clone()),
784                        source_ip: Some(ip_net.ip().to_string()),
785                        gateway: None,
786                    };
787                }
788            }
789        }
790
791        if let Ok(default_iface) = default_net::get_default_interface() {
792            if let Some(iface) = interfaces.iter().find(|i| i.name == default_iface.name) {
793                let src_ip = iface
794                    .ips
795                    .iter()
796                    .find(|ip| ip.is_ipv4())
797                    .map(|ip| ip.ip().to_string());
798                let gw_ip = default_iface.gateway.map(|gw| gw.ip_addr.to_string());
799
800                return ArpRoute {
801                    interface: Some(iface.name.clone()),
802                    source_ip: src_ip,
803                    gateway: gw_ip,
804                };
805            }
806        }
807
808        ArpRoute::default()
809    }
810
811    /// Resolve the destination MAC for this ARP packet.
812    pub fn resolve_dst_mac(&self, buf: &[u8]) -> Option<MacAddress> {
813        let op = self.op(buf).ok()?;
814        match op {
815            opcode::REQUEST => Some(MacAddress::BROADCAST), // who-has uses broadcast
816            opcode::REPLY => None,                          // is-at should have explicit dst
817            _ => None,
818        }
819    }
820
821    #[inline]
822    pub fn header_bytes<'a>(&self, buf: &'a [u8]) -> &'a [u8] {
823        &buf[self.index.start..self.index.end.min(buf.len())]
824    }
825
826    #[inline]
827    pub fn header_copy(&self, buf: &[u8]) -> Vec<u8> {
828        self.header_bytes(buf).to_vec()
829    }
830
831    pub fn op_name(&self, buf: &[u8]) -> &'static str {
832        self.op(buf).map(opcode::name).unwrap_or("unknown")
833    }
834
835    pub fn hwtype_name(&self, buf: &[u8]) -> &'static str {
836        self.hwtype(buf)
837            .map(hardware_type::name)
838            .unwrap_or("unknown")
839    }
840}
841
842impl Layer for ArpLayer {
843    fn kind(&self) -> LayerKind {
844        LayerKind::Arp
845    }
846
847    fn summary(&self, buf: &[u8]) -> String {
848        let op = self.op(buf).unwrap_or(0);
849        let psrc = self
850            .psrc_raw(buf)
851            .map(|a| a.to_string())
852            .unwrap_or_else(|_| "?".into());
853        let pdst = self
854            .pdst_raw(buf)
855            .map(|a| a.to_string())
856            .unwrap_or_else(|_| "?".into());
857
858        match op {
859            opcode::REQUEST => format!("ARP who has {} says {}", pdst, psrc),
860            opcode::REPLY => {
861                let hwsrc = self
862                    .hwsrc_raw(buf)
863                    .map(|a| a.to_string())
864                    .unwrap_or_else(|_| "?".into());
865                format!("ARP {} is at {}", psrc, hwsrc)
866            }
867            _ => format!("ARP {} {} > {}", opcode::name(op), psrc, pdst),
868        }
869    }
870
871    fn header_len(&self, buf: &[u8]) -> usize {
872        self.calculate_len(buf)
873    }
874
875    fn hashret(&self, buf: &[u8]) -> Vec<u8> {
876        self.hashret(buf)
877    }
878
879    fn answers(&self, buf: &[u8], other: &Self, other_buf: &[u8]) -> bool {
880        self.answers(buf, other, other_buf)
881    }
882
883    fn extract_padding<'a>(&self, buf: &'a [u8]) -> (&'a [u8], &'a [u8]) {
884        self.extract_padding(buf)
885    }
886}
887
888// ============================================================================
889// ArpBuilder
890// ============================================================================
891
892#[derive(Debug, Clone)]
893pub struct ArpBuilder {
894    hwtype: u16,
895    ptype: u16,
896    hwlen: Option<u8>,
897    plen: Option<u8>,
898    op: u16,
899    hwsrc: HardwareAddr,
900    psrc: ProtocolAddr,
901    hwdst: HardwareAddr,
902    pdst: ProtocolAddr,
903}
904
905/// Get the default interface's MAC address and IPv4 address.
906fn get_local_mac_and_ip() -> (MacAddress, Ipv4Addr) {
907    let default_mac = MacAddress::ZERO;
908    let default_ip = Ipv4Addr::new(0, 0, 0, 0);
909
910    let default_iface = match default_net::get_default_interface() {
911        Ok(iface) => iface,
912        Err(_) => return (default_mac, default_ip),
913    };
914
915    let interfaces = pnet_datalink::interfaces();
916    let iface = match interfaces.iter().find(|i| i.name == default_iface.name) {
917        Some(i) => i,
918        None => return (default_mac, default_ip),
919    };
920
921    let mac = iface
922        .mac
923        .map(|m| MacAddress::new(m.octets()))
924        .unwrap_or(default_mac);
925
926    let ip = iface
927        .ips
928        .iter()
929        .find_map(|ip_net| {
930            if let IpAddr::V4(v4) = ip_net.ip() {
931                Some(v4)
932            } else {
933                None
934            }
935        })
936        .unwrap_or(default_ip);
937
938    (mac, ip)
939}
940
941impl Default for ArpBuilder {
942    fn default() -> Self {
943        let (local_mac, local_ip) = get_local_mac_and_ip();
944        Self {
945            hwtype: hardware_type::ETHERNET,
946            ptype: protocol_type::IPV4,
947            hwlen: None,
948            plen: None,
949            op: opcode::REQUEST,
950            hwsrc: HardwareAddr::Mac(local_mac),
951            psrc: ProtocolAddr::Ipv4(local_ip),
952            hwdst: HardwareAddr::Mac(MacAddress::ZERO),
953            pdst: ProtocolAddr::Ipv4(Ipv4Addr::new(0, 0, 0, 0)),
954        }
955    }
956}
957
958impl ArpBuilder {
959    pub fn new() -> Self {
960        Self::default()
961    }
962
963    pub fn who_has(pdst: Ipv4Addr) -> Self {
964        Self::default().op(opcode::REQUEST).pdst(pdst)
965    }
966
967    pub fn is_at(psrc: Ipv4Addr, hwsrc: MacAddress) -> Self {
968        Self::default().op(opcode::REPLY).psrc(psrc).hwsrc(hwsrc)
969    }
970
971    pub fn hwtype(mut self, v: u16) -> Self {
972        self.hwtype = v;
973        self
974    }
975    pub fn ptype(mut self, v: u16) -> Self {
976        self.ptype = v;
977        self
978    }
979    pub fn hwlen(mut self, v: u8) -> Self {
980        self.hwlen = Some(v);
981        self
982    }
983    pub fn plen(mut self, v: u8) -> Self {
984        self.plen = Some(v);
985        self
986    }
987    pub fn op(mut self, v: u16) -> Self {
988        self.op = v;
989        self
990    }
991
992    pub fn op_name(mut self, name: &str) -> Self {
993        if let Some(op) = opcode::from_name(name) {
994            self.op = op;
995        }
996        self
997    }
998
999    pub fn hwsrc(mut self, v: MacAddress) -> Self {
1000        self.hwsrc = HardwareAddr::Mac(v);
1001        self
1002    }
1003    pub fn hwsrc_raw(mut self, v: HardwareAddr) -> Self {
1004        self.hwsrc = v;
1005        self
1006    }
1007    pub fn psrc(mut self, v: Ipv4Addr) -> Self {
1008        self.psrc = ProtocolAddr::Ipv4(v);
1009        self
1010    }
1011    pub fn psrc_v6(mut self, v: Ipv6Addr) -> Self {
1012        self.psrc = ProtocolAddr::Ipv6(v);
1013        self.ptype = protocol_type::IPV6;
1014        self
1015    }
1016    pub fn psrc_raw(mut self, v: ProtocolAddr) -> Self {
1017        self.psrc = v;
1018        self
1019    }
1020    pub fn hwdst(mut self, v: MacAddress) -> Self {
1021        self.hwdst = HardwareAddr::Mac(v);
1022        self
1023    }
1024    pub fn hwdst_raw(mut self, v: HardwareAddr) -> Self {
1025        self.hwdst = v;
1026        self
1027    }
1028    pub fn pdst(mut self, v: Ipv4Addr) -> Self {
1029        self.pdst = ProtocolAddr::Ipv4(v);
1030        self
1031    }
1032    pub fn pdst_v6(mut self, v: Ipv6Addr) -> Self {
1033        self.pdst = ProtocolAddr::Ipv6(v);
1034        self.ptype = protocol_type::IPV6;
1035        self
1036    }
1037    pub fn pdst_raw(mut self, v: ProtocolAddr) -> Self {
1038        self.pdst = v;
1039        self
1040    }
1041
1042    pub fn size(&self) -> usize {
1043        let hwlen = self.hwlen.unwrap_or(self.hwsrc.len() as u8) as usize;
1044        let plen = self.plen.unwrap_or(self.psrc.len() as u8) as usize;
1045        ARP_FIXED_HEADER_LEN + 2 * hwlen + 2 * plen
1046    }
1047
1048    pub fn build(&self) -> Vec<u8> {
1049        let mut buf = vec![0u8; self.size()];
1050        self.build_into(&mut buf)
1051            .expect("buffer is correctly sized");
1052        buf
1053    }
1054
1055    pub fn build_into(&self, buf: &mut [u8]) -> Result<(), FieldError> {
1056        let hwlen = self.hwlen.unwrap_or(self.hwsrc.len() as u8);
1057        let plen = self.plen.unwrap_or(self.psrc.len() as u8);
1058        let size = ARP_FIXED_HEADER_LEN + 2 * (hwlen as usize) + 2 * (plen as usize);
1059
1060        if buf.len() < size {
1061            return Err(FieldError::BufferTooShort {
1062                offset: 0,
1063                need: size,
1064                have: buf.len(),
1065            });
1066        }
1067
1068        self.hwtype.write(buf, offsets::HWTYPE)?;
1069        self.ptype.write(buf, offsets::PTYPE)?;
1070        hwlen.write(buf, offsets::HWLEN)?;
1071        plen.write(buf, offsets::PLEN)?;
1072        self.op.write(buf, offsets::OP)?;
1073
1074        let mut offset = offsets::VAR_START;
1075
1076        let hwsrc_bytes = self.hwsrc.as_bytes();
1077        let hwsrc_copy_len = hwsrc_bytes.len().min(hwlen as usize);
1078        buf[offset..offset + hwsrc_copy_len].copy_from_slice(&hwsrc_bytes[..hwsrc_copy_len]);
1079        offset += hwlen as usize;
1080
1081        let psrc_bytes = self.psrc.as_bytes();
1082        let psrc_copy_len = psrc_bytes.len().min(plen as usize);
1083        buf[offset..offset + psrc_copy_len].copy_from_slice(&psrc_bytes[..psrc_copy_len]);
1084        offset += plen as usize;
1085
1086        let hwdst_bytes = self.hwdst.as_bytes();
1087        let hwdst_copy_len = hwdst_bytes.len().min(hwlen as usize);
1088        buf[offset..offset + hwdst_copy_len].copy_from_slice(&hwdst_bytes[..hwdst_copy_len]);
1089        offset += hwlen as usize;
1090
1091        let pdst_bytes = self.pdst.as_bytes();
1092        let pdst_copy_len = pdst_bytes.len().min(plen as usize);
1093        buf[offset..offset + pdst_copy_len].copy_from_slice(&pdst_bytes[..pdst_copy_len]);
1094
1095        Ok(())
1096    }
1097}
1098
1099#[cfg(test)]
1100mod tests {
1101    use super::*;
1102
1103    #[test]
1104    fn test_arp_ipv6_fields() {
1105        let mut buf = vec![0u8; 52]; // 8 fixed + 2*(6+16) for IPv6
1106        let arp = ArpLayer::at_offset(0);
1107
1108        arp.set_hwtype(&mut buf, hardware_type::ETHERNET).unwrap();
1109        arp.set_ptype(&mut buf, protocol_type::IPV6).unwrap();
1110        arp.set_hwlen(&mut buf, 6).unwrap();
1111        arp.set_plen(&mut buf, 16).unwrap();
1112        arp.set_op(&mut buf, opcode::REQUEST).unwrap();
1113
1114        let ipv6 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1);
1115        arp.set_psrc_v6(&mut buf, ipv6).unwrap();
1116        assert_eq!(arp.psrc_v6(&buf).unwrap(), ipv6);
1117    }
1118
1119    #[test]
1120    fn test_extract_padding() {
1121        let mut buf = vec![0u8; 60]; // Ethernet minimum with padding
1122        buf[..28].copy_from_slice(&sample_arp_request());
1123
1124        let arp = ArpLayer::at_offset(0);
1125        let (payload, padding) = arp.extract_padding(&buf);
1126
1127        assert!(payload.is_empty());
1128        assert_eq!(padding.len(), 32); // 60 - 28 = 32 bytes padding
1129    }
1130
1131    #[test]
1132    fn test_route() {
1133        let buf = sample_arp_request();
1134        let arp = ArpLayer::at_offset(0);
1135        let route = arp.route(&buf);
1136
1137        assert!(route.source_ip.is_some());
1138    }
1139
1140    #[test]
1141    fn test_resolve_dst_mac() {
1142        let buf = sample_arp_request();
1143        let arp = ArpLayer::at_offset(0);
1144
1145        assert_eq!(arp.resolve_dst_mac(&buf), Some(MacAddress::BROADCAST));
1146    }
1147
1148    fn sample_arp_request() -> Vec<u8> {
1149        vec![
1150            0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
1151            0xc0, 0xa8, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x01, 0x02,
1152        ]
1153    }
1154}