1use bytes::{Buf, BufMut, Bytes, BytesMut};
2use nex_core::mac::MacAddr;
3use std::net::Ipv4Addr;
4
5use crate::packet::{GenericMutablePacket, Packet};
6
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10pub const DHCP_MIN_PACKET_SIZE: usize = 236;
13
14#[repr(u8)]
16#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
17#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
18pub enum DhcpOperation {
19 Request = 1,
20 Reply = 2,
21 Unknown(u8),
22}
23
24impl DhcpOperation {
25 pub fn new(value: u8) -> Self {
26 match value {
27 1 => Self::Request,
28 2 => Self::Reply,
29 other => Self::Unknown(other),
30 }
31 }
32
33 pub fn value(&self) -> u8 {
34 match self {
35 Self::Request => 1,
36 Self::Reply => 2,
37 Self::Unknown(v) => *v,
38 }
39 }
40}
41
42#[repr(u8)]
44#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
45#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
46pub enum DhcpHardwareType {
47 Ethernet = 1,
48 ExperimentalEthernet = 2,
49 AmateurRadioAX25 = 3,
50 ProteonProNETTokenRing = 4,
51 Chaos = 5,
52 IEEE802Networks = 6,
53 ARCNET = 7,
54 Hyperchannel = 8,
55 Lanstar = 9,
56 AutonetShortAddress = 10,
57 LocalTalk = 11,
58 LocalNet = 12,
59 UltraLink = 13,
60 SMDS = 14,
61 FrameRelay = 15,
62 ATM = 16,
63 HDLC = 17,
64 FibreChannel = 18,
65 ATM1 = 19,
66 PropPointToPointSerial = 20,
67 PPP = 21,
68 SoftwareLoopback = 24,
69 EON = 25,
70 Ethernet3MB = 26,
71 NSIP = 27,
72 Slip = 28,
73 ULTRALink = 29,
74 DS3 = 30,
75 SIP = 31,
76 FrameRelayInterconnect = 32,
77 ATM2 = 33,
78 MILSTD188220 = 34,
79 Metricom = 35,
80 IEEE1394 = 37,
81 MAPOS = 39,
82 Twinaxial = 40,
83 EUI64 = 41,
84 HIPARP = 42,
85 IPandARPoverISO7816_3 = 43,
86 ARPSec = 44,
87 IPsecTunnel = 45,
88 InfiniBand = 47,
89 TIA102CAI = 48,
90 WiegandInterface = 49,
91 PureIP = 50,
92 HWExp1 = 51,
93 HFI = 52,
94 HWExp2 = 53,
95 AEthernet = 54,
96 HWExp3 = 55,
97 IPsecTransport = 56,
98 SDLCRadio = 57,
99 SDLCMultipoint = 58,
100 IWARP = 59,
101 SixLoWPAN = 61,
102 VLAN = 62,
103 ProviderBridging = 63,
104 IEEE802154 = 64,
105 MAPOSinIPv4 = 65,
106 MAPOSinIPv6 = 66,
107 IEEE802154NonASKPHY = 70,
108 Unknown(u8),
109}
110
111impl DhcpHardwareType {
112 pub fn new(value: u8) -> Self {
113 use DhcpHardwareType::*;
114 match value {
115 1 => Ethernet,
116 2 => ExperimentalEthernet,
117 3 => AmateurRadioAX25,
118 4 => ProteonProNETTokenRing,
119 5 => Chaos,
120 6 => IEEE802Networks,
121 7 => ARCNET,
122 8 => Hyperchannel,
123 9 => Lanstar,
124 10 => AutonetShortAddress,
125 11 => LocalTalk,
126 12 => LocalNet,
127 13 => UltraLink,
128 14 => SMDS,
129 15 => FrameRelay,
130 16 => ATM,
131 17 => HDLC,
132 18 => FibreChannel,
133 19 => ATM1,
134 20 => PropPointToPointSerial,
135 21 => PPP,
136 24 => SoftwareLoopback,
137 25 => EON,
138 26 => Ethernet3MB,
139 27 => NSIP,
140 28 => Slip,
141 29 => ULTRALink,
142 30 => DS3,
143 31 => SIP,
144 32 => FrameRelayInterconnect,
145 33 => ATM2,
146 34 => MILSTD188220,
147 35 => Metricom,
148 37 => IEEE1394,
149 39 => MAPOS,
150 40 => Twinaxial,
151 41 => EUI64,
152 42 => HIPARP,
153 43 => IPandARPoverISO7816_3,
154 44 => ARPSec,
155 45 => IPsecTunnel,
156 47 => InfiniBand,
157 48 => TIA102CAI,
158 49 => WiegandInterface,
159 50 => PureIP,
160 51 => HWExp1,
161 52 => HFI,
162 53 => HWExp2,
163 54 => AEthernet,
164 55 => HWExp3,
165 56 => IPsecTransport,
166 57 => SDLCRadio,
167 58 => SDLCMultipoint,
168 59 => IWARP,
169 61 => SixLoWPAN,
170 62 => VLAN,
171 63 => ProviderBridging,
172 64 => IEEE802154,
173 65 => MAPOSinIPv4,
174 66 => MAPOSinIPv6,
175 70 => IEEE802154NonASKPHY,
176 other => Unknown(other),
177 }
178 }
179
180 pub fn value(&self) -> u8 {
181 match self {
182 DhcpHardwareType::Ethernet => 1,
183 DhcpHardwareType::ExperimentalEthernet => 2,
184 DhcpHardwareType::AmateurRadioAX25 => 3,
185 DhcpHardwareType::ProteonProNETTokenRing => 4,
186 DhcpHardwareType::Chaos => 5,
187 DhcpHardwareType::IEEE802Networks => 6,
188 DhcpHardwareType::ARCNET => 7,
189 DhcpHardwareType::Hyperchannel => 8,
190 DhcpHardwareType::Lanstar => 9,
191 DhcpHardwareType::AutonetShortAddress => 10,
192 DhcpHardwareType::LocalTalk => 11,
193 DhcpHardwareType::LocalNet => 12,
194 DhcpHardwareType::UltraLink => 13,
195 DhcpHardwareType::SMDS => 14,
196 DhcpHardwareType::FrameRelay => 15,
197 DhcpHardwareType::ATM => 16,
198 DhcpHardwareType::HDLC => 17,
199 DhcpHardwareType::FibreChannel => 18,
200 DhcpHardwareType::ATM1 => 19,
201 DhcpHardwareType::PropPointToPointSerial => 20,
202 DhcpHardwareType::PPP => 21,
203 DhcpHardwareType::SoftwareLoopback => 24,
204 DhcpHardwareType::EON => 25,
205 DhcpHardwareType::Ethernet3MB => 26,
206 DhcpHardwareType::NSIP => 27,
207 DhcpHardwareType::Slip => 28,
208 DhcpHardwareType::ULTRALink => 29,
209 DhcpHardwareType::DS3 => 30,
210 DhcpHardwareType::SIP => 31,
211 DhcpHardwareType::FrameRelayInterconnect => 32,
212 DhcpHardwareType::ATM2 => 33,
213 DhcpHardwareType::MILSTD188220 => 34,
214 DhcpHardwareType::Metricom => 35,
215 DhcpHardwareType::IEEE1394 => 37,
216 DhcpHardwareType::MAPOS => 39,
217 DhcpHardwareType::Twinaxial => 40,
218 DhcpHardwareType::EUI64 => 41,
219 DhcpHardwareType::HIPARP => 42,
220 DhcpHardwareType::IPandARPoverISO7816_3 => 43,
221 DhcpHardwareType::ARPSec => 44,
222 DhcpHardwareType::IPsecTunnel => 45,
223 DhcpHardwareType::InfiniBand => 47,
224 DhcpHardwareType::TIA102CAI => 48,
225 DhcpHardwareType::WiegandInterface => 49,
226 DhcpHardwareType::PureIP => 50,
227 DhcpHardwareType::HWExp1 => 51,
228 DhcpHardwareType::HFI => 52,
229 DhcpHardwareType::HWExp2 => 53,
230 DhcpHardwareType::AEthernet => 54,
231 DhcpHardwareType::HWExp3 => 55,
232 DhcpHardwareType::IPsecTransport => 56,
233 DhcpHardwareType::SDLCRadio => 57,
234 DhcpHardwareType::SDLCMultipoint => 58,
235 DhcpHardwareType::IWARP => 59,
236 DhcpHardwareType::SixLoWPAN => 61,
237 DhcpHardwareType::VLAN => 62,
238 DhcpHardwareType::ProviderBridging => 63,
239 DhcpHardwareType::IEEE802154 => 64,
240 DhcpHardwareType::MAPOSinIPv4 => 65,
241 DhcpHardwareType::MAPOSinIPv6 => 66,
242 DhcpHardwareType::IEEE802154NonASKPHY => 70,
243 DhcpHardwareType::Unknown(n) => *n,
244 }
245 }
246}
247
248#[derive(Clone, Debug, PartialEq, Eq)]
249#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
250pub struct DhcpHeader {
251 pub op: DhcpOperation,
252 pub htype: DhcpHardwareType,
253 pub hlen: u8,
254 pub hops: u8,
255 pub xid: u32,
256 pub secs: u16,
257 pub flags: u16,
258 pub ciaddr: Ipv4Addr,
259 pub yiaddr: Ipv4Addr,
260 pub siaddr: Ipv4Addr,
261 pub giaddr: Ipv4Addr,
262 pub chaddr: MacAddr,
263 pub chaddr_pad: Vec<u8>,
265 pub sname: Vec<u8>,
267 pub file: Vec<u8>,
269}
270
271#[derive(Clone, Debug, PartialEq, Eq)]
272pub struct DhcpPacket {
273 pub header: DhcpHeader,
274 pub payload: Bytes,
275}
276
277impl Packet for DhcpPacket {
278 type Header = DhcpHeader;
279
280 fn from_buf(mut bytes: &[u8]) -> Option<Self> {
281 if bytes.len() < DHCP_MIN_PACKET_SIZE {
282 return None;
283 }
284
285 let op = DhcpOperation::new(bytes.get_u8());
286 let htype = DhcpHardwareType::new(bytes.get_u8());
287 let hlen = bytes.get_u8();
288 let hops = bytes.get_u8();
289 let xid = bytes.get_u32();
290 let secs = bytes.get_u16();
291 let flags = bytes.get_u16();
292
293 let ciaddr = Ipv4Addr::from(bytes.get_u32());
294 let yiaddr = Ipv4Addr::from(bytes.get_u32());
295 let siaddr = Ipv4Addr::from(bytes.get_u32());
296 let giaddr = Ipv4Addr::from(bytes.get_u32());
297
298 let mut chaddr = [0u8; 6];
299 bytes.copy_to_slice(&mut chaddr);
300 let chaddr = MacAddr::from_octets(chaddr);
301
302 let mut chaddr_pad = [0u8; 10];
303 bytes.copy_to_slice(&mut chaddr_pad);
304
305 let mut sname = [0u8; 64];
306 bytes.copy_to_slice(&mut sname);
307
308 let mut file = [0u8; 128];
309 bytes.copy_to_slice(&mut file);
310
311 let header = DhcpHeader {
312 op,
313 htype,
314 hlen,
315 hops,
316 xid,
317 secs,
318 flags,
319 ciaddr,
320 yiaddr,
321 siaddr,
322 giaddr,
323 chaddr,
324 chaddr_pad: chaddr_pad.to_vec(),
325 sname: sname.to_vec(),
326 file: file.to_vec(),
327 };
328
329 Some(Self {
330 header,
331 payload: Bytes::copy_from_slice(bytes),
332 })
333 }
334
335 fn from_bytes(bytes: Bytes) -> Option<Self> {
336 Self::from_buf(&bytes)
337 }
338
339 fn to_bytes(&self) -> Bytes {
340 let mut buf = BytesMut::with_capacity(DHCP_MIN_PACKET_SIZE + self.payload.len());
341
342 buf.put_u8(self.header.op.value());
343 buf.put_u8(self.header.htype.value());
344 buf.put_u8(self.header.hlen);
345 buf.put_u8(self.header.hops);
346 buf.put_u32(self.header.xid);
347 buf.put_u16(self.header.secs);
348 buf.put_u16(self.header.flags);
349
350 buf.put_slice(&self.header.ciaddr.octets());
351 buf.put_slice(&self.header.yiaddr.octets());
352 buf.put_slice(&self.header.siaddr.octets());
353 buf.put_slice(&self.header.giaddr.octets());
354
355 buf.put_slice(&self.header.chaddr.octets());
356 buf.put_slice(&self.header.chaddr_pad);
357 buf.put_slice(&self.header.sname);
358 buf.put_slice(&self.header.file);
359
360 buf.extend_from_slice(&self.payload);
361
362 buf.freeze()
363 }
364 fn header(&self) -> Bytes {
365 let mut buf = BytesMut::with_capacity(DHCP_MIN_PACKET_SIZE);
366
367 buf.put_u8(self.header.op.value());
368 buf.put_u8(self.header.htype.value());
369 buf.put_u8(self.header.hlen);
370 buf.put_u8(self.header.hops);
371 buf.put_u32(self.header.xid);
372 buf.put_u16(self.header.secs);
373 buf.put_u16(self.header.flags);
374
375 buf.put_slice(&self.header.ciaddr.octets());
376 buf.put_slice(&self.header.yiaddr.octets());
377 buf.put_slice(&self.header.siaddr.octets());
378 buf.put_slice(&self.header.giaddr.octets());
379
380 buf.put_slice(&self.header.chaddr.octets());
381 buf.put_slice(&self.header.chaddr_pad);
382 buf.put_slice(&self.header.sname);
383 buf.put_slice(&self.header.file);
384
385 buf.freeze()
386 }
387
388 fn payload(&self) -> Bytes {
389 self.payload.clone()
390 }
391
392 fn header_len(&self) -> usize {
393 DHCP_MIN_PACKET_SIZE
394 }
395
396 fn payload_len(&self) -> usize {
397 self.payload.len()
398 }
399
400 fn total_len(&self) -> usize {
401 self.header_len() + self.payload_len()
402 }
403
404 fn into_parts(self) -> (Self::Header, Bytes) {
405 (self.header, self.payload)
406 }
407}
408
409pub type MutableDhcpPacket<'a> = GenericMutablePacket<'a, DhcpPacket>;
411
412#[cfg(test)]
413mod tests {
414 use super::*;
415 use crate::packet::MutablePacket;
416 use nex_core::mac::MacAddr;
417
418 #[test]
419 fn test_dhcp_packet_from_bytes_and_to_bytes() {
420 let raw = {
421 let mut buf = BytesMut::with_capacity(DHCP_MIN_PACKET_SIZE);
422 buf.put_u8(1); buf.put_u8(1); buf.put_u8(6); buf.put_u8(0); buf.put_u32(0x12345678); buf.put_u16(0); buf.put_u16(0); buf.put_slice(&[0, 0, 0, 0]); buf.put_slice(&[0, 0, 0, 0]); buf.put_slice(&[0, 0, 0, 0]); buf.put_slice(&[0, 0, 0, 0]); buf.put_slice(&[0x00, 0x11, 0x22, 0x33, 0x44, 0x55]); buf.extend_from_slice(&[0u8; 10]); buf.extend_from_slice(&[0u8; 64]); buf.extend_from_slice(&[0u8; 128]); buf.freeze()
438 };
439
440 let packet = DhcpPacket::from_bytes(raw.clone()).expect("Failed to parse DHCP packet");
441
442 assert_eq!(packet.header.op, DhcpOperation::Request);
443 assert_eq!(packet.header.htype, DhcpHardwareType::Ethernet);
444 assert_eq!(packet.header.hlen, 6);
445 assert_eq!(packet.header.xid, 0x12345678);
446 assert_eq!(
447 packet.header.chaddr,
448 MacAddr::new(0x00, 0x11, 0x22, 0x33, 0x44, 0x55)
449 );
450
451 let rebuilt = packet.to_bytes();
452 assert_eq!(rebuilt, raw);
453 }
454
455 #[test]
456 fn test_mutable_dhcp_packet_alias() {
457 let mut raw = [0u8; DHCP_MIN_PACKET_SIZE + 4];
458 raw[0] = DhcpOperation::Request.value();
459 raw[1] = DhcpHardwareType::Ethernet.value();
460 raw[2] = 6; let mut packet = <MutableDhcpPacket as MutablePacket>::new(&mut raw).expect("mutable dhcp");
463 packet.header_mut()[0] = DhcpOperation::Reply.value();
464 packet.payload_mut()[0] = 0xaa;
465
466 let frozen = packet.freeze().expect("freeze");
467 assert_eq!(frozen.header.op, DhcpOperation::Reply);
468 assert_eq!(frozen.payload[0], 0xaa);
469 }
470}