1use crate::{
2 err::{ValueTooBigError, ValueType},
3 *,
4};
5use arrayvec::ArrayVec;
6
7#[derive(Clone, Debug, Eq, PartialEq, Hash)]
36pub struct Ipv4Header {
37 pub dscp: IpDscp,
39 pub ecn: IpEcn,
41 pub total_len: u16,
43 pub identification: u16,
45 pub dont_fragment: bool,
47 pub more_fragments: bool,
50 pub fragment_offset: IpFragOffset,
54 pub time_to_live: u8,
56 pub protocol: IpNumber,
60 pub header_checksum: u16,
61 pub source: [u8; 4],
63 pub destination: [u8; 4],
65 pub options: Ipv4Options,
67}
68
69impl Ipv4Header {
70 pub const MIN_LEN: usize = 20;
72
73 pub const MIN_LEN_U16: u16 = 20;
75
76 pub const MAX_LEN: usize = 0b1111 * 4;
84
85 #[deprecated(since = "0.14.0", note = "Use `Ipv4Header::MIN_LEN` instead")]
87 pub const SERIALIZED_SIZE: usize = Ipv4Header::MIN_LEN;
88
89 pub fn new(
125 payload_len: u16,
126 time_to_live: u8,
127 protocol: IpNumber,
128 source: [u8; 4],
129 destination: [u8; 4],
130 ) -> Result<Ipv4Header, ValueTooBigError<u16>> {
131 const MAX_PAYLOAD: u16 = u16::MAX - (Ipv4Header::MIN_LEN as u16);
132 if payload_len > MAX_PAYLOAD {
133 Err(ValueTooBigError {
134 actual: payload_len,
135 max_allowed: MAX_PAYLOAD,
136 value_type: ValueType::Ipv4PayloadLength,
137 })
138 } else {
139 Ok(Ipv4Header {
140 dscp: Default::default(),
141 ecn: Default::default(),
142 total_len: payload_len + (Ipv4Header::MIN_LEN as u16),
143 identification: 0,
144 dont_fragment: true,
145 more_fragments: false,
146 fragment_offset: Default::default(),
147 time_to_live,
148 protocol,
149 header_checksum: 0,
150 source,
151 destination,
152 options: Default::default(),
153 })
154 }
155 }
156
157 #[inline]
192 pub fn ihl(&self) -> u8 {
193 (self.options.len_u8() / 4) + 5
194 }
195
196 #[inline]
229 pub fn header_len(&self) -> usize {
230 Ipv4Header::MIN_LEN + self.options.len()
231 }
232
233 #[inline]
273 pub fn payload_len(&self) -> Result<u16, err::LenError> {
274 let header_len = self.header_len() as u16;
276 if header_len <= self.total_len {
277 Ok(self.total_len - header_len)
278 } else {
279 use err::{Layer, LenError};
280 Err(LenError {
281 required_len: header_len.into(),
282 len: self.total_len.into(),
283 len_source: LenSource::Ipv4HeaderTotalLen,
284 layer: Layer::Ipv4Packet,
285 layer_start_offset: 0,
286 })
287 }
288 }
289
290 pub fn set_payload_len(&mut self, value: usize) -> Result<(), ValueTooBigError<usize>> {
329 let max_allowed = usize::from(self.max_payload_len());
330 if value > max_allowed {
331 Err(ValueTooBigError {
332 actual: value,
333 max_allowed,
334 value_type: ValueType::Ipv4PayloadLength,
335 })
336 } else {
337 self.total_len = (self.header_len() + value) as u16;
338 Ok(())
339 }
340 }
341
342 #[inline]
344 pub fn max_payload_len(&self) -> u16 {
345 u16::MAX - u16::from(self.options.len_u8()) - (Ipv4Header::MIN_LEN as u16)
346 }
347
348 #[deprecated(
350 since = "0.14.0",
351 note = "Directly use `&(header.options[..])` instead."
352 )]
353 pub fn options(&self) -> &[u8] {
354 &self.options[..]
355 }
356
357 #[deprecated(
362 since = "0.14.0",
363 note = "Directly set it via the header.options field instead."
364 )]
365 pub fn set_options(&mut self, data: &[u8]) -> Result<(), err::ipv4::BadOptionsLen> {
366 self.options = data.try_into()?;
367 Ok(())
368 }
369
370 #[deprecated(since = "0.10.1", note = "Renamed to `Ipv4Header::from_slice`")]
372 #[inline]
373 pub fn read_from_slice(
374 slice: &[u8],
375 ) -> Result<(Ipv4Header, &[u8]), err::ipv4::HeaderSliceError> {
376 Ipv4Header::from_slice(slice)
377 }
378
379 pub fn from_slice(slice: &[u8]) -> Result<(Ipv4Header, &[u8]), err::ipv4::HeaderSliceError> {
401 let header = Ipv4HeaderSlice::from_slice(slice)?.to_header();
402 let rest = &slice[header.header_len()..];
403 Ok((header, rest))
404 }
405
406 #[cfg(feature = "std")]
409 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
410 pub fn read<T: std::io::Read + std::io::Seek + Sized>(
411 reader: &mut T,
412 ) -> Result<Ipv4Header, err::ipv4::HeaderReadError> {
413 use err::ipv4::HeaderReadError::*;
414
415 let mut first_byte: [u8; 1] = [0; 1];
416 reader.read_exact(&mut first_byte).map_err(Io)?;
417
418 let version_number = first_byte[0] >> 4;
419 if 4 != version_number {
420 use err::ipv4::HeaderError::UnexpectedVersion;
421 return Err(Content(UnexpectedVersion { version_number }));
422 }
423 Ipv4Header::read_without_version(reader, first_byte[0])
424 }
425
426 #[cfg(feature = "std")]
429 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
430 pub fn read_without_version<T: std::io::Read + std::io::Seek + Sized>(
431 reader: &mut T,
432 first_byte: u8,
433 ) -> Result<Ipv4Header, err::ipv4::HeaderReadError> {
434 use err::ipv4::HeaderError::*;
435 use err::ipv4::HeaderReadError::*;
436
437 let mut header_raw = [0u8; 20];
440 header_raw[0] = first_byte;
441 reader.read_exact(&mut header_raw[1..]).map_err(Io)?;
442
443 let ihl = header_raw[0] & 0xf;
444
445 if ihl < 5 {
448 return Err(Content(HeaderLengthSmallerThanHeader { ihl }));
449 }
450
451 let (dscp, ecn) = {
452 let value = header_raw[1];
453 (value >> 2, value & 0b0000_0011)
454 };
455 let total_len = u16::from_be_bytes([header_raw[2], header_raw[3]]);
456 let identification = u16::from_be_bytes([header_raw[4], header_raw[5]]);
457 let (dont_fragment, more_fragments, fragments_offset) = (
458 0 != (header_raw[6] & 0b0100_0000),
459 0 != (header_raw[6] & 0b0010_0000),
460 u16::from_be_bytes([header_raw[6] & 0b0001_1111, header_raw[7]]),
461 );
462 Ok(Ipv4Header {
463 dscp: unsafe {
464 IpDscp::new_unchecked(dscp)
467 },
468 ecn: unsafe {
469 IpEcn::new_unchecked(ecn)
472 },
473 total_len,
474 identification,
475 dont_fragment,
476 more_fragments,
477 fragment_offset: unsafe {
478 IpFragOffset::new_unchecked(fragments_offset)
481 },
482 time_to_live: header_raw[8],
483 protocol: IpNumber(header_raw[9]),
484 header_checksum: u16::from_be_bytes([header_raw[10], header_raw[11]]),
485 source: [
486 header_raw[12],
487 header_raw[13],
488 header_raw[14],
489 header_raw[15],
490 ],
491 destination: [
492 header_raw[16],
493 header_raw[17],
494 header_raw[18],
495 header_raw[19],
496 ],
497 options: {
498 let mut options = Ipv4Options::new();
499 options.len = (ihl - 5) * 4;
500 if false == options.is_empty() {
501 reader.read_exact(options.as_mut()).map_err(Io)?;
502 }
503 options
504 },
505 })
506 }
507
508 #[cfg(feature = "std")]
511 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
512 pub fn write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error> {
513 self.write_ipv4_header_internal(writer, self.calc_header_checksum())
515 }
516
517 #[cfg(feature = "std")]
520 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
521 pub fn write_raw<T: std::io::Write + Sized>(
522 &self,
523 writer: &mut T,
524 ) -> Result<(), std::io::Error> {
525 self.write_ipv4_header_internal(writer, self.header_checksum)
526 }
527
528 pub fn to_bytes(&self) -> ArrayVec<u8, { Ipv4Header::MAX_LEN }> {
531 let total_len_be = self.total_len.to_be_bytes();
533 let id_be = self.identification.to_be_bytes();
534 let frag_and_flags = {
535 let frag_be: [u8; 2] = self.fragment_offset.value().to_be_bytes();
536 let flags = {
537 let mut result = 0;
538 if self.dont_fragment {
539 result |= 64;
540 }
541 if self.more_fragments {
542 result |= 32;
543 }
544 result
545 };
546 [flags | (frag_be[0] & 0x1f), frag_be[1]]
547 };
548 let header_checksum_be = self.header_checksum.to_be_bytes();
549
550 #[rustfmt::skip]
551 let mut header_raw: ArrayVec<u8, { Ipv4Header::MAX_LEN } > = [
552 (4 << 4) | self.ihl(),
553 (self.dscp.value() << 2) | self.ecn.value(),
554 total_len_be[0],
555 total_len_be[1],
556
557 id_be[0], id_be[1], frag_and_flags[0], frag_and_flags[1],
558
559 self.time_to_live, self.protocol.0, header_checksum_be[0], header_checksum_be[1],
560 self.source[0], self.source[1], self.source[2], self.source[3],
561
562 self.destination[0], self.destination[1], self.destination[2], self.destination[3],
563 self.options.buf[0], self.options.buf[1], self.options.buf[2], self.options.buf[3],
564
565 self.options.buf[4], self.options.buf[5], self.options.buf[6], self.options.buf[7],
566 self.options.buf[8], self.options.buf[9], self.options.buf[10], self.options.buf[11],
567
568 self.options.buf[12], self.options.buf[13], self.options.buf[14], self.options.buf[15],
569 self.options.buf[16], self.options.buf[17], self.options.buf[18], self.options.buf[19],
570
571 self.options.buf[20], self.options.buf[21], self.options.buf[22], self.options.buf[23],
572 self.options.buf[24], self.options.buf[25], self.options.buf[26], self.options.buf[27],
573
574 self.options.buf[28], self.options.buf[29], self.options.buf[30], self.options.buf[31],
575 self.options.buf[32], self.options.buf[33], self.options.buf[34], self.options.buf[35],
576
577 self.options.buf[36], self.options.buf[37], self.options.buf[38], self.options.buf[39],
578 ].into();
579
580 unsafe {
583 header_raw.set_len(self.header_len());
584 }
585
586 header_raw
587 }
588
589 #[cfg(feature = "std")]
591 fn write_ipv4_header_internal<T: std::io::Write>(
592 &self,
593 write: &mut T,
594 header_checksum: u16,
595 ) -> Result<(), std::io::Error> {
596 let total_len_be = self.total_len.to_be_bytes();
597 let id_be = self.identification.to_be_bytes();
598 let frag_and_flags = {
599 let frag_be: [u8; 2] = self.fragment_offset.value().to_be_bytes();
600 let flags = {
601 let mut result = 0;
602 if self.dont_fragment {
603 result |= 64;
604 }
605 if self.more_fragments {
606 result |= 32;
607 }
608 result
609 };
610 [flags | (frag_be[0] & 0x1f), frag_be[1]]
611 };
612 let header_checksum_be = header_checksum.to_be_bytes();
613
614 let header_raw = [
615 (4 << 4) | self.ihl(),
616 (self.dscp.value() << 2) | self.ecn.value(),
617 total_len_be[0],
618 total_len_be[1],
619 id_be[0],
620 id_be[1],
621 frag_and_flags[0],
622 frag_and_flags[1],
623 self.time_to_live,
624 self.protocol.0,
625 header_checksum_be[0],
626 header_checksum_be[1],
627 self.source[0],
628 self.source[1],
629 self.source[2],
630 self.source[3],
631 self.destination[0],
632 self.destination[1],
633 self.destination[2],
634 self.destination[3],
635 ];
636 write.write_all(&header_raw)?;
637
638 write.write_all(&self.options)?;
640
641 Ok(())
643 }
644
645 pub fn calc_header_checksum(&self) -> u16 {
647 checksum::Sum16BitWords::new()
648 .add_2bytes([
649 (4 << 4) | self.ihl(),
650 (self.dscp.value() << 2) | self.ecn.value(),
651 ])
652 .add_2bytes(self.total_len.to_be_bytes())
653 .add_2bytes(self.identification.to_be_bytes())
654 .add_2bytes({
655 let frag_off_be = self.fragment_offset.value().to_be_bytes();
656 let flags = {
657 let mut result = 0;
658 if self.dont_fragment {
659 result |= 64;
660 }
661 if self.more_fragments {
662 result |= 32;
663 }
664 result
665 };
666 [flags | (frag_off_be[0] & 0x1f), frag_off_be[1]]
667 })
668 .add_2bytes([self.time_to_live, self.protocol.0])
669 .add_4bytes(self.source)
670 .add_4bytes(self.destination)
671 .add_slice(&self.options)
672 .ones_complement()
673 .to_be()
674 }
675
676 #[inline]
681 pub fn is_fragmenting_payload(&self) -> bool {
682 self.more_fragments || (0 != self.fragment_offset.value())
683 }
684}
685
686impl Default for Ipv4Header {
687 fn default() -> Ipv4Header {
688 Ipv4Header {
689 dscp: Default::default(),
690 ecn: Default::default(),
691 total_len: 0,
692 identification: 0,
693 dont_fragment: true,
694 more_fragments: false,
695 fragment_offset: Default::default(),
696 time_to_live: 0,
697 protocol: IpNumber(255),
698 header_checksum: 0,
699 source: [0; 4],
700 destination: [0; 4],
701 options: Ipv4Options::new(),
702 }
703 }
704}
705
706#[cfg(test)]
707mod test {
708 use crate::{
709 err::{Layer, LenError, ValueTooBigError, ValueType},
710 test_gens::*,
711 *,
712 };
713 use alloc::{format, vec::Vec};
714 use arrayvec::ArrayVec;
715 use proptest::prelude::*;
716 use std::io::Cursor;
717
718 #[test]
719 fn default() {
720 let default: Ipv4Header = Default::default();
721 assert_eq!(5, default.ihl());
722 assert_eq!(0, default.dscp.value());
723 assert_eq!(0, default.ecn.value());
724 assert_eq!(0, default.total_len);
725 assert_eq!(0, default.identification);
726 assert_eq!(true, default.dont_fragment);
727 assert_eq!(false, default.more_fragments);
728 assert_eq!(0, default.fragment_offset.value());
729 assert_eq!(0, default.time_to_live);
730 assert_eq!(IpNumber(255), default.protocol);
731 assert_eq!(0, default.header_checksum);
732 assert_eq!([0; 4], default.source);
733 assert_eq!([0; 4], default.destination);
734 assert_eq!(&default.options[..], &[]);
735 }
736
737 proptest! {
738 #[test]
739 fn debug(input in ipv4_any()) {
740 assert_eq!(&format!("Ipv4Header {{ dscp: {:?}, ecn: {:?}, total_len: {}, identification: {}, dont_fragment: {}, more_fragments: {}, fragment_offset: {:?}, time_to_live: {}, protocol: {:?}, header_checksum: {}, source: {:?}, destination: {:?}, options: {:?} }}",
741 input.dscp,
742 input.ecn,
743 input.total_len,
744 input.identification,
745 input.dont_fragment,
746 input.more_fragments,
747 input.fragment_offset,
748 input.time_to_live,
749 input.protocol,
750 input.header_checksum,
751 input.source,
752 input.destination,
753 input.options
754 ),
755 &format!("{:?}", input)
756 );
757 }
758 }
759
760 proptest! {
761 #[test]
762 fn eq(a in ipv4_any(),
763 b in ipv4_any())
764 {
765 assert!(a == a);
767 assert!(b == b);
768
769 assert_eq!(
772 a.dscp == b.dscp,
773 a == {
774 let mut other = a.clone();
775 other.dscp = b.dscp;
776 other
777 }
778 );
779 assert_eq!(
781 a.ecn == b.ecn,
782 a == {
783 let mut other = a.clone();
784 other.ecn = b.ecn;
785 other
786 }
787 );
788 assert_eq!(
790 a.total_len == b.total_len,
791 a == {
792 let mut other = a.clone();
793 other.total_len = b.total_len;
794 other
795 }
796 );
797 assert_eq!(
799 a.identification == b.identification,
800 a == {
801 let mut other = a.clone();
802 other.identification = b.identification;
803 other
804 }
805 );
806 assert_eq!(
808 a.dont_fragment == b.dont_fragment,
809 a == {
810 let mut other = a.clone();
811 other.dont_fragment = b.dont_fragment;
812 other
813 }
814 );
815 assert_eq!(
817 a.more_fragments == b.more_fragments,
818 a == {
819 let mut other = a.clone();
820 other.more_fragments = b.more_fragments;
821 other
822 }
823 );
824 assert_eq!(
826 a.fragment_offset == b.fragment_offset,
827 a == {
828 let mut other = a.clone();
829 other.fragment_offset = b.fragment_offset;
830 other
831 }
832 );
833 assert_eq!(
835 a.time_to_live == b.time_to_live,
836 a == {
837 let mut other = a.clone();
838 other.time_to_live = b.time_to_live;
839 other
840 }
841 );
842 assert_eq!(
844 a.protocol == b.protocol,
845 a == {
846 let mut other = a.clone();
847 other.protocol = b.protocol;
848 other
849 }
850 );
851 assert_eq!(
853 a.header_checksum == b.header_checksum,
854 a == {
855 let mut other = a.clone();
856 other.header_checksum = b.header_checksum;
857 other
858 }
859 );
860 assert_eq!(
862 a.source == b.source,
863 a == {
864 let mut other = a.clone();
865 other.source = b.source;
866 other
867 }
868 );
869 assert_eq!(
871 a.destination == b.destination,
872 a == {
873 let mut other = a.clone();
874 other.destination = b.destination;
875 other
876 }
877 );
878
879 assert_eq!(
881 a.options == b.options,
882 a == {
883 let mut other = a.clone();
884 other.options = b.options;
885 other
886 }
887 );
888 }
889 }
890
891 proptest! {
892 #[test]
893 fn hash(header in ipv4_any()) {
894 use std::collections::hash_map::DefaultHasher;
895 use core::hash::{Hash, Hasher};
896 let a = {
897 let mut hasher = DefaultHasher::new();
898 header.hash(&mut hasher);
899 hasher.finish()
900 };
901 let b = {
902 let mut hasher = DefaultHasher::new();
903 header.hash(&mut hasher);
904 hasher.finish()
905 };
906 assert_eq!(a, b);
907 }
908 }
909
910 proptest! {
911 #[test]
912 fn new(
913 source_ip in prop::array::uniform4(any::<u8>()),
914 dest_ip in prop::array::uniform4(any::<u8>()),
915 ttl in any::<u8>(),
916 ok_payload_len in 0u16..=(u16::MAX - Ipv4Header::MIN_LEN as u16),
917 err_payload_len in (u16::MAX - Ipv4Header::MIN_LEN as u16 + 1)..=u16::MAX
918 ) {
919 {
921 let result = Ipv4Header::new(
922 ok_payload_len,
923 ttl,
924 ip_number::UDP,
925 source_ip,
926 dest_ip
927 ).unwrap();
928
929 assert_eq!(result.dscp.value(), 0);
930 assert_eq!(result.ecn.value(), 0);
931 assert_eq!(result.total_len, ok_payload_len + Ipv4Header::MIN_LEN as u16);
932 assert_eq!(result.identification, 0);
933 assert_eq!(result.dont_fragment, true);
934 assert_eq!(result.more_fragments, false);
935 assert_eq!(result.fragment_offset.value(), 0);
936 assert_eq!(result.time_to_live, ttl);
937 assert_eq!(result.protocol, ip_number::UDP);
938 assert_eq!(result.header_checksum, 0);
939 assert_eq!(result.source, source_ip);
940 assert_eq!(result.destination, dest_ip);
941 assert_eq!(result.options.as_slice(), &[]);
942 }
943 {
945 assert_eq!(
946 Ipv4Header::new(
947 err_payload_len,
948 ttl,
949 ip_number::UDP,
950 source_ip,
951 dest_ip
952 ),
953 Err(ValueTooBigError::<u16>{
954 actual: err_payload_len,
955 max_allowed: u16::MAX - Ipv4Header::MIN_LEN as u16,
956 value_type: ValueType::Ipv4PayloadLength,
957 })
958 );
959 }
960 }
961 }
962
963 proptest! {
964 #[test]
965 fn ihl(header in ipv4_any()) {
966 assert_eq!(header.ihl(), (header.header_len() / 4) as u8);
967 }
968 }
969
970 proptest! {
971 #[test]
972 fn header_len(header in ipv4_any()) {
973 assert_eq!(header.header_len(), 20 + usize::from(header.options.len()));
974 }
975 }
976
977 proptest! {
978 #[test]
979 fn payload_len(
980 header in ipv4_any()
981 ) {
982 assert_eq!(
984 header.payload_len().unwrap(),
985 header.total_len - 20 - (header.options.len() as u16)
986 );
987 for bad_len in 0u16..(header.header_len() as u16) {
989 let mut header = header.clone();
990 header.total_len = bad_len;
991 assert_eq!(
992 header.payload_len().unwrap_err(),
993 LenError{
994 required_len: header.header_len(),
995 len: bad_len.into(),
996 len_source: LenSource::Ipv4HeaderTotalLen,
997 layer: Layer::Ipv4Packet,
998 layer_start_offset: 0
999 }
1000 );
1001 }
1002
1003 }
1004 }
1005
1006 #[test]
1007 fn set_payload_len() {
1008 let mut header = Ipv4Header::new(0, 0, ip_number::UDP, [0; 4], [0; 4]).unwrap();
1009
1010 header.options = [1, 2, 3, 4].into();
1012
1013 assert!(header.set_payload_len(0).is_ok());
1015 assert_eq!(header.total_len, 24);
1016
1017 const MAX: usize = (core::u16::MAX as usize) - Ipv4Header::MIN_LEN - 4;
1019 assert!(header.set_payload_len(MAX).is_ok());
1020 assert_eq!(header.total_len, core::u16::MAX);
1021
1022 const OVER_MAX: usize = MAX + 1;
1023 assert_eq!(
1024 header.set_payload_len(OVER_MAX),
1025 Err(ValueTooBigError {
1026 actual: OVER_MAX,
1027 max_allowed: usize::from(u16::MAX) - header.header_len(),
1028 value_type: ValueType::Ipv4PayloadLength
1029 })
1030 );
1031 }
1032
1033 proptest! {
1034 #[test]
1035 fn max_payload_len(header in ipv4_any()) {
1036 assert_eq!(header.max_payload_len(), core::u16::MAX - 20 - u16::from(header.options.len_u8()));
1037 }
1038 }
1039
1040 #[test]
1041 #[allow(deprecated)]
1042 fn set_options() {
1043 {
1045 let mut header: Ipv4Header = Default::default();
1046 let options = [1, 2, 3, 4];
1047 assert_eq!(header.set_options(&options), Ok(()));
1048
1049 assert_eq!(&options, header.options());
1050 assert_eq!(24, header.header_len());
1051 assert_eq!(0, header.total_len);
1052 assert_eq!(6, header.ihl());
1053
1054 assert_eq!(header.set_options(&[]), Ok(()));
1056
1057 assert_eq!(&options[..0], header.options());
1058 assert_eq!(20, header.header_len());
1059 assert_eq!(0, header.total_len);
1060 assert_eq!(5, header.ihl());
1061 }
1062 {
1064 let mut header: Ipv4Header = Default::default();
1065 let options = [
1066 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
1067 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
1068 ];
1069 assert_eq!(header.set_options(&options), Ok(()));
1070
1071 assert_eq!(&options[..], header.options());
1072 assert_eq!(60, header.header_len());
1073 assert_eq!(0, header.total_len);
1074 assert_eq!(15, header.ihl());
1075 }
1076 {
1078 let buffer: [u8; 50] = [0; 50];
1079 for len in &[
1080 1usize, 2, 3, 5, 6, 7, 41, 44, ] {
1083 let mut header: Ipv4Header = Default::default();
1084
1085 use self::err::ipv4::BadOptionsLen;
1087 assert_eq!(
1088 Err(BadOptionsLen { bad_len: *len }),
1089 header.set_options(&buffer[..*len])
1090 );
1091
1092 assert_eq!(&buffer[..0], header.options());
1094 assert_eq!(20, header.header_len());
1095 assert_eq!(0, header.total_len);
1096 assert_eq!(5, header.ihl());
1097 }
1098 }
1099 }
1100
1101 proptest! {
1102 #[test]
1103 #[allow(deprecated)]
1104 fn read_from_slice(ref input in ipv4_any()) {
1105 let mut buffer: Vec<u8> = Vec::with_capacity(input.header_len());
1107 input.write_raw(&mut buffer).unwrap();
1108 assert_eq!(input.header_len(), buffer.len());
1109
1110 let result = Ipv4Header::read_from_slice(&buffer).unwrap();
1112 assert_eq!(input, &result.0);
1113 assert_eq!(&buffer[usize::from(input.header_len())..], result.1);
1114 }
1115 }
1116
1117 proptest! {
1118 #[test]
1119 fn from_slice(header in ipv4_any()) {
1120 use err::ipv4::HeaderError::*;
1121 use err::ipv4::HeaderSliceError::*;
1122
1123 {
1125 let mut buffer = ArrayVec::<u8, { Ipv4Header::MAX_LEN + 1 }>::new();
1126 buffer.try_extend_from_slice(&header.to_bytes()).unwrap();
1127 buffer.try_extend_from_slice(&[1]).unwrap();
1128
1129 let (actual_header, actual_rest) = Ipv4Header::from_slice(&buffer).unwrap();
1130 assert_eq!(actual_header, header);
1131 assert_eq!(actual_rest, &[1]);
1132 }
1133
1134 {
1136 let buffer = header.to_bytes();
1137 for len in 0..header.header_len() {
1138 assert_eq!(
1139 Ipv4Header::from_slice(&buffer[..len]),
1140 Err(Len(err::LenError{
1141 required_len: if len < Ipv4Header::MIN_LEN {
1142 Ipv4Header::MIN_LEN
1143 } else {
1144 header.header_len()
1145 },
1146 len: len,
1147 len_source: LenSource::Slice,
1148 layer: err::Layer::Ipv4Header,
1149 layer_start_offset: 0,
1150 }))
1151 );
1152 }
1153 }
1154
1155 for version_number in 0u8..0b1111u8 {
1157 if 4 != version_number {
1158 let mut buffer = header.to_bytes();
1159 buffer[0] = (version_number << 4) | (buffer[0] & 0b1111);
1161 assert_eq!(
1163 Ipv4Header::from_slice(&buffer).unwrap_err(),
1164 Content(UnexpectedVersion{
1165 version_number,
1166 })
1167 );
1168 }
1169 }
1170
1171 for ihl in 0u8..5u8 {
1173 let mut buffer = header.to_bytes();
1174 buffer[0] = (4 << 4) | ihl;
1176 assert_eq!(
1178 Ipv4Header::from_slice(&buffer).unwrap_err(),
1179 Content(HeaderLengthSmallerThanHeader{
1180 ihl,
1181 })
1182 );
1183 }
1184 }
1185 }
1186
1187 proptest! {
1188 #[test]
1189 fn read_and_read_without_version(header in ipv4_any()) {
1190 use err::ipv4::HeaderError::*;
1191 use std::io::Cursor;
1192
1193 {
1195 let buffer = header.to_bytes();
1196
1197 {
1199 let mut cursor = Cursor::new(&buffer);
1200 let actual_header = Ipv4Header::read(&mut cursor).unwrap();
1201 assert_eq!(actual_header, header);
1202 assert_eq!(cursor.position(), header.header_len() as u64);
1203 }
1204 {
1206 let mut cursor = Cursor::new(&buffer[1..]);
1207 let actual_header = Ipv4Header::read_without_version(&mut cursor, buffer[0]).unwrap();
1208 assert_eq!(actual_header, header);
1209 assert_eq!(cursor.position(), (header.header_len() - 1) as u64);
1210 }
1211 }
1212
1213 {
1215 let buffer = header.to_bytes();
1216 for len in 0..header.header_len() {
1217 {
1219 let mut cursor = Cursor::new(&buffer[..len]);
1220 let err = Ipv4Header::read(&mut cursor).unwrap_err();
1221 assert!(err.io_error().is_some());
1222 }
1223
1224 if len > 0 {
1226 let mut cursor = Cursor::new(&buffer[1..len]);
1227 let err = Ipv4Header::read_without_version(&mut cursor, buffer[0]).unwrap_err();
1228 assert!(err.io_error().is_some());
1229 }
1230 }
1231 }
1232
1233 for version_number in 0u8..0b1111u8 {
1235 if 4 != version_number {
1236 let mut buffer = header.to_bytes();
1237 buffer[0] = (version_number << 4) | (buffer[0] & 0b1111);
1239
1240 {
1243 let mut cursor = Cursor::new(&buffer[..]);
1244 let err = Ipv4Header::read(&mut cursor)
1245 .unwrap_err()
1246 .content_error()
1247 .unwrap();
1248 assert_eq!(err, UnexpectedVersion{ version_number });
1249 }
1250
1251 }
1253 }
1254
1255 for ihl in 0u8..5u8 {
1257 let mut buffer = header.to_bytes();
1258 buffer[0] = (4 << 4) | ihl;
1260 {
1263 let mut cursor = Cursor::new(&buffer[..]);
1264 let err = Ipv4Header::read(&mut cursor)
1265 .unwrap_err()
1266 .content_error()
1267 .unwrap();
1268 assert_eq!(err, HeaderLengthSmallerThanHeader{ ihl });
1269 }
1270
1271 {
1273 let mut cursor = Cursor::new(&buffer[1..]);
1274 let err = Ipv4Header::read_without_version(&mut cursor, buffer[0])
1275 .unwrap_err()
1276 .content_error()
1277 .unwrap();
1278 assert_eq!(err, HeaderLengthSmallerThanHeader{ ihl });
1279 }
1280 }
1281 }
1282 }
1283
1284 proptest! {
1285 #[test]
1286 fn write(ref base_header in ipv4_any()) {
1287 use std::io::Cursor;
1288
1289 let header = {
1290 let mut header = base_header.clone();
1291 header.header_checksum = 0;
1294 header
1295 };
1296
1297 {
1299 let buffer = {
1301 let mut buffer: Vec<u8> = Vec::with_capacity(header.header_len());
1302 header.write(&mut buffer).unwrap();
1303 buffer
1304 };
1305 assert_eq!(header.header_len(), buffer.len());
1306
1307 let mut cursor = Cursor::new(&buffer);
1309 let result = Ipv4Header::read(&mut cursor).unwrap();
1310 assert_eq!(header.header_len(), cursor.position() as usize);
1311
1312 let header_with_checksum = {
1314 let mut h = header.clone();
1315 h.header_checksum = h.calc_header_checksum();
1316 h
1317 };
1318 assert_eq!(header_with_checksum, result);
1319 }
1320
1321 for len in 0..header.header_len() {
1323 let mut buffer = [0u8; Ipv4Header::MAX_LEN];
1324 let mut cursor = Cursor::new(&mut buffer[..len]);
1325 assert!(
1326 header.write(&mut cursor).is_err()
1327 );
1328 }
1329 }
1330 }
1331
1332 proptest! {
1333 #[test]
1334 fn write_raw(base_header in ipv4_any()) {
1335 {
1337 let buffer = {
1339 let mut buffer: Vec<u8> = Vec::with_capacity(base_header.header_len());
1340 base_header.write_raw(&mut buffer).unwrap();
1341 buffer
1342 };
1343 assert_eq!(base_header.header_len(), buffer.len());
1344
1345 assert_eq!(
1347 Ipv4Header::from_slice(&buffer).unwrap().0,
1348 base_header
1349 );
1350 }
1351
1352 for len in 0..base_header.header_len() {
1354 let mut buffer = [0u8; Ipv4Header::MAX_LEN];
1355 let mut cursor = Cursor::new(&mut buffer[..len]);
1356 assert!(
1357 base_header.write_raw(&mut cursor).is_err()
1358 );
1359 }
1360 }
1361 }
1362
1363 proptest! {
1364 #[test]
1365 fn to_bytes(base_header in ipv4_any()) {
1366 let bytes = base_header.to_bytes();
1367 assert_eq!(
1368 base_header,
1369 Ipv4HeaderSlice::from_slice(&bytes).unwrap().to_header()
1370 );
1371 }
1372 }
1373
1374 #[test]
1375 fn calc_header_checksum() {
1376 let base: Ipv4Header = Ipv4Header::new(
1377 40,
1378 4, ip_number::UDP,
1380 [192, 168, 1, 1], [212, 10, 11, 123], )
1383 .unwrap();
1384
1385 {
1387 let header = base.clone();
1389 assert_eq!(0xd582, header.calc_header_checksum());
1390 let header = {
1392 let mut header = base.clone();
1393 header.dont_fragment = false;
1394 header.more_fragments = true;
1395 header
1396 };
1397 assert_eq!(0xf582, header.calc_header_checksum());
1398 }
1399 {
1401 let header = {
1402 let mut header = base.clone();
1403 header.options = [1, 2, 3, 4, 5, 6, 7, 8].into();
1404 header.total_len = (header.header_len() + 32) as u16;
1405 header
1406 };
1407 assert_eq!(0xc36e, header.calc_header_checksum());
1408 }
1409 }
1410
1411 #[test]
1412 fn is_fragmenting_payload() {
1413 {
1415 let mut header: Ipv4Header = Default::default();
1416 header.fragment_offset = 0.try_into().unwrap();
1417 header.more_fragments = false;
1418 assert_eq!(false, header.is_fragmenting_payload());
1419 }
1420
1421 {
1423 let mut header: Ipv4Header = Default::default();
1424 header.fragment_offset = 1.try_into().unwrap();
1425 header.more_fragments = false;
1426 assert!(header.is_fragmenting_payload());
1427 }
1428
1429 {
1431 let mut header: Ipv4Header = Default::default();
1432 header.fragment_offset = 0.try_into().unwrap();
1433 header.more_fragments = true;
1434 assert!(header.is_fragmenting_payload());
1435 }
1436 }
1437}