1use crate::{err::ipv4_exts::ExtsWalkError, *};
2
3#[derive(Clone, Debug, Eq, PartialEq, Default)]
11pub struct Ipv4Extensions {
12 pub auth: Option<IpAuthHeader>,
13}
14
15impl Ipv4Extensions {
16 pub const MIN_LEN: usize = 0;
19
20 pub const MAX_LEN: usize = IpAuthHeader::MAX_LEN;
22
23 pub fn from_slice(
26 start_ip_number: IpNumber,
27 slice: &[u8],
28 ) -> Result<(Ipv4Extensions, IpNumber, &[u8]), err::ip_auth::HeaderSliceError> {
29 Ipv4ExtensionsSlice::from_slice(start_ip_number, slice).map(|v| (v.0.to_header(), v.1, v.2))
30 }
31
32 pub fn from_slice_lax(
111 start_ip_number: IpNumber,
112 start_slice: &[u8],
113 ) -> (
114 Ipv4Extensions,
115 IpNumber,
116 &[u8],
117 Option<err::ip_auth::HeaderSliceError>,
118 ) {
119 let (slice, next_ip_number, next_data, error) =
120 Ipv4ExtensionsSlice::from_slice_lax(start_ip_number, start_slice);
121 (slice.to_header(), next_ip_number, next_data, error)
122 }
123
124 #[cfg(feature = "std")]
128 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
129 pub fn read<T: std::io::Read + Sized>(
130 reader: &mut T,
131 start_ip_number: IpNumber,
132 ) -> Result<(Ipv4Extensions, IpNumber), err::ip_auth::HeaderReadError> {
133 use ip_number::*;
134 if AUTH == start_ip_number {
135 let header = IpAuthHeader::read(reader)?;
136 let next_ip_number = header.next_header;
137 Ok((Ipv4Extensions { auth: Some(header) }, next_ip_number))
138 } else {
139 Ok((Default::default(), start_ip_number))
140 }
141 }
142
143 #[cfg(feature = "std")]
147 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
148 pub fn read_limited<T: std::io::Read + Sized>(
149 reader: &mut crate::io::LimitedReader<T>,
150 start_ip_number: IpNumber,
151 ) -> Result<(Ipv4Extensions, IpNumber), err::ip_auth::HeaderLimitedReadError> {
152 use ip_number::*;
153 if AUTH == start_ip_number {
154 let header = IpAuthHeader::read_limited(reader)?;
155 let next_ip_number = header.next_header;
156 Ok((Ipv4Extensions { auth: Some(header) }, next_ip_number))
157 } else {
158 Ok((Default::default(), start_ip_number))
159 }
160 }
161
162 #[cfg(feature = "std")]
164 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
165 pub fn write<T: std::io::Write + Sized>(
166 &self,
167 writer: &mut T,
168 start_ip_number: IpNumber,
169 ) -> Result<(), err::ipv4_exts::HeaderWriteError> {
170 use err::ipv4_exts::{ExtsWalkError::*, HeaderWriteError::*};
171 use ip_number::*;
172 match self.auth {
173 Some(ref header) => {
174 if AUTH == start_ip_number {
175 header.write(writer).map_err(Io)
176 } else {
177 Err(Content(ExtNotReferenced {
178 missing_ext: IpNumber::AUTHENTICATION_HEADER,
179 }))
180 }
181 }
182 None => Ok(()),
183 }
184 }
185
186 pub fn header_len(&self) -> usize {
188 if let Some(ref header) = self.auth {
189 header.header_len()
190 } else {
191 0
192 }
193 }
194
195 pub fn set_next_headers(&mut self, last_protocol_number: IpNumber) -> IpNumber {
202 use ip_number::*;
203
204 let mut next = last_protocol_number;
205
206 if let Some(ref mut header) = self.auth {
207 header.next_header = next;
208 next = AUTH;
209 }
210
211 next
212 }
213
214 pub fn next_header(&self, first_next_header: IpNumber) -> Result<IpNumber, ExtsWalkError> {
220 use ip_number::*;
221 if let Some(ref auth) = self.auth {
222 if first_next_header == AUTH {
223 Ok(auth.next_header)
224 } else {
225 Err(ExtsWalkError::ExtNotReferenced {
226 missing_ext: IpNumber::AUTHENTICATION_HEADER,
227 })
228 }
229 } else {
230 Ok(first_next_header)
231 }
232 }
233
234 #[inline]
236 pub fn is_empty(&self) -> bool {
237 self.auth.is_none()
238 }
239}
240
241#[cfg(test)]
242mod test {
243 use super::*;
244 use crate::ip_number::*;
245 use crate::test_gens::*;
246 use alloc::vec::Vec;
247 use proptest::prelude::*;
248 use std::io::Cursor;
249
250 #[test]
251 fn from_slice() {
252 let auth_header = IpAuthHeader::new(UDP, 0, 0, &[]).unwrap();
253
254 let buffer = {
255 let mut buffer = Vec::with_capacity(auth_header.header_len());
256 auth_header.write(&mut buffer).unwrap();
257 buffer.push(1);
258 buffer.push(2);
259 buffer
260 };
261
262 {
264 let (header, next, rest) = Ipv4Extensions::from_slice(TCP, &buffer).unwrap();
265 assert!(header.auth.is_none());
266 assert_eq!(TCP, next);
267 assert_eq!(rest, &buffer);
268 }
269
270 {
272 let (actual, next, rest) = Ipv4Extensions::from_slice(AUTH, &buffer).unwrap();
273 assert_eq!(actual.auth.unwrap(), auth_header);
274 assert_eq!(UDP, next);
275 assert_eq!(rest, &buffer[auth_header.header_len()..]);
276 }
277
278 {
280 use err::ip_auth::HeaderSliceError::Len;
281 const AUTH_HEADER_LEN: usize = 12;
282 assert_eq!(
283 Ipv4Extensions::from_slice(AUTH, &buffer[..auth_header.header_len() - 1])
284 .unwrap_err(),
285 Len(err::LenError {
286 required_len: AUTH_HEADER_LEN,
287 len: auth_header.header_len() - 1,
288 len_source: LenSource::Slice,
289 layer: err::Layer::IpAuthHeader,
290 layer_start_offset: 0,
291 })
292 );
293 }
294 }
295
296 proptest! {
297 #[test]
298 fn from_slice_lax(auth in ip_auth_any()) {
299 use crate::ip_number::{UDP, AUTHENTICATION_HEADER};
300 use crate::err::{*, ip_auth::HeaderSliceError::Len};
301
302 {
304 let data = auth.to_bytes();
305
306 let (ipv4_exts, next_ip_num, next_data, err) =
307 Ipv4Extensions::from_slice_lax(AUTHENTICATION_HEADER, &data);
308
309 assert_eq!(ipv4_exts.auth, Some(auth.clone()));
311 assert_eq!(next_ip_num, auth.next_header);
312 assert_eq!(next_data, &[]);
313 assert!(err.is_none());
314 }
315 {
317 let data = [0,1,2,3];
318 let (ipv4_exts, next_ip_num, next_data, err) =
320 Ipv4Extensions::from_slice_lax(UDP, &data);
321
322 assert!(ipv4_exts.is_empty());
325 assert_eq!(next_ip_num, UDP);
326 assert_eq!(next_data, &data);
327 assert!(err.is_none());
329 }
330 {
332 let (ipv4_exts, next_ip_num, next_data, err) =
334 Ipv4Extensions::from_slice_lax(AUTHENTICATION_HEADER, &[]);
335
336 assert!(ipv4_exts.is_empty());
338 assert_eq!(next_ip_num, AUTHENTICATION_HEADER);
339 assert_eq!(next_data, &[]);
340 assert_eq!(err, Some(Len(LenError{
342 required_len: IpAuthHeader::MIN_LEN,
343 len: 0,
344 len_source: LenSource::Slice,
345 layer: Layer::IpAuthHeader,
346 layer_start_offset: 0,
347 })));
348 }
349 }
350 }
351
352 proptest! {
353 #[test]
354 fn read(auth in ip_auth_any()) {
355 {
357 let mut cursor = Cursor::new(&[]);
358 let (actual, next) = Ipv4Extensions::read(&mut cursor, UDP).unwrap();
359 assert_eq!(next, UDP);
360 assert_eq!(
361 actual,
362 Ipv4Extensions{
363 auth: None,
364 }
365 );
366 }
367
368 {
370 let buffer = {
371 let mut buffer = Vec::with_capacity(auth.header_len());
372 auth.write(&mut buffer).unwrap();
373 buffer.push(1);
374 buffer
375 };
376 let mut cursor = Cursor::new(&buffer);
377 let (actual, next) = Ipv4Extensions::read(&mut cursor, AUTH).unwrap();
378 assert_eq!(auth.header_len(), cursor.position() as usize);
379 assert_eq!(next, auth.next_header);
380 assert_eq!(
381 actual,
382 Ipv4Extensions{
383 auth: Some(auth.clone()),
384 }
385 );
386 }
387
388 {
390 let mut cursor = Cursor::new(&[]);
391 assert!(Ipv4Extensions::read(&mut cursor, AUTH).is_err());
392 }
393 }
394 }
395
396 #[test]
397 fn write() {
398 {
400 let mut buffer = Vec::new();
401 Ipv4Extensions { auth: None }
402 .write(&mut buffer, UDP)
403 .unwrap();
404 assert_eq!(0, buffer.len());
405 }
406
407 let auth_header = IpAuthHeader::new(UDP, 0, 0, &[]).unwrap();
409 {
410 let mut buffer = Vec::with_capacity(auth_header.header_len());
411 Ipv4Extensions {
412 auth: Some(auth_header.clone()),
413 }
414 .write(&mut buffer, AUTH)
415 .unwrap();
416 let (read_header, _) = IpAuthHeader::from_slice(&buffer).unwrap();
417 assert_eq!(auth_header, read_header);
418 }
419
420 {
422 use crate::err::ipv4_exts::ExtsWalkError::ExtNotReferenced;
423
424 let mut buffer = Vec::new();
425 let err = Ipv4Extensions {
426 auth: Some(auth_header.clone()),
427 }
428 .write(&mut buffer, UDP)
429 .unwrap_err();
430 assert_eq!(
431 err.content().unwrap(),
432 &ExtNotReferenced {
433 missing_ext: IpNumber::AUTHENTICATION_HEADER,
434 }
435 );
436 }
437
438 {
440 let mut buffer = Vec::with_capacity(auth_header.header_len() - 1);
441 buffer.resize(auth_header.header_len() - 1, 0);
442 let mut cursor = Cursor::new(&mut buffer[..]);
443 let err = Ipv4Extensions {
444 auth: Some(auth_header.clone()),
445 }
446 .write(&mut cursor, AUTH)
447 .unwrap_err();
448 assert!(err.io().is_some());
449 }
450 }
451
452 #[test]
453 fn header_len() {
454 assert_eq!(0, Ipv4Extensions { auth: None }.header_len());
456
457 {
459 let auth = IpAuthHeader::new(UDP, 0, 0, &[]).unwrap();
460 assert_eq!(
461 auth.header_len(),
462 Ipv4Extensions { auth: Some(auth) }.header_len()
463 );
464 }
465 {
467 let auth = IpAuthHeader::new(UDP, 0, 0, &[1, 2, 3, 4]).unwrap();
468 assert_eq!(
469 auth.header_len(),
470 Ipv4Extensions { auth: Some(auth) }.header_len()
471 );
472 }
473 }
474
475 #[test]
476 fn set_next_headers() {
477 {
479 let mut exts = Ipv4Extensions { auth: None };
480 assert_eq!(UDP, exts.set_next_headers(UDP));
481 }
482
483 {
485 let mut exts = Ipv4Extensions {
486 auth: Some(IpAuthHeader::new(TCP, 0, 0, &[]).unwrap()),
487 };
488 assert_eq!(TCP, exts.auth.as_ref().unwrap().next_header);
489 let re = exts.set_next_headers(UDP);
491 assert_eq!(AUTH, re);
492 assert_eq!(UDP, exts.auth.as_ref().unwrap().next_header);
493 }
494 }
495
496 #[test]
497 fn next_header() {
498 {
500 let exts = Ipv4Extensions { auth: None };
501 assert_eq!(UDP, exts.next_header(UDP).unwrap());
502 }
503 {
505 let exts = Ipv4Extensions {
506 auth: Some(IpAuthHeader::new(TCP, 0, 0, &[]).unwrap()),
507 };
508
509 assert_eq!(TCP, exts.next_header(AUTH).unwrap());
511
512 use crate::err::ipv4_exts::ExtsWalkError::ExtNotReferenced;
514 assert_eq!(
515 ExtNotReferenced {
516 missing_ext: IpNumber::AUTHENTICATION_HEADER
517 },
518 exts.next_header(TCP).unwrap_err()
519 );
520 }
521 }
522
523 #[test]
524 fn is_empty() {
525 assert!(Ipv4Extensions { auth: None }.is_empty());
527
528 assert_eq!(
530 false,
531 Ipv4Extensions {
532 auth: Some(IpAuthHeader::new(ip_number::UDP, 0, 0, &[]).unwrap()),
533 }
534 .is_empty()
535 );
536 }
537
538 proptest! {
539 #[test]
540 fn debug(auth in ip_auth_any()) {
541 use alloc::format;
542
543 assert_eq!(
545 &format!("Ipv4Extensions {{ auth: {:?} }}", Option::<IpAuthHeader>::None),
546 &format!(
547 "{:?}",
548 Ipv4Extensions {
549 auth: None,
550 }
551 )
552 );
553
554 assert_eq!(
556 &format!("Ipv4Extensions {{ auth: {:?} }}", Some(auth.clone())),
557 &format!(
558 "{:?}",
559 Ipv4Extensions {
560 auth: Some(auth.clone()),
561 }
562 )
563 );
564 }
565 }
566
567 proptest! {
568 #[test]
569 fn clone_eq(auth in ip_auth_any()) {
570 {
572 let header = Ipv4Extensions{
573 auth: None,
574 };
575 assert_eq!(
576 header.clone(),
577 Ipv4Extensions{
578 auth: None,
579 }
580 );
581 }
582
583 {
585 let header = Ipv4Extensions{
586 auth: Some(auth.clone()),
587 };
588 assert_eq!(
589 header.clone(),
590 Ipv4Extensions{
591 auth: Some(auth.clone()),
592 }
593 );
594 }
595 }
596 }
597}