capsule/packets/
arp.rs

1/*
2* Copyright 2019 Comcast Cable Communications Management, LLC
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*
16* SPDX-License-Identifier: Apache-2.0
17*/
18
19//! Address Resolution Protocol.
20
21use crate::net::MacAddr;
22use crate::packets::types::u16be;
23use crate::packets::{EtherTypes, Ethernet, Internal, Packet};
24use crate::{ensure, SizeOf};
25use anyhow::{anyhow, Result};
26use std::fmt;
27use std::net::Ipv4Addr;
28use std::ptr::NonNull;
29
30/// Address Resolution Protocol packet based on [IETF RFC 826].
31///
32/// ```
33///  0                   1                   2                   3
34///  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
35/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36/// |         Hardware Type         |         Protocol Type         |
37/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38/// |    H Length   |    P Length   |         Operation Code        |
39/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40/// |                   Sender Hardware Address                     |
41/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42/// |                   Sender Protocol Address                     |
43/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44/// |                   Target Hardware Address                     |
45/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46/// |                   Target Protocol Address                     |
47/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48/// ```
49///
50/// - *Hardware Type*: (16 bits)
51///      The network link protocol type.
52///
53/// - *Protocol Type*: (16 bits)
54///      The internetwork protocol for which the ARP request is intended.
55///
56/// - *H Length*: (8 bits)
57///      Length (in octets) of a hardware address.
58///
59/// - *P Length*: (8 bits)
60///      Length (in octets) of a protocol address.
61///
62/// - *Operation Code*: (16 bits)
63///      The operation that the sender is performing.
64///
65/// - *Sender Hardware Address*: (variable)
66///      Hardware address of the sender. In an ARP request this field is used
67///      to indicate the address of the host sending the request. In an ARP
68///      reply this field is used to indicate the address of the host that the
69///      request was looking for. The address size is defined by *H Length*.
70///
71/// - *Sender Protocol Address*: (variable)
72///      Protocol address of the sender. The address size is defined by
73///      *P Length*.
74///
75/// - *Target Hardware Address*: (variable)
76///      Hardware address of the intended receiver. In an ARP request this
77///      field is ignored. In an ARP reply this field is used to indicate the
78///      address of the host that originated the ARP request. The address
79///      size is defined by *H Length*.
80///
81/// - *Target Protocol Address*: (variable)
82///      Protocol address of the intended receiver. The address size is
83///      defined by *P Length*.
84///
85/// [IETF RFC 826]: https://tools.ietf.org/html/rfc826
86pub struct Arp<H: HardwareAddr, P: ProtocolAddr> {
87    envelope: Ethernet,
88    header: NonNull<ArpHeader<H, P>>,
89    offset: usize,
90}
91
92impl<H: HardwareAddr, P: ProtocolAddr> Arp<H, P> {
93    #[inline]
94    fn header(&self) -> &ArpHeader<H, P> {
95        unsafe { self.header.as_ref() }
96    }
97
98    #[inline]
99    fn header_mut(&mut self) -> &mut ArpHeader<H, P> {
100        unsafe { self.header.as_mut() }
101    }
102
103    /// Returns the hardware type.
104    #[inline]
105    pub fn hardware_type(&self) -> HardwareType {
106        HardwareType::new(self.header().hardware_type.into())
107    }
108
109    /// Sets the hardware type.
110    #[inline]
111    fn set_hardware_type(&mut self, hardware_type: HardwareType) {
112        self.header_mut().hardware_type = hardware_type.0.into()
113    }
114
115    /// Returns the protocol type.
116    #[inline]
117    pub fn protocol_type(&self) -> ProtocolType {
118        ProtocolType::new(self.header().protocol_type.into())
119    }
120
121    /// Sets the protocol type.
122    #[inline]
123    fn set_protocol_type(&mut self, protocol_type: ProtocolType) {
124        self.header_mut().protocol_type = protocol_type.0.into()
125    }
126
127    /// Returns the hardware address length.
128    #[inline]
129    pub fn hardware_addr_len(&self) -> u8 {
130        self.header().hardware_addr_len
131    }
132
133    /// Sets the hardware address length.
134    #[inline]
135    fn set_hardware_addr_len(&mut self, len: u8) {
136        self.header_mut().hardware_addr_len = len
137    }
138
139    /// Returns the protocol address length.
140    #[inline]
141    pub fn protocol_addr_len(&self) -> u8 {
142        self.header().protocol_addr_len
143    }
144
145    /// Sets the protocol address length.
146    #[inline]
147    fn set_protocol_addr_len(&mut self, len: u8) {
148        self.header_mut().protocol_addr_len = len
149    }
150
151    /// Returns the operation code.
152    #[inline]
153    pub fn operation_code(&self) -> OperationCode {
154        OperationCode::new(self.header().operation_code.into())
155    }
156
157    /// Sets the operation code.
158    #[inline]
159    pub fn set_operation_code(&mut self, code: OperationCode) {
160        self.header_mut().operation_code = code.0.into()
161    }
162
163    /// Returns the sender hardware address.
164    #[inline]
165    pub fn sender_hardware_addr(&self) -> H {
166        self.header().sender_hardware_addr
167    }
168
169    /// Sets the sender hardware address.
170    #[inline]
171    pub fn set_sender_hardware_addr(&mut self, addr: H) {
172        self.header_mut().sender_hardware_addr = addr
173    }
174
175    /// Returns the sender protocol address.
176    #[inline]
177    pub fn sender_protocol_addr(&self) -> P {
178        self.header().sender_protocol_addr
179    }
180
181    /// Sets the sender protocol address.
182    #[inline]
183    pub fn set_sender_protocol_addr(&mut self, addr: P) {
184        self.header_mut().sender_protocol_addr = addr
185    }
186
187    /// Returns the target hardware address.
188    #[inline]
189    pub fn target_hardware_addr(&self) -> H {
190        self.header().target_hardware_addr
191    }
192
193    /// Sets the target hardware address.
194    #[inline]
195    pub fn set_target_hardware_addr(&mut self, addr: H) {
196        self.header_mut().target_hardware_addr = addr
197    }
198
199    /// Returns the target protocol address.
200    #[inline]
201    pub fn target_protocol_addr(&self) -> P {
202        self.header().target_protocol_addr
203    }
204
205    /// Sets the target protocol address.
206    #[inline]
207    pub fn set_target_protocol_addr(&mut self, addr: P) {
208        self.header_mut().target_protocol_addr = addr
209    }
210}
211
212impl<H: HardwareAddr, P: ProtocolAddr> fmt::Debug for Arp<H, P> {
213    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214        f.debug_struct("arp")
215            .field("hardware_type", &format!("{}", self.hardware_type()))
216            .field("protocol_type", &format!("{}", self.protocol_type()))
217            .field("hardware_addr_len", &self.hardware_addr_len())
218            .field("protocol_addr_len", &self.protocol_addr_len())
219            .field("operation_code", &format!("{}", self.operation_code()))
220            .field(
221                "sender_hardware_addr",
222                &format!("{}", self.sender_hardware_addr()),
223            )
224            .field(
225                "sender_protocol_addr",
226                &format!("{}", self.sender_protocol_addr()),
227            )
228            .field(
229                "target_hardware_addr",
230                &format!("{}", self.target_hardware_addr()),
231            )
232            .field(
233                "target_protocol_addr",
234                &format!("{}", self.target_protocol_addr()),
235            )
236            .field("$offset", &self.offset())
237            .field("$len", &self.len())
238            .field("$header_len", &self.header_len())
239            .finish()
240    }
241}
242
243impl<H: HardwareAddr, P: ProtocolAddr> Packet for Arp<H, P> {
244    /// The preceding type for ARP must be `Ethernet`.
245    type Envelope = Ethernet;
246
247    #[inline]
248    fn envelope(&self) -> &Self::Envelope {
249        &self.envelope
250    }
251
252    #[inline]
253    fn envelope_mut(&mut self) -> &mut Self::Envelope {
254        &mut self.envelope
255    }
256
257    #[inline]
258    fn offset(&self) -> usize {
259        self.offset
260    }
261
262    #[inline]
263    fn header_len(&self) -> usize {
264        ArpHeader::<H, P>::size_of()
265    }
266
267    #[inline]
268    unsafe fn clone(&self, internal: Internal) -> Self {
269        Arp {
270            envelope: self.envelope.clone(internal),
271            header: self.header,
272            offset: self.offset,
273        }
274    }
275
276    /// Parses the Ethernet payload as an ARP packet.
277    ///
278    /// # Errors
279    ///
280    /// Returns an error if the [`ether_type`] is not set to [`EtherTypes::ARP`].
281    /// Returns an error if the payload does not have sufficient data for the
282    /// ARP header. Returns an error if any of the following values does not match
283    /// expectation.
284    ///   * hardware type
285    ///   * hardware address length
286    ///   * protocol type
287    ///   * protocol address length
288    ///
289    /// [`ether_type`]: Ethernet::ether_type
290    /// [`EtherTypes::Arp`]: EtherTypes::Arp
291    #[inline]
292    fn try_parse(envelope: Self::Envelope, _internal: Internal) -> Result<Self> {
293        ensure!(
294            envelope.ether_type() == EtherTypes::Arp,
295            anyhow!("not an ARP packet.")
296        );
297
298        let mbuf = envelope.mbuf();
299        let offset = envelope.payload_offset();
300        let header = mbuf.read_data(offset)?;
301
302        let packet = Arp {
303            envelope,
304            header,
305            offset,
306        };
307
308        ensure!(
309            packet.hardware_type() == H::addr_type(),
310            anyhow!(
311                "hardware type {} does not match expected {}.",
312                packet.hardware_type(),
313                H::addr_type()
314            )
315        );
316        ensure!(
317            packet.protocol_type() == P::addr_type(),
318            anyhow!(
319                "protocol type {} does not match expected {}.",
320                packet.protocol_type(),
321                P::addr_type()
322            )
323        );
324        ensure!(
325            packet.hardware_addr_len() == H::size_of() as u8,
326            anyhow!(
327                "hardware address length {} does not match expected {}.",
328                packet.hardware_addr_len(),
329                H::size_of()
330            )
331        );
332        ensure!(
333            packet.protocol_addr_len() == P::size_of() as u8,
334            anyhow!(
335                "protocol address length {} does not match expected {}.",
336                packet.protocol_addr_len(),
337                P::size_of()
338            )
339        );
340
341        Ok(packet)
342    }
343
344    /// Prepends an ARP packet to the beginning of the Ethernet's payload.
345    ///
346    /// [`ether_type`] is set to [`EtherTypes::Arp`]. `hardware_type`,
347    /// `hardware_addr_len`, `protocol_type`, `protocol_addr_len` are set
348    /// based on `H` and `P`.
349    ///
350    /// # Errors
351    ///
352    /// Returns an error if the buffer does not have enough free space.
353    ///
354    /// [`ether_type`]: Ethernet::ether_type
355    /// [`EtherTypes::Arp`]: EtherTypes::Arp
356    #[inline]
357    fn try_push(mut envelope: Self::Envelope, _internal: Internal) -> Result<Self> {
358        let offset = envelope.payload_offset();
359        let mbuf = envelope.mbuf_mut();
360
361        mbuf.extend(offset, ArpHeader::<H, P>::size_of())?;
362        let header = mbuf.write_data(offset, &ArpHeader::<H, P>::default())?;
363
364        envelope.set_ether_type(EtherTypes::Arp);
365
366        let mut packet = Arp {
367            envelope,
368            header,
369            offset,
370        };
371
372        packet.set_hardware_type(H::addr_type());
373        packet.set_protocol_type(P::addr_type());
374        packet.set_hardware_addr_len(H::size_of() as u8);
375        packet.set_protocol_addr_len(P::size_of() as u8);
376
377        Ok(packet)
378    }
379
380    #[inline]
381    fn deparse(self) -> Self::Envelope {
382        self.envelope
383    }
384}
385
386/// [IANA] assigned hardware type.
387///
388/// See [`HardwareTypes`] for which are current supported.
389///
390/// [IANA]: https://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml#arp-parameters-2
391/// [`HardwareTypes`]: crate::packets::arp::HardwareTypes
392#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
393#[repr(C, packed)]
394pub struct HardwareType(u16);
395
396impl HardwareType {
397    /// Creates a new hardware type.
398    pub fn new(value: u16) -> Self {
399        HardwareType(value)
400    }
401}
402
403/// Supported hardware types.
404#[allow(non_snake_case)]
405#[allow(non_upper_case_globals)]
406pub mod HardwareTypes {
407    use super::HardwareType;
408
409    /// Ethernet.
410    pub const Ethernet: HardwareType = HardwareType(0x0001);
411}
412
413impl fmt::Display for HardwareType {
414    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
415        write!(
416            f,
417            "{}",
418            match *self {
419                HardwareTypes::Ethernet => "Ethernet".to_string(),
420                _ => {
421                    let t = self.0;
422                    format!("0x{:04x}", t)
423                }
424            }
425        )
426    }
427}
428
429/// [IANA] assigned protocol type.
430///
431/// See [`ProtocolTypes`] for which are current supported.
432///
433/// [IANA]: https://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml#arp-parameters-3
434/// [`ProtocolTypes`]: crate::packets::arp::ProtocolTypes
435#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
436#[repr(C, packed)]
437pub struct ProtocolType(u16);
438
439impl ProtocolType {
440    /// Creates a new protocol type.
441    pub fn new(value: u16) -> Self {
442        ProtocolType(value)
443    }
444}
445
446/// Supported protocol types.
447#[allow(non_snake_case)]
448#[allow(non_upper_case_globals)]
449pub mod ProtocolTypes {
450    use super::ProtocolType;
451
452    /// Internet protocol version 4.
453    pub const Ipv4: ProtocolType = ProtocolType(0x0800);
454}
455
456impl fmt::Display for ProtocolType {
457    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
458        write!(
459            f,
460            "{}",
461            match *self {
462                ProtocolTypes::Ipv4 => "IPv4".to_string(),
463                _ => {
464                    let t = self.0;
465                    format!("0x{:04x}", t)
466                }
467            }
468        )
469    }
470}
471
472/// [IANA] assigned operation code.
473///
474/// See [`OperationCodes`] for which are current supported.
475///
476/// [IANA]: https://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml
477/// [`OperationCodes`]: crate::packets::arp::OperationCodes
478#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
479#[repr(C, packed)]
480pub struct OperationCode(u16);
481
482impl OperationCode {
483    /// Creates a new operation code.
484    pub fn new(value: u16) -> Self {
485        OperationCode(value)
486    }
487}
488
489/// Supported operation codes.
490#[allow(non_snake_case)]
491#[allow(non_upper_case_globals)]
492pub mod OperationCodes {
493    use super::OperationCode;
494
495    /// Request.
496    pub const Request: OperationCode = OperationCode(1);
497    /// Reply.
498    pub const Reply: OperationCode = OperationCode(2);
499    /// Request reverse.
500    pub const RequestReverse: OperationCode = OperationCode(3);
501    /// Reply reverse.
502    pub const ReplyReverse: OperationCode = OperationCode(4);
503}
504
505impl fmt::Display for OperationCode {
506    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
507        write!(
508            f,
509            "{}",
510            match *self {
511                OperationCodes::Request => "Request".to_string(),
512                OperationCodes::Reply => "Reply".to_string(),
513                OperationCodes::RequestReverse => "Request reverse".to_string(),
514                OperationCodes::ReplyReverse => "Reply reverse".to_string(),
515                _ => {
516                    let t = self.0;
517                    format!("0x{:04x}", t)
518                }
519            }
520        )
521    }
522}
523
524/// A trait implemented by ARP hardware address types.
525pub trait HardwareAddr: SizeOf + Copy + fmt::Display {
526    /// Returns the associated hardware type of the given address.
527    fn addr_type() -> HardwareType;
528
529    /// Returns the default value.
530    ///
531    /// This is synonymous with `Default::default`, but is necessary when
532    /// an external crate type doesn't implement the `Default` trait.
533    fn default() -> Self;
534}
535
536impl SizeOf for MacAddr {
537    fn size_of() -> usize {
538        6
539    }
540}
541
542impl HardwareAddr for MacAddr {
543    fn addr_type() -> HardwareType {
544        HardwareTypes::Ethernet
545    }
546
547    fn default() -> Self {
548        Default::default()
549    }
550}
551
552/// A trait implemented by ARP protocol address types.
553pub trait ProtocolAddr: SizeOf + Copy + fmt::Display {
554    /// Returns the associated protocol type of the given address.
555    fn addr_type() -> ProtocolType;
556
557    /// Returns the default value.
558    ///
559    /// This is synonymous with `Default::default`, but is necessary when
560    /// an external crate type doesn't implement the `Default` trait.
561    fn default() -> Self;
562}
563
564impl SizeOf for Ipv4Addr {
565    fn size_of() -> usize {
566        4
567    }
568}
569
570impl ProtocolAddr for Ipv4Addr {
571    fn addr_type() -> ProtocolType {
572        ProtocolTypes::Ipv4
573    }
574
575    fn default() -> Self {
576        Ipv4Addr::UNSPECIFIED
577    }
578}
579
580/// A type alias for an IPv4 ARP packet.
581pub type Arp4 = Arp<MacAddr, Ipv4Addr>;
582
583/// ARP header.
584#[allow(missing_debug_implementations)]
585#[derive(Copy, SizeOf)]
586#[repr(C, packed)]
587struct ArpHeader<H: HardwareAddr, P: ProtocolAddr> {
588    hardware_type: u16be,
589    protocol_type: u16be,
590    hardware_addr_len: u8,
591    protocol_addr_len: u8,
592    operation_code: u16be,
593    sender_hardware_addr: H,
594    sender_protocol_addr: P,
595    target_hardware_addr: H,
596    target_protocol_addr: P,
597}
598
599impl<H: HardwareAddr, P: ProtocolAddr> Clone for ArpHeader<H, P> {
600    fn clone(&self) -> Self {
601        ArpHeader {
602            hardware_type: self.hardware_type,
603            protocol_type: self.protocol_type,
604            hardware_addr_len: self.hardware_addr_len,
605            protocol_addr_len: self.protocol_addr_len,
606            operation_code: self.operation_code,
607            sender_hardware_addr: self.sender_hardware_addr,
608            sender_protocol_addr: self.sender_protocol_addr,
609            target_hardware_addr: self.target_hardware_addr,
610            target_protocol_addr: self.target_protocol_addr,
611        }
612    }
613}
614
615impl<H: HardwareAddr, P: ProtocolAddr> Default for ArpHeader<H, P> {
616    fn default() -> Self {
617        ArpHeader {
618            hardware_type: u16be::default(),
619            protocol_type: u16be::default(),
620            hardware_addr_len: 0,
621            protocol_addr_len: 0,
622            operation_code: u16be::default(),
623            sender_hardware_addr: H::default(),
624            sender_protocol_addr: P::default(),
625            target_hardware_addr: H::default(),
626            target_protocol_addr: P::default(),
627        }
628    }
629}
630
631#[cfg(test)]
632mod tests {
633    use super::*;
634    use crate::testils::byte_arrays::ARP4_PACKET;
635    use crate::Mbuf;
636
637    #[test]
638    fn size_of_arp_header() {
639        assert_eq!(28, ArpHeader::<MacAddr, Ipv4Addr>::size_of());
640    }
641
642    #[capsule::test]
643    fn parse_arp_packet() {
644        let packet = Mbuf::from_bytes(&ARP4_PACKET).unwrap();
645        let ethernet = packet.parse::<Ethernet>().unwrap();
646        let arp4 = ethernet.parse::<Arp4>().unwrap();
647
648        assert_eq!(HardwareTypes::Ethernet, arp4.hardware_type());
649        assert_eq!(ProtocolTypes::Ipv4, arp4.protocol_type());
650        assert_eq!(6, arp4.hardware_addr_len());
651        assert_eq!(4, arp4.protocol_addr_len());
652        assert_eq!(OperationCodes::Request, arp4.operation_code());
653        assert_eq!("00:00:00:00:00:01", arp4.sender_hardware_addr().to_string());
654        assert_eq!("139.133.217.110", arp4.sender_protocol_addr().to_string());
655        assert_eq!("00:00:00:00:00:00", arp4.target_hardware_addr().to_string());
656        assert_eq!("139.133.233.2", arp4.target_protocol_addr().to_string());
657    }
658
659    #[capsule::test]
660    fn push_arp_packet() {
661        let packet = Mbuf::new().unwrap();
662        let ethernet = packet.push::<Ethernet>().unwrap();
663        let mut arp4 = ethernet.push::<Arp4>().unwrap();
664
665        assert_eq!(ArpHeader::<MacAddr, Ipv4Addr>::size_of(), arp4.len());
666
667        // make sure types are set properly
668        assert_eq!(HardwareTypes::Ethernet, arp4.hardware_type());
669        assert_eq!(ProtocolTypes::Ipv4, arp4.protocol_type());
670        assert_eq!(6, arp4.hardware_addr_len());
671        assert_eq!(4, arp4.protocol_addr_len());
672
673        // check the setters
674        arp4.set_operation_code(OperationCodes::Reply);
675        assert_eq!(OperationCodes::Reply, arp4.operation_code());
676        arp4.set_sender_hardware_addr(MacAddr::new(0, 0, 0, 0, 0, 1));
677        assert_eq!("00:00:00:00:00:01", arp4.sender_hardware_addr().to_string());
678        arp4.set_sender_protocol_addr(Ipv4Addr::new(10, 0, 0, 1));
679        assert_eq!("10.0.0.1", arp4.sender_protocol_addr().to_string());
680        arp4.set_target_hardware_addr(MacAddr::new(0, 0, 0, 0, 0, 2));
681        assert_eq!("00:00:00:00:00:02", arp4.target_hardware_addr().to_string());
682        arp4.set_target_protocol_addr(Ipv4Addr::new(10, 0, 0, 2));
683        assert_eq!("10.0.0.2", arp4.target_protocol_addr().to_string());
684
685        // make sure the ether type is fixed
686        assert_eq!(EtherTypes::Arp, arp4.envelope().ether_type());
687    }
688}