1use core::convert::TryInto as _;
4
5use std::collections::HashMap;
6use std::sync::{OnceLock, RwLock};
7
8use serde::Serialize;
9
10use crate::errors::Error;
11use crate::types::{IPv4Address, LayerCreatorFn};
12use crate::Layer;
13
14pub const IPV4_BASE_HEADER_LENGTH: usize = 20_usize;
16
17pub const IPV4_OPTION_EOOL: u8 = 0;
18pub const IPV4_OPTION_NOP: u8 = 1;
19pub const IPV4_OPTION_RR: u8 = 7;
20pub const IPV4_OPTION_MTUP: u8 = 11;
21pub const IPV4_OPTION_MTUR: u8 = 12;
22
23pub const IPPROTO_RAW: u8 = 0xFF;
24
25fn get_protocol_map() -> &'static RwLock<HashMap<u8, LayerCreatorFn>> {
26 static PROTOCOLS_MAP: OnceLock<RwLock<HashMap<u8, LayerCreatorFn>>> = OnceLock::new();
27 PROTOCOLS_MAP.get_or_init(|| RwLock::new(HashMap::new()))
28}
29
30pub(crate) fn register_defaults() -> Result<(), Error> {
34 use crate::layers::ethernet::register_ethertype;
35
36 get_protocol_map();
37
38 register_ethertype(crate::types::ETHERTYPE_IP, IPv4::creator)?;
39
40 Ok(())
41}
42
43pub fn register_protocol(proto: u8, creator: LayerCreatorFn) -> Result<(), Error> {
50 let mut map = get_protocol_map().write().unwrap();
51 if map.contains_key(&proto) {
52 return Err(Error::RegisterError(format!("proto: {}", proto)));
53 }
54 map.insert(proto, creator);
55
56 Ok(())
57}
58
59#[derive(Debug, Serialize, PartialEq)]
60#[serde(tag = "type")]
61pub enum IPOption {
62 EOOL,
63 NOP,
64 RR {
65 len: u8,
66 ptr: u8,
67 route: Vec<IPv4Address>,
68 },
69 MTUP {
70 len: u8,
71 value: u16,
72 },
73 MTUR {
74 len: u8,
75 value: u16,
76 },
77 Other {
78 value: u8,
79 len: u8,
80 data: Vec<u8>,
81 },
82}
83
84#[derive(Debug, Default, Serialize)]
85pub struct IPv4 {
86 version: u8,
87 hdr_len: u8,
88 tos: u8,
89 len: u16,
90 #[serde(serialize_with = "crate::types::hex::serialize_lower_hex_u16")]
91 id: u16,
92 #[serde(serialize_with = "crate::types::hex::serialize_lower_hex_u8")]
93 flags: u8,
94 frag_offset: u16,
95 ttl: u8,
96 proto: u8,
97 #[serde(serialize_with = "crate::types::hex::serialize_lower_hex_u16")]
98 checksum: u16,
99 src_addr: IPv4Address,
100 dst_addr: IPv4Address,
101 #[serde(skip_serializing_if = "Vec::is_empty")]
102 options: Vec<IPOption>,
103}
104
105impl IPv4 {
106 pub fn new() -> Self {
107 Self {
108 version: 4,
109 hdr_len: (IPV4_BASE_HEADER_LENGTH / 4) as u8,
110 proto: IPPROTO_RAW,
111 len: IPV4_BASE_HEADER_LENGTH as u16,
112 ..Default::default()
113 }
114 }
115
116 pub(crate) fn creator() -> Box<dyn Layer + Send> {
117 Box::<IPv4>::default()
118 }
119}
120
121impl IPv4 {
122 fn options_from_bytes(&mut self, bytes: &[u8], mut remaining: usize) -> Result<usize, Error> {
123 let mut i = 0_usize;
124 let max_option_bytes = self.hdr_len as usize * 4 - IPV4_BASE_HEADER_LENGTH;
125 let mut done = i >= max_option_bytes;
126
127 while !done {
128 let (option, consumed) = Self::option_from_bytes(&bytes[i..], remaining)?;
129 i += consumed;
130 remaining -= consumed;
131 if i >= max_option_bytes || option == IPOption::EOOL {
132 done = true;
133 }
134 self.options.push(option);
135 }
136
137 Ok(i)
138 }
139
140 fn option_from_bytes(bytes: &[u8], remaining: usize) -> Result<(IPOption, usize), Error> {
141 let mut i = 0_usize;
142
143 if remaining < 1 {
144 return Err(Error::TooShort {
145 required: 2,
146 available: remaining,
147 data: hex::encode(bytes),
148 });
149 }
150
151 let value = bytes[0];
152
153 let option = match value {
155 IPV4_OPTION_EOOL => {
156 i += 1;
157 IPOption::EOOL
159 }
160 IPV4_OPTION_NOP => {
161 i += 1;
162 IPOption::NOP
164 }
165 IPV4_OPTION_RR => {
166 let ((len, data), consumed) = Self::option_data_from_bytes(&bytes[i..], remaining)?;
167 i += consumed;
168 let ptr = data[0];
171 let mut route = Vec::new();
172
173 {
174 let ptr = ptr as usize - 3;
176 let mut i = 1_usize;
177 while i + 2 < len as usize && i < ptr {
179 let addr = data[i..i + 4].try_into().unwrap();
180 route.push(addr);
181 i += 4;
182 }
183 }
184
185 IPOption::RR { len, ptr, route }
186 }
187 IPV4_OPTION_MTUP | IPV4_OPTION_MTUR => {
188 let ((len, data), consumed) = Self::option_data_from_bytes(&bytes[i..], remaining)?;
189 i += consumed;
190 if len < 4 {
193 return Err(Error::TooShort {
194 required: 4,
195 available: len.into(),
196 data: hex::encode(data),
197 });
198 }
199
200 let mtu = u16::from_be_bytes(data[0..2].try_into().unwrap());
201
202 match value {
203 IPV4_OPTION_MTUP => IPOption::MTUP { len, value: mtu },
204 IPV4_OPTION_MTUR => IPOption::MTUR { len, value: mtu },
205 _ => unreachable!("Value should either be 11 or 12"),
206 }
207 }
208 value => {
209 let ((len, data), consumed) = Self::option_data_from_bytes(&bytes[i..], remaining)?;
210 i += consumed;
211 IPOption::Other {
214 value,
215 len,
216 data: data.into(),
217 }
218 }
219 };
220
221 Ok((option, i))
222 }
223
224 fn option_data_from_bytes(
225 bytes: &[u8],
226 mut remaining: usize,
227 ) -> Result<((u8, &[u8]), usize), Error> {
228 let mut i = 1_usize;
230 remaining -= 1;
231 if remaining < 1 {
233 return Err(Error::TooShort {
234 required: 1,
235 available: remaining,
236 data: hex::encode(bytes),
237 });
238 }
239 let len = bytes[i] as usize;
241 i += 1;
242 remaining -= 1;
243
244 if remaining + 2 < len {
245 return Err(Error::TooShort {
246 required: len,
247 available: remaining + 2,
248 data: hex::encode(bytes),
249 });
250 }
251 let data = &bytes[i..i + len - 2];
252 i += len - 2;
253 Ok(((len as u8, data), i))
256 }
257
258 #[cfg(feature = "sculpting")]
259 fn calculate_checksum(_bytes: &[u8]) -> u16 {
260 0
261 }
262}
263
264impl Layer for IPv4 {
265 fn decode_bytes(
266 &mut self,
267 bytes: &[u8],
268 ) -> Result<(Option<Box<dyn Layer + Send>>, usize), Error> {
269 let mut decoded = 0_usize;
270 let mut remaining = bytes.len();
271
272 self.version = bytes[0] >> 4;
273 self.hdr_len = bytes[0] & 0x0f;
274 if bytes.len() < (self.hdr_len * 4).into() {
276 return Err(Error::TooShort {
277 required: self.hdr_len as usize * 4,
278 available: bytes.len(),
279 data: hex::encode(bytes),
280 });
281 }
282 self.tos = bytes[1];
283 self.len = u16::from_be_bytes(bytes[2..4].try_into().unwrap());
284 self.id = u16::from_be_bytes(bytes[4..6].try_into().unwrap());
285 let flags_offset = u16::from_be_bytes(bytes[6..8].try_into().unwrap());
286 self.flags = (flags_offset >> 13) as u8;
287 self.frag_offset = flags_offset & 0x1fff;
288 self.ttl = bytes[8];
289 self.proto = bytes[9];
290 self.checksum = u16::from_be_bytes(bytes[10..12].try_into().unwrap());
291 self.src_addr = bytes[12..16].try_into().unwrap();
292 self.dst_addr = bytes[16..20].try_into().unwrap();
293
294 decoded += IPV4_BASE_HEADER_LENGTH;
295 remaining -= IPV4_BASE_HEADER_LENGTH;
296
297 if bytes.len() < self.hdr_len as usize * 4 {
299 return Err(Error::TooShort {
300 required: self.hdr_len as usize * 4,
301 available: bytes.len(),
302 data: hex::encode(bytes),
303 });
304 }
305
306 let consumed = self.options_from_bytes(&bytes[decoded..], remaining)?;
307 decoded += consumed;
308 let map = get_protocol_map().read().unwrap();
310 let layer = map.get(&self.proto);
311
312 match layer {
313 None => Ok((None, decoded)),
314 Some(l4_creator) => Ok((Some(l4_creator()), decoded)),
315 }
316 }
317
318 fn name(&self) -> &'static str {
319 "IPv4"
320 }
321
322 fn short_name(&self) -> &'static str {
323 "ip"
324 }
325
326 #[cfg(feature = "sculpting")]
327 fn stack_and_encode(
328 &mut self,
329 next_layer: Option<&[u8]>,
330 info: &str,
331 ) -> Result<Vec<u8>, Error> {
332 self.len = self.hdr_len as u16 * 4 + next_layer.unwrap_or_default().len() as u16;
333 self.proto = match info {
334 "raw" => IPPROTO_RAW,
335 _ => self.proto,
336 };
337
338 let mut result = Vec::with_capacity(self.len as usize);
339
340 let byte = (self.version << 4) | self.hdr_len;
341 result.push(byte);
342 result.push(self.tos);
343 result.extend(self.len.to_be_bytes());
344 result.extend(self.id.to_be_bytes());
345
346 let word = (self.flags as u16) << 13 | self.frag_offset;
347 result.extend(word.to_be_bytes());
348 result.push(self.ttl);
349 result.push(self.proto);
350
351 let checksum_start = result.len();
352 result.extend(self.checksum.to_be_bytes());
353 result.extend(self.src_addr.as_slice());
354 result.extend(self.dst_addr.as_slice());
355
356 if !self.options.is_empty() {
357 todo!();
358 }
359
360 result.extend(next_layer.unwrap_or_default());
361
362 let checksum = IPv4::calculate_checksum(&result);
363 result[checksum_start..checksum_start + 2].copy_from_slice(&checksum.to_be_bytes());
364 Ok(result)
365 }
366}
367
368#[cfg(test)]
369mod tests {
370 use crate::{layers, Layer};
371
372 fn test_options(packet: &[u8], options: &[super::IPOption]) {
373 let _ = layers::register_defaults();
374
375 let mut ipv4 = Box::new(super::IPv4::default());
376 let p = ipv4.decode_bytes(packet);
377 assert!(p.is_ok(), "{:#?}", ipv4);
378
379 assert_eq!(ipv4.options.as_slice(), options);
380 }
381
382 wasm_tests! {
383 #[test]
384 fn parse_ipv4_option_packet_1() {
385 let ipv4_packet = hex::decode("08003715e6bc00123f4a33d208004600004caa1d0000801111caac1f1336ac1f1349010101003e3000a10034fa4e302a02010004067075626c6963a01d02012a02010002010030123010060c2b060102012b0e01010601050500").unwrap();
386 let options = [
387 super::IPOption::NOP,
388 super::IPOption::NOP,
389 super::IPOption::NOP,
390 super::IPOption::EOOL,
391 ];
392
393 test_options(&ipv4_packet[14..], &options);
394 }
395
396 #[test]
397 fn parse_ipv4_option_packet_2() {
398 let ipv4_packet = hex::decode("08003715e6bc00123f4a33d208004600004caa1d0000801111caac1f1336ac1f13495f03ff003e3000a10034fa4e302a02010004067075626c6963a01d02012a02010002010030123010060c2b060102012b0e01010601050500").unwrap();
399 let options = [
400 super::IPOption::Other {
401 value: 0x5f,
402 len: 3,
403 data: vec![0xff],
404 },
405 super::IPOption::EOOL,
406 ];
407
408 test_options(&ipv4_packet[14..], &options);
409 }
410
411 #[test]
412 fn parse_ipv4_option_packet_3() {
413 let ipv4_packet = hex::decode("08003715e6bc00123f4a33d2080047000050aa1d0000801111caac1f1336ac1f1349070707deadbeef003e3000a10034fa4e302a02010004067075626c6963a01d02012a02010002010030123010060c2b060102012b0e01010601050500").unwrap();
414 let options = [
415 super::IPOption::RR {
416 len: 7,
417 ptr: 7,
418 route: vec![[0xde, 0xad, 0xbe, 0xef].into()],
419 },
420 super::IPOption::EOOL,
421 ];
422
423 test_options(&ipv4_packet[14..], &options);
424 }
425
426 #[test]
427 fn parse_ipv4_option_packet_4() {
428 let ipv4_packet = hex::decode("08003715e6bc00123f4a33d2080047000050aa1d0000801111caac1f1336ac1f13490b04dead0c04beef3e3000a10034fa4e302a02010004067075626c6963a01d02012a02010002010030123010060c2b060102012b0e01010601050500").unwrap();
429 let options = [
430 super::IPOption::MTUP {
431 len: 4,
432 value: 57005,
433 },
434 super::IPOption::MTUR {
435 len: 4,
436 value: 48879,
437 },
438 ];
439
440 test_options(&ipv4_packet[14..], &options);
441 }
442 }
443}