1#![deny(missing_docs)]
18
19use packet_dissector_core::dissector::{DispatchHint, DissectResult, Dissector};
20use packet_dissector_core::error::PacketError;
21use packet_dissector_core::field::{FieldDescriptor, FieldType, FieldValue};
22use packet_dissector_core::packet::DissectBuffer;
23use packet_dissector_core::util::{read_be_u16, read_be_u32};
24
25fn icmp_type_name(v: u8) -> Option<&'static str> {
27 match v {
28 0 => Some("Echo Reply"),
29 3 => Some("Destination Unreachable"),
30 5 => Some("Redirect"),
31 8 => Some("Echo Request"),
32 11 => Some("Time Exceeded"),
33 12 => Some("Parameter Problem"),
34 _ => None,
35 }
36}
37
38const HEADER_SIZE: usize = 8;
40const TIMESTAMP_SIZE: usize = 20;
42const ADDRESS_MASK_SIZE: usize = 12;
44const IPV4_MIN_HEADER: usize = 20;
46
47const FD_TYPE: usize = 0;
48const FD_CODE: usize = 1;
49const FD_CHECKSUM: usize = 2;
50const FD_IDENTIFIER: usize = 3;
51const FD_SEQUENCE_NUMBER: usize = 4;
52const FD_DATA: usize = 5;
53const FD_GATEWAY: usize = 6;
54const FD_POINTER: usize = 7;
55const FD_LENGTH: usize = 8;
56const FD_NEXT_HOP_MTU: usize = 9;
57const FD_INVOKING_PACKET: usize = 10;
58const FD_NUM_ADDRS: usize = 11;
59const FD_ADDR_ENTRY_SIZE: usize = 12;
60const FD_LIFETIME: usize = 13;
61const FD_ENTRIES: usize = 14;
62const FD_ORIGINATE_TIMESTAMP: usize = 15;
63const FD_RECEIVE_TIMESTAMP: usize = 16;
64const FD_TRANSMIT_TIMESTAMP: usize = 17;
65const FD_ADDRESS_MASK: usize = 18;
66const FD_SUBTYPE: usize = 19;
67const FD_LOCAL: usize = 20;
68const FD_STATE: usize = 21;
69const FD_ACTIVE: usize = 22;
70const FD_IPV4: usize = 23;
71const FD_IPV6: usize = 24;
72const FD_PHOTURIS_RESERVED: usize = 25;
73const FD_PHOTURIS_POINTER: usize = 26;
74const FD_EXTENSIONS: usize = 27;
75
76const EXT_HEADER_SIZE: usize = 4;
79const EXT_OBJECT_HEADER_SIZE: usize = 4;
81const EXT_COMPAT_MIN_ORIG_DATAGRAM: usize = 128;
84
85const EXT_VERSION: usize = 0;
87const EXT_RESERVED: usize = 1;
88const EXT_CHECKSUM: usize = 2;
89const EXT_OBJECTS: usize = 3;
90
91const EOBJ_LENGTH: usize = 0;
93const EOBJ_CLASS_NUM: usize = 1;
94const EOBJ_C_TYPE: usize = 2;
95const EOBJ_PAYLOAD: usize = 3;
96const EOBJ_MPLS_LABELS: usize = 4;
97const EOBJ_INTERFACE_ROLE: usize = 5;
98const EOBJ_IF_INDEX: usize = 6;
99const EOBJ_AFI: usize = 7;
100const EOBJ_ADDRESS_LENGTH: usize = 8;
101const EOBJ_IPV4_ADDRESS: usize = 9;
102const EOBJ_IPV6_ADDRESS: usize = 10;
103const EOBJ_INTERFACE_NAME: usize = 11;
104const EOBJ_MTU: usize = 12;
105
106const MPLS_LABEL: usize = 0;
108const MPLS_TC: usize = 1;
109const MPLS_S: usize = 2;
110const MPLS_TTL: usize = 3;
111
112const IPC_VERSION: usize = 0;
113const IPC_IHL: usize = 1;
114const IPC_TOTAL_LENGTH: usize = 2;
115const IPC_PROTOCOL: usize = 3;
116const IPC_SRC: usize = 4;
117const IPC_DST: usize = 5;
118const IPC_SRC_PORT: usize = 6;
119const IPC_DST_PORT: usize = 7;
120const IPC_TRANSPORT_DATA: usize = 8;
121
122static INVOKING_PACKET_CHILDREN: &[FieldDescriptor] = &[
123 FieldDescriptor::new("version", "Version", FieldType::U8),
124 FieldDescriptor::new("ihl", "Internet Header Length", FieldType::U8),
125 FieldDescriptor::new("total_length", "Total Length", FieldType::U16),
126 FieldDescriptor::new("protocol", "Protocol", FieldType::U8),
127 FieldDescriptor::new("src", "Source Address", FieldType::Ipv4Addr),
128 FieldDescriptor::new("dst", "Destination Address", FieldType::Ipv4Addr),
129 FieldDescriptor::new("src_port", "Source Port", FieldType::U16).optional(),
130 FieldDescriptor::new("dst_port", "Destination Port", FieldType::U16).optional(),
131 FieldDescriptor::new("transport_data", "Transport Data", FieldType::Bytes).optional(),
132];
133
134const REC_ROUTER_ADDRESS: usize = 0;
135const REC_PREFERENCE_LEVEL: usize = 1;
136
137static ROUTER_ENTRY_CHILDREN: &[FieldDescriptor] = &[
138 FieldDescriptor::new("router_address", "Router Address", FieldType::Ipv4Addr),
139 FieldDescriptor::new("preference_level", "Preference Level", FieldType::I32),
144];
145
146static MPLS_LABEL_CHILDREN: &[FieldDescriptor] = &[
149 FieldDescriptor::new("label", "Label", FieldType::U32),
150 FieldDescriptor::new("tc", "Traffic Class", FieldType::U8),
151 FieldDescriptor::new("s", "Bottom of Stack", FieldType::U8),
152 FieldDescriptor::new("ttl", "Time to Live", FieldType::U8),
153];
154
155static EXTENSION_OBJECT_CHILDREN: &[FieldDescriptor] = &[
161 FieldDescriptor::new("length", "Length", FieldType::U16),
162 FieldDescriptor::new("class_num", "Class-Num", FieldType::U8),
163 FieldDescriptor::new("c_type", "C-Type", FieldType::U8),
164 FieldDescriptor::new("payload", "Payload", FieldType::Bytes).optional(),
165 FieldDescriptor::new("mpls_labels", "MPLS Label Stack", FieldType::Array)
166 .optional()
167 .with_children(MPLS_LABEL_CHILDREN),
168 FieldDescriptor::new("interface_role", "Interface Role", FieldType::U8).optional(),
169 FieldDescriptor::new("if_index", "ifIndex", FieldType::U32).optional(),
170 FieldDescriptor::new("afi", "Address Family Identifier", FieldType::U16).optional(),
171 FieldDescriptor::new("address_length", "Address Length", FieldType::U8).optional(),
172 FieldDescriptor::new("ipv4_address", "IPv4 Address", FieldType::Ipv4Addr).optional(),
173 FieldDescriptor::new("ipv6_address", "IPv6 Address", FieldType::Ipv6Addr).optional(),
174 FieldDescriptor::new("interface_name", "Interface Name", FieldType::Bytes).optional(),
175 FieldDescriptor::new("mtu", "MTU", FieldType::U32).optional(),
176];
177
178static EXTENSION_CHILDREN: &[FieldDescriptor] = &[
181 FieldDescriptor::new("version", "Version", FieldType::U8),
182 FieldDescriptor::new("reserved", "Reserved", FieldType::U16),
183 FieldDescriptor::new("checksum", "Checksum", FieldType::U16),
184 FieldDescriptor::new("objects", "Objects", FieldType::Array)
185 .with_children(EXTENSION_OBJECT_CHILDREN),
186];
187
188static FIELD_DESCRIPTORS: &[FieldDescriptor] = &[
189 FieldDescriptor {
190 name: "type",
191 display_name: "Type",
192 field_type: FieldType::U8,
193 optional: false,
194 children: None,
195 display_fn: Some(|v, _siblings| match v {
196 FieldValue::U8(t) => icmp_type_name(*t),
197 _ => None,
198 }),
199 format_fn: None,
200 },
201 FieldDescriptor::new("code", "Code", FieldType::U8),
202 FieldDescriptor::new("checksum", "Checksum", FieldType::U16),
203 FieldDescriptor::new("identifier", "Identifier", FieldType::U16).optional(),
204 FieldDescriptor::new("sequence_number", "Sequence Number", FieldType::U16).optional(),
205 FieldDescriptor::new("data", "Data", FieldType::Bytes).optional(),
206 FieldDescriptor::new("gateway", "Gateway Internet Address", FieldType::Ipv4Addr).optional(),
207 FieldDescriptor::new("pointer", "Pointer", FieldType::U8).optional(),
208 FieldDescriptor::new("length", "Length", FieldType::U8).optional(),
209 FieldDescriptor::new("next_hop_mtu", "Next-Hop MTU", FieldType::U16).optional(),
210 FieldDescriptor::new("invoking_packet", "Invoking Packet", FieldType::Object)
211 .optional()
212 .with_children(INVOKING_PACKET_CHILDREN),
213 FieldDescriptor::new("num_addrs", "Number of Addresses", FieldType::U8).optional(),
214 FieldDescriptor::new("addr_entry_size", "Address Entry Size", FieldType::U8).optional(),
215 FieldDescriptor::new("lifetime", "Lifetime", FieldType::U16).optional(),
216 FieldDescriptor::new("entries", "Entries", FieldType::Array)
217 .optional()
218 .with_children(ROUTER_ENTRY_CHILDREN),
219 FieldDescriptor::new("originate_timestamp", "Originate Timestamp", FieldType::U32).optional(),
220 FieldDescriptor::new("receive_timestamp", "Receive Timestamp", FieldType::U32).optional(),
221 FieldDescriptor::new("transmit_timestamp", "Transmit Timestamp", FieldType::U32).optional(),
222 FieldDescriptor::new("address_mask", "Address Mask", FieldType::Ipv4Addr).optional(),
223 FieldDescriptor::new("subtype", "Subtype", FieldType::U8).optional(),
224 FieldDescriptor::new("local", "Local", FieldType::U8).optional(),
225 FieldDescriptor::new("state", "State", FieldType::U8).optional(),
226 FieldDescriptor::new("active", "Active", FieldType::U8).optional(),
227 FieldDescriptor::new("ipv4", "IPv4", FieldType::U8).optional(),
228 FieldDescriptor::new("ipv6", "IPv6", FieldType::U8).optional(),
229 FieldDescriptor::new("photuris_reserved", "Reserved", FieldType::U16).optional(),
234 FieldDescriptor::new("photuris_pointer", "Pointer", FieldType::U16).optional(),
235 FieldDescriptor::new("extensions", "ICMP Extension Structure", FieldType::Object)
239 .optional()
240 .with_children(EXTENSION_CHILDREN),
241];
242
243pub struct IcmpDissector;
245
246fn push_invoking_packet<'pkt>(buf: &mut DissectBuffer<'pkt>, data: &'pkt [u8], offset: usize) {
248 if data.len() >= IPV4_MIN_HEADER {
249 let version = data[0] >> 4;
250 let ihl = data[0] & 0x0f;
251 let total_length = read_be_u16(data, 2).unwrap_or_default();
252 let protocol = data[9];
253 let src = [data[12], data[13], data[14], data[15]];
254 let dst = [data[16], data[17], data[18], data[19]];
255
256 let obj_idx = buf.begin_container(
257 &FIELD_DESCRIPTORS[FD_INVOKING_PACKET],
258 FieldValue::Object(0..0),
259 offset..offset + data.len(),
260 );
261 buf.push_field(
262 &INVOKING_PACKET_CHILDREN[IPC_VERSION],
263 FieldValue::U8(version),
264 offset..offset + 1,
265 );
266 buf.push_field(
267 &INVOKING_PACKET_CHILDREN[IPC_IHL],
268 FieldValue::U8(ihl),
269 offset..offset + 1,
270 );
271 buf.push_field(
272 &INVOKING_PACKET_CHILDREN[IPC_TOTAL_LENGTH],
273 FieldValue::U16(total_length),
274 offset + 2..offset + 4,
275 );
276 buf.push_field(
277 &INVOKING_PACKET_CHILDREN[IPC_PROTOCOL],
278 FieldValue::U8(protocol),
279 offset + 9..offset + 10,
280 );
281 buf.push_field(
282 &INVOKING_PACKET_CHILDREN[IPC_SRC],
283 FieldValue::Ipv4Addr(src),
284 offset + 12..offset + 16,
285 );
286 buf.push_field(
287 &INVOKING_PACKET_CHILDREN[IPC_DST],
288 FieldValue::Ipv4Addr(dst),
289 offset + 16..offset + 20,
290 );
291
292 let ip_header_len = (ihl as usize) * 4;
296 if ip_header_len >= IPV4_MIN_HEADER && data.len() > ip_header_len {
297 let transport = &data[ip_header_len..];
298 let transport_offset = offset + ip_header_len;
299 match protocol {
300 6 | 17 => {
301 if transport.len() >= 4 {
303 let src_port = u16::from_be_bytes([transport[0], transport[1]]);
304 let dst_port = u16::from_be_bytes([transport[2], transport[3]]);
305 buf.push_field(
306 &INVOKING_PACKET_CHILDREN[IPC_SRC_PORT],
307 FieldValue::U16(src_port),
308 transport_offset..transport_offset + 2,
309 );
310 buf.push_field(
311 &INVOKING_PACKET_CHILDREN[IPC_DST_PORT],
312 FieldValue::U16(dst_port),
313 transport_offset + 2..transport_offset + 4,
314 );
315 }
316 }
317 _ => {
318 buf.push_field(
319 &INVOKING_PACKET_CHILDREN[IPC_TRANSPORT_DATA],
320 FieldValue::Bytes(transport),
321 transport_offset..transport_offset + transport.len(),
322 );
323 }
324 }
325 }
326
327 buf.end_container(obj_idx);
328 } else {
329 buf.push_field(
330 &FIELD_DESCRIPTORS[FD_INVOKING_PACKET],
331 FieldValue::Bytes(data),
332 offset..offset + data.len(),
333 );
334 }
335}
336
337fn push_extensions<'pkt>(buf: &mut DissectBuffer<'pkt>, data: &'pkt [u8], offset: usize) {
348 if data.len() < EXT_HEADER_SIZE {
349 return;
350 }
351 let version = data[0] >> 4;
353 let reserved = (u16::from(data[0] & 0x0F) << 8) | u16::from(data[1]);
354 let checksum = read_be_u16(data, 2).unwrap_or_default();
355
356 let ext_idx = buf.begin_container(
357 &FIELD_DESCRIPTORS[FD_EXTENSIONS],
358 FieldValue::Object(0..0),
359 offset..offset + data.len(),
360 );
361 buf.push_field(
362 &EXTENSION_CHILDREN[EXT_VERSION],
363 FieldValue::U8(version),
364 offset..offset + 1,
365 );
366 buf.push_field(
367 &EXTENSION_CHILDREN[EXT_RESERVED],
368 FieldValue::U16(reserved),
369 offset..offset + 2,
370 );
371 buf.push_field(
372 &EXTENSION_CHILDREN[EXT_CHECKSUM],
373 FieldValue::U16(checksum),
374 offset + 2..offset + 4,
375 );
376
377 let objects_idx = buf.begin_container(
378 &EXTENSION_CHILDREN[EXT_OBJECTS],
379 FieldValue::Array(0..0),
380 offset + EXT_HEADER_SIZE..offset + data.len(),
381 );
382 let mut pos = EXT_HEADER_SIZE;
383 while pos + EXT_OBJECT_HEADER_SIZE <= data.len() {
384 let obj_len = read_be_u16(data, pos).unwrap_or_default() as usize;
386 let class_num = data[pos + 2];
387 let c_type = data[pos + 3];
388 if obj_len < EXT_OBJECT_HEADER_SIZE || pos + obj_len > data.len() {
390 break;
391 }
392 let body = &data[pos + EXT_OBJECT_HEADER_SIZE..pos + obj_len];
393 let body_offset = offset + pos + EXT_OBJECT_HEADER_SIZE;
394 let c_type_offset = offset + pos + 3;
395
396 let obj_idx = buf.begin_container(
397 &EXTENSION_CHILDREN[EXT_OBJECTS],
398 FieldValue::Object(0..0),
399 offset + pos..offset + pos + obj_len,
400 );
401 buf.push_field(
402 &EXTENSION_OBJECT_CHILDREN[EOBJ_LENGTH],
403 FieldValue::U16(obj_len as u16),
404 offset + pos..offset + pos + 2,
405 );
406 buf.push_field(
407 &EXTENSION_OBJECT_CHILDREN[EOBJ_CLASS_NUM],
408 FieldValue::U8(class_num),
409 offset + pos + 2..offset + pos + 3,
410 );
411 buf.push_field(
412 &EXTENSION_OBJECT_CHILDREN[EOBJ_C_TYPE],
413 FieldValue::U8(c_type),
414 offset + pos + 3..offset + pos + 4,
415 );
416
417 match (class_num, c_type) {
418 (1, 1) => push_mpls_labels(buf, body, body_offset),
421 (2, _) => push_interface_info(buf, body, body_offset, c_type, c_type_offset),
425 (3, _) => push_interface_id(buf, body, body_offset, c_type),
428 _ => {
429 if !body.is_empty() {
430 buf.push_field(
431 &EXTENSION_OBJECT_CHILDREN[EOBJ_PAYLOAD],
432 FieldValue::Bytes(body),
433 body_offset..body_offset + body.len(),
434 );
435 }
436 }
437 }
438 buf.end_container(obj_idx);
439 pos += obj_len;
440 }
441 buf.end_container(objects_idx);
442 buf.end_container(ext_idx);
443}
444
445fn push_mpls_labels<'pkt>(buf: &mut DissectBuffer<'pkt>, body: &'pkt [u8], offset: usize) {
450 let arr_idx = buf.begin_container(
451 &EXTENSION_OBJECT_CHILDREN[EOBJ_MPLS_LABELS],
452 FieldValue::Array(0..0),
453 offset..offset + body.len(),
454 );
455 let mut p = 0usize;
456 while p + 4 <= body.len() {
457 let b0 = u32::from(body[p]);
458 let b1 = u32::from(body[p + 1]);
459 let b2 = u32::from(body[p + 2]);
460 let label = (b0 << 12) | (b1 << 4) | (b2 >> 4);
462 let tc = (body[p + 2] >> 1) & 0x07;
463 let s = body[p + 2] & 0x01;
464 let ttl = body[p + 3];
465
466 let entry_idx = buf.begin_container(
467 &EXTENSION_OBJECT_CHILDREN[EOBJ_MPLS_LABELS],
468 FieldValue::Object(0..0),
469 offset + p..offset + p + 4,
470 );
471 buf.push_field(
472 &MPLS_LABEL_CHILDREN[MPLS_LABEL],
473 FieldValue::U32(label),
474 offset + p..offset + p + 3,
475 );
476 buf.push_field(
477 &MPLS_LABEL_CHILDREN[MPLS_TC],
478 FieldValue::U8(tc),
479 offset + p + 2..offset + p + 3,
480 );
481 buf.push_field(
482 &MPLS_LABEL_CHILDREN[MPLS_S],
483 FieldValue::U8(s),
484 offset + p + 2..offset + p + 3,
485 );
486 buf.push_field(
487 &MPLS_LABEL_CHILDREN[MPLS_TTL],
488 FieldValue::U8(ttl),
489 offset + p + 3..offset + p + 4,
490 );
491 buf.end_container(entry_idx);
492 p += 4;
493 }
494 buf.end_container(arr_idx);
495}
496
497fn push_interface_info<'pkt>(
505 buf: &mut DissectBuffer<'pkt>,
506 body: &'pkt [u8],
507 body_offset: usize,
508 c_type: u8,
509 c_type_offset: usize,
510) {
511 let role = (c_type >> 6) & 0x03;
514 let has_ifindex = (c_type & 0x08) != 0;
515 let has_addr = (c_type & 0x04) != 0;
516 let has_name = (c_type & 0x02) != 0;
517 let has_mtu = (c_type & 0x01) != 0;
518
519 buf.push_field(
520 &EXTENSION_OBJECT_CHILDREN[EOBJ_INTERFACE_ROLE],
521 FieldValue::U8(role),
522 c_type_offset..c_type_offset + 1,
523 );
524
525 let mut p = 0usize;
526 if has_ifindex {
527 if p + 4 > body.len() {
528 return;
529 }
530 let ifindex = read_be_u32(body, p).unwrap_or_default();
531 buf.push_field(
532 &EXTENSION_OBJECT_CHILDREN[EOBJ_IF_INDEX],
533 FieldValue::U32(ifindex),
534 body_offset + p..body_offset + p + 4,
535 );
536 p += 4;
537 }
538 if has_addr {
539 if p + 4 > body.len() {
541 return;
542 }
543 let afi = read_be_u16(body, p).unwrap_or_default();
544 buf.push_field(
545 &EXTENSION_OBJECT_CHILDREN[EOBJ_AFI],
546 FieldValue::U16(afi),
547 body_offset + p..body_offset + p + 2,
548 );
549 p += 4; match afi {
551 1 => {
553 if p + 4 > body.len() {
554 return;
555 }
556 let addr = [body[p], body[p + 1], body[p + 2], body[p + 3]];
557 buf.push_field(
558 &EXTENSION_OBJECT_CHILDREN[EOBJ_IPV4_ADDRESS],
559 FieldValue::Ipv4Addr(addr),
560 body_offset + p..body_offset + p + 4,
561 );
562 p += 4;
563 }
564 2 => {
565 if p + 16 > body.len() {
566 return;
567 }
568 let mut addr = [0u8; 16];
569 addr.copy_from_slice(&body[p..p + 16]);
570 buf.push_field(
571 &EXTENSION_OBJECT_CHILDREN[EOBJ_IPV6_ADDRESS],
572 FieldValue::Ipv6Addr(addr),
573 body_offset + p..body_offset + p + 16,
574 );
575 p += 16;
576 }
577 _ => return,
578 }
579 }
580 if has_name {
581 if p >= body.len() {
584 return;
585 }
586 let name_total = body[p] as usize;
587 if name_total < 2 || p + name_total > body.len() {
588 return;
589 }
590 let name_bytes = &body[p + 1..p + name_total];
591 buf.push_field(
592 &EXTENSION_OBJECT_CHILDREN[EOBJ_INTERFACE_NAME],
593 FieldValue::Bytes(name_bytes),
594 body_offset + p + 1..body_offset + p + name_total,
595 );
596 p += name_total;
597 }
598 if has_mtu {
599 if p + 4 > body.len() {
601 return;
602 }
603 let mtu = read_be_u32(body, p).unwrap_or_default();
604 buf.push_field(
605 &EXTENSION_OBJECT_CHILDREN[EOBJ_MTU],
606 FieldValue::U32(mtu),
607 body_offset + p..body_offset + p + 4,
608 );
609 }
610}
611
612fn push_interface_id<'pkt>(
620 buf: &mut DissectBuffer<'pkt>,
621 body: &'pkt [u8],
622 body_offset: usize,
623 c_type: u8,
624) {
625 match c_type {
626 1 if !body.is_empty() => {
627 buf.push_field(
628 &EXTENSION_OBJECT_CHILDREN[EOBJ_INTERFACE_NAME],
629 FieldValue::Bytes(body),
630 body_offset..body_offset + body.len(),
631 );
632 }
633 2 if body.len() >= 4 => {
634 let ifindex = read_be_u32(body, 0).unwrap_or_default();
635 buf.push_field(
636 &EXTENSION_OBJECT_CHILDREN[EOBJ_IF_INDEX],
637 FieldValue::U32(ifindex),
638 body_offset..body_offset + 4,
639 );
640 }
641 3 => {
642 if body.len() < 4 {
643 return;
644 }
645 let afi = read_be_u16(body, 0).unwrap_or_default();
646 let addr_len = body[2];
647 buf.push_field(
648 &EXTENSION_OBJECT_CHILDREN[EOBJ_AFI],
649 FieldValue::U16(afi),
650 body_offset..body_offset + 2,
651 );
652 buf.push_field(
653 &EXTENSION_OBJECT_CHILDREN[EOBJ_ADDRESS_LENGTH],
654 FieldValue::U8(addr_len),
655 body_offset + 2..body_offset + 3,
656 );
657 match afi {
658 1 if addr_len as usize >= 4 && body.len() >= 8 => {
660 let a = [body[4], body[5], body[6], body[7]];
661 buf.push_field(
662 &EXTENSION_OBJECT_CHILDREN[EOBJ_IPV4_ADDRESS],
663 FieldValue::Ipv4Addr(a),
664 body_offset + 4..body_offset + 8,
665 );
666 }
667 2 if addr_len as usize >= 16 && body.len() >= 20 => {
668 let mut a = [0u8; 16];
669 a.copy_from_slice(&body[4..20]);
670 buf.push_field(
671 &EXTENSION_OBJECT_CHILDREN[EOBJ_IPV6_ADDRESS],
672 FieldValue::Ipv6Addr(a),
673 body_offset + 4..body_offset + 20,
674 );
675 }
676 _ => {}
677 }
678 }
679 _ => {}
680 }
681}
682
683fn rfc4884_extension_offset(data_len: usize, length: u8) -> Option<usize> {
691 if length == 0 {
692 return None;
693 }
694 let orig_len = (length as usize) * 4;
695 let padded = orig_len.max(EXT_COMPAT_MIN_ORIG_DATAGRAM);
696 let ext_start = HEADER_SIZE + padded;
697 if ext_start + EXT_HEADER_SIZE <= data_len {
698 Some(ext_start)
699 } else {
700 None
701 }
702}
703
704impl Dissector for IcmpDissector {
705 fn name(&self) -> &'static str {
706 "Internet Control Message Protocol"
707 }
708 fn short_name(&self) -> &'static str {
709 "ICMP"
710 }
711 fn field_descriptors(&self) -> &'static [FieldDescriptor] {
712 FIELD_DESCRIPTORS
713 }
714
715 fn dissect<'pkt>(
716 &self,
717 data: &'pkt [u8],
718 buf: &mut DissectBuffer<'pkt>,
719 offset: usize,
720 ) -> Result<DissectResult, PacketError> {
721 if data.len() < HEADER_SIZE {
722 return Err(PacketError::Truncated {
723 expected: HEADER_SIZE,
724 actual: data.len(),
725 });
726 }
727
728 let icmp_type = data[0];
729 let code = data[1];
730 let checksum = read_be_u16(data, 2)?;
731
732 buf.begin_layer(
733 self.short_name(),
734 None,
735 FIELD_DESCRIPTORS,
736 offset..offset + data.len(),
737 );
738 buf.push_field(
739 &FIELD_DESCRIPTORS[FD_TYPE],
740 FieldValue::U8(icmp_type),
741 offset..offset + 1,
742 );
743 buf.push_field(
744 &FIELD_DESCRIPTORS[FD_CODE],
745 FieldValue::U8(code),
746 offset + 1..offset + 2,
747 );
748 buf.push_field(
749 &FIELD_DESCRIPTORS[FD_CHECKSUM],
750 FieldValue::U16(checksum),
751 offset + 2..offset + 4,
752 );
753
754 match icmp_type {
755 0 | 8 => {
758 let identifier = read_be_u16(data, 4)?;
759 let sequence_number = read_be_u16(data, 6)?;
760 buf.push_field(
761 &FIELD_DESCRIPTORS[FD_IDENTIFIER],
762 FieldValue::U16(identifier),
763 offset + 4..offset + 6,
764 );
765 buf.push_field(
766 &FIELD_DESCRIPTORS[FD_SEQUENCE_NUMBER],
767 FieldValue::U16(sequence_number),
768 offset + 6..offset + 8,
769 );
770 if data.len() > HEADER_SIZE {
771 buf.push_field(
772 &FIELD_DESCRIPTORS[FD_DATA],
773 FieldValue::Bytes(&data[HEADER_SIZE..]),
774 offset + HEADER_SIZE..offset + data.len(),
775 );
776 }
777 }
778 3 => {
782 let length = data[5];
785 if length > 0 {
786 buf.push_field(
787 &FIELD_DESCRIPTORS[FD_LENGTH],
788 FieldValue::U8(length),
789 offset + 5..offset + 6,
790 );
791 }
792 if code == 4 {
793 let next_hop_mtu = read_be_u16(data, 6)?;
796 buf.push_field(
797 &FIELD_DESCRIPTORS[FD_NEXT_HOP_MTU],
798 FieldValue::U16(next_hop_mtu),
799 offset + 6..offset + 8,
800 );
801 }
802 if data.len() > HEADER_SIZE {
803 push_invoking_packet(buf, &data[HEADER_SIZE..], offset + HEADER_SIZE);
804 }
805 if let Some(ext_start) = rfc4884_extension_offset(data.len(), length) {
806 push_extensions(buf, &data[ext_start..], offset + ext_start);
807 }
808 }
809 4 if data.len() > HEADER_SIZE => {
812 push_invoking_packet(buf, &data[HEADER_SIZE..], offset + HEADER_SIZE);
813 }
814 11 => {
818 let length = data[5];
821 if length > 0 {
822 buf.push_field(
823 &FIELD_DESCRIPTORS[FD_LENGTH],
824 FieldValue::U8(length),
825 offset + 5..offset + 6,
826 );
827 }
828 if data.len() > HEADER_SIZE {
829 push_invoking_packet(buf, &data[HEADER_SIZE..], offset + HEADER_SIZE);
830 }
831 if let Some(ext_start) = rfc4884_extension_offset(data.len(), length) {
832 push_extensions(buf, &data[ext_start..], offset + ext_start);
833 }
834 }
835 5 => {
838 let gateway = [data[4], data[5], data[6], data[7]];
839 buf.push_field(
840 &FIELD_DESCRIPTORS[FD_GATEWAY],
841 FieldValue::Ipv4Addr(gateway),
842 offset + 4..offset + 8,
843 );
844 if data.len() > HEADER_SIZE {
845 push_invoking_packet(buf, &data[HEADER_SIZE..], offset + HEADER_SIZE);
846 }
847 }
848 12 => {
851 let pointer = data[4];
853 buf.push_field(
854 &FIELD_DESCRIPTORS[FD_POINTER],
855 FieldValue::U8(pointer),
856 offset + 4..offset + 5,
857 );
858 let length = data[5];
861 if length > 0 {
862 buf.push_field(
863 &FIELD_DESCRIPTORS[FD_LENGTH],
864 FieldValue::U8(length),
865 offset + 5..offset + 6,
866 );
867 }
868 if data.len() > HEADER_SIZE {
869 push_invoking_packet(buf, &data[HEADER_SIZE..], offset + HEADER_SIZE);
870 }
871 if let Some(ext_start) = rfc4884_extension_offset(data.len(), length) {
872 push_extensions(buf, &data[ext_start..], offset + ext_start);
873 }
874 }
875 9 => {
878 let num_addrs = data[4];
879 let addr_entry_size = data[5];
880 let lifetime = read_be_u16(data, 6)?;
881 buf.push_field(
882 &FIELD_DESCRIPTORS[FD_NUM_ADDRS],
883 FieldValue::U8(num_addrs),
884 offset + 4..offset + 5,
885 );
886 buf.push_field(
887 &FIELD_DESCRIPTORS[FD_ADDR_ENTRY_SIZE],
888 FieldValue::U8(addr_entry_size),
889 offset + 5..offset + 6,
890 );
891 buf.push_field(
892 &FIELD_DESCRIPTORS[FD_LIFETIME],
893 FieldValue::U16(lifetime),
894 offset + 6..offset + 8,
895 );
896
897 let entry_bytes = addr_entry_size as usize * 4;
898 let array_idx = buf.begin_container(
899 &FIELD_DESCRIPTORS[FD_ENTRIES],
900 FieldValue::Array(0..0),
901 offset + HEADER_SIZE..offset + data.len(),
902 );
903 let mut pos = HEADER_SIZE;
904 for _ in 0..num_addrs {
905 if pos + entry_bytes > data.len() || entry_bytes < 8 {
906 break;
907 }
908 let router_addr = [data[pos], data[pos + 1], data[pos + 2], data[pos + 3]];
909 let pref = read_be_u32(data, pos + 4)? as i32;
912 let obj_idx = buf.begin_container(
913 &ROUTER_ENTRY_CHILDREN[REC_ROUTER_ADDRESS], FieldValue::Object(0..0),
915 offset + pos..offset + pos + entry_bytes,
916 );
917 buf.push_field(
918 &ROUTER_ENTRY_CHILDREN[REC_ROUTER_ADDRESS],
919 FieldValue::Ipv4Addr(router_addr),
920 offset + pos..offset + pos + 4,
921 );
922 buf.push_field(
923 &ROUTER_ENTRY_CHILDREN[REC_PREFERENCE_LEVEL],
924 FieldValue::I32(pref),
925 offset + pos + 4..offset + pos + 8,
926 );
927 buf.end_container(obj_idx);
928 pos += entry_bytes;
929 }
930 buf.end_container(array_idx);
931 }
932 10 => {}
935 13 | 14 => {
938 if data.len() < TIMESTAMP_SIZE {
939 return Err(PacketError::Truncated {
940 expected: TIMESTAMP_SIZE,
941 actual: data.len(),
942 });
943 }
944 let identifier = read_be_u16(data, 4)?;
945 let sequence_number = read_be_u16(data, 6)?;
946 let originate = read_be_u32(data, 8)?;
947 let receive = read_be_u32(data, 12)?;
948 let transmit = read_be_u32(data, 16)?;
949 buf.push_field(
950 &FIELD_DESCRIPTORS[FD_IDENTIFIER],
951 FieldValue::U16(identifier),
952 offset + 4..offset + 6,
953 );
954 buf.push_field(
955 &FIELD_DESCRIPTORS[FD_SEQUENCE_NUMBER],
956 FieldValue::U16(sequence_number),
957 offset + 6..offset + 8,
958 );
959 buf.push_field(
960 &FIELD_DESCRIPTORS[FD_ORIGINATE_TIMESTAMP],
961 FieldValue::U32(originate),
962 offset + 8..offset + 12,
963 );
964 buf.push_field(
965 &FIELD_DESCRIPTORS[FD_RECEIVE_TIMESTAMP],
966 FieldValue::U32(receive),
967 offset + 12..offset + 16,
968 );
969 buf.push_field(
970 &FIELD_DESCRIPTORS[FD_TRANSMIT_TIMESTAMP],
971 FieldValue::U32(transmit),
972 offset + 16..offset + 20,
973 );
974 }
975 15 | 16 => {
978 let identifier = read_be_u16(data, 4)?;
979 let sequence_number = read_be_u16(data, 6)?;
980 buf.push_field(
981 &FIELD_DESCRIPTORS[FD_IDENTIFIER],
982 FieldValue::U16(identifier),
983 offset + 4..offset + 6,
984 );
985 buf.push_field(
986 &FIELD_DESCRIPTORS[FD_SEQUENCE_NUMBER],
987 FieldValue::U16(sequence_number),
988 offset + 6..offset + 8,
989 );
990 }
991 17 | 18 => {
994 if data.len() < ADDRESS_MASK_SIZE {
995 return Err(PacketError::Truncated {
996 expected: ADDRESS_MASK_SIZE,
997 actual: data.len(),
998 });
999 }
1000 let identifier = read_be_u16(data, 4)?;
1001 let sequence_number = read_be_u16(data, 6)?;
1002 let mask = [data[8], data[9], data[10], data[11]];
1003 buf.push_field(
1004 &FIELD_DESCRIPTORS[FD_IDENTIFIER],
1005 FieldValue::U16(identifier),
1006 offset + 4..offset + 6,
1007 );
1008 buf.push_field(
1009 &FIELD_DESCRIPTORS[FD_SEQUENCE_NUMBER],
1010 FieldValue::U16(sequence_number),
1011 offset + 6..offset + 8,
1012 );
1013 buf.push_field(
1014 &FIELD_DESCRIPTORS[FD_ADDRESS_MASK],
1015 FieldValue::Ipv4Addr(mask),
1016 offset + 8..offset + 12,
1017 );
1018 }
1019 40 => {
1024 let reserved = read_be_u16(data, 4)?;
1025 let pointer = read_be_u16(data, 6)?;
1026 buf.push_field(
1027 &FIELD_DESCRIPTORS[FD_PHOTURIS_RESERVED],
1028 FieldValue::U16(reserved),
1029 offset + 4..offset + 6,
1030 );
1031 buf.push_field(
1032 &FIELD_DESCRIPTORS[FD_PHOTURIS_POINTER],
1033 FieldValue::U16(pointer),
1034 offset + 6..offset + 8,
1035 );
1036 if data.len() > HEADER_SIZE {
1037 push_invoking_packet(buf, &data[HEADER_SIZE..], offset + HEADER_SIZE);
1038 }
1039 }
1040 41 => {
1043 let subtype = data[4];
1044 buf.push_field(
1045 &FIELD_DESCRIPTORS[FD_SUBTYPE],
1046 FieldValue::U8(subtype),
1047 offset + 4..offset + 5,
1048 );
1049 if data.len() > HEADER_SIZE {
1050 buf.push_field(
1051 &FIELD_DESCRIPTORS[FD_DATA],
1052 FieldValue::Bytes(&data[HEADER_SIZE..]),
1053 offset + HEADER_SIZE..offset + data.len(),
1054 );
1055 }
1056 }
1057 42 => {
1062 let identifier = read_be_u16(data, 4)?;
1063 let sequence_number = u16::from(data[6]);
1066 let local = data[7] & 0x01;
1067 buf.push_field(
1068 &FIELD_DESCRIPTORS[FD_IDENTIFIER],
1069 FieldValue::U16(identifier),
1070 offset + 4..offset + 6,
1071 );
1072 buf.push_field(
1073 &FIELD_DESCRIPTORS[FD_SEQUENCE_NUMBER],
1074 FieldValue::U16(sequence_number),
1075 offset + 6..offset + 7,
1076 );
1077 buf.push_field(
1078 &FIELD_DESCRIPTORS[FD_LOCAL],
1079 FieldValue::U8(local),
1080 offset + 7..offset + 8,
1081 );
1082 if data.len() > HEADER_SIZE {
1083 push_extensions(buf, &data[HEADER_SIZE..], offset + HEADER_SIZE);
1084 }
1085 }
1086 43 => {
1089 let identifier = read_be_u16(data, 4)?;
1090 let sequence_number = u16::from(data[6]);
1093 let flags_byte = data[7];
1094 let state = (flags_byte >> 5) & 0x07;
1095 let active = (flags_byte >> 2) & 0x01;
1096 let ipv4_flag = (flags_byte >> 1) & 0x01;
1097 let ipv6_flag = flags_byte & 0x01;
1098 buf.push_field(
1099 &FIELD_DESCRIPTORS[FD_IDENTIFIER],
1100 FieldValue::U16(identifier),
1101 offset + 4..offset + 6,
1102 );
1103 buf.push_field(
1104 &FIELD_DESCRIPTORS[FD_SEQUENCE_NUMBER],
1105 FieldValue::U16(sequence_number),
1106 offset + 6..offset + 7,
1107 );
1108 buf.push_field(
1109 &FIELD_DESCRIPTORS[FD_STATE],
1110 FieldValue::U8(state),
1111 offset + 7..offset + 8,
1112 );
1113 buf.push_field(
1114 &FIELD_DESCRIPTORS[FD_ACTIVE],
1115 FieldValue::U8(active),
1116 offset + 7..offset + 8,
1117 );
1118 buf.push_field(
1119 &FIELD_DESCRIPTORS[FD_IPV4],
1120 FieldValue::U8(ipv4_flag),
1121 offset + 7..offset + 8,
1122 );
1123 buf.push_field(
1124 &FIELD_DESCRIPTORS[FD_IPV6],
1125 FieldValue::U8(ipv6_flag),
1126 offset + 7..offset + 8,
1127 );
1128 }
1129 _ => {}
1130 }
1131
1132 buf.end_layer();
1133
1134 Ok(DissectResult::new(data.len(), DispatchHint::End))
1135 }
1136}
1137
1138#[cfg(test)]
1139mod tests {
1140 use super::*;
1178
1179 fn build_dest_unreachable(code: u8, invoking: &[u8]) -> Vec<u8> {
1181 let mut pkt = Vec::with_capacity(HEADER_SIZE + invoking.len());
1182 pkt.push(3); pkt.push(code);
1184 pkt.extend_from_slice(&[0x00, 0x00]); pkt.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); pkt.extend_from_slice(invoking);
1187 pkt
1188 }
1189
1190 fn build_ipv4_header(protocol: u8, src: [u8; 4], dst: [u8; 4]) -> Vec<u8> {
1192 let mut hdr = vec![0u8; 20];
1193 hdr[0] = 0x45; hdr[2] = 0x00; hdr[3] = 0x28; hdr[9] = protocol;
1197 hdr[12..16].copy_from_slice(&src);
1198 hdr[16..20].copy_from_slice(&dst);
1199 hdr
1200 }
1201
1202 #[test]
1203 fn parse_invoking_packet_ipv4_only() {
1204 let invoking = build_ipv4_header(17, [10, 0, 0, 1], [10, 0, 0, 2]);
1205 let data = build_dest_unreachable(0, &invoking);
1206
1207 let mut buf = DissectBuffer::new();
1208 IcmpDissector.dissect(&data, &mut buf, 0).unwrap();
1209
1210 let layer = &buf.layers()[0];
1211 let fields = buf.layer_fields(layer);
1212 let ip_obj = fields
1213 .iter()
1214 .find(|f| f.descriptor.name == "invoking_packet")
1215 .unwrap();
1216 let range = match &ip_obj.value {
1217 FieldValue::Object(r) => r.clone(),
1218 other => panic!("expected Object, got {other:?}"),
1219 };
1220 let children = buf.nested_fields(&range);
1221 assert_eq!(children[IPC_VERSION].value, FieldValue::U8(4));
1222 assert_eq!(children[IPC_IHL].value, FieldValue::U8(5));
1223 assert_eq!(children[IPC_PROTOCOL].value, FieldValue::U8(17));
1224 assert_eq!(children[IPC_SRC].value, FieldValue::Ipv4Addr([10, 0, 0, 1]));
1225 assert_eq!(children[IPC_DST].value, FieldValue::Ipv4Addr([10, 0, 0, 2]));
1226 }
1227
1228 #[test]
1229 fn parse_dest_unreachable_udp_ports() {
1230 let src = [192, 168, 1, 1];
1231 let dst = [192, 168, 1, 2];
1232 let mut invoking = build_ipv4_header(17, src, dst); invoking.extend_from_slice(&[0x1F, 0x90]); invoking.extend_from_slice(&[0x00, 0x35]); invoking.extend_from_slice(&[0x00, 0x08, 0x00, 0x00]); let data = build_dest_unreachable(3, &invoking); let mut buf = DissectBuffer::new();
1240 IcmpDissector.dissect(&data, &mut buf, 0).unwrap();
1241
1242 let layer = &buf.layers()[0];
1243 let fields = buf.layer_fields(layer);
1244 let ip_obj = fields
1245 .iter()
1246 .find(|f| f.descriptor.name == "invoking_packet")
1247 .unwrap();
1248 let range = match &ip_obj.value {
1249 FieldValue::Object(r) => r.clone(),
1250 other => panic!("expected Object, got {other:?}"),
1251 };
1252 let children = buf.nested_fields(&range);
1253 let src_port = children
1254 .iter()
1255 .find(|f| f.descriptor.name == "src_port")
1256 .unwrap();
1257 assert_eq!(src_port.value, FieldValue::U16(8080));
1258 let dst_port = children
1259 .iter()
1260 .find(|f| f.descriptor.name == "dst_port")
1261 .unwrap();
1262 assert_eq!(dst_port.value, FieldValue::U16(53));
1263 }
1264
1265 #[test]
1266 fn parse_dest_unreachable_tcp_ports() {
1267 let src = [10, 0, 0, 1];
1268 let dst = [10, 0, 0, 2];
1269 let mut invoking = build_ipv4_header(6, src, dst); invoking.extend_from_slice(&[0x00, 0x50]); invoking.extend_from_slice(&[0xC0, 0x00]); invoking.extend_from_slice(&[0x00, 0x00, 0x00, 0x01]); let data = build_dest_unreachable(3, &invoking);
1275
1276 let mut buf = DissectBuffer::new();
1277 IcmpDissector.dissect(&data, &mut buf, 0).unwrap();
1278
1279 let layer = &buf.layers()[0];
1280 let fields = buf.layer_fields(layer);
1281 let ip_obj = fields
1282 .iter()
1283 .find(|f| f.descriptor.name == "invoking_packet")
1284 .unwrap();
1285 let range = match &ip_obj.value {
1286 FieldValue::Object(r) => r.clone(),
1287 other => panic!("expected Object, got {other:?}"),
1288 };
1289 let children = buf.nested_fields(&range);
1290 let src_port = children
1291 .iter()
1292 .find(|f| f.descriptor.name == "src_port")
1293 .unwrap();
1294 assert_eq!(src_port.value, FieldValue::U16(80));
1295 let dst_port = children
1296 .iter()
1297 .find(|f| f.descriptor.name == "dst_port")
1298 .unwrap();
1299 assert_eq!(dst_port.value, FieldValue::U16(49152));
1300 }
1301
1302 #[test]
1303 fn parse_dest_unreachable_other_protocol() {
1304 let mut invoking = build_ipv4_header(1, [10, 0, 0, 1], [10, 0, 0, 2]); invoking.extend_from_slice(&[0x08, 0x00, 0xAB, 0xCD, 0x00, 0x01, 0x00, 0x01]);
1306 let data = build_dest_unreachable(0, &invoking);
1307
1308 let mut buf = DissectBuffer::new();
1309 IcmpDissector.dissect(&data, &mut buf, 0).unwrap();
1310
1311 let layer = &buf.layers()[0];
1312 let fields = buf.layer_fields(layer);
1313 let ip_obj = fields
1314 .iter()
1315 .find(|f| f.descriptor.name == "invoking_packet")
1316 .unwrap();
1317 let range = match &ip_obj.value {
1318 FieldValue::Object(r) => r.clone(),
1319 other => panic!("expected Object, got {other:?}"),
1320 };
1321 let children = buf.nested_fields(&range);
1322 let transport = children
1323 .iter()
1324 .find(|f| f.descriptor.name == "transport_data")
1325 .unwrap();
1326 assert!(matches!(transport.value, FieldValue::Bytes(_)));
1327 }
1328
1329 #[test]
1330 fn parse_dest_unreachable_truncated_transport() {
1331 let invoking = build_ipv4_header(17, [10, 0, 0, 1], [10, 0, 0, 2]);
1333 let data = build_dest_unreachable(3, &invoking);
1334
1335 let mut buf = DissectBuffer::new();
1336 IcmpDissector.dissect(&data, &mut buf, 0).unwrap();
1337
1338 let layer = &buf.layers()[0];
1339 let fields = buf.layer_fields(layer);
1340 let ip_obj = fields
1341 .iter()
1342 .find(|f| f.descriptor.name == "invoking_packet")
1343 .unwrap();
1344 let range = match &ip_obj.value {
1345 FieldValue::Object(r) => r.clone(),
1346 other => panic!("expected Object, got {other:?}"),
1347 };
1348 let children = buf.nested_fields(&range);
1349 assert!(children.iter().all(|f| f.descriptor.name != "src_port"));
1351 assert!(children.iter().all(|f| f.descriptor.name != "dst_port"));
1352 assert!(
1353 children
1354 .iter()
1355 .all(|f| f.descriptor.name != "transport_data")
1356 );
1357 }
1358
1359 #[test]
1362 fn parse_truncated_header() {
1363 let data = [0x08, 0x00, 0x00, 0x00]; let mut buf = DissectBuffer::new();
1365 let err = IcmpDissector.dissect(&data, &mut buf, 0).unwrap_err();
1366 assert!(
1367 matches!(
1368 err,
1369 PacketError::Truncated {
1370 expected: 8,
1371 actual: 4
1372 }
1373 ),
1374 "expected Truncated(8,4), got {err:?}"
1375 );
1376 }
1377
1378 #[test]
1379 fn parse_echo_request() {
1380 let data: &[u8] = &[
1382 0x08, 0x00, 0xAB, 0xCD, 0x12, 0x34, 0x00, 0x01, 0xDE, 0xAD, ];
1386 let mut buf = DissectBuffer::new();
1387 IcmpDissector.dissect(data, &mut buf, 0).unwrap();
1388
1389 let layer = &buf.layers()[0];
1390 let fields = buf.layer_fields(layer);
1391 assert_eq!(fields[FD_TYPE].value, FieldValue::U8(8));
1392 assert_eq!(fields[FD_CODE].value, FieldValue::U8(0));
1393 assert_eq!(fields[FD_CHECKSUM].value, FieldValue::U16(0xABCD));
1394 let id = fields
1395 .iter()
1396 .find(|f| f.descriptor.name == "identifier")
1397 .unwrap();
1398 assert_eq!(id.value, FieldValue::U16(0x1234));
1399 let seq = fields
1400 .iter()
1401 .find(|f| f.descriptor.name == "sequence_number")
1402 .unwrap();
1403 assert_eq!(seq.value, FieldValue::U16(1));
1404 let payload = fields.iter().find(|f| f.descriptor.name == "data").unwrap();
1405 assert_eq!(payload.value, FieldValue::Bytes(&[0xDE, 0xAD]));
1406 }
1407
1408 #[test]
1409 fn parse_dest_unreachable_fragmentation_needed() {
1410 let data: &[u8] = &[
1412 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x05, 0xDC, ];
1415 let mut buf = DissectBuffer::new();
1416 IcmpDissector.dissect(data, &mut buf, 0).unwrap();
1417
1418 let layer = &buf.layers()[0];
1419 let fields = buf.layer_fields(layer);
1420 let mtu = fields
1421 .iter()
1422 .find(|f| f.descriptor.name == "next_hop_mtu")
1423 .unwrap();
1424 assert_eq!(mtu.value, FieldValue::U16(1500));
1425 }
1426
1427 #[test]
1428 fn parse_dest_unreachable_with_rfc4884_length() {
1429 let mut data = vec![
1431 0x03, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, ];
1434 data.extend_from_slice(&[0u8; 28]);
1436 let mut buf = DissectBuffer::new();
1437 IcmpDissector.dissect(&data, &mut buf, 0).unwrap();
1438
1439 let layer = &buf.layers()[0];
1440 let fields = buf.layer_fields(layer);
1441 let len = fields
1442 .iter()
1443 .find(|f| f.descriptor.name == "length")
1444 .unwrap();
1445 assert_eq!(len.value, FieldValue::U8(7));
1446 }
1447
1448 #[test]
1449 fn parse_redirect() {
1450 let data: &[u8] = &[
1452 0x05, 0x01, 0x00, 0x00, 0xC0, 0xA8, 0x01, 0x01, ];
1455 let mut buf = DissectBuffer::new();
1456 IcmpDissector.dissect(data, &mut buf, 0).unwrap();
1457
1458 let layer = &buf.layers()[0];
1459 let fields = buf.layer_fields(layer);
1460 let gw = fields
1461 .iter()
1462 .find(|f| f.descriptor.name == "gateway")
1463 .unwrap();
1464 assert_eq!(gw.value, FieldValue::Ipv4Addr([192, 168, 1, 1]));
1465 }
1466
1467 #[test]
1468 fn parse_parameter_problem() {
1469 let data: &[u8] = &[
1471 0x0C, 0x00, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, ];
1474 let mut buf = DissectBuffer::new();
1475 IcmpDissector.dissect(data, &mut buf, 0).unwrap();
1476
1477 let layer = &buf.layers()[0];
1478 let fields = buf.layer_fields(layer);
1479 let ptr = fields
1480 .iter()
1481 .find(|f| f.descriptor.name == "pointer")
1482 .unwrap();
1483 assert_eq!(ptr.value, FieldValue::U8(8));
1484 assert_eq!(ptr.descriptor.field_type, FieldType::U8);
1485 let len = fields
1486 .iter()
1487 .find(|f| f.descriptor.name == "length")
1488 .unwrap();
1489 assert_eq!(len.value, FieldValue::U8(3));
1490 }
1491
1492 #[test]
1493 fn parse_timestamp_request() {
1494 let data: &[u8] = &[
1496 0x0D, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x51, 0x80, 0x00, 0x02, 0xA3, 0x00, 0x00, 0x03, 0xF4, 0x80, ];
1502 let mut buf = DissectBuffer::new();
1503 IcmpDissector.dissect(data, &mut buf, 0).unwrap();
1504
1505 let layer = &buf.layers()[0];
1506 let fields = buf.layer_fields(layer);
1507 let orig = fields
1508 .iter()
1509 .find(|f| f.descriptor.name == "originate_timestamp")
1510 .unwrap();
1511 assert_eq!(orig.value, FieldValue::U32(86400));
1512 let recv = fields
1513 .iter()
1514 .find(|f| f.descriptor.name == "receive_timestamp")
1515 .unwrap();
1516 assert_eq!(recv.value, FieldValue::U32(172800));
1517 let xmit = fields
1518 .iter()
1519 .find(|f| f.descriptor.name == "transmit_timestamp")
1520 .unwrap();
1521 assert_eq!(xmit.value, FieldValue::U32(259200));
1522 }
1523
1524 #[test]
1525 fn parse_timestamp_truncated() {
1526 let data: &[u8] = &[
1528 0x0D, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
1533 let mut buf = DissectBuffer::new();
1534 let err = IcmpDissector.dissect(data, &mut buf, 0).unwrap_err();
1535 assert!(
1536 matches!(
1537 err,
1538 PacketError::Truncated {
1539 expected: 20,
1540 actual: 16
1541 }
1542 ),
1543 "expected Truncated(20,16), got {err:?}"
1544 );
1545 }
1546
1547 #[test]
1548 fn parse_address_mask_reply() {
1549 let data: &[u8] = &[
1551 0x12, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x05, 0xFF, 0xFF, 0xFF, 0x00, ];
1555 let mut buf = DissectBuffer::new();
1556 IcmpDissector.dissect(data, &mut buf, 0).unwrap();
1557
1558 let layer = &buf.layers()[0];
1559 let fields = buf.layer_fields(layer);
1560 let mask = fields
1561 .iter()
1562 .find(|f| f.descriptor.name == "address_mask")
1563 .unwrap();
1564 assert_eq!(mask.value, FieldValue::Ipv4Addr([255, 255, 255, 0]));
1565 }
1566
1567 #[test]
1570 fn parse_router_advertisement_signed_preference() {
1571 let data: &[u8] = &[
1574 0x09, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x1E, 0xC0, 0xA8, 0x01, 0x01, 0x00, 0x00, 0x00, 0x64, ];
1579 let mut buf = DissectBuffer::new();
1580 IcmpDissector.dissect(data, &mut buf, 0).unwrap();
1581
1582 let layer = &buf.layers()[0];
1583 let fields = buf.layer_fields(layer);
1584 let entries = fields
1585 .iter()
1586 .find(|f| f.descriptor.name == "entries")
1587 .unwrap();
1588 let range = match &entries.value {
1589 FieldValue::Array(r) => r.clone(),
1590 other => panic!("expected Array, got {other:?}"),
1591 };
1592 let items = buf.nested_fields(&range);
1593 let obj = items.iter().find(|f| f.value.is_object()).unwrap();
1594 let obj_range = match &obj.value {
1595 FieldValue::Object(r) => r.clone(),
1596 other => panic!("expected Object, got {other:?}"),
1597 };
1598 let children = buf.nested_fields(&obj_range);
1599 let pref = children
1600 .iter()
1601 .find(|f| f.descriptor.name == "preference_level")
1602 .unwrap();
1603 assert_eq!(pref.descriptor.field_type, FieldType::I32);
1605 assert_eq!(pref.value, FieldValue::I32(100));
1606 }
1607
1608 #[test]
1609 fn parse_router_advertisement_do_not_use() {
1610 let data: &[u8] = &[
1612 0x09, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x1E, 0x0A, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, ];
1617 let mut buf = DissectBuffer::new();
1618 IcmpDissector.dissect(data, &mut buf, 0).unwrap();
1619
1620 let layer = &buf.layers()[0];
1621 let fields = buf.layer_fields(layer);
1622 let entries = fields
1623 .iter()
1624 .find(|f| f.descriptor.name == "entries")
1625 .unwrap();
1626 let range = match &entries.value {
1627 FieldValue::Array(r) => r.clone(),
1628 other => panic!("expected Array, got {other:?}"),
1629 };
1630 let items = buf.nested_fields(&range);
1631 let obj = items.iter().find(|f| f.value.is_object()).unwrap();
1632 let obj_range = match &obj.value {
1633 FieldValue::Object(r) => r.clone(),
1634 other => panic!("expected Object, got {other:?}"),
1635 };
1636 let children = buf.nested_fields(&obj_range);
1637 let pref = children
1638 .iter()
1639 .find(|f| f.descriptor.name == "preference_level")
1640 .unwrap();
1641 assert_eq!(pref.value, FieldValue::I32(i32::MIN));
1642 }
1643
1644 #[test]
1645 fn parse_photuris() {
1646 let data: &[u8] = &[
1648 0x28, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, ];
1651 let mut buf = DissectBuffer::new();
1652 IcmpDissector.dissect(data, &mut buf, 0).unwrap();
1653
1654 let layer = &buf.layers()[0];
1655 let fields = buf.layer_fields(layer);
1656
1657 let reserved = fields
1659 .iter()
1660 .find(|f| f.descriptor.name == "photuris_reserved")
1661 .unwrap();
1662 assert_eq!(reserved.value, FieldValue::U16(0));
1663 assert_eq!(reserved.descriptor.field_type, FieldType::U16);
1664
1665 let ptr = fields
1667 .iter()
1668 .find(|f| f.descriptor.name == "photuris_pointer")
1669 .unwrap();
1670 assert_eq!(ptr.value, FieldValue::U16(20));
1671 assert_eq!(ptr.descriptor.field_type, FieldType::U16);
1672 }
1673
1674 #[test]
1677 fn parse_extended_echo_request() {
1678 let data: &[u8] = &[
1680 0x2A, 0x00, 0x00, 0x00, 0xAB, 0xCD, 0x07, 0x01, ];
1683 let mut buf = DissectBuffer::new();
1684 IcmpDissector.dissect(data, &mut buf, 0).unwrap();
1685
1686 let layer = &buf.layers()[0];
1687 let fields = buf.layer_fields(layer);
1688 let id = fields
1689 .iter()
1690 .find(|f| f.descriptor.name == "identifier")
1691 .unwrap();
1692 assert_eq!(id.value, FieldValue::U16(0xABCD));
1693 let seq = fields
1694 .iter()
1695 .find(|f| f.descriptor.name == "sequence_number")
1696 .unwrap();
1697 assert_eq!(seq.value, FieldValue::U16(7));
1699 let local = fields
1700 .iter()
1701 .find(|f| f.descriptor.name == "local")
1702 .unwrap();
1703 assert_eq!(local.value, FieldValue::U8(1)); }
1705
1706 #[test]
1707 fn parse_extended_echo_reply() {
1708 let data: &[u8] = &[
1712 0x2B, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x46, ];
1715 let mut buf = DissectBuffer::new();
1716 IcmpDissector.dissect(data, &mut buf, 0).unwrap();
1717
1718 let layer = &buf.layers()[0];
1719 let fields = buf.layer_fields(layer);
1720 let state = fields
1721 .iter()
1722 .find(|f| f.descriptor.name == "state")
1723 .unwrap();
1724 assert_eq!(state.value, FieldValue::U8(2)); let active = fields
1726 .iter()
1727 .find(|f| f.descriptor.name == "active")
1728 .unwrap();
1729 assert_eq!(active.value, FieldValue::U8(1));
1730 let ipv4 = fields.iter().find(|f| f.descriptor.name == "ipv4").unwrap();
1731 assert_eq!(ipv4.value, FieldValue::U8(1));
1732 let ipv6 = fields.iter().find(|f| f.descriptor.name == "ipv6").unwrap();
1733 assert_eq!(ipv6.value, FieldValue::U8(0));
1734 }
1735
1736 fn build_time_exceeded_with_extensions(ext: &[u8]) -> Vec<u8> {
1742 let mut pkt = Vec::with_capacity(HEADER_SIZE + 128 + ext.len());
1743 pkt.push(11); pkt.push(0); pkt.extend_from_slice(&[0x00, 0x00]); pkt.push(0); pkt.push(32); pkt.extend_from_slice(&[0x00, 0x00]); pkt.extend_from_slice(&[0u8; 128]);
1751 pkt.extend_from_slice(ext);
1752 pkt
1753 }
1754
1755 fn extension_object_ranges(
1760 buf: &DissectBuffer<'_>,
1761 layer_idx: usize,
1762 ) -> Vec<core::ops::Range<u32>> {
1763 let layer = &buf.layers()[layer_idx];
1764 let fields = buf.layer_fields(layer);
1765 let ext = fields
1766 .iter()
1767 .find(|f| f.descriptor.name == "extensions")
1768 .expect("extensions field present");
1769 let ext_range = match &ext.value {
1770 FieldValue::Object(r) => r.clone(),
1771 other => panic!("expected Object, got {other:?}"),
1772 };
1773 let ext_children = buf.nested_fields(&ext_range);
1774 let objects = ext_children
1775 .iter()
1776 .find(|f| f.descriptor.name == "objects")
1777 .expect("objects array");
1778 let objects_range = match &objects.value {
1779 FieldValue::Array(r) => r.clone(),
1780 other => panic!("expected Array, got {other:?}"),
1781 };
1782 let items = buf.nested_fields(&objects_range);
1783 let mut result = Vec::new();
1784 let mut i = 0;
1785 while i < items.len() {
1786 let f = &items[i];
1787 match &f.value {
1788 FieldValue::Object(r) => {
1789 let descendants = (r.end - r.start) as usize;
1790 result.push(r.clone());
1791 i += 1 + descendants;
1792 }
1793 FieldValue::Array(r) => {
1794 let descendants = (r.end - r.start) as usize;
1795 i += 1 + descendants;
1796 }
1797 _ => i += 1,
1798 }
1799 }
1800 result
1801 }
1802
1803 #[test]
1804 fn parse_extension_header_fields() {
1805 let ext = [
1808 0x20, 0x00, 0x12, 0x34, 0x00, 0x05, 0x63, 0x01, 0xAA, 0x00, 0x00,
1811 0x00, ];
1813 let pkt = build_time_exceeded_with_extensions(&ext[..9]); let mut buf = DissectBuffer::new();
1815 IcmpDissector.dissect(&pkt, &mut buf, 0).unwrap();
1816
1817 let layer = &buf.layers()[0];
1818 let fields = buf.layer_fields(layer);
1819 let ext_field = fields
1820 .iter()
1821 .find(|f| f.descriptor.name == "extensions")
1822 .unwrap();
1823 let ext_range = match &ext_field.value {
1824 FieldValue::Object(r) => r.clone(),
1825 other => panic!("expected Object, got {other:?}"),
1826 };
1827 let children = buf.nested_fields(&ext_range);
1828 let version = children
1829 .iter()
1830 .find(|f| f.descriptor.name == "version")
1831 .unwrap();
1832 assert_eq!(version.value, FieldValue::U8(2));
1833 let reserved = children
1834 .iter()
1835 .find(|f| f.descriptor.name == "reserved")
1836 .unwrap();
1837 assert_eq!(reserved.value, FieldValue::U16(0));
1838 let checksum = children
1839 .iter()
1840 .find(|f| f.descriptor.name == "checksum")
1841 .unwrap();
1842 assert_eq!(checksum.value, FieldValue::U16(0x1234));
1843 }
1844
1845 #[test]
1846 fn parse_extensions_not_parsed_when_length_zero() {
1847 let mut pkt = vec![
1850 11, 0, 0, 0, 0, 0, 0, 0, ];
1853 pkt.extend_from_slice(&[0u8; 128]);
1855 let mut buf = DissectBuffer::new();
1856 IcmpDissector.dissect(&pkt, &mut buf, 0).unwrap();
1857
1858 let layer = &buf.layers()[0];
1859 let fields = buf.layer_fields(layer);
1860 assert!(
1861 fields.iter().all(|f| f.descriptor.name != "extensions"),
1862 "extensions must not be present when RFC 4884 Length is 0"
1863 );
1864 }
1865
1866 #[test]
1867 fn parse_extension_mpls_label_stack_class1() {
1868 let ext = [
1874 0x20, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x01, 0x01, 0x12, 0x34, 0x5A, 0x40, 0x00, 0x01, 0x01, 0x20, ];
1879 let pkt = build_time_exceeded_with_extensions(&ext);
1880 let mut buf = DissectBuffer::new();
1881 IcmpDissector.dissect(&pkt, &mut buf, 0).unwrap();
1882
1883 let objs = extension_object_ranges(&buf, 0);
1884 assert_eq!(objs.len(), 1, "one MPLS object");
1885 let obj_children = buf.nested_fields(&objs[0]);
1886 let class_num = obj_children
1887 .iter()
1888 .find(|f| f.descriptor.name == "class_num")
1889 .unwrap();
1890 assert_eq!(class_num.value, FieldValue::U8(1));
1891 let mpls_labels = obj_children
1892 .iter()
1893 .find(|f| f.descriptor.name == "mpls_labels")
1894 .unwrap();
1895 let mpls_range = match &mpls_labels.value {
1896 FieldValue::Array(r) => r.clone(),
1897 other => panic!("expected Array, got {other:?}"),
1898 };
1899 let entries: Vec<_> = buf
1900 .nested_fields(&mpls_range)
1901 .iter()
1902 .filter_map(|f| match &f.value {
1903 FieldValue::Object(r) => Some(r.clone()),
1904 _ => None,
1905 })
1906 .collect();
1907 assert_eq!(entries.len(), 2);
1908
1909 let lse1 = buf.nested_fields(&entries[0]);
1911 let l1 = lse1.iter().find(|f| f.descriptor.name == "label").unwrap();
1912 assert_eq!(l1.value, FieldValue::U32(0x12345));
1913 let tc1 = lse1.iter().find(|f| f.descriptor.name == "tc").unwrap();
1914 assert_eq!(tc1.value, FieldValue::U8(5));
1915 let s1 = lse1.iter().find(|f| f.descriptor.name == "s").unwrap();
1916 assert_eq!(s1.value, FieldValue::U8(0));
1917 let ttl1 = lse1.iter().find(|f| f.descriptor.name == "ttl").unwrap();
1918 assert_eq!(ttl1.value, FieldValue::U8(64));
1919
1920 let lse2 = buf.nested_fields(&entries[1]);
1922 let l2 = lse2.iter().find(|f| f.descriptor.name == "label").unwrap();
1923 assert_eq!(l2.value, FieldValue::U32(0x00010));
1924 let s2 = lse2.iter().find(|f| f.descriptor.name == "s").unwrap();
1925 assert_eq!(s2.value, FieldValue::U8(1));
1926 let ttl2 = lse2.iter().find(|f| f.descriptor.name == "ttl").unwrap();
1927 assert_eq!(ttl2.value, FieldValue::U8(32));
1928 }
1929
1930 #[test]
1931 fn parse_extension_interface_info_class2_all_sub_objects() {
1932 let ext = [
1939 0x20, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x02, 0x8F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0xC0, 0xA8, 0x00, 0x01, 0x08, b'e', b't', b'h', b'0', 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xDC, ];
1948 let pkt = build_time_exceeded_with_extensions(&ext);
1949 let mut buf = DissectBuffer::new();
1950 IcmpDissector.dissect(&pkt, &mut buf, 0).unwrap();
1951
1952 let objs = extension_object_ranges(&buf, 0);
1953 assert_eq!(objs.len(), 1);
1954 let obj = buf.nested_fields(&objs[0]);
1955
1956 let role = obj
1957 .iter()
1958 .find(|f| f.descriptor.name == "interface_role")
1959 .unwrap();
1960 assert_eq!(role.value, FieldValue::U8(2));
1961
1962 let ifi = obj
1963 .iter()
1964 .find(|f| f.descriptor.name == "if_index")
1965 .unwrap();
1966 assert_eq!(ifi.value, FieldValue::U32(7));
1967
1968 let afi = obj.iter().find(|f| f.descriptor.name == "afi").unwrap();
1969 assert_eq!(afi.value, FieldValue::U16(1));
1970
1971 let ip = obj
1972 .iter()
1973 .find(|f| f.descriptor.name == "ipv4_address")
1974 .unwrap();
1975 assert_eq!(ip.value, FieldValue::Ipv4Addr([192, 168, 0, 1]));
1976
1977 let name = obj
1978 .iter()
1979 .find(|f| f.descriptor.name == "interface_name")
1980 .unwrap();
1981 assert_eq!(name.value, FieldValue::Bytes(b"eth0\x00\x00\x00"));
1983
1984 let mtu = obj.iter().find(|f| f.descriptor.name == "mtu").unwrap();
1985 assert_eq!(mtu.value, FieldValue::U32(1500));
1986 }
1987
1988 #[test]
1989 fn parse_extension_interface_info_class2_ipv6_address() {
1990 let ext = [
1994 0x20, 0x00, 0x00, 0x00, 0x00, 0x18, 0x02, 0x04, 0x00, 0x02, 0x00, 0x00, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ];
2000 let pkt = build_time_exceeded_with_extensions(&ext);
2001 let mut buf = DissectBuffer::new();
2002 IcmpDissector.dissect(&pkt, &mut buf, 0).unwrap();
2003
2004 let objs = extension_object_ranges(&buf, 0);
2005 let obj = buf.nested_fields(&objs[0]);
2006 let role = obj
2007 .iter()
2008 .find(|f| f.descriptor.name == "interface_role")
2009 .unwrap();
2010 assert_eq!(role.value, FieldValue::U8(0));
2011 let ipv6 = obj
2012 .iter()
2013 .find(|f| f.descriptor.name == "ipv6_address")
2014 .unwrap();
2015 let mut expected = [0u8; 16];
2016 expected[0] = 0x20;
2017 expected[1] = 0x01;
2018 expected[2] = 0x0d;
2019 expected[3] = 0xb8;
2020 expected[15] = 0x01;
2021 assert_eq!(ipv6.value, FieldValue::Ipv6Addr(expected));
2022 }
2023
2024 #[test]
2025 fn parse_extension_interface_id_class3_by_index() {
2026 let ext = [
2028 0x20, 0x00, 0x00, 0x00, 0x00, 0x08, 0x03, 0x02, 0x00, 0x00, 0x00, 0x2A, ];
2032 let pkt = build_time_exceeded_with_extensions(&ext);
2033 let mut buf = DissectBuffer::new();
2034 IcmpDissector.dissect(&pkt, &mut buf, 0).unwrap();
2035
2036 let objs = extension_object_ranges(&buf, 0);
2037 let obj = buf.nested_fields(&objs[0]);
2038 let ifi = obj
2039 .iter()
2040 .find(|f| f.descriptor.name == "if_index")
2041 .unwrap();
2042 assert_eq!(ifi.value, FieldValue::U32(42));
2043 }
2044
2045 #[test]
2046 fn parse_extension_interface_id_class3_by_name() {
2047 let ext = [
2049 0x20, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x01, b'e', b'n', b'0', 0x00, 0x00, 0x00, 0x00, 0x00, ];
2054 let pkt = build_time_exceeded_with_extensions(&ext);
2055 let mut buf = DissectBuffer::new();
2056 IcmpDissector.dissect(&pkt, &mut buf, 0).unwrap();
2057
2058 let objs = extension_object_ranges(&buf, 0);
2059 let obj = buf.nested_fields(&objs[0]);
2060 let name = obj
2061 .iter()
2062 .find(|f| f.descriptor.name == "interface_name")
2063 .unwrap();
2064 assert_eq!(name.value, FieldValue::Bytes(b"en0\x00\x00\x00\x00\x00"));
2065 }
2066
2067 #[test]
2068 fn parse_extension_interface_id_class3_by_address_ipv4() {
2069 let ext = [
2071 0x20, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x03, 0x00, 0x01, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x01, ];
2076 let pkt = build_time_exceeded_with_extensions(&ext);
2077 let mut buf = DissectBuffer::new();
2078 IcmpDissector.dissect(&pkt, &mut buf, 0).unwrap();
2079
2080 let objs = extension_object_ranges(&buf, 0);
2081 let obj = buf.nested_fields(&objs[0]);
2082 let afi = obj.iter().find(|f| f.descriptor.name == "afi").unwrap();
2083 assert_eq!(afi.value, FieldValue::U16(1));
2084 let alen = obj
2085 .iter()
2086 .find(|f| f.descriptor.name == "address_length")
2087 .unwrap();
2088 assert_eq!(alen.value, FieldValue::U8(4));
2089 let ip = obj
2090 .iter()
2091 .find(|f| f.descriptor.name == "ipv4_address")
2092 .unwrap();
2093 assert_eq!(ip.value, FieldValue::Ipv4Addr([10, 0, 0, 1]));
2094 }
2095
2096 #[test]
2097 fn parse_extension_interface_id_class3_by_address_ipv6() {
2098 let ext = [
2101 0x20, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x03, 0x00, 0x02, 0x10, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ];
2107 let pkt = build_time_exceeded_with_extensions(&ext);
2108 let mut buf = DissectBuffer::new();
2109 IcmpDissector.dissect(&pkt, &mut buf, 0).unwrap();
2110
2111 let objs = extension_object_ranges(&buf, 0);
2112 let obj = buf.nested_fields(&objs[0]);
2113 let ipv6 = obj
2114 .iter()
2115 .find(|f| f.descriptor.name == "ipv6_address")
2116 .unwrap();
2117 let mut expected = [0u8; 16];
2118 expected[0] = 0xfe;
2119 expected[1] = 0x80;
2120 expected[15] = 0x05;
2121 assert_eq!(ipv6.value, FieldValue::Ipv6Addr(expected));
2122 }
2123
2124 #[test]
2125 fn parse_extension_unknown_class_preserves_payload() {
2126 let ext = [
2129 0x20, 0x00, 0x00, 0x00, 0x00, 0x08, 0x7F, 0x05, 0xDE, 0xAD, 0xBE, 0xEF, ];
2133 let pkt = build_time_exceeded_with_extensions(&ext);
2134 let mut buf = DissectBuffer::new();
2135 IcmpDissector.dissect(&pkt, &mut buf, 0).unwrap();
2136
2137 let objs = extension_object_ranges(&buf, 0);
2138 let obj = buf.nested_fields(&objs[0]);
2139 let payload = obj.iter().find(|f| f.descriptor.name == "payload").unwrap();
2140 assert_eq!(payload.value, FieldValue::Bytes(&[0xDE, 0xAD, 0xBE, 0xEF]));
2141 }
2142
2143 #[test]
2144 fn parse_extension_malformed_object_length_stops_parsing() {
2145 let ext = [
2148 0x20, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0xAA, 0xBB, 0xCC, 0xDD, ];
2152 let pkt = build_time_exceeded_with_extensions(&ext);
2153 let mut buf = DissectBuffer::new();
2154 IcmpDissector.dissect(&pkt, &mut buf, 0).unwrap();
2155
2156 let objs = extension_object_ranges(&buf, 0);
2159 assert!(
2160 objs.is_empty(),
2161 "malformed object length must not yield objects"
2162 );
2163 }
2164
2165 #[test]
2166 fn parse_extended_echo_request_with_interface_id_extension() {
2167 let mut pkt = vec![
2170 42, 0, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, ];
2173 let ext = [
2174 0x20, 0x00, 0x00, 0x00, 0x00, 0x08, 0x03, 0x02, 0x00, 0x00, 0x00, 0x03, ];
2178 pkt.extend_from_slice(&ext);
2179
2180 let mut buf = DissectBuffer::new();
2181 IcmpDissector.dissect(&pkt, &mut buf, 0).unwrap();
2182
2183 let objs = extension_object_ranges(&buf, 0);
2184 assert_eq!(objs.len(), 1);
2185 let obj = buf.nested_fields(&objs[0]);
2186 let ifi = obj
2187 .iter()
2188 .find(|f| f.descriptor.name == "if_index")
2189 .unwrap();
2190 assert_eq!(ifi.value, FieldValue::U32(3));
2191 }
2192
2193 #[test]
2194 fn rfc4884_extension_offset_padding_semantics() {
2195 assert_eq!(rfc4884_extension_offset(200, 32), Some(HEADER_SIZE + 128));
2197 assert_eq!(rfc4884_extension_offset(200, 10), Some(HEADER_SIZE + 128));
2199 assert_eq!(rfc4884_extension_offset(300, 40), Some(HEADER_SIZE + 160));
2201 assert_eq!(rfc4884_extension_offset(200, 0), None);
2203 assert_eq!(rfc4884_extension_offset(100, 32), None);
2205 }
2206}