• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::*;
2 use core::slice::from_raw_parts;
3 
4 /// Deprecated. Use [Ipv6RawExtHeaderSlice] instead.
5 #[deprecated(
6     since = "0.14.0",
7     note = "Please use the type Ipv6RawExtHeaderSlice instead"
8 )]
9 pub type Ipv6RawExtensionHeaderSlice<'a> = Ipv6RawExtHeaderSlice<'a>;
10 
11 /// Slice containing an IPv6 extension header without specific decoding methods (fallback in case no specific implementation is available).
12 ///
13 /// Slice containing an IPv6 extension header with only minimal data interpretation. NOTE only ipv6 header
14 /// extensions with the first two bytes representing the next header and the header length
15 /// in 8-octets (- 8 octets) can be represented with this struct. This excludes the "Authentication
16 /// Header" (AH) and "Encapsulating Security Payload" (ESP).
17 ///
18 /// The following headers can be represented in a Ipv6ExtensionHeaderSlice:
19 /// * HopbyHop
20 /// * Destination Options
21 /// * Routing
22 /// * Mobility
23 /// * Host Identity Protocol
24 /// * Shim6 Protocol
25 #[derive(Clone, Debug, Eq, PartialEq)]
26 pub struct Ipv6RawExtHeaderSlice<'a> {
27     /// Slice containing the packet data.
28     slice: &'a [u8],
29 }
30 
31 impl<'a> Ipv6RawExtHeaderSlice<'a> {
32     /// Returns true if the given header type ip number can be represented in an `Ipv6ExtensionHeaderSlice`.
header_type_supported(next_header: IpNumber) -> bool33     pub fn header_type_supported(next_header: IpNumber) -> bool {
34         Ipv6RawExtHeader::header_type_supported(next_header)
35     }
36 
37     /// Creates a generic ipv6 extension header slice from a slice.
from_slice(slice: &'a [u8]) -> Result<Ipv6RawExtHeaderSlice<'a>, err::LenError>38     pub fn from_slice(slice: &'a [u8]) -> Result<Ipv6RawExtHeaderSlice<'a>, err::LenError> {
39         //check length
40         if slice.len() < 8 {
41             return Err(err::LenError {
42                 required_len: 8,
43                 len: slice.len(),
44                 len_source: LenSource::Slice,
45                 layer: err::Layer::Ipv6ExtHeader,
46                 layer_start_offset: 0,
47             });
48         }
49 
50         //check length
51         let len = ((slice[1] as usize) + 1) * 8;
52 
53         //check the length again now that the expected length is known
54         if slice.len() < len {
55             return Err(err::LenError {
56                 required_len: len,
57                 len: slice.len(),
58                 len_source: LenSource::Slice,
59                 layer: err::Layer::Ipv6ExtHeader,
60                 layer_start_offset: 0,
61             });
62         }
63 
64         //all good
65         Ok(Ipv6RawExtHeaderSlice {
66             // SAFETY:
67             // Safe as the slice has been checked in the previous if
68             // to have at least the the length of the variable len.
69             slice: unsafe { from_raw_parts(slice.as_ptr(), len) },
70         })
71     }
72 
73     /// Creates a raw ipv6 extension header slice from a slice (assumes slice
74     /// size & content was validated before).
75     ///
76     /// # Safety
77     ///
78     /// This method assumes that the slice was previously validated to contain
79     /// a valid & supported raw ipv6 extension header. This means the slice length
80     /// must at least be at least 8 and `(slice[1] + 1)*8`. The data that the
81     /// slice points must also be valid (meaning no nullptr or alike allowed).
82     ///
83     /// If these preconditions are not fulfilled the behavior of this function
84     /// and the methods of the return [`IpAuthHeaderSlice`] will be undefined.
from_slice_unchecked(slice: &'a [u8]) -> Ipv6RawExtHeaderSlice<'a>85     pub unsafe fn from_slice_unchecked(slice: &'a [u8]) -> Ipv6RawExtHeaderSlice<'a> {
86         Ipv6RawExtHeaderSlice {
87             slice: from_raw_parts(slice.as_ptr(), ((*slice.get_unchecked(1) as usize) + 1) * 8),
88         }
89     }
90 
91     /// Returns the slice containing the ipv6 extension header
92     #[inline]
slice(&self) -> &'a [u8]93     pub fn slice(&self) -> &'a [u8] {
94         self.slice
95     }
96 
97     /// Returns the IP protocol number of the next header or transport layer protocol.
98     ///
99     /// See [IpNumber] or [ip_number] for a definition of the known values.
100     #[inline]
next_header(&self) -> IpNumber101     pub fn next_header(&self) -> IpNumber {
102         IpNumber(unsafe { *self.slice.get_unchecked(0) })
103     }
104 
105     /// Returns a slice containing the payload data of the header.
106     ///
107     /// This contains all the data after the header length field
108     /// until the end of the header (length specified by the
109     /// hdr ext length field).
110     #[inline]
payload(&self) -> &'a [u8]111     pub fn payload(&self) -> &'a [u8] {
112         unsafe { from_raw_parts(self.slice.as_ptr().add(2), self.slice.len() - 2) }
113     }
114 
115     /// Convert the slice to an [Ipv6RawExtHeader].
116     ///
117     /// Decode some of the fields and copy the results to a
118     /// [Ipv6RawExtHeader] struct together with a slice pointing
119     /// to the non decoded parts.
to_header(&self) -> Ipv6RawExtHeader120     pub fn to_header(&self) -> Ipv6RawExtHeader {
121         Ipv6RawExtHeader::new_raw(self.next_header(), self.payload()).unwrap()
122     }
123 }
124 
125 #[cfg(test)]
126 mod test {
127     use crate::{test_gens::*, *};
128     use alloc::{format, vec::Vec};
129     use proptest::prelude::*;
130 
131     proptest! {
132         #[test]
133         fn debug(header in ipv6_raw_ext_any()) {
134             let bytes = header.to_bytes();
135             let slice = Ipv6RawExtHeaderSlice::from_slice(&bytes).unwrap();
136             assert_eq!(
137                 format!("{:?}", slice),
138                 format!("Ipv6RawExtHeaderSlice {{ slice: {:?} }}", slice.slice())
139             );
140         }
141     }
142 
143     proptest! {
144         #[test]
145         fn clone_eq(header in ipv6_raw_ext_any()) {
146             let bytes = header.to_bytes();
147             let slice = Ipv6RawExtHeaderSlice::from_slice(&bytes).unwrap();
148             assert_eq!(slice.clone(), slice);
149         }
150     }
151 
152     #[test]
header_type_supported()153     fn header_type_supported() {
154         use ip_number::*;
155         for value in 0..=u8::MAX {
156             let expected_supported = match IpNumber(value) {
157                 IPV6_HOP_BY_HOP | IPV6_DEST_OPTIONS | IPV6_ROUTE | MOBILITY | HIP | SHIM6 => true,
158                 _ => false,
159             };
160             assert_eq!(
161                 expected_supported,
162                 Ipv6RawExtHeaderSlice::header_type_supported(IpNumber(value))
163             );
164         }
165     }
166 
167     proptest! {
168         #[test]
169         fn from_slice(header in ipv6_raw_ext_any()) {
170             // ok
171             {
172                 let mut bytes = Vec::with_capacity(header.header_len() + 2);
173                 bytes.extend_from_slice(&header.to_bytes());
174                 bytes.push(1);
175                 bytes.push(2);
176 
177                 let (actual_header, actual_rest) = Ipv6RawExtHeader::from_slice(&bytes).unwrap();
178                 assert_eq!(actual_header, header);
179                 assert_eq!(actual_rest, &[1, 2]);
180             }
181 
182             // length error
183             {
184                 let bytes = header.to_bytes();
185                 for len in 0..bytes.len() {
186                     assert_eq!(
187                         Ipv6RawExtHeader::from_slice(&bytes[..len]).unwrap_err(),
188                         err::LenError{
189                             required_len: if len < Ipv6RawExtHeader::MIN_LEN {
190                                 Ipv6RawExtHeader::MIN_LEN
191                             } else {
192                                 header.header_len()
193                             },
194                             len: len,
195                             len_source: LenSource::Slice,
196                             layer: err::Layer::Ipv6ExtHeader,
197                             layer_start_offset: 0,
198                         }
199                     );
200                 }
201             }
202         }
203     }
204 
205     proptest! {
206         #[test]
207         fn from_slice_unchecked(header in ipv6_raw_ext_any()) {
208             let bytes = header.to_bytes();
209             let slice = unsafe {
210                 Ipv6RawExtHeaderSlice::from_slice_unchecked(&bytes)
211             };
212             assert_eq!(&bytes[..], slice.slice());
213         }
214     }
215 
216     proptest! {
217         #[test]
218         fn getters(header in ipv6_raw_ext_any()) {
219             let bytes = header.to_bytes();
220             let slice = Ipv6RawExtHeaderSlice::from_slice(&bytes).unwrap();
221             assert_eq!(slice.next_header(), header.next_header);
222             assert_eq!(slice.payload(), header.payload());
223         }
224     }
225 
226     proptest! {
227         #[test]
228         fn to_header(header in ipv6_raw_ext_any()) {
229             let bytes = header.to_bytes();
230             let slice = Ipv6RawExtHeaderSlice::from_slice(&bytes).unwrap();
231             assert_eq!(header, slice.to_header());
232         }
233     }
234 }
235