1use etherparse::Ipv6HeaderSlice;
4use smallvec::SmallVec;
5
6use super::ethernet::ethertype;
7use super::{FieldValue, ParseContext, ParseResult, Protocol, TunnelType};
8use crate::schema::{DataKind, FieldDescriptor};
9
10pub mod next_header {
12 pub const HOP_BY_HOP: u8 = 0;
13 pub const IPIP: u8 = 4;
15 #[allow(dead_code)] pub const TCP: u8 = 6;
17 #[allow(dead_code)] pub const UDP: u8 = 17;
19 pub const IPV6_IN_IP: u8 = 41;
21 pub const ROUTING: u8 = 43;
22 pub const FRAGMENT: u8 = 44;
23 #[allow(dead_code)] pub const ESP: u8 = 50;
25 pub const AH: u8 = 51;
26 #[allow(dead_code)] pub const ICMPV6: u8 = 58;
28 #[allow(dead_code)] pub const NO_NEXT_HEADER: u8 = 59;
30 pub const DESTINATION: u8 = 60;
31 pub const MOBILITY: u8 = 135;
32}
33
34fn is_extension_header(nh: u8) -> bool {
36 matches!(
37 nh,
38 next_header::HOP_BY_HOP
39 | next_header::ROUTING
40 | next_header::FRAGMENT
41 | next_header::DESTINATION
42 | next_header::AH
43 | next_header::MOBILITY
44 )
45}
46
47#[derive(Debug, Clone, Copy)]
49pub struct Ipv6Protocol;
50
51impl Protocol for Ipv6Protocol {
52 fn name(&self) -> &'static str {
53 "ipv6"
54 }
55
56 fn display_name(&self) -> &'static str {
57 "IPv6"
58 }
59
60 fn can_parse(&self, context: &ParseContext) -> Option<u32> {
61 match context.hint("ethertype") {
62 Some(et) if et == ethertype::IPV6 as u64 => Some(100),
63 _ => None,
64 }
65 }
66
67 fn parse<'a>(&self, data: &'a [u8], _context: &ParseContext) -> ParseResult<'a> {
68 match Ipv6HeaderSlice::from_slice(data) {
69 Ok(ipv6) => {
70 let mut fields = SmallVec::new();
71
72 fields.push(("version", FieldValue::UInt8(6)));
73 fields.push(("traffic_class", FieldValue::UInt8(ipv6.traffic_class())));
74 fields.push(("flow_label", FieldValue::UInt32(ipv6.flow_label().value())));
75 fields.push(("payload_length", FieldValue::UInt16(ipv6.payload_length())));
76 fields.push(("next_header", FieldValue::UInt8(ipv6.next_header().0)));
77 fields.push(("hop_limit", FieldValue::UInt8(ipv6.hop_limit())));
78 fields.push(("src_ip", FieldValue::ipv6(&ipv6.source())));
79 fields.push(("dst_ip", FieldValue::ipv6(&ipv6.destination())));
80
81 let base_header_len = ipv6.slice().len();
82 let payload = &data[base_header_len..];
83 let first_next_header = ipv6.next_header().0;
84
85 let (final_next_header, ext_consumed, ext_fields) =
87 parse_extension_headers(first_next_header, payload);
88
89 for (k, v) in ext_fields {
91 fields.push((k, v));
92 }
93
94 let mut child_hints = SmallVec::new();
95 child_hints.push(("ip_protocol", final_next_header as u64));
96 child_hints.push(("ip_version", 6));
97
98 if final_next_header == next_header::IPIP {
100 child_hints.push(("tunnel_type", TunnelType::Ip4InIp6 as u64));
102 child_hints.push(("ethertype", ethertype::IPV4 as u64));
104 } else if final_next_header == next_header::IPV6_IN_IP {
105 child_hints.push(("tunnel_type", TunnelType::Ip6InIp6 as u64));
107 child_hints.push(("ethertype", ethertype::IPV6 as u64));
109 }
110
111 let total_consumed = base_header_len + ext_consumed;
112 ParseResult::success(fields, &data[total_consumed..], child_hints)
113 }
114 Err(e) => ParseResult::error(format!("IPv6 parse error: {e}"), data),
115 }
116 }
117
118 fn schema_fields(&self) -> Vec<FieldDescriptor> {
119 vec![
120 FieldDescriptor::new("ipv6.version", DataKind::UInt8).set_nullable(true),
122 FieldDescriptor::new("ipv6.traffic_class", DataKind::UInt8).set_nullable(true),
123 FieldDescriptor::new("ipv6.flow_label", DataKind::UInt32).set_nullable(true),
124 FieldDescriptor::new("ipv6.payload_length", DataKind::UInt16).set_nullable(true),
125 FieldDescriptor::new("ipv6.next_header", DataKind::UInt8).set_nullable(true),
126 FieldDescriptor::new("ipv6.hop_limit", DataKind::UInt8).set_nullable(true),
127 FieldDescriptor::new("ipv6.src_ip", DataKind::String).set_nullable(true),
128 FieldDescriptor::new("ipv6.dst_ip", DataKind::String).set_nullable(true),
129 FieldDescriptor::new("ipv6.ext_hop_by_hop", DataKind::Bool).set_nullable(true),
131 FieldDescriptor::new("ipv6.ext_routing", DataKind::Bool).set_nullable(true),
132 FieldDescriptor::new("ipv6.ext_fragment", DataKind::Bool).set_nullable(true),
133 FieldDescriptor::new("ipv6.ext_destination", DataKind::Bool).set_nullable(true),
134 FieldDescriptor::new("ipv6.frag_offset", DataKind::UInt16).set_nullable(true),
136 FieldDescriptor::new("ipv6.frag_more", DataKind::Bool).set_nullable(true),
137 FieldDescriptor::new("ipv6.frag_id", DataKind::UInt32).set_nullable(true),
138 FieldDescriptor::new("ipv6.routing_type", DataKind::UInt8).set_nullable(true),
140 FieldDescriptor::new("ipv6.segments_left", DataKind::UInt8).set_nullable(true),
141 ]
142 }
143
144 fn child_protocols(&self) -> &[&'static str] {
145 &["tcp", "udp", "icmpv6"]
146 }
147
148 fn dependencies(&self) -> &'static [&'static str] {
149 &["ethernet", "vlan", "mpls", "gre", "vxlan", "gtp"]
150 }
151}
152
153fn parse_extension_headers(
155 first_nh: u8,
156 data: &[u8],
157) -> (u8, usize, SmallVec<[(&'static str, FieldValue<'_>); 16]>) {
158 let mut fields = SmallVec::new();
159 let mut offset = 0;
160 let mut current_nh = first_nh;
161
162 let mut has_hop_by_hop = false;
164 let mut has_routing = false;
165 let mut has_fragment = false;
166 let mut has_destination = false;
167
168 while is_extension_header(current_nh) && offset < data.len() {
169 match current_nh {
170 next_header::HOP_BY_HOP => {
171 has_hop_by_hop = true;
172 if let Some((next_nh, consumed)) = parse_generic_ext_header(&data[offset..]) {
173 current_nh = next_nh;
174 offset += consumed;
175 } else {
176 break;
177 }
178 }
179 next_header::ROUTING => {
180 has_routing = true;
181 if let Some((next_nh, consumed, routing_fields)) =
182 parse_routing_header(&data[offset..])
183 {
184 for (k, v) in routing_fields {
185 fields.push((k, v));
186 }
187 current_nh = next_nh;
188 offset += consumed;
189 } else {
190 break;
191 }
192 }
193 next_header::FRAGMENT => {
194 has_fragment = true;
195 if let Some((next_nh, consumed, frag_fields)) =
196 parse_fragment_header(&data[offset..])
197 {
198 for (k, v) in frag_fields {
199 fields.push((k, v));
200 }
201 current_nh = next_nh;
202 offset += consumed;
203 } else {
204 break;
205 }
206 }
207 next_header::DESTINATION => {
208 has_destination = true;
209 if let Some((next_nh, consumed)) = parse_generic_ext_header(&data[offset..]) {
210 current_nh = next_nh;
211 offset += consumed;
212 } else {
213 break;
214 }
215 }
216 next_header::AH => {
217 if let Some((next_nh, consumed)) = parse_ah_header(&data[offset..]) {
219 current_nh = next_nh;
220 offset += consumed;
221 } else {
222 break;
223 }
224 }
225 next_header::MOBILITY => {
226 if let Some((next_nh, consumed)) = parse_generic_ext_header(&data[offset..]) {
227 current_nh = next_nh;
228 offset += consumed;
229 } else {
230 break;
231 }
232 }
233 _ => break,
234 }
235 }
236
237 fields.push(("ext_hop_by_hop", FieldValue::Bool(has_hop_by_hop)));
239 fields.push(("ext_routing", FieldValue::Bool(has_routing)));
240 fields.push(("ext_fragment", FieldValue::Bool(has_fragment)));
241 fields.push(("ext_destination", FieldValue::Bool(has_destination)));
242
243 (current_nh, offset, fields)
244}
245
246fn parse_generic_ext_header(data: &[u8]) -> Option<(u8, usize)> {
249 if data.len() < 2 {
250 return None;
251 }
252
253 let next_header = data[0];
254 let hdr_ext_len = data[1] as usize;
255 let total_len = (hdr_ext_len + 1) * 8;
257
258 if data.len() < total_len {
259 return None;
260 }
261
262 Some((next_header, total_len))
263}
264
265#[allow(clippy::type_complexity)]
268fn parse_fragment_header(
269 data: &[u8],
270) -> Option<(u8, usize, SmallVec<[(&'static str, FieldValue<'_>); 16]>)> {
271 if data.len() < 8 {
273 return None;
274 }
275
276 let mut fields = SmallVec::new();
277
278 let next_header = data[0];
279 let frag_offset_and_flags = u16::from_be_bytes([data[2], data[3]]);
281 let frag_offset = frag_offset_and_flags >> 3; let more_fragments = (frag_offset_and_flags & 0x0001) != 0; let identification = u32::from_be_bytes([data[4], data[5], data[6], data[7]]);
284
285 fields.push(("frag_offset", FieldValue::UInt16(frag_offset)));
286 fields.push(("frag_more", FieldValue::Bool(more_fragments)));
287 fields.push(("frag_id", FieldValue::UInt32(identification)));
288
289 Some((next_header, 8, fields))
290}
291
292#[allow(clippy::type_complexity)]
295fn parse_routing_header(
296 data: &[u8],
297) -> Option<(u8, usize, SmallVec<[(&'static str, FieldValue<'_>); 16]>)> {
298 if data.len() < 4 {
299 return None;
300 }
301
302 let mut fields = SmallVec::new();
303
304 let next_header = data[0];
305 let hdr_ext_len = data[1] as usize;
306 let routing_type = data[2];
307 let segments_left = data[3];
308
309 let total_len = (hdr_ext_len + 1) * 8;
311
312 if data.len() < total_len {
313 return None;
314 }
315
316 fields.push(("routing_type", FieldValue::UInt8(routing_type)));
317 fields.push(("segments_left", FieldValue::UInt8(segments_left)));
318
319 Some((next_header, total_len, fields))
320}
321
322fn parse_ah_header(data: &[u8]) -> Option<(u8, usize)> {
325 if data.len() < 8 {
326 return None;
327 }
328
329 let next_header = data[0];
330 let payload_len = data[1] as usize;
331 let total_len = (payload_len + 2) * 4;
333
334 if data.len() < total_len {
335 return None;
336 }
337
338 Some((next_header, total_len))
339}
340
341#[cfg(test)]
342mod tests {
343 use super::*;
344
345 fn create_ipv6_context() -> ParseContext {
346 let mut context = ParseContext::new(1);
347 context.insert_hint("ethertype", ethertype::IPV6 as u64);
348 context
349 }
350
351 #[test]
352 fn test_parse_ipv6() {
353 let header = [
355 0x60, 0x00, 0x00, 0x00, 0x00, 0x14, 0x06, 0x40, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
361 0x00, 0x01, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
363 0x00, 0x02,
364 ];
365
366 let parser = Ipv6Protocol;
367 let context = create_ipv6_context();
368
369 let result = parser.parse(&header, &context);
370
371 assert!(result.is_ok());
372 assert_eq!(result.get("version"), Some(&FieldValue::UInt8(6)));
373 assert_eq!(result.get("hop_limit"), Some(&FieldValue::UInt8(64)));
374 assert_eq!(result.get("next_header"), Some(&FieldValue::UInt8(6)));
375 assert_eq!(result.hint("ip_protocol"), Some(6u64));
376 assert_eq!(result.hint("ip_version"), Some(6u64));
377 }
378
379 #[test]
380 fn test_can_parse_with_ipv6_ethertype() {
381 let parser = Ipv6Protocol;
382
383 let context1 = ParseContext::new(1);
385 assert!(parser.can_parse(&context1).is_none());
386
387 let mut context2 = ParseContext::new(1);
389 context2.insert_hint("ethertype", ethertype::IPV4 as u64);
390 assert!(parser.can_parse(&context2).is_none());
391
392 let mut context3 = ParseContext::new(1);
394 context3.insert_hint("ethertype", ethertype::IPV6 as u64);
395 assert!(parser.can_parse(&context3).is_some());
396 }
397
398 #[test]
399 fn test_parse_ipv6_with_udp() {
400 let header = [
402 0x60, 0x0a, 0xbc, 0xde, 0x00, 0x08, 0x11, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
408 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
410 0x00, 0x01,
411 ];
412
413 let parser = Ipv6Protocol;
414 let context = create_ipv6_context();
415
416 let result = parser.parse(&header, &context);
417
418 assert!(result.is_ok());
419 assert_eq!(result.get("next_header"), Some(&FieldValue::UInt8(17)));
420 assert_eq!(result.get("hop_limit"), Some(&FieldValue::UInt8(128)));
421 assert_eq!(result.hint("ip_protocol"), Some(17u64));
422 }
423
424 #[test]
425 fn test_parse_ipv6_too_short() {
426 let short_data = [0x60, 0x00, 0x00, 0x00]; let parser = Ipv6Protocol;
429 let context = create_ipv6_context();
430
431 let result = parser.parse(&short_data, &context);
432
433 assert!(!result.is_ok());
434 assert!(result.error.is_some());
435 }
436
437 #[test]
438 fn test_parse_hop_by_hop_options() {
439 let mut packet = vec![
441 0x60, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40, ];
446 packet.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
448 packet.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
450 packet.extend_from_slice(&[
452 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]);
456 packet.extend_from_slice(&[0x00, 0x50, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00]);
458
459 let parser = Ipv6Protocol;
460 let context = create_ipv6_context();
461
462 let result = parser.parse(&packet, &context);
463
464 assert!(result.is_ok());
465 assert_eq!(result.get("ext_hop_by_hop"), Some(&FieldValue::Bool(true)));
466 assert_eq!(result.get("ext_routing"), Some(&FieldValue::Bool(false)));
467 assert_eq!(result.hint("ip_protocol"), Some(6u64)); }
469
470 #[test]
471 fn test_parse_routing_header() {
472 let mut packet = vec![
474 0x60, 0x00, 0x00, 0x00, 0x00, 0x10, 0x2b, 0x40, ];
479 packet.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
481 packet.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
483 packet.extend_from_slice(&[
485 0x06, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, ]);
491
492 let parser = Ipv6Protocol;
493 let context = create_ipv6_context();
494
495 let result = parser.parse(&packet, &context);
496
497 assert!(result.is_ok());
498 assert_eq!(result.get("ext_routing"), Some(&FieldValue::Bool(true)));
499 assert_eq!(result.get("routing_type"), Some(&FieldValue::UInt8(2)));
500 assert_eq!(result.get("segments_left"), Some(&FieldValue::UInt8(1)));
501 assert_eq!(result.hint("ip_protocol"), Some(6u64));
502 }
503
504 #[test]
505 fn test_parse_fragment_header() {
506 let mut packet = vec![
508 0x60, 0x00, 0x00, 0x00, 0x00, 0x10, 0x2c, 0x40, ];
513 packet.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
515 packet.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
517 packet.extend_from_slice(&[
519 0x06, 0x00, 0x00, 0x09, 0x12, 0x34, 0x56, 0x78, ]);
524
525 let parser = Ipv6Protocol;
526 let context = create_ipv6_context();
527
528 let result = parser.parse(&packet, &context);
529
530 assert!(result.is_ok());
531 assert_eq!(result.get("ext_fragment"), Some(&FieldValue::Bool(true)));
532 assert_eq!(result.get("frag_offset"), Some(&FieldValue::UInt16(1)));
533 assert_eq!(result.get("frag_more"), Some(&FieldValue::Bool(true)));
534 assert_eq!(result.get("frag_id"), Some(&FieldValue::UInt32(0x12345678)));
535 }
536
537 #[test]
538 fn test_parse_destination_options() {
539 let mut packet = vec![
541 0x60, 0x00, 0x00, 0x00, 0x00, 0x10, 0x3c, 0x40,
543 ];
544 packet.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
546 packet.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
547 packet.extend_from_slice(&[0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
549
550 let parser = Ipv6Protocol;
551 let context = create_ipv6_context();
552
553 let result = parser.parse(&packet, &context);
554
555 assert!(result.is_ok());
556 assert_eq!(result.get("ext_destination"), Some(&FieldValue::Bool(true)));
557 assert_eq!(result.hint("ip_protocol"), Some(6u64));
558 }
559
560 #[test]
561 fn test_parse_extension_header_chaining() {
562 let mut packet = vec![
564 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x40, ];
568 packet.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
570 packet.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
571 packet.extend_from_slice(&[0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
573 packet.extend_from_slice(&[0x2c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00]);
575 packet.extend_from_slice(&[0x06, 0x00, 0x00, 0x00, 0xab, 0xcd, 0xef, 0x12]);
577
578 let parser = Ipv6Protocol;
579 let context = create_ipv6_context();
580
581 let result = parser.parse(&packet, &context);
582
583 assert!(result.is_ok());
584 assert_eq!(result.get("ext_hop_by_hop"), Some(&FieldValue::Bool(true)));
585 assert_eq!(result.get("ext_routing"), Some(&FieldValue::Bool(true)));
586 assert_eq!(result.get("ext_fragment"), Some(&FieldValue::Bool(true)));
587 assert_eq!(result.hint("ip_protocol"), Some(6u64));
588 }
589
590 #[test]
591 fn test_fragment_offset_and_m_flag() {
592 let mut packet = vec![0x60, 0x00, 0x00, 0x00, 0x00, 0x10, 0x2c, 0x40];
594 packet.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
595 packet.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
596 packet.extend_from_slice(&[0x06, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x01]);
598
599 let parser = Ipv6Protocol;
600 let context = create_ipv6_context();
601
602 let result = parser.parse(&packet, &context);
603
604 assert!(result.is_ok());
605 assert_eq!(result.get("frag_offset"), Some(&FieldValue::UInt16(185)));
606 assert_eq!(result.get("frag_more"), Some(&FieldValue::Bool(false)));
607 }
608
609 #[test]
610 fn test_segments_left_field() {
611 let mut packet = vec![0x60, 0x00, 0x00, 0x00, 0x00, 0x10, 0x2b, 0x40];
612 packet.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
613 packet.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
614 packet.extend_from_slice(&[0x06, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00]);
616
617 let parser = Ipv6Protocol;
618 let context = create_ipv6_context();
619
620 let result = parser.parse(&packet, &context);
621
622 assert!(result.is_ok());
623 assert_eq!(result.get("segments_left"), Some(&FieldValue::UInt8(5)));
624 }
625
626 #[test]
627 fn test_unknown_extension_header_skipping() {
628 let mut packet = vec![0x60, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40];
630 packet.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
631 packet.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
632 packet.extend_from_slice(&[0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
634
635 let parser = Ipv6Protocol;
636 let context = create_ipv6_context();
637
638 let result = parser.parse(&packet, &context);
639
640 assert!(result.is_ok());
641 assert_eq!(result.get("ext_hop_by_hop"), Some(&FieldValue::Bool(true)));
642 assert_eq!(result.hint("ip_protocol"), Some(250u64));
644 }
645
646 #[test]
647 fn test_ipv4_in_ipv6_tunnel() {
648 let mut packet = vec![
650 0x60, 0x00, 0x00, 0x00, 0x00, 0x14, 0x04, 0x40, ];
655 packet.extend_from_slice(&[
657 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658 0x00, 0x01,
659 ]);
660 packet.extend_from_slice(&[
662 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
663 0x00, 0x02,
664 ]);
665 packet.extend_from_slice(&[0x45, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00]);
667
668 let parser = Ipv6Protocol;
669 let context = create_ipv6_context();
670
671 let result = parser.parse(&packet, &context);
672
673 assert!(result.is_ok());
674 assert_eq!(result.get("next_header"), Some(&FieldValue::UInt8(4)));
675 assert_eq!(result.hint("ip_protocol"), Some(4u64));
677 assert_eq!(result.hint("ethertype"), Some(ethertype::IPV4 as u64));
679 assert_eq!(
681 result.hint("tunnel_type"),
682 Some(TunnelType::Ip4InIp6 as u64)
683 );
684 }
685
686 #[test]
687 fn test_ipv6_in_ipv6_tunnel() {
688 let mut packet = vec![
690 0x60, 0x00, 0x00, 0x00, 0x00, 0x28, 0x29, 0x40, ];
695 packet.extend_from_slice(&[
697 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
698 0x00, 0x01,
699 ]);
700 packet.extend_from_slice(&[
702 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
703 0x00, 0x02,
704 ]);
705 packet.extend_from_slice(&[0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x40]);
707
708 let parser = Ipv6Protocol;
709 let context = create_ipv6_context();
710
711 let result = parser.parse(&packet, &context);
712
713 assert!(result.is_ok());
714 assert_eq!(result.get("next_header"), Some(&FieldValue::UInt8(41)));
715 assert_eq!(result.hint("ip_protocol"), Some(41u64));
717 assert_eq!(result.hint("ethertype"), Some(ethertype::IPV6 as u64));
719 assert_eq!(
721 result.hint("tunnel_type"),
722 Some(TunnelType::Ip6InIp6 as u64)
723 );
724 }
725}