1use alloc::vec;
4use alloc::vec::Vec;
5
6use crate::types::{ArpHardwareType, ArpOperation, EtherType};
7use crate::util::{read_u16be, BuildError};
8
9pub const ARP_HEADER_LEN: usize = 28;
11
12#[derive(Debug, Clone)]
14pub struct ArpPacket<'a> {
15 buf: &'a [u8],
16}
17
18impl<'a> ArpPacket<'a> {
19 crate::parser_new!(ARP_HEADER_LEN);
20
21 #[inline]
23 pub fn as_bytes(&self) -> &'a [u8] { self.buf }
24
25 #[inline]
26 pub fn hardware_type(&self) -> ArpHardwareType {
27 ArpHardwareType::from(read_u16be(&self.buf[..2]))
28 }
29
30 #[inline]
31 pub fn protocol_type(&self) -> EtherType {
32 EtherType::from(read_u16be(&self.buf[2..4]))
33 }
34
35 #[inline]
36 pub fn hw_addr_len(&self) -> u8 {
37 self.buf[4]
38 }
39
40 #[inline]
41 pub fn proto_addr_len(&self) -> u8 {
42 self.buf[5]
43 }
44
45 #[inline]
46 pub fn operation(&self) -> ArpOperation {
47 ArpOperation::from(read_u16be(&self.buf[6..8]))
48 }
49
50 #[inline]
51 pub fn sender_hw_addr(&self) -> &'a [u8] {
52 let len = self.hw_addr_len() as usize;
53 &self.buf[8..8 + len]
54 }
55
56 #[inline]
57 pub fn sender_proto_addr(&self) -> &'a [u8] {
58 let hw_len = self.hw_addr_len() as usize;
59 let start = 8 + hw_len;
60 let len = self.proto_addr_len() as usize;
61 &self.buf[start..start + len]
62 }
63
64 #[inline]
65 pub fn target_hw_addr(&self) -> &'a [u8] {
66 let hw_len = self.hw_addr_len() as usize;
67 let proto_len = self.proto_addr_len() as usize;
68 let start = 8 + hw_len + proto_len;
69 &self.buf[start..start + hw_len]
70 }
71
72 #[inline]
73 pub fn target_proto_addr(&self) -> &'a [u8] {
74 let hw_len = self.hw_addr_len() as usize;
75 let proto_len = self.proto_addr_len() as usize;
76 let start = 8 + hw_len + proto_len + hw_len;
77 &self.buf[start..start + proto_len]
78 }
79
80 #[inline]
81 pub fn is_request(&self) -> bool {
82 self.operation() == ArpOperation::Request
83 }
84
85 #[inline]
86 pub fn is_reply(&self) -> bool {
87 self.operation() == ArpOperation::Reply
88 }
89}
90
91#[derive(Debug, Clone)]
97pub struct ArpPacketBuilder {
98 hw_type: u16,
99 proto_type: u16,
100 hw_addr_len: u8,
101 proto_addr_len: u8,
102 operation: u16,
103 sender_hw: Vec<u8>,
104 sender_proto: Vec<u8>,
105 target_hw: Vec<u8>,
106 target_proto: Vec<u8>,
107}
108
109impl Default for ArpPacketBuilder {
110 fn default() -> Self {
111 Self::new()
112 }
113}
114
115impl ArpPacketBuilder {
116 pub fn new() -> Self {
118 Self {
119 hw_type: 1, proto_type: 0x0800, hw_addr_len: 6,
122 proto_addr_len: 4,
123 operation: 1, sender_hw: vec![0u8; 6],
125 sender_proto: vec![0u8; 4],
126 target_hw: vec![0u8; 6],
127 target_proto: vec![0u8; 4],
128 }
129 }
130
131 pub fn hardware_type(mut self, ht: ArpHardwareType) -> Self {
132 self.hw_type = ht.into();
133 self
134 }
135
136 pub fn protocol_type(mut self, pt: EtherType) -> Self {
137 self.proto_type = pt.into();
138 self
139 }
140
141 pub fn operation(mut self, op: ArpOperation) -> Self {
142 self.operation = op.into();
143 self
144 }
145
146 pub fn sender_hw_addr(mut self, addr: &[u8]) -> Result<Self, BuildError> {
147 if addr.len() as u8 != self.hw_addr_len {
148 return Err(BuildError::InvalidField {
149 field: "sender_hw_addr",
150 reason: "length mismatch",
151 });
152 }
153 self.sender_hw = addr.to_vec();
154 Ok(self)
155 }
156
157 pub fn sender_proto_addr(mut self, addr: &[u8]) -> Result<Self, BuildError> {
158 if addr.len() as u8 != self.proto_addr_len {
159 return Err(BuildError::InvalidField {
160 field: "sender_proto_addr",
161 reason: "length mismatch",
162 });
163 }
164 self.sender_proto = addr.to_vec();
165 Ok(self)
166 }
167
168 pub fn target_hw_addr(mut self, addr: &[u8]) -> Result<Self, BuildError> {
169 if addr.len() as u8 != self.hw_addr_len {
170 return Err(BuildError::InvalidField {
171 field: "target_hw_addr",
172 reason: "length mismatch",
173 });
174 }
175 self.target_hw = addr.to_vec();
176 Ok(self)
177 }
178
179 pub fn target_proto_addr(mut self, addr: &[u8]) -> Result<Self, BuildError> {
180 if addr.len() as u8 != self.proto_addr_len {
181 return Err(BuildError::InvalidField {
182 field: "target_proto_addr",
183 reason: "length mismatch",
184 });
185 }
186 self.target_proto = addr.to_vec();
187 Ok(self)
188 }
189
190 pub fn build(self) -> Vec<u8> {
191 let total = 8 + self.sender_hw.len() + self.sender_proto.len()
192 + self.target_hw.len() + self.target_proto.len();
193 let mut buf = Vec::with_capacity(total);
194
195 buf.extend_from_slice(&self.hw_type.to_be_bytes());
196 buf.extend_from_slice(&self.proto_type.to_be_bytes());
197 buf.push(self.hw_addr_len);
198 buf.push(self.proto_addr_len);
199 buf.extend_from_slice(&self.operation.to_be_bytes());
200 buf.extend_from_slice(&self.sender_hw);
201 buf.extend_from_slice(&self.sender_proto);
202 buf.extend_from_slice(&self.target_hw);
203 buf.extend_from_slice(&self.target_proto);
204
205 buf
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use super::*;
212
213 const SAMPLE_ARP_REQUEST: &[u8] = &[
215 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xC0, 0xA8, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8, 0x01, 0x02, ];
225
226 #[test]
227 fn parse_arp_request() {
228 let pkt = ArpPacket::new(SAMPLE_ARP_REQUEST).unwrap();
229 assert_eq!(pkt.hardware_type(), ArpHardwareType::Ethernet);
230 assert_eq!(pkt.protocol_type(), EtherType::Ipv4);
231 assert!(pkt.is_request());
232 assert!(!pkt.is_reply());
233 assert_eq!(pkt.sender_hw_addr(), &[0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
234 assert_eq!(pkt.sender_proto_addr(), &[192, 168, 1, 1]);
235 assert_eq!(pkt.target_hw_addr(), &[0u8; 6]);
236 assert_eq!(pkt.target_proto_addr(), &[192, 168, 1, 2]);
237 }
238
239 #[test]
240 fn parse_too_short() {
241 assert!(ArpPacket::new(&[0u8; 27]).is_none());
242 assert!(ArpPacket::new(&[]).is_none());
243 }
244
245 #[test]
246 fn build_and_parse_roundtrip() {
247 let buf = ArpPacketBuilder::new()
248 .operation(ArpOperation::Reply)
249 .sender_hw_addr(&[0x11, 0x22, 0x33, 0x44, 0x55, 0x66])
250 .unwrap()
251 .sender_proto_addr(&[10, 0, 0, 1])
252 .unwrap()
253 .target_hw_addr(&[0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF])
254 .unwrap()
255 .target_proto_addr(&[10, 0, 0, 2])
256 .unwrap()
257 .build();
258
259 let pkt = ArpPacket::new(&buf).unwrap();
260 assert!(pkt.is_reply());
261 assert_eq!(pkt.sender_hw_addr(), &[0x11, 0x22, 0x33, 0x44, 0x55, 0x66]);
262 assert_eq!(pkt.target_proto_addr(), &[10, 0, 0, 2]);
263 }
264}