• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{
2     err::{ip, Layer, LenError},
3     *,
4 };
5 
6 /// Slice containing the IP header (v4 or v6), extension headers &
7 /// payload.
8 #[derive(Clone, Debug, Eq, PartialEq)]
9 pub enum IpSlice<'a> {
10     /// The ipv4 header & the decoded extension headers.
11     Ipv4(Ipv4Slice<'a>),
12     /// The ipv6 header & the decoded extension headers.
13     Ipv6(Ipv6Slice<'a>),
14 }
15 
16 impl<'a> IpSlice<'a> {
17     /// Returns a reference to the `Ipv4Slice` if `self` is a `IpSlice::Ipv4`.
ipv4(&self) -> Option<&Ipv4Slice>18     pub fn ipv4(&self) -> Option<&Ipv4Slice> {
19         use IpSlice::*;
20         match self {
21             Ipv4(slice) => Some(slice),
22             Ipv6(_) => None,
23         }
24     }
25 
26     /// Returns a reference to the `Ipv6Slice` if `self` is a `IpSlice::Ipv6`.
ipv6(&self) -> Option<&Ipv6Slice>27     pub fn ipv6(&self) -> Option<&Ipv6Slice> {
28         use IpSlice::*;
29         match self {
30             Ipv4(_) => None,
31             Ipv6(slice) => Some(slice),
32         }
33     }
34 
35     /// Returns true if the payload is fragmented.
is_fragmenting_payload(&self) -> bool36     pub fn is_fragmenting_payload(&self) -> bool {
37         match self {
38             IpSlice::Ipv4(s) => s.is_payload_fragmented(),
39             IpSlice::Ipv6(s) => s.is_payload_fragmented(),
40         }
41     }
42 
43     /// Return the source address as an std::net::Ipvddr (requires
44     /// crate feature `std`).
45     #[cfg(feature = "std")]
46     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
source_addr(&self) -> std::net::IpAddr47     pub fn source_addr(&self) -> std::net::IpAddr {
48         match self {
49             IpSlice::Ipv4(s) => s.header().source_addr().into(),
50             IpSlice::Ipv6(s) => s.header().source_addr().into(),
51         }
52     }
53 
54     /// Return the destination address as an std::net::IpAddr (requires
55     /// crate feature `std`).
56     #[cfg(feature = "std")]
57     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
destination_addr(&self) -> std::net::IpAddr58     pub fn destination_addr(&self) -> std::net::IpAddr {
59         match self {
60             IpSlice::Ipv4(s) => s.header().destination_addr().into(),
61             IpSlice::Ipv6(s) => s.header().destination_addr().into(),
62         }
63     }
64 
65     /// Returns a slice containing the data after the IP header
66     /// and IP extensions headers.
67     #[inline]
payload(&self) -> &IpPayloadSlice<'a>68     pub fn payload(&self) -> &IpPayloadSlice<'a> {
69         use IpSlice::*;
70         match self {
71             Ipv4(ipv4) => ipv4.payload(),
72             Ipv6(ipv6) => ipv6.payload(),
73         }
74     }
75 
76     /// Returns the ip number the type of payload of the IP packet.
77     ///
78     /// This function returns the ip number stored in the last
79     /// IP header or extension header.
80     #[inline]
payload_ip_number(&self) -> IpNumber81     pub fn payload_ip_number(&self) -> IpNumber {
82         use IpSlice::*;
83         match self {
84             Ipv4(ipv4) => ipv4.payload().ip_number,
85             Ipv6(ipv6) => ipv6.payload().ip_number,
86         }
87     }
88 
89     /// Separates and validates IP headers (including extension headers)
90     /// in the given slice and determine the sub-slice containing the payload
91     /// of the IP packet.
from_slice(slice: &[u8]) -> Result<IpSlice, err::ip::SliceError>92     pub fn from_slice(slice: &[u8]) -> Result<IpSlice, err::ip::SliceError> {
93         use crate::ip_number::AUTH;
94         use err::ip::{HeaderError::*, HeadersError::*, SliceError::*};
95         use IpSlice::*;
96 
97         if slice.is_empty() {
98             Err(Len(err::LenError {
99                 required_len: 1,
100                 len: slice.len(),
101                 len_source: LenSource::Slice,
102                 layer: err::Layer::IpHeader,
103                 layer_start_offset: 0,
104             }))
105         } else {
106             // SAFETY: Safe as slice is not empty.
107             let first_byte = unsafe { slice.get_unchecked(0) };
108             match first_byte >> 4 {
109                 4 => {
110                     let ihl = first_byte & 0xf;
111 
112                     // check that the ihl has at least the length of the base IPv4 header
113                     if ihl < 5 {
114                         return Err(IpHeaders(Ip(Ipv4HeaderLengthSmallerThanHeader { ihl })));
115                     }
116 
117                     // check there is enough data for the header
118                     let header_len = (usize::from(ihl)) * 4;
119                     if slice.len() < header_len {
120                         return Err(Len(err::LenError {
121                             required_len: header_len,
122                             len: slice.len(),
123                             len_source: LenSource::Slice,
124                             layer: err::Layer::Ipv4Header,
125                             layer_start_offset: 0,
126                         }));
127                     }
128 
129                     // SAFETY:
130                     // Safe as the slice length is checked to be at least
131                     // header_len or greater above.
132                     let header = unsafe {
133                         Ipv4HeaderSlice::from_slice_unchecked(core::slice::from_raw_parts(
134                             slice.as_ptr(),
135                             header_len,
136                         ))
137                     };
138 
139                     // check the total_length at least contains the header
140                     let total_len = usize::from(header.total_len());
141                     if total_len < header_len {
142                         return Err(Len(LenError {
143                             required_len: header_len,
144                             len: total_len,
145                             len_source: LenSource::Ipv4HeaderTotalLen,
146                             layer: Layer::Ipv4Packet,
147                             layer_start_offset: 0,
148                         }));
149                     }
150 
151                     // validate the total length against the slice
152                     let header_payload = if slice.len() < total_len {
153                         return Err(Len(LenError {
154                             required_len: total_len,
155                             len: slice.len(),
156                             len_source: LenSource::Slice,
157                             layer: Layer::Ipv4Packet,
158                             layer_start_offset: 0,
159                         }));
160                     } else {
161                         unsafe {
162                             core::slice::from_raw_parts(
163                                 // SAFETY: Safe as slice.len() >= header_len was validated
164                                 // in a if statement above.
165                                 slice.as_ptr().add(header_len),
166                                 // SAFETY: Safe as total_length >= header_len was verified in an
167                                 // if statement above as well as that slice.len() >= total_length_usize.
168                                 total_len - header_len,
169                             )
170                         }
171                     };
172 
173                     // slice extension headers
174                     // decode the authentication header if needed
175                     let fragmented = header.is_fragmenting_payload();
176                     match header.protocol() {
177                         AUTH => {
178                             use crate::err::ip_auth::HeaderSliceError as E;
179 
180                             // parse extension headers
181                             let auth = match IpAuthHeaderSlice::from_slice(header_payload) {
182                                 Ok(s) => s,
183                                 Err(err) => match err {
184                                     E::Len(mut l) => {
185                                         // change the length source to the ipv4 header
186                                         l.len_source = LenSource::Ipv4HeaderTotalLen;
187                                         l.layer_start_offset += header.slice().len();
188                                         return Err(Len(l));
189                                     }
190                                     E::Content(err) => {
191                                         return Err(IpHeaders(ip::HeadersError::Ipv4Ext(err)))
192                                     }
193                                 },
194                             };
195 
196                             // remove the extension header from the payload
197                             let payload = unsafe {
198                                 core::slice::from_raw_parts(
199                                     header_payload.as_ptr().add(auth.slice().len()),
200                                     header_payload.len() - auth.slice().len(),
201                                 )
202                             };
203                             Ok(Ipv4(Ipv4Slice {
204                                 header,
205                                 exts: Ipv4ExtensionsSlice { auth: Some(auth) },
206                                 payload: IpPayloadSlice {
207                                     ip_number: auth.next_header(),
208                                     fragmented,
209                                     len_source: LenSource::Ipv4HeaderTotalLen,
210                                     payload,
211                                 },
212                             }))
213                         }
214                         ip_number => Ok(Ipv4(Ipv4Slice {
215                             header,
216                             exts: Ipv4ExtensionsSlice { auth: None },
217                             payload: IpPayloadSlice {
218                                 ip_number,
219                                 fragmented,
220                                 len_source: LenSource::Ipv4HeaderTotalLen,
221                                 payload: header_payload,
222                             },
223                         })),
224                     }
225                 }
226                 6 => {
227                     // check length
228                     if slice.len() < Ipv6Header::LEN {
229                         return Err(Len(err::LenError {
230                             required_len: Ipv6Header::LEN,
231                             len: slice.len(),
232                             len_source: LenSource::Slice,
233                             layer: err::Layer::Ipv6Header,
234                             layer_start_offset: 0,
235                         }));
236                     }
237 
238                     let header = unsafe {
239                         Ipv6HeaderSlice::from_slice_unchecked(core::slice::from_raw_parts(
240                             slice.as_ptr(),
241                             Ipv6Header::LEN,
242                         ))
243                     };
244 
245                     // restrict slice by the length specified in the header
246                     let (header_payload, len_source) =
247                         if 0 == header.payload_length() && slice.len() > Ipv6Header::LEN {
248                             // In case the payload_length is 0 assume that the entire
249                             // rest of the slice is part of the packet until the jumbogram
250                             // parameters can be parsed.
251 
252                             // TODO: Add payload length parsing from the jumbogram
253                             (
254                                 unsafe {
255                                     core::slice::from_raw_parts(
256                                         slice.as_ptr().add(Ipv6Header::LEN),
257                                         slice.len() - Ipv6Header::LEN,
258                                     )
259                                 },
260                                 LenSource::Slice,
261                             )
262                         } else {
263                             let payload_len = usize::from(header.payload_length());
264                             let expected_len = Ipv6Header::LEN + payload_len;
265                             if slice.len() < expected_len {
266                                 return Err(Len(LenError {
267                                     required_len: expected_len,
268                                     len: slice.len(),
269                                     len_source: LenSource::Slice,
270                                     layer: Layer::Ipv6Packet,
271                                     layer_start_offset: 0,
272                                 }));
273                             } else {
274                                 (
275                                     unsafe {
276                                         core::slice::from_raw_parts(
277                                             slice.as_ptr().add(Ipv6Header::LEN),
278                                             payload_len,
279                                         )
280                                     },
281                                     LenSource::Ipv6HeaderPayloadLen,
282                                 )
283                             }
284                         };
285 
286                     // parse extension headers
287                     let (exts, payload_ip_number, payload) =
288                         Ipv6ExtensionsSlice::from_slice(header.next_header(), header_payload)
289                             .map_err(|err| {
290                                 // modify length errors
291                                 use crate::err::ipv6_exts::HeaderSliceError as I;
292                                 match err {
293                                     I::Len(mut err) => {
294                                         err.len_source = LenSource::Ipv6HeaderPayloadLen;
295                                         err.layer_start_offset += Ipv6Header::LEN;
296                                         Len(err)
297                                     }
298                                     I::Content(err) => IpHeaders(ip::HeadersError::Ipv6Ext(err)),
299                                 }
300                             })?;
301 
302                     let fragmented = exts.is_fragmenting_payload();
303                     Ok(Ipv6(Ipv6Slice {
304                         header,
305                         exts,
306                         payload: IpPayloadSlice {
307                             ip_number: payload_ip_number,
308                             fragmented,
309                             len_source,
310                             payload,
311                         },
312                     }))
313                 }
314                 version_number => Err(IpHeaders(Ip(UnsupportedIpVersion { version_number }))),
315             }
316         }
317     }
318 }
319 
320 impl<'a> From<Ipv4Slice<'a>> for IpSlice<'a> {
from(value: Ipv4Slice<'a>) -> Self321     fn from(value: Ipv4Slice<'a>) -> Self {
322         IpSlice::Ipv4(value)
323     }
324 }
325 
326 impl<'a> From<Ipv6Slice<'a>> for IpSlice<'a> {
from(value: Ipv6Slice<'a>) -> Self327     fn from(value: Ipv6Slice<'a>) -> Self {
328         IpSlice::Ipv6(value)
329     }
330 }
331 
332 #[cfg(test)]
333 mod test {
334     use super::*;
335     use crate::test_gens::*;
336     use alloc::{format, vec::Vec};
337     use proptest::prelude::*;
338     use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
339 
340     #[test]
debug_clone_eq()341     fn debug_clone_eq() {
342         // ipv4
343         {
344             let mut header: Ipv4Header = Default::default();
345             header.protocol = ip_number::UDP;
346             header.set_payload_len(0).unwrap();
347             let buffer = header.to_bytes();
348 
349             let ipv4 = Ipv4Slice::from_slice(&buffer).unwrap();
350             let slice = IpSlice::Ipv4(ipv4.clone());
351 
352             // clone & eq
353             assert_eq!(slice.clone(), slice);
354 
355             // debug
356             assert_eq!(format!("{:?}", slice), format!("Ipv4({:?})", ipv4));
357         }
358         // ipv6
359         {
360             let header = Ipv6Header {
361                 payload_length: 0,
362                 next_header: ip_number::UDP,
363                 ..Default::default()
364             };
365             let buffer = header.to_bytes();
366             let ipv6 = Ipv6Slice::from_slice(&buffer).unwrap();
367             let slice = IpSlice::Ipv6(ipv6.clone());
368 
369             // clone & eq
370             assert_eq!(slice.clone(), slice);
371 
372             // debug
373             assert_eq!(format!("{:?}", slice), format!("Ipv6({:?})", ipv6));
374         }
375     }
376 
377     #[test]
is_fragmenting_payload()378     fn is_fragmenting_payload() {
379         for fragment in [false, true] {
380             use ip_number::UDP;
381             // ipv4
382             {
383                 let mut ipv4 = Ipv4Header::new(0, 1, UDP, [3, 4, 5, 6], [7, 8, 9, 10]).unwrap();
384                 if fragment {
385                     ipv4.fragment_offset = 123.try_into().unwrap();
386                 }
387 
388                 let data = ipv4.to_bytes();
389                 let ipv4_slice = Ipv4Slice::from_slice(&data).unwrap();
390                 assert_eq!(fragment, IpSlice::Ipv4(ipv4_slice).is_fragmenting_payload());
391             }
392 
393             // ipv6
394             {
395                 let ipv6_frag = Ipv6FragmentHeader {
396                     next_header: UDP,
397                     fragment_offset: IpFragOffset::ZERO,
398                     more_fragments: fragment,
399                     identification: 0,
400                 };
401                 let ipv6 = Ipv6Header {
402                     traffic_class: 0,
403                     flow_label: 1.try_into().unwrap(),
404                     payload_length: ipv6_frag.header_len() as u16,
405                     next_header: ip_number::IPV6_FRAG,
406                     hop_limit: 4,
407                     source: [1; 16],
408                     destination: [2; 16],
409                 };
410                 let mut data = Vec::with_capacity(ipv6.header_len() + ipv6_frag.header_len());
411                 data.extend_from_slice(&ipv6.to_bytes());
412                 data.extend_from_slice(&ipv6_frag.to_bytes());
413 
414                 assert_eq!(
415                     fragment,
416                     IpSlice::Ipv6(Ipv6Slice::from_slice(&data).unwrap()).is_fragmenting_payload()
417                 );
418             }
419         }
420     }
421 
422     #[cfg(feature = "std")]
423     #[test]
source_addr()424     fn source_addr() {
425         // ipv4
426         {
427             let data = Ipv4Header::new(0, 1, 2.into(), [3, 4, 5, 6], [7, 8, 9, 10])
428                 .unwrap()
429                 .to_bytes();
430             assert_eq!(
431                 IpAddr::V4(Ipv4Addr::from([3, 4, 5, 6])),
432                 IpSlice::Ipv4(Ipv4Slice::from_slice(&data[..]).unwrap()).source_addr()
433             );
434         }
435 
436         // ipv6
437         {
438             let data = Ipv6Header {
439                 traffic_class: 0,
440                 flow_label: 1.try_into().unwrap(),
441                 payload_length: 0,
442                 next_header: ip_number::IGMP,
443                 hop_limit: 4,
444                 source: [1; 16],
445                 destination: [2; 16],
446             }
447             .to_bytes();
448 
449             assert_eq!(
450                 IpAddr::V6(Ipv6Addr::from([1; 16])),
451                 IpSlice::Ipv6(Ipv6Slice::from_slice(&data[..]).unwrap()).source_addr()
452             );
453         }
454     }
455 
456     #[cfg(feature = "std")]
457     #[test]
destination_addr()458     fn destination_addr() {
459         use crate::ip_number::UDP;
460 
461         // ipv4
462         {
463             let data = Ipv4Header::new(0, 1, UDP, [3, 4, 5, 6], [7, 8, 9, 10])
464                 .unwrap()
465                 .to_bytes();
466 
467             assert_eq!(
468                 IpAddr::V4(Ipv4Addr::from([7, 8, 9, 10])),
469                 IpSlice::Ipv4(Ipv4Slice::from_slice(&data[..]).unwrap()).destination_addr()
470             );
471         }
472 
473         // ipv6
474         {
475             let data = Ipv6Header {
476                 traffic_class: 0,
477                 flow_label: 1.try_into().unwrap(),
478                 payload_length: 0,
479                 next_header: ip_number::IGMP,
480                 hop_limit: 4,
481                 source: [1; 16],
482                 destination: [2; 16],
483             }
484             .to_bytes();
485 
486             assert_eq!(
487                 IpAddr::V6(Ipv6Addr::from([2; 16])),
488                 IpSlice::Ipv6(Ipv6Slice::from_slice(&data).unwrap()).destination_addr()
489             );
490         }
491     }
492 
493     #[test]
payload()494     fn payload() {
495         let payload: [u8; 4] = [1, 2, 3, 4];
496         // ipv4
497         {
498             let header = Ipv4Header::new(
499                 payload.len() as u16,
500                 1,
501                 ip_number::UDP,
502                 [3, 4, 5, 6],
503                 [7, 8, 9, 10],
504             )
505             .unwrap();
506             let mut data = Vec::with_capacity(header.header_len() + payload.len());
507             data.extend_from_slice(&header.to_bytes());
508             data.extend_from_slice(&payload);
509             assert_eq!(
510                 IpSlice::Ipv4(Ipv4Slice::from_slice(&data[..]).unwrap()).payload(),
511                 &IpPayloadSlice {
512                     ip_number: ip_number::UDP.into(),
513                     fragmented: header.is_fragmenting_payload(),
514                     len_source: LenSource::Ipv4HeaderTotalLen,
515                     payload: &payload,
516                 }
517             );
518         }
519 
520         // ipv6
521         {
522             let header = Ipv6Header {
523                 traffic_class: 0,
524                 flow_label: 1.try_into().unwrap(),
525                 payload_length: payload.len() as u16,
526                 next_header: ip_number::UDP,
527                 hop_limit: 4,
528                 source: [1; 16],
529                 destination: [2; 16],
530             };
531             let mut data = Vec::with_capacity(header.header_len() + payload.len());
532             data.extend_from_slice(&header.to_bytes());
533             data.extend_from_slice(&payload);
534             assert_eq!(
535                 IpSlice::Ipv6(Ipv6Slice::from_slice(&data[..]).unwrap()).payload(),
536                 &IpPayloadSlice {
537                     ip_number: ip_number::UDP.into(),
538                     fragmented: false,
539                     len_source: LenSource::Ipv6HeaderPayloadLen,
540                     payload: &payload,
541                 }
542             );
543         }
544     }
545 
546     #[test]
payload_ip_number()547     fn payload_ip_number() {
548         use crate::ip_number::{IGMP, UDP};
549 
550         // ipv4
551         {
552             let data = Ipv4Header::new(0, 1, UDP, [3, 4, 5, 6], [7, 8, 9, 10])
553                 .unwrap()
554                 .to_bytes();
555             assert_eq!(
556                 UDP,
557                 IpSlice::Ipv4(Ipv4Slice::from_slice(&data[..]).unwrap()).payload_ip_number()
558             );
559         }
560 
561         // ipv6
562         {
563             let data = Ipv6Header {
564                 traffic_class: 0,
565                 flow_label: 1.try_into().unwrap(),
566                 payload_length: 0,
567                 next_header: IGMP,
568                 hop_limit: 4,
569                 source: [1; 16],
570                 destination: [2; 16],
571             }
572             .to_bytes();
573 
574             assert_eq!(
575                 IGMP,
576                 IpSlice::Ipv6(Ipv6Slice::from_slice(&data).unwrap()).payload_ip_number()
577             );
578         }
579     }
580 
581     proptest! {
582         #[test]
583         fn from_ip_slice(
584             ipv4_header in ipv4_any(),
585             ipv4_exts in ipv4_extensions_with(ip_number::UDP),
586             ipv6_header in ipv6_any(),
587             mut ipv6_exts in ipv6_extensions_with(ip_number::UDP)
588         ) {
589             let payload = [1,2,3,4];
590 
591             // setup header length & fields
592             let ipv4_header = {
593                 let mut header = ipv4_header;
594                 header.protocol = if ipv4_exts.auth.is_some() {
595                     ip_number::AUTH
596                 } else {
597                     ip_number::UDP
598                 };
599                 header.total_len = (header.header_len() + ipv4_exts.header_len() + payload.len()) as u16;
600                 header.header_checksum = header.calc_header_checksum();
601                 header
602             };
603 
604             let ipv4 = IpHeaders::Ipv4(
605                 ipv4_header.clone(),
606                 ipv4_exts.clone()
607             );
608 
609             let ipv6_header = {
610                 let mut header = ipv6_header;
611                 header.next_header = ipv6_exts.set_next_headers(ip_number::UDP);
612                 header.payload_length = (ipv6_exts.header_len() + payload.len()) as u16;
613                 header
614             };
615 
616             let ipv6 = IpHeaders::Ipv6(
617                 ipv6_header.clone(),
618                 ipv6_exts.clone()
619             );
620 
621             // happy path v4
622             {
623                 // build packet
624                 let mut data = Vec::with_capacity(ipv4.header_len() + payload.len());
625                 ipv4.write(&mut data).unwrap();
626                 data.extend_from_slice(&payload);
627 
628                 // run test
629                 let actual = IpSlice::from_slice(&data).unwrap();
630                 assert!(actual.ipv6().is_none());
631                 let actual = actual.ipv4().unwrap().clone();
632                 assert_eq!(actual.header.to_header(), ipv4_header);
633                 assert_eq!(actual.extensions().to_header(), ipv4_exts);
634                 assert_eq!(
635                     actual.payload,
636                     IpPayloadSlice{
637                         ip_number: ip_number::UDP.into(),
638                         fragmented: ipv4_header.is_fragmenting_payload(),
639                         len_source: LenSource::Ipv4HeaderTotalLen,
640                         payload: &payload
641                     }
642                 );
643             }
644 
645             // happy path v6
646             {
647                 // build packet
648                 let mut data = Vec::with_capacity(ipv6.header_len() + payload.len());
649                 ipv6.write(&mut data).unwrap();
650                 data.extend_from_slice(&payload);
651 
652                 // run test
653                 let actual = crate::IpSlice::from_slice(&data).unwrap();
654                 assert!(actual.ipv4().is_none());
655                 let actual = actual.ipv6().unwrap().clone();
656                 assert_eq!(actual.header.to_header(), ipv6_header);
657                 assert_eq!(
658                     Ipv6Extensions::from_slice(
659                         ipv6_header.next_header,
660                         actual.extensions().slice()
661                     ).unwrap().0,
662                     ipv6_exts
663                 );
664                 assert_eq!(
665                     actual.payload,
666                     IpPayloadSlice{
667                         ip_number: ip_number::UDP.into(),
668                         fragmented: ipv6_exts.is_fragmenting_payload(),
669                         len_source: LenSource::Ipv6HeaderPayloadLen,
670                         payload: &payload
671                     }
672                 );
673             }
674 
675             // ipv6 with zero payload length (should fallback to the slice length)
676             {
677                 let ipv6_header = {
678                     let mut header = ipv6_header.clone();
679                     // set the payload length to zero so the payload identifier
680                     // has to fallback to the slice length
681                     header.payload_length = 0;
682                     header
683                 };
684 
685                 // build packet
686                 let mut data = Vec::with_capacity(ipv6.header_len() + payload.len());
687                 ipv6_header.write(&mut data).unwrap();
688                 ipv6_exts.write(&mut data, ipv6_header.next_header).unwrap();
689                 data.extend_from_slice(&payload);
690 
691                 // run test
692                 let actual = crate::IpSlice::from_slice(&data).unwrap();
693                 assert!(actual.ipv4().is_none());
694                 let actual = actual.ipv6().unwrap().clone();
695                 assert_eq!(actual.header.to_header(), ipv6_header);
696                 assert_eq!(
697                     Ipv6Extensions::from_slice(
698                         ipv6_header.next_header,
699                         actual.extensions().slice()
700                     ).unwrap().0,
701                     ipv6_exts
702                 );
703                 assert_eq!(
704                     actual.payload,
705                     IpPayloadSlice{
706                         ip_number: ip_number::UDP.into(),
707                         fragmented: ipv6_exts.is_fragmenting_payload(),
708                         len_source: LenSource::Slice,
709                         payload: &payload
710                     }
711                 );
712             }
713 
714         }
715     }
716 
717     proptest! {
718         #[test]
719         fn from_ipv4_slice(
720             ipv4_header in ipv4_unknown()
721         ) {
722             let mut header = ipv4_header.clone();
723             header.total_len = (header.header_len() + 4) as u16;
724 
725             let mut buffer = Vec::with_capacity(header.total_len.into());
726             buffer.extend_from_slice(&header.to_bytes()[..]);
727             buffer.extend_from_slice(&[1,2,3,4]);
728             let s = Ipv4Slice::from_slice(&buffer).unwrap();
729             let actual: IpSlice = s.clone().into();
730             assert_eq!(IpSlice::Ipv4(s), actual);
731         }
732     }
733 
734     proptest! {
735         #[test]
736         fn from_ipv6_slice(
737             ipv6_header in ipv6_unknown()
738         ) {
739             let mut header = ipv6_header.clone();
740             header.payload_length = 4;
741 
742             let mut buffer = Vec::with_capacity(header.header_len() + 4);
743             buffer.extend_from_slice(&header.to_bytes()[..]);
744             buffer.extend_from_slice(&[1,2,3,4]);
745             let s = Ipv6Slice::from_slice(&buffer).unwrap();
746             let actual: IpSlice = s.clone().into();
747             assert_eq!(IpSlice::Ipv6(s), actual);
748         }
749     }
750 }
751