Thanks to visit codestin.com
Credit goes to docs.rs

etherparse/net/
arp_eth_ipv4_packet.rs

1use core::net::Ipv4Addr;
2
3use crate::{ArpHardwareId, EtherType};
4
5use super::{ArpOperation, ArpPacket};
6
7/// An ethernet & IPv4 "Address Resolution Protocol" Packet (a specific
8/// version of [`crate::ArpPacket`]).
9#[derive(Clone, Debug, PartialEq, Eq, Hash)]
10pub struct ArpEthIpv4Packet {
11    /// Specifies the operation that the sender is performing.
12    pub operation: ArpOperation,
13
14    /// Sender MAC address.
15    pub sender_mac: [u8; 6],
16
17    /// Sender IPv4 address.
18    pub sender_ipv4: [u8; 4],
19
20    /// Sender MAC address.
21    pub target_mac: [u8; 6],
22
23    /// Target IPv4 address.
24    pub target_ipv4: [u8; 4],
25}
26
27impl ArpEthIpv4Packet {
28    /// Number of octets/bytes of the serialized packet.
29    pub const LEN: usize = 8 + 6 * 2 + 4 * 2;
30
31    /// Sender IPv4 address as [`core::net::Ipv4Addr`].
32    #[inline]
33    pub const fn sender_ipv4_addr(&self) -> Ipv4Addr {
34        Ipv4Addr::new(
35            self.sender_ipv4[0],
36            self.sender_ipv4[1],
37            self.sender_ipv4[2],
38            self.sender_ipv4[3],
39        )
40    }
41
42    /// Target IPv4 address as [`core::net::Ipv4Addr`].
43    #[inline]
44    pub const fn target_ipv4_addr(&self) -> Ipv4Addr {
45        Ipv4Addr::new(
46            self.target_ipv4[0],
47            self.target_ipv4[1],
48            self.target_ipv4[2],
49            self.target_ipv4[3],
50        )
51    }
52
53    /// Returns the serialized header.
54    pub const fn to_bytes(&self) -> [u8; Self::LEN] {
55        const ETH_HW_TYPE: [u8; 2] = ArpHardwareId::ETHERNET.0.to_be_bytes();
56        const IPV4_ETH_TYPE: [u8; 2] = EtherType::IPV4.0.to_be_bytes();
57        let op = self.operation.0.to_be_bytes();
58        [
59            ETH_HW_TYPE[0],
60            ETH_HW_TYPE[1],
61            IPV4_ETH_TYPE[0],
62            IPV4_ETH_TYPE[1],
63            6,
64            4,
65            op[0],
66            op[1],
67            self.sender_mac[0],
68            self.sender_mac[1],
69            self.sender_mac[2],
70            self.sender_mac[3],
71            self.sender_mac[4],
72            self.sender_mac[5],
73            self.sender_ipv4[0],
74            self.sender_ipv4[1],
75            self.sender_ipv4[2],
76            self.sender_ipv4[3],
77            self.target_mac[0],
78            self.target_mac[1],
79            self.target_mac[2],
80            self.target_mac[3],
81            self.target_mac[4],
82            self.target_mac[5],
83            self.target_ipv4[0],
84            self.target_ipv4[1],
85            self.target_ipv4[2],
86            self.target_ipv4[3],
87        ]
88    }
89
90    /// Converts the packet to generic arp packet.
91    #[inline]
92    pub const fn to_arp_packet(&self) -> ArpPacket {
93        // SAFETY: This is safe as
94        // * Both the hardware addresses have matching length 6 which is bellow the max of 255.
95        // * Both the protocol addresses have matching length 6 which is bellow the max of 255.
96        unsafe {
97            ArpPacket::new_unchecked(
98                ArpHardwareId::ETHERNET,
99                EtherType::IPV4,
100                self.operation,
101                &self.sender_mac,
102                &self.sender_ipv4,
103                &self.target_mac,
104                &self.target_ipv4,
105            )
106        }
107    }
108}
109
110impl From<ArpEthIpv4Packet> for ArpPacket {
111    fn from(value: ArpEthIpv4Packet) -> Self {
112        value.to_arp_packet()
113    }
114}
115
116impl TryFrom<ArpPacket> for ArpEthIpv4Packet {
117    type Error = crate::err::arp::ArpEthIpv4FromError;
118
119    fn try_from(value: ArpPacket) -> Result<Self, Self::Error> {
120        value.try_eth_ipv4()
121    }
122}
123
124#[cfg(test)]
125mod tests {
126    use super::*;
127    use crate::test_gens::*;
128    use proptest::prelude::*;
129
130    proptest! {
131        #[test]
132        fn sender_ipv4_addr(
133            arp in arp_eth_ipv4_packet_any()
134        ) {
135            assert_eq!(
136                arp.sender_ipv4_addr(),
137                Ipv4Addr::new(
138                    arp.sender_ipv4[0],
139                    arp.sender_ipv4[1],
140                    arp.sender_ipv4[2],
141                    arp.sender_ipv4[3]
142                )
143            )
144        }
145    }
146
147    proptest! {
148        #[test]
149        fn target_ipv4_addr(
150            arp in arp_eth_ipv4_packet_any()
151        ) {
152            assert_eq!(
153                arp.target_ipv4_addr(),
154                Ipv4Addr::new(
155                    arp.target_ipv4[0],
156                    arp.target_ipv4[1],
157                    arp.target_ipv4[2],
158                    arp.target_ipv4[3]
159                )
160            )
161        }
162    }
163
164    proptest! {
165        #[test]
166        fn to_bytes(
167            arp in arp_eth_ipv4_packet_any()
168        ) {
169            assert_eq!(
170                &arp.to_bytes()[..],
171                &arp.to_arp_packet().to_bytes()[..]
172            );
173        }
174    }
175
176    proptest! {
177        #[test]
178        fn to_arp_packet(
179            arp in arp_eth_ipv4_packet_any()
180        ) {
181            let actual = arp.to_arp_packet();
182            assert_eq!(ArpHardwareId::ETHERNET, actual.hw_addr_type);
183            assert_eq!(EtherType::IPV4, actual.proto_addr_type);
184            assert_eq!(6, actual.hw_addr_size());
185            assert_eq!(4, actual.protocol_addr_size());
186            assert_eq!(&arp.target_mac[..], actual.target_hw_addr());
187            assert_eq!(&arp.target_ipv4[..], actual.target_protocol_addr());
188            assert_eq!(&arp.sender_mac[..], actual.sender_hw_addr());
189            assert_eq!(&arp.sender_ipv4[..], actual.sender_protocol_addr());
190        }
191    }
192
193    proptest! {
194        #[test]
195        fn into_arp_packet(
196            arp in arp_eth_ipv4_packet_any()
197        ) {
198            let actual = ArpPacket::from(arp.clone());
199            assert_eq!(actual, arp.to_arp_packet());
200        }
201    }
202
203    proptest! {
204        #[test]
205        fn try_from_arp_packet(
206            arp in arp_packet_any()
207        ) {
208            let actual = ArpEthIpv4Packet::try_from(arp.clone());
209            assert_eq!(actual, arp.clone().try_eth_ipv4());
210        }
211    }
212}