1 use crate::*; 2 3 /// Slices of the IPv4 extension headers present after the ip header. 4 /// 5 /// Currently supported: 6 /// * Authentication Header 7 /// 8 /// Currently not supported: 9 /// * Encapsulating Security Payload Header (ESP) 10 #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] 11 pub struct Ipv4ExtensionsSlice<'a> { 12 pub auth: Option<IpAuthHeaderSlice<'a>>, 13 } 14 15 impl<'a> Ipv4ExtensionsSlice<'a> { 16 /// Read all known ipv4 extensions and return an `Ipv4ExtensionSlices` with the 17 /// identified slices, the final ip number and a slice pointing to the non parsed data. from_slice( start_ip_number: IpNumber, start_slice: &'a [u8], ) -> Result<(Ipv4ExtensionsSlice<'a>, IpNumber, &'a [u8]), err::ip_auth::HeaderSliceError>18 pub fn from_slice( 19 start_ip_number: IpNumber, 20 start_slice: &'a [u8], 21 ) -> Result<(Ipv4ExtensionsSlice<'a>, IpNumber, &'a [u8]), err::ip_auth::HeaderSliceError> { 22 use ip_number::*; 23 if AUTH == start_ip_number { 24 let header = IpAuthHeaderSlice::from_slice(start_slice)?; 25 let rest = &start_slice[header.slice().len()..]; 26 let next_header = header.next_header(); 27 Ok(( 28 Ipv4ExtensionsSlice { auth: Some(header) }, 29 next_header, 30 rest, 31 )) 32 } else { 33 Ok((Default::default(), start_ip_number, start_slice)) 34 } 35 } 36 37 /// Collects all ipv4 extension headers in a slice until an error 38 /// is encountered or a "non IP extension header" is found and 39 /// returns the successfully parsed parts (+ the unparsed slice 40 /// it's [`IpNumber`] and the error if one occurred). 41 /// 42 /// The returned values are 43 /// 44 /// * [`Ipv4ExtensionsSlice`] containing the successfully parsed IPv6 extension headers 45 /// * [`IpNumber`] of unparsed data 46 /// * Slice with unparsed data 47 /// * Optional with error if there was an error wich stoped the parsing. 48 /// 49 /// # Examples 50 /// 51 /// ``` 52 /// use etherparse::{Ipv4ExtensionsSlice, IpAuthHeader, ip_number::{UDP, AUTHENTICATION_HEADER}}; 53 /// 54 /// let auth_header = IpAuthHeader::new(UDP, 0, 0, &[]).unwrap(); 55 /// let data = auth_header.to_bytes(); 56 /// 57 /// let (ipv4_exts, next_ip_num, next_data, err) = 58 /// Ipv4ExtensionsSlice::from_slice_lax(AUTHENTICATION_HEADER, &data); 59 /// 60 /// // authentication header is separated and no error occurred 61 /// assert!(ipv4_exts.auth.is_some()); 62 /// assert_eq!(next_ip_num, UDP); 63 /// assert_eq!(next_data, &[]); 64 /// assert!(err.is_none()); 65 /// ``` 66 /// 67 /// It is also ok to pass in a "non ip extension": 68 /// 69 /// ``` 70 /// use etherparse::{Ipv4ExtensionsSlice, ip_number::UDP}; 71 /// 72 /// let data = [0,1,2,3]; 73 /// // passing a non "ip extension header" ip number 74 /// let (ipv4_exts, next_ip_num, next_data, err) = 75 /// Ipv4ExtensionsSlice::from_slice_lax(UDP, &data); 76 /// 77 /// // the original data gets returned as UDP is not a 78 /// // an IP extension header 79 /// assert!(ipv4_exts.is_empty()); 80 /// assert_eq!(next_ip_num, UDP); 81 /// assert_eq!(next_data, &data); 82 /// // no errors gets triggered as the data is valid 83 /// assert!(err.is_none()); 84 /// ``` 85 /// 86 /// In case an error occurred the original data gets 87 /// returned together with the error: 88 /// 89 /// ``` 90 /// use etherparse::{ 91 /// Ipv4ExtensionsSlice, 92 /// IpAuthHeader, 93 /// ip_number::AUTHENTICATION_HEADER, 94 /// LenSource, 95 /// err::{ip_auth::HeaderSliceError::Len, LenError, Layer} 96 /// }; 97 /// 98 /// // providing not enough data 99 /// let (ipv4_exts, next_ip_num, next_data, err) = 100 /// Ipv4ExtensionsSlice::from_slice_lax(AUTHENTICATION_HEADER, &[]); 101 /// 102 /// // original data will be returned with no data parsed 103 /// assert!(ipv4_exts.is_empty()); 104 /// assert_eq!(next_ip_num, AUTHENTICATION_HEADER); 105 /// assert_eq!(next_data, &[]); 106 /// // the error that stopped the parsing will also be returned 107 /// assert_eq!(err, Some(Len(LenError{ 108 /// required_len: IpAuthHeader::MIN_LEN, 109 /// len: 0, 110 /// len_source: LenSource::Slice, 111 /// layer: Layer::IpAuthHeader, 112 /// layer_start_offset: 0, 113 /// }))); 114 /// ``` from_slice_lax( start_ip_number: IpNumber, start_slice: &'a [u8], ) -> ( Ipv4ExtensionsSlice<'a>, IpNumber, &'a [u8], Option<err::ip_auth::HeaderSliceError>, )115 pub fn from_slice_lax( 116 start_ip_number: IpNumber, 117 start_slice: &'a [u8], 118 ) -> ( 119 Ipv4ExtensionsSlice<'a>, 120 IpNumber, 121 &'a [u8], 122 Option<err::ip_auth::HeaderSliceError>, 123 ) { 124 use ip_number::*; 125 if AUTH == start_ip_number { 126 match IpAuthHeaderSlice::from_slice(start_slice) { 127 Ok(header) => { 128 let rest = unsafe { 129 // SAFE as header.slice() has the same start and is a 130 // subslice of start_slice. 131 core::slice::from_raw_parts( 132 start_slice.as_ptr().add(header.slice().len()), 133 start_slice.len() - header.slice().len(), 134 ) 135 }; 136 let next_header = header.next_header(); 137 ( 138 Ipv4ExtensionsSlice { auth: Some(header) }, 139 next_header, 140 rest, 141 None, 142 ) 143 } 144 Err(err) => ( 145 Ipv4ExtensionsSlice { auth: None }, 146 start_ip_number, 147 start_slice, 148 Some(err), 149 ), 150 } 151 } else { 152 ( 153 Ipv4ExtensionsSlice { auth: None }, 154 start_ip_number, 155 start_slice, 156 None, 157 ) 158 } 159 } 160 161 /// Convert the slices into actual headers. to_header(&self) -> Ipv4Extensions162 pub fn to_header(&self) -> Ipv4Extensions { 163 Ipv4Extensions { 164 auth: self.auth.as_ref().map(|v| v.to_header()), 165 } 166 } 167 168 /// Returns true if no IPv4 extension header is present (all fields `None`). 169 #[inline] is_empty(&self) -> bool170 pub fn is_empty(&self) -> bool { 171 self.auth.is_none() 172 } 173 } 174 175 #[cfg(test)] 176 mod test { 177 use super::*; 178 use crate::test_gens::*; 179 use alloc::vec::Vec; 180 use proptest::prelude::*; 181 182 proptest! { 183 #[test] 184 fn debug(auth in ip_auth_any()) { 185 use alloc::format; 186 187 // None 188 assert_eq!( 189 &format!("Ipv4ExtensionsSlice {{ auth: {:?} }}", Option::<IpAuthHeader>::None), 190 &format!( 191 "{:?}", 192 Ipv4ExtensionsSlice { 193 auth: None, 194 } 195 ) 196 ); 197 198 // Some 199 let buffer = { 200 let mut buffer = Vec::with_capacity(auth.header_len()); 201 auth.write(&mut buffer).unwrap(); 202 buffer 203 }; 204 let auth_slice = IpAuthHeaderSlice::from_slice(&buffer).unwrap(); 205 assert_eq!( 206 &format!("Ipv4ExtensionsSlice {{ auth: {:?} }}", Some(auth_slice.clone())), 207 &format!( 208 "{:?}", 209 Ipv4ExtensionsSlice { 210 auth: Some(auth_slice.clone()), 211 } 212 ) 213 ); 214 } 215 } 216 217 proptest! { 218 #[test] 219 fn clone_eq(auth in ip_auth_any()) { 220 // None 221 { 222 let header = Ipv4ExtensionsSlice{ 223 auth: None, 224 }; 225 assert_eq!( 226 header.clone(), 227 Ipv4ExtensionsSlice{ 228 auth: None, 229 } 230 ); 231 } 232 233 // Some 234 { 235 let buffer = { 236 let mut buffer = Vec::with_capacity(auth.header_len()); 237 auth.write(&mut buffer).unwrap(); 238 buffer 239 }; 240 let auth_slice = IpAuthHeaderSlice::from_slice(&buffer).unwrap(); 241 let slice = Ipv4ExtensionsSlice { 242 auth: Some(auth_slice.clone()), 243 }; 244 assert_eq!( 245 slice.clone(), 246 Ipv4ExtensionsSlice{ 247 auth: Some(auth_slice.clone()), 248 } 249 ); 250 } 251 } 252 } 253 254 proptest! { 255 #[test] 256 fn from_slice_lax(auth in ip_auth_any()) { 257 use crate::ip_number::{UDP, AUTHENTICATION_HEADER}; 258 use crate::err::{*, ip_auth::HeaderSliceError::Len}; 259 260 // normal read 261 { 262 let data = auth.to_bytes(); 263 264 let (ipv4_exts, next_ip_num, next_data, err) = 265 Ipv4ExtensionsSlice::from_slice_lax(AUTHENTICATION_HEADER, &data); 266 267 // authentication header is separated and no error occurred 268 assert_eq!(ipv4_exts.auth.unwrap().to_header(), auth); 269 assert_eq!(next_ip_num, auth.next_header); 270 assert_eq!(next_data, &[]); 271 assert!(err.is_none()); 272 } 273 // normal read with no extension header 274 { 275 let data = [0,1,2,3]; 276 // passing a non "ip extension header" ip number 277 let (ipv4_exts, next_ip_num, next_data, err) = 278 Ipv4ExtensionsSlice::from_slice_lax(UDP, &data); 279 280 // the original data gets returned as UDP is not a 281 // an IP extension header 282 assert!(ipv4_exts.is_empty()); 283 assert_eq!(next_ip_num, UDP); 284 assert_eq!(next_data, &data); 285 // no errors gets triggered as the data is valid 286 assert!(err.is_none()); 287 } 288 // len error during parsing 289 { 290 // providing not enough data 291 let (ipv4_exts, next_ip_num, next_data, err) = 292 Ipv4ExtensionsSlice::from_slice_lax(AUTHENTICATION_HEADER, &[]); 293 294 // original data will be returned with no data parsed 295 assert!(ipv4_exts.is_empty()); 296 assert_eq!(next_ip_num, AUTHENTICATION_HEADER); 297 assert_eq!(next_data, &[]); 298 // the error that stopped the parsing will also be returned 299 assert_eq!(err, Some(Len(LenError{ 300 required_len: IpAuthHeader::MIN_LEN, 301 len: 0, 302 len_source: LenSource::Slice, 303 layer: Layer::IpAuthHeader, 304 layer_start_offset: 0, 305 }))); 306 } 307 } 308 } 309 310 proptest! { 311 #[test] 312 fn to_header(auth in ip_auth_any()) { 313 // None 314 assert_eq!( 315 Ipv4ExtensionsSlice{ 316 auth: None, 317 }.to_header(), 318 Ipv4Extensions{ 319 auth: None, 320 } 321 ); 322 323 // Some 324 { 325 let buffer = { 326 let mut buffer = Vec::with_capacity(auth.header_len()); 327 auth.write(&mut buffer).unwrap(); 328 buffer 329 }; 330 let slice = Ipv4ExtensionsSlice{ 331 auth: Some( 332 IpAuthHeaderSlice::from_slice(&buffer).unwrap() 333 ), 334 }; 335 assert_eq!( 336 slice.to_header(), 337 Ipv4Extensions{ 338 auth: Some(auth.clone()), 339 } 340 ); 341 } 342 } 343 } 344 345 #[test] is_empty()346 fn is_empty() { 347 // empty 348 assert!(Ipv4ExtensionsSlice { auth: None }.is_empty()); 349 350 // auth 351 { 352 let buffer = { 353 let auth = IpAuthHeader::new(ip_number::UDP, 0, 0, &[]).unwrap(); 354 let mut buffer = Vec::with_capacity(auth.header_len()); 355 auth.write(&mut buffer).unwrap(); 356 buffer 357 }; 358 assert_eq!( 359 false, 360 Ipv4ExtensionsSlice { 361 auth: Some(IpAuthHeaderSlice::from_slice(&buffer).unwrap()), 362 } 363 .is_empty() 364 ); 365 } 366 } 367 } 368