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