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