1pub mod builder;
7pub mod checksum;
8pub mod error;
9pub mod extensions;
10pub mod types;
11
12pub use builder::IcmpBuilder;
14
15pub use checksum::{icmp_checksum, verify_icmp_checksum};
17pub use error::{ERROR_MIN_PAYLOAD, ERROR_TYPES, error_payload_offset, is_error_type};
18pub use extensions::{
19 InterfaceInformation, IpAddr, class_name as extension_class_name, has_extensions,
20 parse_extension_header, parse_extension_object, parse_interface_information,
21};
22pub use types::{ICMP_ANSWERS, code_name, type_name};
23
24use crate::layer::field::{FieldDesc, FieldError, FieldType, FieldValue};
25use crate::layer::{Layer, LayerIndex, LayerKind};
26use std::net::Ipv4Addr;
27
28pub const ICMP_MIN_HEADER_LEN: usize = 8;
30
31pub mod offsets {
33 pub const TYPE: usize = 0;
34 pub const CODE: usize = 1;
35 pub const CHECKSUM: usize = 2;
36
37 pub const ID: usize = 4;
41 pub const SEQ: usize = 6;
42
43 pub const GATEWAY: usize = 4;
45
46 pub const UNUSED_DU: usize = 4;
48 pub const LENGTH_DU: usize = 5;
49 pub const NEXT_HOP_MTU: usize = 6;
50
51 pub const UNUSED_TE: usize = 4;
53 pub const LENGTH_TE: usize = 6;
54
55 pub const PTR: usize = 4;
57 pub const UNUSED_PP: usize = 5;
58 pub const LENGTH_PP: usize = 6;
59
60 pub const TS_ORI: usize = 8;
62 pub const TS_RX: usize = 12;
63 pub const TS_TX: usize = 16;
64
65 pub const ADDR_MASK: usize = 4;
67}
68
69pub static FIELDS: &[FieldDesc] = &[
71 FieldDesc::new("type", offsets::TYPE, 1, FieldType::U8),
72 FieldDesc::new("code", offsets::CODE, 1, FieldType::U8),
73 FieldDesc::new("chksum", offsets::CHECKSUM, 2, FieldType::U16),
74 FieldDesc::new("id", offsets::ID, 2, FieldType::U16),
76 FieldDesc::new("seq", offsets::SEQ, 2, FieldType::U16),
77];
78
79#[derive(Debug, Clone)]
105pub struct IcmpLayer {
106 pub index: LayerIndex,
107}
108
109impl IcmpLayer {
110 pub fn new(index: LayerIndex) -> Self {
112 Self { index }
113 }
114
115 pub fn icmp_type(&self, buf: &[u8]) -> Result<u8, FieldError> {
117 let slice = self.index.slice(buf);
118 if slice.is_empty() {
119 return Err(FieldError::BufferTooShort {
120 offset: self.index.start + offsets::TYPE,
121 need: 1,
122 have: 0,
123 });
124 }
125 Ok(slice[offsets::TYPE])
126 }
127
128 pub fn code(&self, buf: &[u8]) -> Result<u8, FieldError> {
130 let slice = self.index.slice(buf);
131 if slice.len() < offsets::CODE + 1 {
132 return Err(FieldError::BufferTooShort {
133 offset: self.index.start + offsets::CODE,
134 need: 1,
135 have: slice.len().saturating_sub(offsets::CODE),
136 });
137 }
138 Ok(slice[offsets::CODE])
139 }
140
141 pub fn checksum(&self, buf: &[u8]) -> Result<u16, FieldError> {
143 let slice = self.index.slice(buf);
144 if slice.len() < offsets::CHECKSUM + 2 {
145 return Err(FieldError::BufferTooShort {
146 offset: self.index.start + offsets::CHECKSUM,
147 need: 2,
148 have: slice.len().saturating_sub(offsets::CHECKSUM),
149 });
150 }
151 Ok(u16::from_be_bytes([
152 slice[offsets::CHECKSUM],
153 slice[offsets::CHECKSUM + 1],
154 ]))
155 }
156
157 pub fn id(&self, buf: &[u8]) -> Result<Option<u16>, FieldError> {
161 let icmp_type = self.icmp_type(buf)?;
162
163 if !matches!(
165 icmp_type,
166 types::types::ECHO_REQUEST
167 | types::types::ECHO_REPLY
168 | types::types::TIMESTAMP
169 | types::types::TIMESTAMP_REPLY
170 | types::types::INFO_REQUEST
171 | types::types::INFO_REPLY
172 | types::types::ADDRESS_MASK_REQUEST
173 | types::types::ADDRESS_MASK_REPLY
174 ) {
175 return Ok(None);
176 }
177
178 let slice = self.index.slice(buf);
179 if slice.len() < offsets::ID + 2 {
180 return Err(FieldError::BufferTooShort {
181 offset: self.index.start + offsets::ID,
182 need: 2,
183 have: slice.len().saturating_sub(offsets::ID),
184 });
185 }
186 Ok(Some(u16::from_be_bytes([
187 slice[offsets::ID],
188 slice[offsets::ID + 1],
189 ])))
190 }
191
192 pub fn seq(&self, buf: &[u8]) -> Result<Option<u16>, FieldError> {
196 let icmp_type = self.icmp_type(buf)?;
197
198 if !matches!(
200 icmp_type,
201 types::types::ECHO_REQUEST
202 | types::types::ECHO_REPLY
203 | types::types::TIMESTAMP
204 | types::types::TIMESTAMP_REPLY
205 | types::types::INFO_REQUEST
206 | types::types::INFO_REPLY
207 | types::types::ADDRESS_MASK_REQUEST
208 | types::types::ADDRESS_MASK_REPLY
209 ) {
210 return Ok(None);
211 }
212
213 let slice = self.index.slice(buf);
214 if slice.len() < offsets::SEQ + 2 {
215 return Err(FieldError::BufferTooShort {
216 offset: self.index.start + offsets::SEQ,
217 need: 2,
218 have: slice.len().saturating_sub(offsets::SEQ),
219 });
220 }
221 Ok(Some(u16::from_be_bytes([
222 slice[offsets::SEQ],
223 slice[offsets::SEQ + 1],
224 ])))
225 }
226
227 pub fn gateway(&self, buf: &[u8]) -> Result<Option<Ipv4Addr>, FieldError> {
231 let icmp_type = self.icmp_type(buf)?;
232
233 if icmp_type != types::types::REDIRECT {
234 return Ok(None);
235 }
236
237 let slice = self.index.slice(buf);
238 if slice.len() < offsets::GATEWAY + 4 {
239 return Err(FieldError::BufferTooShort {
240 offset: self.index.start + offsets::GATEWAY,
241 need: 4,
242 have: slice.len().saturating_sub(offsets::GATEWAY),
243 });
244 }
245
246 Ok(Some(Ipv4Addr::new(
247 slice[offsets::GATEWAY],
248 slice[offsets::GATEWAY + 1],
249 slice[offsets::GATEWAY + 2],
250 slice[offsets::GATEWAY + 3],
251 )))
252 }
253
254 pub fn next_hop_mtu(&self, buf: &[u8]) -> Result<Option<u16>, FieldError> {
258 let icmp_type = self.icmp_type(buf)?;
259 let code = self.code(buf)?;
260
261 if icmp_type != types::types::DEST_UNREACH || code != 4 {
263 return Ok(None);
264 }
265
266 let slice = self.index.slice(buf);
267 if slice.len() < offsets::NEXT_HOP_MTU + 2 {
268 return Err(FieldError::BufferTooShort {
269 offset: self.index.start + offsets::NEXT_HOP_MTU,
270 need: 2,
271 have: slice.len().saturating_sub(offsets::NEXT_HOP_MTU),
272 });
273 }
274
275 Ok(Some(u16::from_be_bytes([
276 slice[offsets::NEXT_HOP_MTU],
277 slice[offsets::NEXT_HOP_MTU + 1],
278 ])))
279 }
280
281 pub fn ptr(&self, buf: &[u8]) -> Result<Option<u8>, FieldError> {
285 let icmp_type = self.icmp_type(buf)?;
286
287 if icmp_type != types::types::PARAM_PROBLEM {
288 return Ok(None);
289 }
290
291 let slice = self.index.slice(buf);
292 if slice.len() < offsets::PTR + 1 {
293 return Err(FieldError::BufferTooShort {
294 offset: self.index.start + offsets::PTR,
295 need: 1,
296 have: slice.len().saturating_sub(offsets::PTR),
297 });
298 }
299
300 Ok(Some(slice[offsets::PTR]))
301 }
302
303 pub fn ts_ori(&self, buf: &[u8]) -> Result<Option<u32>, FieldError> {
308 let icmp_type = self.icmp_type(buf)?;
309
310 if !matches!(
311 icmp_type,
312 types::types::TIMESTAMP | types::types::TIMESTAMP_REPLY
313 ) {
314 return Ok(None);
315 }
316
317 let slice = self.index.slice(buf);
318 if slice.len() < offsets::TS_ORI + 4 {
319 return Err(FieldError::BufferTooShort {
320 offset: self.index.start + offsets::TS_ORI,
321 need: 4,
322 have: slice.len().saturating_sub(offsets::TS_ORI),
323 });
324 }
325
326 Ok(Some(u32::from_be_bytes([
327 slice[offsets::TS_ORI],
328 slice[offsets::TS_ORI + 1],
329 slice[offsets::TS_ORI + 2],
330 slice[offsets::TS_ORI + 3],
331 ])))
332 }
333
334 pub fn ts_rx(&self, buf: &[u8]) -> Result<Option<u32>, FieldError> {
339 let icmp_type = self.icmp_type(buf)?;
340
341 if !matches!(
342 icmp_type,
343 types::types::TIMESTAMP | types::types::TIMESTAMP_REPLY
344 ) {
345 return Ok(None);
346 }
347
348 let slice = self.index.slice(buf);
349 if slice.len() < offsets::TS_RX + 4 {
350 return Err(FieldError::BufferTooShort {
351 offset: self.index.start + offsets::TS_RX,
352 need: 4,
353 have: slice.len().saturating_sub(offsets::TS_RX),
354 });
355 }
356
357 Ok(Some(u32::from_be_bytes([
358 slice[offsets::TS_RX],
359 slice[offsets::TS_RX + 1],
360 slice[offsets::TS_RX + 2],
361 slice[offsets::TS_RX + 3],
362 ])))
363 }
364
365 pub fn ts_tx(&self, buf: &[u8]) -> Result<Option<u32>, FieldError> {
370 let icmp_type = self.icmp_type(buf)?;
371
372 if !matches!(
373 icmp_type,
374 types::types::TIMESTAMP | types::types::TIMESTAMP_REPLY
375 ) {
376 return Ok(None);
377 }
378
379 let slice = self.index.slice(buf);
380 if slice.len() < offsets::TS_TX + 4 {
381 return Err(FieldError::BufferTooShort {
382 offset: self.index.start + offsets::TS_TX,
383 need: 4,
384 have: slice.len().saturating_sub(offsets::TS_TX),
385 });
386 }
387
388 Ok(Some(u32::from_be_bytes([
389 slice[offsets::TS_TX],
390 slice[offsets::TS_TX + 1],
391 slice[offsets::TS_TX + 2],
392 slice[offsets::TS_TX + 3],
393 ])))
394 }
395
396 pub fn addr_mask(&self, buf: &[u8]) -> Result<Option<Ipv4Addr>, FieldError> {
400 let icmp_type = self.icmp_type(buf)?;
401
402 if !matches!(
403 icmp_type,
404 types::types::ADDRESS_MASK_REQUEST | types::types::ADDRESS_MASK_REPLY
405 ) {
406 return Ok(None);
407 }
408
409 let slice = self.index.slice(buf);
410 if slice.len() < offsets::ADDR_MASK + 4 {
411 return Err(FieldError::BufferTooShort {
412 offset: self.index.start + offsets::ADDR_MASK,
413 need: 4,
414 have: slice.len().saturating_sub(offsets::ADDR_MASK),
415 });
416 }
417
418 Ok(Some(Ipv4Addr::new(
419 slice[offsets::ADDR_MASK],
420 slice[offsets::ADDR_MASK + 1],
421 slice[offsets::ADDR_MASK + 2],
422 slice[offsets::ADDR_MASK + 3],
423 )))
424 }
425
426 pub fn set_type(&self, buf: &mut [u8], value: u8) -> Result<(), FieldError> {
428 let start = self.index.start + offsets::TYPE;
429 if buf.len() < start + 1 {
430 return Err(FieldError::BufferTooShort {
431 offset: start,
432 need: 1,
433 have: buf.len().saturating_sub(start),
434 });
435 }
436 buf[start] = value;
437 Ok(())
438 }
439
440 pub fn set_code(&self, buf: &mut [u8], value: u8) -> Result<(), FieldError> {
442 let start = self.index.start + offsets::CODE;
443 if buf.len() < start + 1 {
444 return Err(FieldError::BufferTooShort {
445 offset: start,
446 need: 1,
447 have: buf.len().saturating_sub(start),
448 });
449 }
450 buf[start] = value;
451 Ok(())
452 }
453
454 pub fn set_checksum(&self, buf: &mut [u8], value: u16) -> Result<(), FieldError> {
456 let start = self.index.start + offsets::CHECKSUM;
457 if buf.len() < start + 2 {
458 return Err(FieldError::BufferTooShort {
459 offset: start,
460 need: 2,
461 have: buf.len().saturating_sub(start),
462 });
463 }
464 buf[start..start + 2].copy_from_slice(&value.to_be_bytes());
465 Ok(())
466 }
467
468 pub fn set_id(&self, buf: &mut [u8], value: u16) -> Result<(), FieldError> {
470 let start = self.index.start + offsets::ID;
471 if buf.len() < start + 2 {
472 return Err(FieldError::BufferTooShort {
473 offset: start,
474 need: 2,
475 have: buf.len().saturating_sub(start),
476 });
477 }
478 buf[start..start + 2].copy_from_slice(&value.to_be_bytes());
479 Ok(())
480 }
481
482 pub fn set_seq(&self, buf: &mut [u8], value: u16) -> Result<(), FieldError> {
484 let start = self.index.start + offsets::SEQ;
485 if buf.len() < start + 2 {
486 return Err(FieldError::BufferTooShort {
487 offset: start,
488 need: 2,
489 have: buf.len().saturating_sub(start),
490 });
491 }
492 buf[start..start + 2].copy_from_slice(&value.to_be_bytes());
493 Ok(())
494 }
495
496 pub fn set_gateway(&self, buf: &mut [u8], value: Ipv4Addr) -> Result<(), FieldError> {
498 let start = self.index.start + offsets::GATEWAY;
499 if buf.len() < start + 4 {
500 return Err(FieldError::BufferTooShort {
501 offset: start,
502 need: 4,
503 have: buf.len().saturating_sub(start),
504 });
505 }
506 buf[start..start + 4].copy_from_slice(&value.octets());
507 Ok(())
508 }
509
510 pub fn set_next_hop_mtu(&self, buf: &mut [u8], value: u16) -> Result<(), FieldError> {
512 let start = self.index.start + offsets::NEXT_HOP_MTU;
513 if buf.len() < start + 2 {
514 return Err(FieldError::BufferTooShort {
515 offset: start,
516 need: 2,
517 have: buf.len().saturating_sub(start),
518 });
519 }
520 buf[start..start + 2].copy_from_slice(&value.to_be_bytes());
521 Ok(())
522 }
523
524 pub fn set_ptr(&self, buf: &mut [u8], value: u8) -> Result<(), FieldError> {
526 let start = self.index.start + offsets::PTR;
527 if buf.len() < start + 1 {
528 return Err(FieldError::BufferTooShort {
529 offset: start,
530 need: 1,
531 have: buf.len().saturating_sub(start),
532 });
533 }
534 buf[start] = value;
535 Ok(())
536 }
537
538 pub fn set_ts_ori(&self, buf: &mut [u8], value: u32) -> Result<(), FieldError> {
540 let start = self.index.start + offsets::TS_ORI;
541 if buf.len() < start + 4 {
542 return Err(FieldError::BufferTooShort {
543 offset: start,
544 need: 4,
545 have: buf.len().saturating_sub(start),
546 });
547 }
548 buf[start..start + 4].copy_from_slice(&value.to_be_bytes());
549 Ok(())
550 }
551
552 pub fn set_ts_rx(&self, buf: &mut [u8], value: u32) -> Result<(), FieldError> {
554 let start = self.index.start + offsets::TS_RX;
555 if buf.len() < start + 4 {
556 return Err(FieldError::BufferTooShort {
557 offset: start,
558 need: 4,
559 have: buf.len().saturating_sub(start),
560 });
561 }
562 buf[start..start + 4].copy_from_slice(&value.to_be_bytes());
563 Ok(())
564 }
565
566 pub fn set_ts_tx(&self, buf: &mut [u8], value: u32) -> Result<(), FieldError> {
568 let start = self.index.start + offsets::TS_TX;
569 if buf.len() < start + 4 {
570 return Err(FieldError::BufferTooShort {
571 offset: start,
572 need: 4,
573 have: buf.len().saturating_sub(start),
574 });
575 }
576 buf[start..start + 4].copy_from_slice(&value.to_be_bytes());
577 Ok(())
578 }
579
580 pub fn set_addr_mask(&self, buf: &mut [u8], value: Ipv4Addr) -> Result<(), FieldError> {
582 let start = self.index.start + offsets::ADDR_MASK;
583 if buf.len() < start + 4 {
584 return Err(FieldError::BufferTooShort {
585 offset: start,
586 need: 4,
587 have: buf.len().saturating_sub(start),
588 });
589 }
590 buf[start..start + 4].copy_from_slice(&value.octets());
591 Ok(())
592 }
593
594 pub fn summary(&self, buf: &[u8]) -> String {
596 if let (Ok(icmp_type), Ok(code)) = (self.icmp_type(buf), self.code(buf)) {
597 let type_str = type_name(icmp_type);
598 let code_str = code_name(icmp_type, code);
599
600 let details = match icmp_type {
602 types::types::REDIRECT => {
603 if let Ok(Some(gw)) = self.gateway(buf) {
604 format!(" gw={}", gw)
605 } else {
606 String::new()
607 }
608 }
609 types::types::DEST_UNREACH if code == 4 => {
610 if let Ok(Some(mtu)) = self.next_hop_mtu(buf) {
612 format!(" mtu={}", mtu)
613 } else {
614 String::new()
615 }
616 }
617 types::types::PARAM_PROBLEM => {
618 if let Ok(Some(ptr)) = self.ptr(buf) {
619 format!(" ptr={}", ptr)
620 } else {
621 String::new()
622 }
623 }
624 types::types::ECHO_REQUEST | types::types::ECHO_REPLY => {
625 let id_str = self
626 .id(buf)
627 .ok()
628 .flatten()
629 .map(|id| format!(" id={}", id))
630 .unwrap_or_default();
631 let seq_str = self
632 .seq(buf)
633 .ok()
634 .flatten()
635 .map(|seq| format!(" seq={}", seq))
636 .unwrap_or_default();
637 format!("{}{}", id_str, seq_str)
638 }
639 _ => String::new(),
640 };
641
642 format!("ICMP {} {}{}", type_str, code_str, details)
643 } else {
644 "ICMP".to_string()
645 }
646 }
647
648 pub fn header_len(&self, buf: &[u8]) -> usize {
650 if let Ok(icmp_type) = self.icmp_type(buf) {
653 match icmp_type {
654 types::types::TIMESTAMP | types::types::TIMESTAMP_REPLY => 20,
655 _ => ICMP_MIN_HEADER_LEN,
656 }
657 } else {
658 ICMP_MIN_HEADER_LEN
659 }
660 }
661
662 pub fn field_names(&self) -> &'static [&'static str] {
664 &[
665 "type",
666 "code",
667 "chksum",
668 "id",
669 "seq",
670 "gw",
671 "ptr",
672 "mtu",
673 "ts_ori",
674 "ts_rx",
675 "ts_tx",
676 "addr_mask",
677 ]
678 }
679
680 pub fn get_field(&self, buf: &[u8], name: &str) -> Option<Result<FieldValue, FieldError>> {
682 match name {
683 "type" => Some(self.icmp_type(buf).map(FieldValue::U8)),
684 "code" => Some(self.code(buf).map(FieldValue::U8)),
685 "chksum" => Some(self.checksum(buf).map(FieldValue::U16)),
686 "id" => Some(
687 self.id(buf)
688 .and_then(|opt| {
689 opt.ok_or(FieldError::InvalidValue(
690 "id field not available for this ICMP type".into(),
691 ))
692 })
693 .map(FieldValue::U16),
694 ),
695 "seq" => Some(
696 self.seq(buf)
697 .and_then(|opt| {
698 opt.ok_or(FieldError::InvalidValue(
699 "seq field not available for this ICMP type".into(),
700 ))
701 })
702 .map(FieldValue::U16),
703 ),
704 "gw" => Some(
705 self.gateway(buf)
706 .and_then(|opt| {
707 opt.ok_or(FieldError::InvalidValue(
708 "gw field not available for this ICMP type".into(),
709 ))
710 })
711 .map(|addr| FieldValue::Ipv4(addr)),
712 ),
713 "ptr" => Some(
714 self.ptr(buf)
715 .and_then(|opt| {
716 opt.ok_or(FieldError::InvalidValue(
717 "ptr field not available for this ICMP type".into(),
718 ))
719 })
720 .map(FieldValue::U8),
721 ),
722 "mtu" => Some(
723 self.next_hop_mtu(buf)
724 .and_then(|opt| {
725 opt.ok_or(FieldError::InvalidValue(
726 "mtu field not available for this ICMP type".into(),
727 ))
728 })
729 .map(FieldValue::U16),
730 ),
731 "ts_ori" => Some(
732 self.ts_ori(buf)
733 .and_then(|opt| {
734 opt.ok_or(FieldError::InvalidValue(
735 "ts_ori field not available for this ICMP type".into(),
736 ))
737 })
738 .map(FieldValue::U32),
739 ),
740 "ts_rx" => Some(
741 self.ts_rx(buf)
742 .and_then(|opt| {
743 opt.ok_or(FieldError::InvalidValue(
744 "ts_rx field not available for this ICMP type".into(),
745 ))
746 })
747 .map(FieldValue::U32),
748 ),
749 "ts_tx" => Some(
750 self.ts_tx(buf)
751 .and_then(|opt| {
752 opt.ok_or(FieldError::InvalidValue(
753 "ts_tx field not available for this ICMP type".into(),
754 ))
755 })
756 .map(FieldValue::U32),
757 ),
758 "addr_mask" => Some(
759 self.addr_mask(buf)
760 .and_then(|opt| {
761 opt.ok_or(FieldError::InvalidValue(
762 "addr_mask field not available for this ICMP type".into(),
763 ))
764 })
765 .map(|addr| FieldValue::Ipv4(addr)),
766 ),
767 _ => None,
768 }
769 }
770
771 pub fn set_field(
773 &self,
774 buf: &mut [u8],
775 name: &str,
776 value: FieldValue,
777 ) -> Option<Result<(), FieldError>> {
778 match name {
779 "type" => {
780 if let FieldValue::U8(v) = value {
781 Some(self.set_type(buf, v))
782 } else {
783 Some(Err(FieldError::InvalidValue(format!(
784 "type: expected U8, got {:?}",
785 value
786 ))))
787 }
788 }
789 "code" => {
790 if let FieldValue::U8(v) = value {
791 Some(self.set_code(buf, v))
792 } else {
793 Some(Err(FieldError::InvalidValue(format!(
794 "code: expected U8, got {:?}",
795 value
796 ))))
797 }
798 }
799 "chksum" => {
800 if let FieldValue::U16(v) = value {
801 Some(self.set_checksum(buf, v))
802 } else {
803 Some(Err(FieldError::InvalidValue(format!(
804 "chksum: expected U16, got {:?}",
805 value
806 ))))
807 }
808 }
809 "id" => {
810 if let FieldValue::U16(v) = value {
811 Some(self.set_id(buf, v))
812 } else {
813 Some(Err(FieldError::InvalidValue(format!(
814 "id: expected U16, got {:?}",
815 value
816 ))))
817 }
818 }
819 "seq" => {
820 if let FieldValue::U16(v) = value {
821 Some(self.set_seq(buf, v))
822 } else {
823 Some(Err(FieldError::InvalidValue(format!(
824 "seq: expected U16, got {:?}",
825 value
826 ))))
827 }
828 }
829 "gw" => {
830 if let FieldValue::Ipv4(v) = value {
831 Some(self.set_gateway(buf, v))
832 } else {
833 Some(Err(FieldError::InvalidValue(format!(
834 "gw: expected Ipv4, got {:?}",
835 value
836 ))))
837 }
838 }
839 "ptr" => {
840 if let FieldValue::U8(v) = value {
841 Some(self.set_ptr(buf, v))
842 } else {
843 Some(Err(FieldError::InvalidValue(format!(
844 "ptr: expected U8, got {:?}",
845 value
846 ))))
847 }
848 }
849 "mtu" => {
850 if let FieldValue::U16(v) = value {
851 Some(self.set_next_hop_mtu(buf, v))
852 } else {
853 Some(Err(FieldError::InvalidValue(format!(
854 "mtu: expected U16, got {:?}",
855 value
856 ))))
857 }
858 }
859 "ts_ori" => {
860 if let FieldValue::U32(v) = value {
861 Some(self.set_ts_ori(buf, v))
862 } else {
863 Some(Err(FieldError::InvalidValue(format!(
864 "ts_ori: expected U32, got {:?}",
865 value
866 ))))
867 }
868 }
869 "ts_rx" => {
870 if let FieldValue::U32(v) = value {
871 Some(self.set_ts_rx(buf, v))
872 } else {
873 Some(Err(FieldError::InvalidValue(format!(
874 "ts_rx: expected U32, got {:?}",
875 value
876 ))))
877 }
878 }
879 "ts_tx" => {
880 if let FieldValue::U32(v) = value {
881 Some(self.set_ts_tx(buf, v))
882 } else {
883 Some(Err(FieldError::InvalidValue(format!(
884 "ts_tx: expected U32, got {:?}",
885 value
886 ))))
887 }
888 }
889 "addr_mask" => {
890 if let FieldValue::Ipv4(v) = value {
891 Some(self.set_addr_mask(buf, v))
892 } else {
893 Some(Err(FieldError::InvalidValue(format!(
894 "addr_mask: expected Ipv4, got {:?}",
895 value
896 ))))
897 }
898 }
899 _ => None,
900 }
901 }
902}
903
904impl Layer for IcmpLayer {
905 fn kind(&self) -> LayerKind {
906 LayerKind::Icmp
907 }
908
909 fn summary(&self, data: &[u8]) -> String {
910 self.summary(data)
911 }
912
913 fn header_len(&self, data: &[u8]) -> usize {
914 self.header_len(data)
915 }
916
917 fn hashret(&self, data: &[u8]) -> Vec<u8> {
918 if let (Ok(Some(id)), Ok(Some(seq))) = (self.id(data), self.seq(data)) {
920 let mut hash = Vec::with_capacity(4);
921 hash.extend_from_slice(&id.to_be_bytes());
922 hash.extend_from_slice(&seq.to_be_bytes());
923 hash
924 } else {
925 vec![]
927 }
928 }
929
930 fn answers(&self, data: &[u8], other: &Self, other_data: &[u8]) -> bool {
931 if let (Ok(self_type), Ok(other_type)) = (self.icmp_type(data), other.icmp_type(other_data))
933 {
934 for &(req_type, reply_type) in ICMP_ANSWERS {
936 if self_type == reply_type && other_type == req_type {
937 if let (
939 Ok(Some(self_id)),
940 Ok(Some(other_id)),
941 Ok(Some(self_seq)),
942 Ok(Some(other_seq)),
943 ) = (
944 self.id(data),
945 other.id(other_data),
946 self.seq(data),
947 other.seq(other_data),
948 ) {
949 return self_id == other_id && self_seq == other_seq;
950 }
951 return true;
952 }
953 }
954 }
955 false
956 }
957
958 fn extract_padding<'a>(&self, data: &'a [u8]) -> (&'a [u8], &'a [u8]) {
959 let header_len = self.header_len(data);
962 let start = self.index.start;
963 let end = data.len();
964
965 if start + header_len <= end {
966 (&data[start..end], &[])
967 } else {
968 (&data[start..end], &[])
969 }
970 }
971
972 fn field_names(&self) -> &'static [&'static str] {
973 self.field_names()
974 }
975}
976
977#[cfg(test)]
978mod tests {
979 use super::*;
980
981 #[test]
982 fn test_icmp_echo_parse() {
983 let data = [
985 0x08, 0x00, 0x12, 0x34, 0x56, 0x78, 0x00, 0x01, 0x48, 0x65, 0x6c, 0x6c, 0x6f, ];
993
994 let index = LayerIndex::new(LayerKind::Icmp, 0, ICMP_MIN_HEADER_LEN);
995 let icmp = IcmpLayer::new(index);
996
997 assert_eq!(icmp.icmp_type(&data).unwrap(), 8);
998 assert_eq!(icmp.code(&data).unwrap(), 0);
999 assert_eq!(icmp.checksum(&data).unwrap(), 0x1234);
1000 assert_eq!(icmp.id(&data).unwrap(), Some(0x5678));
1001 assert_eq!(icmp.seq(&data).unwrap(), Some(1));
1002 }
1003
1004 #[test]
1005 fn test_icmp_summary() {
1006 let data = [
1007 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, ];
1013
1014 let index = LayerIndex::new(LayerKind::Icmp, 0, ICMP_MIN_HEADER_LEN);
1015 let icmp = IcmpLayer::new(index);
1016
1017 let summary = icmp.summary(&data);
1018 assert!(summary.contains("echo-request"));
1019 }
1020
1021 #[test]
1022 fn test_icmp_set_fields() {
1023 let mut data = vec![0u8; 8];
1024 let index = LayerIndex::new(LayerKind::Icmp, 0, ICMP_MIN_HEADER_LEN);
1025 let icmp = IcmpLayer::new(index);
1026
1027 icmp.set_type(&mut data, types::types::ECHO_REPLY).unwrap();
1028 icmp.set_code(&mut data, 0).unwrap();
1029 icmp.set_checksum(&mut data, 0xABCD).unwrap();
1030 icmp.set_id(&mut data, 0x1234).unwrap();
1031 icmp.set_seq(&mut data, 42).unwrap();
1032
1033 assert_eq!(icmp.icmp_type(&data).unwrap(), types::types::ECHO_REPLY);
1034 assert_eq!(icmp.code(&data).unwrap(), 0);
1035 assert_eq!(icmp.checksum(&data).unwrap(), 0xABCD);
1036 assert_eq!(icmp.id(&data).unwrap(), Some(0x1234));
1037 assert_eq!(icmp.seq(&data).unwrap(), Some(42));
1038 }
1039
1040 #[test]
1041 fn test_icmp_answers() {
1042 let request_data = [
1044 0x08, 0x00, 0x00, 0x00, 0x12, 0x34, 0x00, 0x05, ];
1049
1050 let reply_data = [
1052 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x00, 0x05, ];
1057
1058 let request_index = LayerIndex::new(LayerKind::Icmp, 0, ICMP_MIN_HEADER_LEN);
1059 let reply_index = LayerIndex::new(LayerKind::Icmp, 0, ICMP_MIN_HEADER_LEN);
1060
1061 let request = IcmpLayer::new(request_index);
1062 let reply = IcmpLayer::new(reply_index);
1063
1064 assert!(reply.answers(&reply_data, &request, &request_data));
1065 assert!(!request.answers(&request_data, &reply, &reply_data));
1066 }
1067
1068 #[test]
1069 fn test_icmp_dest_unreach_no_id() {
1070 let data = [
1072 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
1079
1080 let index = LayerIndex::new(LayerKind::Icmp, 0, ICMP_MIN_HEADER_LEN);
1081 let icmp = IcmpLayer::new(index);
1082
1083 assert_eq!(icmp.icmp_type(&data).unwrap(), 3);
1084 assert_eq!(icmp.code(&data).unwrap(), 3);
1085 assert_eq!(icmp.id(&data).unwrap(), None);
1086 assert_eq!(icmp.seq(&data).unwrap(), None);
1087 }
1088
1089 #[test]
1090 fn test_icmp_redirect_gateway() {
1091 let data = [
1093 0x05, 0x01, 0x00, 0x00, 192, 168, 1, 1, ];
1098
1099 let index = LayerIndex::new(LayerKind::Icmp, 0, ICMP_MIN_HEADER_LEN);
1100 let icmp = IcmpLayer::new(index);
1101
1102 assert_eq!(icmp.icmp_type(&data).unwrap(), 5);
1103 assert_eq!(
1104 icmp.gateway(&data).unwrap(),
1105 Some(Ipv4Addr::new(192, 168, 1, 1))
1106 );
1107 }
1108
1109 #[test]
1110 fn test_icmp_dest_unreach_mtu() {
1111 let mut data = vec![
1113 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x05, 0xdc, ];
1120
1121 let index = LayerIndex::new(LayerKind::Icmp, 0, ICMP_MIN_HEADER_LEN);
1122 let icmp = IcmpLayer::new(index);
1123
1124 assert_eq!(icmp.icmp_type(&data).unwrap(), 3);
1125 assert_eq!(icmp.code(&data).unwrap(), 4);
1126 assert_eq!(icmp.next_hop_mtu(&data).unwrap(), Some(1500));
1127
1128 icmp.set_next_hop_mtu(&mut data, 1400).unwrap();
1130 assert_eq!(icmp.next_hop_mtu(&data).unwrap(), Some(1400));
1131 }
1132
1133 #[test]
1134 fn test_icmp_param_problem_ptr() {
1135 let mut data = vec![
1137 0x0c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, ];
1144
1145 let index = LayerIndex::new(LayerKind::Icmp, 0, ICMP_MIN_HEADER_LEN);
1146 let icmp = IcmpLayer::new(index);
1147
1148 assert_eq!(icmp.icmp_type(&data).unwrap(), 12);
1149 assert_eq!(icmp.ptr(&data).unwrap(), Some(20));
1150
1151 icmp.set_ptr(&mut data, 30).unwrap();
1153 assert_eq!(icmp.ptr(&data).unwrap(), Some(30));
1154 }
1155
1156 #[test]
1157 fn test_icmp_timestamp_fields() {
1158 let mut data = vec![
1160 0x0d, 0x00, 0x00, 0x00, 0x12, 0x34, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x30, 0x00, ];
1172
1173 let index = LayerIndex::new(LayerKind::Icmp, 0, 20); let icmp = IcmpLayer::new(index);
1175
1176 assert_eq!(icmp.icmp_type(&data).unwrap(), 13);
1177 assert_eq!(icmp.code(&data).unwrap(), 0);
1178 assert_eq!(icmp.id(&data).unwrap(), Some(0x1234));
1179 assert_eq!(icmp.seq(&data).unwrap(), Some(1));
1180 assert_eq!(icmp.ts_ori(&data).unwrap(), Some(4096));
1181 assert_eq!(icmp.ts_rx(&data).unwrap(), Some(8192));
1182 assert_eq!(icmp.ts_tx(&data).unwrap(), Some(12288));
1183
1184 icmp.set_ts_ori(&mut data, 5000).unwrap();
1186 icmp.set_ts_rx(&mut data, 6000).unwrap();
1187 icmp.set_ts_tx(&mut data, 7000).unwrap();
1188
1189 assert_eq!(icmp.ts_ori(&data).unwrap(), Some(5000));
1190 assert_eq!(icmp.ts_rx(&data).unwrap(), Some(6000));
1191 assert_eq!(icmp.ts_tx(&data).unwrap(), Some(7000));
1192 }
1193
1194 #[test]
1195 fn test_icmp_timestamp_header_len() {
1196 let data = vec![
1198 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1200 0x00, 0x00, 0x00, 0x00, 0x00,
1201 ];
1202
1203 let index = LayerIndex::new(LayerKind::Icmp, 0, ICMP_MIN_HEADER_LEN);
1204 let icmp = IcmpLayer::new(index);
1205
1206 assert_eq!(icmp.header_len(&data), 20);
1207 }
1208
1209 #[test]
1210 fn test_icmp_address_mask() {
1211 let mut data = vec![
1213 0x11, 0x00, 0x00, 0x00, 255, 255, 255, 0, ];
1218
1219 let index = LayerIndex::new(LayerKind::Icmp, 0, ICMP_MIN_HEADER_LEN);
1220 let icmp = IcmpLayer::new(index);
1221
1222 assert_eq!(icmp.icmp_type(&data).unwrap(), 17);
1223 assert_eq!(
1224 icmp.addr_mask(&data).unwrap(),
1225 Some(Ipv4Addr::new(255, 255, 255, 0))
1226 );
1227
1228 icmp.set_addr_mask(&mut data, Ipv4Addr::new(255, 255, 0, 0))
1230 .unwrap();
1231 assert_eq!(
1232 icmp.addr_mask(&data).unwrap(),
1233 Some(Ipv4Addr::new(255, 255, 0, 0))
1234 );
1235 }
1236
1237 #[test]
1238 fn test_icmp_conditional_fields_none() {
1239 let data = vec![
1241 0x08, 0x00, 0x00, 0x00, 0x12, 0x34, 0x00, 0x01,
1243 ];
1244
1245 let index = LayerIndex::new(LayerKind::Icmp, 0, ICMP_MIN_HEADER_LEN);
1246 let icmp = IcmpLayer::new(index);
1247
1248 assert_eq!(icmp.gateway(&data).unwrap(), None);
1249 assert_eq!(icmp.ptr(&data).unwrap(), None);
1250 assert_eq!(icmp.next_hop_mtu(&data).unwrap(), None);
1251 assert_eq!(icmp.addr_mask(&data).unwrap(), None);
1252 assert_eq!(icmp.ts_ori(&data).unwrap(), None);
1253 assert_eq!(icmp.ts_rx(&data).unwrap(), None);
1254 assert_eq!(icmp.ts_tx(&data).unwrap(), None);
1255 }
1256
1257 #[test]
1258 fn test_icmp_summary_with_details() {
1259 let echo_data = vec![
1263 0x08, 0x00, 0x00, 0x00, 0x12, 0x34, 0x00, 0x05, ];
1266 let index = LayerIndex::new(LayerKind::Icmp, 0, ICMP_MIN_HEADER_LEN);
1267 let icmp = IcmpLayer::new(index);
1268 let summary = icmp.summary(&echo_data);
1269 assert!(summary.contains("id="));
1270 assert!(summary.contains("seq="));
1271
1272 let redirect_data = vec![
1274 0x05, 0x01, 0x00, 0x00, 192, 168, 1, 1, ];
1276 let icmp = IcmpLayer::new(index);
1277 let summary = icmp.summary(&redirect_data);
1278 assert!(summary.contains("gw="));
1279
1280 let pp_data = vec![
1282 0x0c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
1284 ];
1285 let icmp = IcmpLayer::new(index);
1286 let summary = icmp.summary(&pp_data);
1287 assert!(summary.contains("ptr="));
1288
1289 let du_data = vec![
1291 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x05, 0xdc, ];
1294 let icmp = IcmpLayer::new(index);
1295 let summary = icmp.summary(&du_data);
1296 assert!(summary.contains("mtu="));
1297 }
1298
1299 #[test]
1300 fn test_icmp_set_gateway() {
1301 let mut data = vec![
1303 0x05, 0x01, 0x00, 0x00, 0, 0, 0, 0, ];
1305
1306 let index = LayerIndex::new(LayerKind::Icmp, 0, ICMP_MIN_HEADER_LEN);
1307 let icmp = IcmpLayer::new(index);
1308
1309 icmp.set_gateway(&mut data, Ipv4Addr::new(10, 0, 0, 1))
1310 .unwrap();
1311 assert_eq!(
1312 icmp.gateway(&data).unwrap(),
1313 Some(Ipv4Addr::new(10, 0, 0, 1))
1314 );
1315 }
1316
1317 #[test]
1318 fn test_icmp_error_type_detection() {
1319 assert!(error::is_error_type(types::types::DEST_UNREACH));
1321 assert!(error::is_error_type(types::types::TIME_EXCEEDED));
1322 assert!(error::is_error_type(types::types::PARAM_PROBLEM));
1323 assert!(error::is_error_type(types::types::SOURCE_QUENCH));
1324 assert!(error::is_error_type(types::types::REDIRECT));
1325
1326 assert!(!error::is_error_type(types::types::ECHO_REQUEST));
1327 assert!(!error::is_error_type(types::types::ECHO_REPLY));
1328 }
1329
1330 #[test]
1331 fn test_icmp_error_payload_offset() {
1332 assert_eq!(
1334 error::error_payload_offset(types::types::DEST_UNREACH),
1335 Some(8)
1336 );
1337 assert_eq!(
1338 error::error_payload_offset(types::types::TIME_EXCEEDED),
1339 Some(8)
1340 );
1341
1342 assert_eq!(
1344 error::error_payload_offset(types::types::ECHO_REQUEST),
1345 None
1346 );
1347 }
1348}