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