zero_packet/datalink/
arp.rs

1use crate::misc::{bytes_to_mac, IpFormatter};
2use core::{fmt, str::from_utf8};
3
4/// The length of an ARP header in bytes.
5pub const ARP_HEADER_LENGTH: usize = 28;
6
7/// Writes ARP header fields.
8pub struct ArpWriter<'a> {
9    pub bytes: &'a mut [u8],
10}
11
12impl<'a> ArpWriter<'a> {
13    /// Creates a new `ArpWriter` from the given slice.
14    #[inline]
15    pub fn new(bytes: &'a mut [u8]) -> Result<Self, &'static str> {
16        if bytes.len() < ARP_HEADER_LENGTH {
17            return Err("Slice is too short to contain an ARP header.");
18        }
19
20        Ok(Self { bytes })
21    }
22
23    /// Returns the header length in bytes.
24    #[inline]
25    pub fn header_len(&self) -> usize {
26        ARP_HEADER_LENGTH
27    }
28
29    /// Sets the hardware type field.
30    ///
31    /// Specifies the type of hardware used for the network (e.g. Ethernet).
32    #[inline]
33    pub fn set_htype(&mut self, hardware_type: u16) {
34        self.bytes[0] = (hardware_type >> 8) as u8;
35        self.bytes[1] = hardware_type as u8;
36    }
37
38    /// Sets the protocol type field.
39    ///
40    /// Specifies the type of protocol address (e.g. IPv4).
41    #[inline]
42    pub fn set_ptype(&mut self, protocol_type: u16) {
43        self.bytes[2] = (protocol_type >> 8) as u8;
44        self.bytes[3] = protocol_type as u8;
45    }
46
47    /// Sets the hardware length field.
48    ///
49    /// Specifies the length of the hardware address in bytes.
50    #[inline]
51    pub fn set_hlen(&mut self, hardware_address_length: u8) {
52        self.bytes[4] = hardware_address_length;
53    }
54
55    /// Sets the protocol length field.
56    ///
57    /// Specifies the length of the protocol address in bytes.
58    #[inline]
59    pub fn set_plen(&mut self, protocol_address_length: u8) {
60        self.bytes[5] = protocol_address_length;
61    }
62
63    /// Sets the operation field.
64    ///
65    /// Specifies the operation being performed (e.g. request, reply).
66    #[inline]
67    pub fn set_oper(&mut self, operation: u16) {
68        self.bytes[6] = (operation >> 8) as u8;
69        self.bytes[7] = operation as u8;
70    }
71
72    /// Sets the sender hardware address field.
73    ///
74    /// Specifies the hardware address of the sender.
75    #[inline]
76    pub fn set_sha(&mut self, sender_hardware_address: &[u8; 6]) {
77        self.bytes[8] = sender_hardware_address[0];
78        self.bytes[9] = sender_hardware_address[1];
79        self.bytes[10] = sender_hardware_address[2];
80        self.bytes[11] = sender_hardware_address[3];
81        self.bytes[12] = sender_hardware_address[4];
82        self.bytes[13] = sender_hardware_address[5];
83    }
84
85    /// Sets the sender protocol address field.
86    ///
87    /// Specifies the protocol address of the sender.
88    #[inline]
89    pub fn set_spa(&mut self, sender_protocol_address: &[u8; 4]) {
90        self.bytes[14] = sender_protocol_address[0];
91        self.bytes[15] = sender_protocol_address[1];
92        self.bytes[16] = sender_protocol_address[2];
93        self.bytes[17] = sender_protocol_address[3];
94    }
95
96    /// Sets the target hardware address field.
97    ///
98    /// Specifies the hardware address of the receiver.
99    #[inline]
100    pub fn set_tha(&mut self, target_hardware_address: &[u8; 6]) {
101        self.bytes[18] = target_hardware_address[0];
102        self.bytes[19] = target_hardware_address[1];
103        self.bytes[20] = target_hardware_address[2];
104        self.bytes[21] = target_hardware_address[3];
105        self.bytes[22] = target_hardware_address[4];
106        self.bytes[23] = target_hardware_address[5];
107    }
108
109    /// Sets the target protocol address field.
110    ///
111    /// Specifies the protocol address of the receiver.
112    #[inline]
113    pub fn set_tpa(&mut self, target_protocol_address: &[u8; 4]) {
114        self.bytes[24] = target_protocol_address[0];
115        self.bytes[25] = target_protocol_address[1];
116        self.bytes[26] = target_protocol_address[2];
117        self.bytes[27] = target_protocol_address[3];
118    }
119}
120
121/// Reads ARP header fields.
122#[derive(PartialEq)]
123pub struct ArpReader<'a> {
124    pub bytes: &'a [u8],
125}
126
127impl<'a> ArpReader<'a> {
128    /// Creates a new `ArpReader` from the given slice.
129    #[inline]
130    pub fn new(bytes: &'a [u8]) -> Result<Self, &'static str> {
131        if bytes.len() < ARP_HEADER_LENGTH {
132            return Err("Slice is too short to contain an ARP header.");
133        }
134
135        Ok(Self { bytes })
136    }
137
138    /// Returns the hardware type field.
139    ///
140    /// Specifies the type of hardware used for the network (e.g. Ethernet).
141    #[inline]
142    pub fn htype(&self) -> u16 {
143        ((self.bytes[0] as u16) << 8) | (self.bytes[1] as u16)
144    }
145
146    /// Returns the protocol type field.
147    ///
148    /// Specifies the type of protocol address (e.g. IPv4).
149    #[inline]
150    pub fn ptype(&self) -> u16 {
151        ((self.bytes[2] as u16) << 8) | (self.bytes[3] as u16)
152    }
153
154    /// Returns the hardware length field.
155    ///
156    /// Specifies the length of the hardware address in bytes.
157    #[inline]
158    pub fn hlen(&self) -> u8 {
159        self.bytes[4]
160    }
161
162    /// Returns the protocol length field.
163    ///
164    /// Specifies the length of the protocol address in bytes.
165    #[inline]
166    pub fn plen(&self) -> u8 {
167        self.bytes[5]
168    }
169
170    /// Returns the operation field.
171    ///
172    /// Specifies the operation being performed (e.g. request, reply).
173    #[inline]
174    pub fn oper(&self) -> u16 {
175        ((self.bytes[6] as u16) << 8) | (self.bytes[7] as u16)
176    }
177
178    /// Returns the sender hardware address field.
179    ///
180    /// Specifies the hardware address of the sender.
181    #[inline]
182    pub fn sha(&self) -> &[u8] {
183        &self.bytes[8..14]
184    }
185
186    /// Returns the sender protocol address field.
187    ///
188    /// Specifies the protocol address of the sender.
189    #[inline]
190    pub fn spa(&self) -> &[u8] {
191        &self.bytes[14..18]
192    }
193
194    /// Returns the target hardware address field.
195    ///
196    /// Specifies the hardware address of the receiver
197    #[inline]
198    pub fn tha(&self) -> &[u8] {
199        &self.bytes[18..24]
200    }
201
202    /// Returns the target protocol address field.
203    ///
204    /// Specifies the protocol address of the receiver.
205    #[inline]
206    pub fn tpa(&self) -> &[u8] {
207        &self.bytes[24..28]
208    }
209
210    /// Returns the header length in bytes.
211    #[inline]
212    pub fn header_len(&self) -> usize {
213        ARP_HEADER_LENGTH
214    }
215
216    /// Returns a reference to the header.
217    #[inline]
218    pub fn header(&self) -> &'a [u8] {
219        &self.bytes[..ARP_HEADER_LENGTH]
220    }
221
222    /// Returns a reference to the payload.
223    #[inline]
224    pub fn payload(&self) -> &[u8] {
225        &self.bytes[ARP_HEADER_LENGTH..]
226    }
227}
228
229impl fmt::Debug for ArpReader<'_> {
230    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231        let sender_ip = self.spa();
232        let target_ip = self.tpa();
233        let mut sha_buf = [0u8; 18];
234        let sha_len = bytes_to_mac(self.sha(), &mut sha_buf);
235        let sha_hex = from_utf8(&sha_buf[..sha_len]).unwrap();
236        let mut tha_buf = [0u8; 18];
237        let tha_len = bytes_to_mac(self.tha(), &mut tha_buf);
238        let tha_hex = from_utf8(&tha_buf[..tha_len]).unwrap();
239        f.debug_struct("Arp")
240            .field("hardware_type", &self.htype())
241            .field("protocol_type", &self.ptype())
242            .field("hardware_address_length", &self.hlen())
243            .field("protocol_address_length", &self.plen())
244            .field("operation", &self.oper())
245            .field("sender_hardware_address", &sha_hex)
246            .field("sender_protocol_address", &IpFormatter(sender_ip))
247            .field("target_hardware_address", &tha_hex)
248            .field("target_protocol_address", &IpFormatter(target_ip))
249            .finish()
250    }
251}
252
253#[cfg(test)]
254mod tests {
255    use super::*;
256
257    #[test]
258    fn getters_and_setters() {
259        // Raw packet.
260        let mut bytes = [0; 28];
261
262        // Create an ARP writer.
263        let mut writer = ArpWriter::new(&mut bytes).unwrap();
264
265        // Set the ARP header fields.
266        writer.set_htype(1);
267        writer.set_ptype(2);
268        writer.set_hlen(3);
269        writer.set_plen(4);
270        writer.set_oper(5);
271        writer.set_sha(&[6, 7, 8, 9, 10, 11]);
272        writer.set_spa(&[12, 13, 14, 15]);
273        writer.set_tha(&[16, 17, 18, 19, 20, 21]);
274        writer.set_tpa(&[22, 23, 24, 25]);
275
276        // Create an ARP reader.
277        let reader = ArpReader::new(&bytes).unwrap();
278
279        // Ensure the fields are set and retrieved correctly.
280        assert_eq!(reader.ptype(), 2);
281        assert_eq!(reader.htype(), 1);
282        assert_eq!(reader.hlen(), 3);
283        assert_eq!(reader.plen(), 4);
284        assert_eq!(reader.oper(), 5);
285        assert_eq!(reader.sha(), &[6, 7, 8, 9, 10, 11]);
286        assert_eq!(reader.spa(), &[12, 13, 14, 15]);
287        assert_eq!(reader.tha(), &[16, 17, 18, 19, 20, 21]);
288        assert_eq!(reader.tpa(), &[22, 23, 24, 25]);
289    }
290}