• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::*;
2 use core::slice::from_raw_parts;
3 
4 /// A slice containing an ipv6 header of a network package.
5 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
6 pub struct Ipv6HeaderSlice<'a> {
7     slice: &'a [u8],
8 }
9 
10 impl<'a> Ipv6HeaderSlice<'a> {
11     /// Creates a slice containing an ipv6 header (without header extensions).
from_slice(slice: &'a [u8]) -> Result<Ipv6HeaderSlice<'a>, err::ipv6::HeaderSliceError>12     pub fn from_slice(slice: &'a [u8]) -> Result<Ipv6HeaderSlice<'a>, err::ipv6::HeaderSliceError> {
13         use err::ipv6::{HeaderError::*, HeaderSliceError::*};
14 
15         // check length
16         if slice.len() < Ipv6Header::LEN {
17             return Err(Len(err::LenError {
18                 required_len: Ipv6Header::LEN,
19                 len: slice.len(),
20                 len_source: LenSource::Slice,
21                 layer: err::Layer::Ipv6Header,
22                 layer_start_offset: 0,
23             }));
24         }
25 
26         // read version & ihl
27         //
28         // SAFETY:
29         // This is safe as the slice len is checked to be
30         // at least 40 bytes at the start of the function.
31         let version_number = unsafe { slice.get_unchecked(0) >> 4 };
32 
33         // check version
34         if 6 != version_number {
35             return Err(Content(UnexpectedVersion { version_number }));
36         }
37 
38         // all good
39         Ok(Ipv6HeaderSlice {
40             // SAFETY:
41             // This is safe as the slice length is checked to be
42             // at least Ipv6Header::LEN (40)
43             // at the start of the function.
44             slice: unsafe { from_raw_parts(slice.as_ptr(), Ipv6Header::LEN) },
45         })
46     }
47 
48     /// Converts the given slice into a ipv6 header slice WITHOUT any
49     /// checks to ensure that the data present is an ipv4 header or that the
50     /// slice length is matching the header length.
51     ///
52     /// If you are not sure what this means, use [`Ipv6HeaderSlice::from_slice`]
53     /// instead.
54     ///
55     /// # Safety
56     ///
57     /// It must ensured that the slice length is at least [`Ipv6Header::LEN`].
58     #[inline]
from_slice_unchecked(slice: &[u8]) -> Ipv6HeaderSlice59     pub(crate) unsafe fn from_slice_unchecked(slice: &[u8]) -> Ipv6HeaderSlice {
60         Ipv6HeaderSlice { slice }
61     }
62 
63     /// Returns the slice containing the ipv6 header
64     #[inline]
slice(&self) -> &'a [u8]65     pub fn slice(&self) -> &'a [u8] {
66         self.slice
67     }
68 
69     /// Read the "version" field from the slice (should be 6).
70     #[inline]
version(&self) -> u871     pub fn version(&self) -> u8 {
72         // SAFETY:
73         // Safe as the slice length is set to
74         // Ipv6Header::LEN (40) during construction
75         // of the struct.
76         unsafe { *self.slice.get_unchecked(0) >> 4 }
77     }
78 
79     /// Read the "traffic class" field from the slice.
80     #[inline]
traffic_class(&self) -> u881     pub fn traffic_class(&self) -> u8 {
82         // SAFETY:
83         // Safe as the slice length is set to
84         // Ipv6Header::LEN (40) during construction
85         // of the struct.
86         unsafe { (self.slice.get_unchecked(0) << 4) | (self.slice.get_unchecked(1) >> 4) }
87     }
88 
89     /// Read the "flow label" field from the slice.
90     #[inline]
flow_label(&self) -> Ipv6FlowLabel91     pub fn flow_label(&self) -> Ipv6FlowLabel {
92         unsafe {
93             // SAFETY:
94             // Slice access safe as the slice length is set to Ipv6Header::LEN (40)
95             // during construction of the struct.
96             // Conversion to flow label safe as the bitmask & 0 constant guarantee
97             // that the value does not exceed 20 bits.
98             Ipv6FlowLabel::new_unchecked(u32::from_be_bytes([
99                 0,
100                 *self.slice.get_unchecked(1) & 0xf,
101                 *self.slice.get_unchecked(2),
102                 *self.slice.get_unchecked(3),
103             ]))
104         }
105     }
106 
107     /// Read the "payload length" field from  the slice. The length should contain the length of all extension headers and payload.
108     #[inline]
payload_length(&self) -> u16109     pub fn payload_length(&self) -> u16 {
110         // SAFETY:
111         // Safe as the slice length is set to
112         // Ipv6Header::LEN (40) during construction
113         // of the struct.
114         unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(4)) }
115     }
116 
117     /// Read the "next header" field from the slice.
118     ///
119     /// The next header value specifies what the next header or transport
120     /// layer protocol is (see [IpNumber] or [ip_number] for a definitions of ids).
121     #[inline]
next_header(&self) -> IpNumber122     pub fn next_header(&self) -> IpNumber {
123         // SAFETY:
124         // Safe as the slice length is set to
125         // Ipv6Header::LEN (40) during construction
126         // of the struct.
127         IpNumber(unsafe { *self.slice.get_unchecked(6) })
128     }
129 
130     /// Read the "hop limit" field from the slice. The hop limit specifies the number of hops the packet can take before it is discarded.
131     #[inline]
hop_limit(&self) -> u8132     pub fn hop_limit(&self) -> u8 {
133         // SAFETY:
134         // Safe as the slice length is set to
135         // Ipv6Header::LEN (40) during construction
136         // of the struct.
137         unsafe { *self.slice.get_unchecked(7) }
138     }
139 
140     /// Returns a slice containing the IPv6 source address.
141     #[inline]
source(&self) -> [u8; 16]142     pub fn source(&self) -> [u8; 16] {
143         // SAFETY:
144         // Safe as the slice length is set to
145         // Ipv6Header::LEN (40) during construction
146         // of the struct.
147         unsafe { get_unchecked_16_byte_array(self.slice.as_ptr().add(8)) }
148     }
149 
150     /// Return the ipv6 source address as an std::net::Ipv6Addr
151     #[cfg(feature = "std")]
152     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
153     #[inline]
source_addr(&self) -> std::net::Ipv6Addr154     pub fn source_addr(&self) -> std::net::Ipv6Addr {
155         std::net::Ipv6Addr::from(self.source())
156     }
157 
158     /// Returns a slice containing the IPv6 destination address.
159     #[inline]
destination(&self) -> [u8; 16]160     pub fn destination(&self) -> [u8; 16] {
161         // SAFETY:
162         // Safe as the slice length is set to
163         // Ipv6Header::LEN (40) during construction
164         // of the struct.
165         unsafe { get_unchecked_16_byte_array(self.slice.as_ptr().add(24)) }
166     }
167 
168     /// Return the ipv6 destination address as an std::net::Ipv6Addr
169     #[cfg(feature = "std")]
170     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
171     #[inline]
destination_addr(&self) -> std::net::Ipv6Addr172     pub fn destination_addr(&self) -> std::net::Ipv6Addr {
173         std::net::Ipv6Addr::from(self.destination())
174     }
175 
176     /// Decode all the fields and copy the results to a Ipv6Header struct
to_header(&self) -> Ipv6Header177     pub fn to_header(&self) -> Ipv6Header {
178         Ipv6Header {
179             traffic_class: self.traffic_class(),
180             flow_label: self.flow_label(),
181             payload_length: self.payload_length(),
182             next_header: self.next_header(),
183             hop_limit: self.hop_limit(),
184             source: self.source(),
185             destination: self.destination(),
186         }
187     }
188 
189     /// Returns the length of the IPv6 header in bytes (same as [`crate::Ipv6Header::LEN`]).
header_len(&self) -> usize190     pub const fn header_len(&self) -> usize {
191         Ipv6Header::LEN
192     }
193 }
194 
195 #[cfg(test)]
196 mod test {
197     use crate::{err::ipv6::HeaderError::*, err::ipv6::HeaderSliceError::*, test_gens::*, *};
198     use alloc::format;
199     use proptest::*;
200 
201     #[test]
debug()202     fn debug() {
203         let header: Ipv6Header = Default::default();
204         let bytes = header.to_bytes();
205         let slice = Ipv6HeaderSlice::from_slice(&bytes).unwrap();
206         assert_eq!(
207             format!("{:?}", slice),
208             format!("Ipv6HeaderSlice {{ slice: {:?} }}", &bytes[..])
209         );
210     }
211 
212     proptest! {
213         #[test]
214         fn clone_eq(header in ipv6_any()) {
215             let bytes = header.to_bytes();
216             let slice = Ipv6HeaderSlice::from_slice(&bytes).unwrap();
217             assert_eq!(slice.clone(), slice);
218         }
219     }
220 
221     proptest! {
222         #[test]
223         fn from_slice(
224             header in ipv6_any(),
225             bad_version in 0..=0b1111u8)
226         {
227             // ok read
228             {
229                 let bytes = header.to_bytes();
230                 let actual = Ipv6HeaderSlice::from_slice(&bytes).unwrap();
231                 assert_eq!(actual.slice(), &bytes[..]);
232             }
233 
234             // version error
235             if bad_version != 6 {
236                 let mut bytes = header.to_bytes();
237                 // inject a bad version number
238                 bytes[0] = (0b1111 & bytes[0]) | (bad_version << 4);
239 
240                 assert_eq!(
241                     Ipv6HeaderSlice::from_slice(&bytes).unwrap_err(),
242                     Content(UnexpectedVersion{ version_number: bad_version })
243                 );
244             }
245 
246             // length error
247             {
248                 let bytes = header.to_bytes();
249                 for len in 0..bytes.len() {
250                     assert_eq!(
251                         Ipv6HeaderSlice::from_slice(&bytes[..len])
252                             .unwrap_err(),
253                         Len(err::LenError{
254                             required_len: Ipv6Header::LEN,
255                             len: len,
256                             len_source: LenSource::Slice,
257                             layer: err::Layer::Ipv6Header,
258                             layer_start_offset: 0,
259                         })
260                     );
261                 }
262             }
263         }
264     }
265 
266     proptest! {
267         #[test]
268         fn from_slice_unchecked(header in ipv6_any()) {
269             let bytes = header.to_bytes();
270             let actual = unsafe {
271                 Ipv6HeaderSlice::from_slice_unchecked(&bytes)
272             };
273             assert_eq!(actual.slice(), &bytes[..]);
274         }
275     }
276 
277     proptest! {
278         #[test]
279         fn getters(header in ipv6_any()) {
280             let bytes = header.to_bytes();
281             let actual = Ipv6HeaderSlice::from_slice(&bytes).unwrap();
282             assert_eq!(actual.slice(), &bytes[..]);
283             assert_eq!(actual.version(), 6);
284             assert_eq!(actual.traffic_class(), header.traffic_class);
285             assert_eq!(actual.flow_label(), header.flow_label);
286             assert_eq!(actual.payload_length(), header.payload_length);
287             assert_eq!(actual.next_header(), header.next_header);
288             assert_eq!(actual.hop_limit(), header.hop_limit);
289             assert_eq!(actual.source(), header.source);
290             assert_eq!(actual.destination(), header.destination);
291         }
292     }
293 
294     #[cfg(feature = "std")]
295     proptest! {
296         #[test]
297         fn getters_std(header in ipv6_any()) {
298             let bytes = header.to_bytes();
299             let actual = Ipv6HeaderSlice::from_slice(&bytes).unwrap();
300             assert_eq!(actual.source_addr(), std::net::Ipv6Addr::from(header.source));
301             assert_eq!(actual.destination_addr(), std::net::Ipv6Addr::from(header.destination));
302         }
303     }
304 
305     proptest! {
306         #[test]
307         fn to_header(header in ipv6_any()) {
308             let bytes = header.to_bytes();
309             let actual = Ipv6HeaderSlice::from_slice(&bytes).unwrap();
310             assert_eq!(actual.to_header(), header);
311         }
312     }
313 }
314