1 use crate::*; 2 3 /// Slice containing laxly parsed the network headers & payloads (e.g. IPv4, IPv6, ARP). 4 /// 5 /// Compared to the normal [`NetSlice`] this slice allows the 6 /// payload to be incomplete/cut off and errors to be present in 7 /// the IpPayload. 8 /// 9 /// The main usecases for "laxly" parsed slices are are: 10 /// 11 /// * Parsing packets that have been cut off. This is, for example, useful to 12 /// parse packets returned via ICMP as these usually only contain the start. 13 /// * Parsing packets where the `total_len` (for IPv4) or `payload_len` (for IPv6) 14 /// have not yet been set. This can be useful when parsing packets which have 15 /// been recorded in a layer before the length field was set (e.g. before the 16 /// operating system set the length fields). 17 #[derive(Clone, Debug, Eq, PartialEq)] 18 pub enum LaxNetSlice<'a> { 19 /// IPv4 header & the decoded extension headers. 20 Ipv4(LaxIpv4Slice<'a>), 21 /// IPv6 header & the decoded extension headers. 22 Ipv6(LaxIpv6Slice<'a>), 23 /// "Address Resolution Protocol" Packet, 24 Arp(ArpPacketSlice<'a>), 25 } 26 27 impl<'a> LaxNetSlice<'a> { 28 /// Returns a reference to ip payload if the net slice contains 29 /// an ipv4 or ipv6 slice. 30 #[inline] ip_payload_ref(&self) -> Option<&LaxIpPayloadSlice<'a>>31 pub fn ip_payload_ref(&self) -> Option<&LaxIpPayloadSlice<'a>> { 32 match self { 33 LaxNetSlice::Ipv4(s) => Some(&s.payload), 34 LaxNetSlice::Ipv6(s) => Some(&s.payload), 35 LaxNetSlice::Arp(_) => None, 36 } 37 } 38 } 39 40 impl<'a> From<LaxIpSlice<'a>> for LaxNetSlice<'a> { 41 #[inline] from(value: LaxIpSlice<'a>) -> LaxNetSlice<'a>42 fn from(value: LaxIpSlice<'a>) -> LaxNetSlice<'a> { 43 match value { 44 LaxIpSlice::Ipv4(ipv4) => LaxNetSlice::Ipv4(ipv4), 45 LaxIpSlice::Ipv6(ipv6) => LaxNetSlice::Ipv6(ipv6), 46 } 47 } 48 } 49 50 impl<'a> From<LaxIpv4Slice<'a>> for LaxNetSlice<'a> { 51 #[inline] from(value: LaxIpv4Slice<'a>) -> LaxNetSlice<'a>52 fn from(value: LaxIpv4Slice<'a>) -> LaxNetSlice<'a> { 53 LaxNetSlice::Ipv4(value) 54 } 55 } 56 57 impl<'a> From<LaxIpv6Slice<'a>> for LaxNetSlice<'a> { 58 #[inline] from(value: LaxIpv6Slice<'a>) -> LaxNetSlice<'a>59 fn from(value: LaxIpv6Slice<'a>) -> LaxNetSlice<'a> { 60 LaxNetSlice::Ipv6(value) 61 } 62 } 63 64 #[cfg(test)] 65 mod tests { 66 use crate::*; 67 use alloc::{format, vec::Vec}; 68 69 #[test] debug()70 fn debug() { 71 let bytes = Ipv6Header { 72 next_header: IpNumber::UDP, 73 ..Default::default() 74 } 75 .to_bytes(); 76 let s = LaxIpv6Slice::from_slice(&bytes).unwrap().0; 77 let n = LaxNetSlice::Ipv6(s.clone()); 78 assert_eq!(format!("{n:?}"), format!("Ipv6({s:?})")); 79 } 80 81 #[test] clone_eq()82 fn clone_eq() { 83 let bytes = Ipv6Header { 84 next_header: IpNumber::UDP, 85 ..Default::default() 86 } 87 .to_bytes(); 88 let s = LaxNetSlice::Ipv6(LaxIpv6Slice::from_slice(&bytes).unwrap().0); 89 assert_eq!(s, s.clone()) 90 } 91 92 #[test] ip_payload_ref()93 fn ip_payload_ref() { 94 // ipv4 95 { 96 let payload = [1, 2, 3, 4]; 97 let bytes = { 98 let mut bytes = Vec::with_capacity(Ipv4Header::MIN_LEN + 4); 99 bytes.extend_from_slice( 100 &(Ipv4Header { 101 total_len: Ipv4Header::MIN_LEN_U16 + 4, 102 protocol: IpNumber::UDP, 103 ..Default::default() 104 }) 105 .to_bytes(), 106 ); 107 bytes.extend_from_slice(&payload); 108 bytes 109 }; 110 let s = LaxNetSlice::Ipv4(LaxIpv4Slice::from_slice(&bytes).unwrap().0); 111 assert_eq!( 112 s.ip_payload_ref(), 113 Some(&LaxIpPayloadSlice { 114 ip_number: IpNumber::UDP, 115 fragmented: false, 116 len_source: LenSource::Ipv4HeaderTotalLen, 117 payload: &payload, 118 incomplete: false, 119 }) 120 ); 121 } 122 // ipv6 123 { 124 let payload = [1, 2, 3, 4]; 125 let bytes = { 126 let mut bytes = Vec::with_capacity(Ipv6Header::LEN + 4); 127 bytes.extend_from_slice( 128 &(Ipv6Header { 129 next_header: IpNumber::UDP, 130 payload_length: 4, 131 ..Default::default() 132 }) 133 .to_bytes(), 134 ); 135 bytes.extend_from_slice(&payload); 136 bytes 137 }; 138 let s = LaxNetSlice::Ipv6(LaxIpv6Slice::from_slice(&bytes).unwrap().0); 139 assert_eq!( 140 s.ip_payload_ref(), 141 Some(&LaxIpPayloadSlice { 142 ip_number: IpNumber::UDP, 143 fragmented: false, 144 len_source: LenSource::Ipv6HeaderPayloadLen, 145 payload: &payload, 146 incomplete: false, 147 }) 148 ); 149 } 150 } 151 152 #[test] from()153 fn from() { 154 // IpSlice::Ipv4 155 { 156 let payload = [1, 2, 3, 4]; 157 let bytes = { 158 let mut bytes = Vec::with_capacity(Ipv4Header::MIN_LEN + 4); 159 bytes.extend_from_slice( 160 &(Ipv4Header { 161 total_len: Ipv4Header::MIN_LEN_U16 + 4, 162 protocol: IpNumber::UDP, 163 ..Default::default() 164 }) 165 .to_bytes(), 166 ); 167 bytes.extend_from_slice(&payload); 168 bytes 169 }; 170 let i = LaxIpv4Slice::from_slice(&bytes).unwrap().0; 171 let actual: LaxNetSlice = LaxIpSlice::Ipv4(i.clone()).into(); 172 assert_eq!(LaxNetSlice::Ipv4(i.clone()), actual); 173 } 174 // LaxIpv4Slice 175 { 176 let payload = [1, 2, 3, 4]; 177 let bytes = { 178 let mut bytes = Vec::with_capacity(Ipv4Header::MIN_LEN + 4); 179 bytes.extend_from_slice( 180 &(Ipv4Header { 181 total_len: Ipv4Header::MIN_LEN_U16 + 4, 182 protocol: IpNumber::UDP, 183 ..Default::default() 184 }) 185 .to_bytes(), 186 ); 187 bytes.extend_from_slice(&payload); 188 bytes 189 }; 190 let i = LaxIpv4Slice::from_slice(&bytes).unwrap().0; 191 let actual: LaxNetSlice = i.clone().into(); 192 assert_eq!(LaxNetSlice::Ipv4(i.clone()), actual); 193 } 194 // IpSlice::Ipv6 195 { 196 let payload = [1, 2, 3, 4]; 197 let bytes = { 198 let mut bytes = Vec::with_capacity(Ipv6Header::LEN + 4); 199 bytes.extend_from_slice( 200 &(Ipv6Header { 201 next_header: IpNumber::UDP, 202 payload_length: 4, 203 ..Default::default() 204 }) 205 .to_bytes(), 206 ); 207 bytes.extend_from_slice(&payload); 208 bytes 209 }; 210 let i = LaxIpv6Slice::from_slice(&bytes).unwrap().0; 211 let actual: LaxNetSlice = i.clone().into(); 212 assert_eq!(LaxNetSlice::Ipv6(i.clone()), actual); 213 } 214 } 215 } 216