1 use crate::{ 2 err::{ipv4::SliceError, Layer, LenError}, 3 *, 4 }; 5 6 /// Slice containing the IPv4 headers & payload. 7 #[derive(Clone, Debug, Eq, PartialEq)] 8 pub struct Ipv4Slice<'a> { 9 pub(crate) header: Ipv4HeaderSlice<'a>, 10 pub(crate) exts: Ipv4ExtensionsSlice<'a>, 11 pub(crate) payload: IpPayloadSlice<'a>, 12 } 13 14 impl<'a> Ipv4Slice<'a> { 15 /// Separates and validates IPv4 headers (including extension headers) 16 /// in the given slice and determine the sub-slice containing the payload 17 /// of the IPv4 packet. 18 /// 19 /// Note that his function returns an [`crate::err::LenError`] if the given slice 20 /// contains less data then the `total_len` field in the IPv4 header indicates 21 /// should be present. 22 /// 23 /// If you want to ignore these kind of length errors based on the length 24 /// fields in the IP headers use [`crate::LaxIpv4Slice::from_slice`] instead. from_slice(slice: &[u8]) -> Result<Ipv4Slice, SliceError>25 pub fn from_slice(slice: &[u8]) -> Result<Ipv4Slice, SliceError> { 26 use crate::ip_number::AUTH; 27 28 // decode the header 29 let header = Ipv4HeaderSlice::from_slice(slice).map_err(|err| { 30 use crate::err::ipv4::HeaderSliceError::*; 31 match err { 32 Len(err) => SliceError::Len(err), 33 Content(err) => SliceError::Header(err), 34 } 35 })?; 36 37 // validate total_len at least contains the header 38 let header_total_len: usize = header.total_len().into(); 39 if header_total_len < header.slice().len() { 40 return Err(SliceError::Len(LenError { 41 required_len: header.slice().len(), 42 len: header_total_len, 43 len_source: LenSource::Ipv4HeaderTotalLen, 44 layer: Layer::Ipv4Packet, 45 layer_start_offset: 0, 46 })); 47 } 48 49 // check slice length based on the total length 50 let header_payload = if slice.len() < header_total_len { 51 return Err(SliceError::Len(LenError { 52 required_len: header_total_len, 53 len: slice.len(), 54 len_source: LenSource::Slice, 55 layer: Layer::Ipv4Packet, 56 layer_start_offset: 0, 57 })); 58 } else { 59 unsafe { 60 core::slice::from_raw_parts( 61 slice.as_ptr().add(header.slice().len()), 62 header_total_len - header.slice().len(), 63 ) 64 } 65 }; 66 67 // decode the authentication header if needed 68 let fragmented = header.is_fragmenting_payload(); 69 match header.protocol() { 70 AUTH => { 71 use crate::err::ip_auth::HeaderSliceError as E; 72 73 // parse extension headers 74 let auth = match IpAuthHeaderSlice::from_slice(header_payload) { 75 Ok(s) => s, 76 Err(err) => match err { 77 E::Len(mut l) => { 78 // change the length source to the ipv4 header 79 l.len_source = LenSource::Ipv4HeaderTotalLen; 80 l.layer_start_offset += header.slice().len(); 81 return Err(SliceError::Len(l)); 82 } 83 E::Content(err) => return Err(SliceError::Exts(err)), 84 }, 85 }; 86 87 // remove the extension header from the payload 88 let payload = unsafe { 89 core::slice::from_raw_parts( 90 header_payload.as_ptr().add(auth.slice().len()), 91 header_payload.len() - auth.slice().len(), 92 ) 93 }; 94 let ip_number = auth.next_header(); 95 Ok(Ipv4Slice { 96 header, 97 exts: Ipv4ExtensionsSlice { auth: Some(auth) }, 98 payload: IpPayloadSlice { 99 ip_number, 100 fragmented, 101 len_source: LenSource::Ipv4HeaderTotalLen, 102 payload, 103 }, 104 }) 105 } 106 ip_number => Ok(Ipv4Slice { 107 header, 108 exts: Ipv4ExtensionsSlice { auth: None }, 109 payload: IpPayloadSlice { 110 ip_number, 111 fragmented, 112 len_source: LenSource::Ipv4HeaderTotalLen, 113 payload: header_payload, 114 }, 115 }), 116 } 117 } 118 119 /// Returns a slice containing the IPv4 header. 120 #[inline] header(&self) -> Ipv4HeaderSlice121 pub fn header(&self) -> Ipv4HeaderSlice { 122 self.header 123 } 124 125 /// Returns a slice containing the IPv4 extension headers. 126 #[inline] extensions(&self) -> Ipv4ExtensionsSlice127 pub fn extensions(&self) -> Ipv4ExtensionsSlice { 128 self.exts 129 } 130 131 /// Returns a slice containing the data after the IPv4 header 132 /// and IPv4 extensions headers. 133 #[inline] payload(&self) -> &IpPayloadSlice<'a>134 pub fn payload(&self) -> &IpPayloadSlice<'a> { 135 &self.payload 136 } 137 138 /// Returns the ip number the type of payload of the IPv4 packet. 139 /// 140 /// This function returns the ip number stored in the last 141 /// IPv4 header or extension header. 142 #[inline] payload_ip_number(&self) -> IpNumber143 pub fn payload_ip_number(&self) -> IpNumber { 144 self.payload.ip_number 145 } 146 147 /// Returns true if the payload is flagged as being fragmented. 148 #[inline] is_payload_fragmented(&self) -> bool149 pub fn is_payload_fragmented(&self) -> bool { 150 self.header.is_fragmenting_payload() 151 } 152 } 153 154 #[cfg(test)] 155 mod test { 156 use super::*; 157 use crate::test_gens::*; 158 use alloc::{format, vec::Vec}; 159 use proptest::prelude::*; 160 161 proptest! { 162 #[test] 163 fn debug_clone_eq( 164 ipv4_base in ipv4_any(), 165 auth in ip_auth_any() 166 ) { 167 let payload: [u8;4] = [1,2,3,4]; 168 let mut data = Vec::with_capacity( 169 ipv4_base.header_len() + 170 auth.header_len() + 171 payload.len() 172 ); 173 let mut ipv4 = ipv4_base.clone(); 174 ipv4.protocol = crate::ip_number::AUTH; 175 ipv4.set_payload_len(auth.header_len() + payload.len()).unwrap(); 176 data.extend_from_slice(&ipv4.to_bytes()); 177 data.extend_from_slice(&auth.to_bytes()); 178 data.extend_from_slice(&payload); 179 180 // decode packet 181 let slice = Ipv4Slice::from_slice(&data).unwrap(); 182 183 // check debug output 184 prop_assert_eq!( 185 format!("{:?}", slice), 186 format!( 187 "Ipv4Slice {{ header: {:?}, exts: {:?}, payload: {:?} }}", 188 slice.header(), 189 slice.extensions(), 190 slice.payload() 191 ) 192 ); 193 prop_assert_eq!(slice.clone(), slice); 194 } 195 } 196 197 proptest! { 198 #[test] 199 fn from_slice( 200 ipv4_base in ipv4_any(), 201 auth in ip_auth_any() 202 ) { 203 let payload: [u8;6] = [1,2,3,4,5,6]; 204 205 // build packets 206 let data_without_ext = { 207 let mut data = Vec::with_capacity( 208 ipv4_base.header_len() + 209 payload.len() + 210 4 211 ); 212 let mut ipv4 = ipv4_base.clone(); 213 ipv4.set_payload_len(payload.len()).unwrap(); 214 ipv4.protocol = crate::ip_number::UDP; 215 data.extend_from_slice(&ipv4.to_bytes()); 216 data.extend_from_slice(&payload); 217 data.extend_from_slice(&[0,0,0,0]); 218 data 219 }; 220 let data_with_ext = { 221 let payload: [u8;6] = [1,2,3,4,5,6]; 222 let mut data = Vec::with_capacity( 223 ipv4_base.header_len() + 224 auth.header_len() + 225 payload.len() + 226 4 227 ); 228 let mut ipv4 = ipv4_base.clone(); 229 ipv4.set_payload_len(auth.header_len() + payload.len()).unwrap(); 230 ipv4.protocol = crate::ip_number::AUTH; 231 data.extend_from_slice(&ipv4.to_bytes()); 232 data.extend_from_slice(&auth.to_bytes()); 233 data.extend_from_slice(&payload); 234 data.extend_from_slice(&[0,0,0,0]); 235 data 236 }; 237 238 // parsing without extensions 239 { 240 let actual = Ipv4Slice::from_slice(&data_without_ext).unwrap(); 241 prop_assert_eq!(actual.header().slice(), &data_without_ext[..ipv4_base.header_len()]); 242 prop_assert!(actual.extensions().auth.is_none()); 243 prop_assert_eq!( 244 &actual.payload, 245 &IpPayloadSlice{ 246 ip_number: ip_number::UDP.into(), 247 fragmented: ipv4_base.is_fragmenting_payload(), 248 len_source: LenSource::Ipv4HeaderTotalLen, 249 payload: &payload 250 } 251 ); 252 prop_assert_eq!(actual.payload_ip_number(), ip_number::UDP.into()); 253 } 254 255 // parsing with extensions 256 { 257 let actual = Ipv4Slice::from_slice(&data_with_ext).unwrap(); 258 prop_assert_eq!(actual.header().slice(), &data_with_ext[..ipv4_base.header_len()]); 259 prop_assert_eq!( 260 actual.extensions().auth.unwrap(), 261 IpAuthHeaderSlice::from_slice(&data_with_ext[ipv4_base.header_len()..]).unwrap() 262 ); 263 prop_assert_eq!( 264 &actual.payload, 265 &IpPayloadSlice{ 266 ip_number: auth.next_header.into(), 267 fragmented: ipv4_base.is_fragmenting_payload(), 268 len_source: LenSource::Ipv4HeaderTotalLen, 269 payload: &payload 270 } 271 ); 272 prop_assert_eq!(actual.payload_ip_number(), auth.next_header.into()); 273 } 274 275 // header length error 276 for len in 0..Ipv4Header::MIN_LEN { 277 prop_assert_eq!( 278 Ipv4Slice::from_slice(&data_without_ext[..len]).unwrap_err(), 279 SliceError::Len( 280 LenError{ 281 required_len: Ipv4Header::MIN_LEN, 282 len, 283 len_source: LenSource::Slice, 284 layer: Layer::Ipv4Header, 285 layer_start_offset: 0, 286 } 287 ) 288 ); 289 } 290 291 // header content error 292 { 293 use crate::err::ipv4::HeaderError; 294 // inject invalid icv 295 let mut data = data_without_ext.clone(); 296 data[0] = data[0] & 0xf0; // icv 0 297 prop_assert_eq!( 298 Ipv4Slice::from_slice(&data).unwrap_err(), 299 SliceError::Header( 300 HeaderError::HeaderLengthSmallerThanHeader { ihl: 0 } 301 ) 302 ); 303 } 304 305 // payload length error without auth header 306 { 307 use crate::err::{LenError, Layer}; 308 309 let required_len = ipv4_base.header_len() + payload.len(); 310 prop_assert_eq!( 311 Ipv4Slice::from_slice(&data_without_ext[..required_len - 1]).unwrap_err(), 312 SliceError::Len(LenError{ 313 required_len: required_len, 314 len: required_len - 1, 315 len_source: LenSource::Slice, 316 layer: Layer::Ipv4Packet, 317 layer_start_offset: 0, 318 }) 319 ); 320 } 321 322 // payload length error auth header 323 { 324 use crate::err::{LenError, Layer}; 325 326 let required_len = ipv4_base.header_len() + auth.header_len() + payload.len(); 327 prop_assert_eq!( 328 Ipv4Slice::from_slice(&data_with_ext[..required_len - 1]).unwrap_err(), 329 SliceError::Len(LenError{ 330 required_len: required_len, 331 len: required_len - 1, 332 len_source: LenSource::Slice, 333 layer: Layer::Ipv4Packet, 334 layer_start_offset: 0, 335 }) 336 ); 337 } 338 339 // auth length error 340 { 341 use crate::err::{LenError, Layer}; 342 343 // inject a total_length that is smaller then the auth header 344 let mut data = data_with_ext.clone(); 345 let total_len_too_small = ipv4_base.header_len() + auth.header_len() - 1; 346 { 347 let tltsm = (total_len_too_small as u16).to_be_bytes(); 348 data[2] = tltsm[0]; 349 data[3] = tltsm[1]; 350 } 351 352 prop_assert_eq!( 353 Ipv4Slice::from_slice(&data).unwrap_err(), 354 SliceError::Len( 355 LenError{ 356 required_len: auth.header_len(), 357 len: auth.header_len() - 1, 358 len_source: LenSource::Ipv4HeaderTotalLen, 359 layer: Layer::IpAuthHeader, 360 layer_start_offset: ipv4_base.header_len(), 361 } 362 ) 363 ); 364 } 365 366 // auth content error 367 { 368 use crate::err::ip_auth::HeaderError; 369 370 // inject zero as auth header length 371 let mut data = data_with_ext.clone(); 372 data[ipv4_base.header_len() + 1] = 0; 373 374 prop_assert_eq!( 375 Ipv4Slice::from_slice(&data).unwrap_err(), 376 SliceError::Exts( 377 HeaderError::ZeroPayloadLen 378 ) 379 ); 380 } 381 } 382 } 383 384 #[test] is_payload_fragmented()385 fn is_payload_fragmented() { 386 use crate::ip_number::UDP; 387 // non-fragmented 388 { 389 let payload: [u8; 6] = [1, 2, 3, 4, 5, 6]; 390 let ipv4 = 391 Ipv4Header::new(payload.len() as u16, 1, UDP, [3, 4, 5, 6], [7, 8, 9, 10]).unwrap(); 392 let data = { 393 let mut data = Vec::with_capacity(ipv4.header_len() + payload.len()); 394 data.extend_from_slice(&ipv4.to_bytes()); 395 data.extend_from_slice(&payload); 396 data 397 }; 398 399 let slice = Ipv4Slice::from_slice(&data).unwrap(); 400 assert!(false == slice.is_payload_fragmented()); 401 } 402 // fragmented 403 { 404 let payload: [u8; 6] = [1, 2, 3, 4, 5, 6]; 405 let mut ipv4 = 406 Ipv4Header::new(payload.len() as u16, 1, UDP, [3, 4, 5, 6], [7, 8, 9, 10]).unwrap(); 407 ipv4.fragment_offset = 123.try_into().unwrap(); 408 let data = { 409 let mut data = Vec::with_capacity(ipv4.header_len() + payload.len()); 410 data.extend_from_slice(&ipv4.to_bytes()); 411 data.extend_from_slice(&payload); 412 data 413 }; 414 415 let slice = Ipv4Slice::from_slice(&data).unwrap(); 416 assert!(slice.is_payload_fragmented()); 417 } 418 } 419 } 420