1 use crate::{
2     err::{packet::SliceError, Layer},
3     *,
4 };
5 
6 /// Helper class for laxly slicing packets.
7 pub(crate) struct LaxSlicedPacketCursor<'a> {
8     pub offset: usize,
9     pub result: LaxSlicedPacket<'a>,
10 }
11 
12 impl<'a> LaxSlicedPacketCursor<'a> {
parse_from_ethernet2(slice: &'a [u8]) -> Result<LaxSlicedPacket<'a>, err::LenError>13     pub fn parse_from_ethernet2(slice: &'a [u8]) -> Result<LaxSlicedPacket<'a>, err::LenError> {
14         use ether_type::*;
15         use LinkSlice::*;
16 
17         let mut cursor = LaxSlicedPacketCursor {
18             offset: 0,
19             result: LaxSlicedPacket {
20                 link: None,
21                 vlan: None,
22                 net: None,
23                 transport: None,
24                 stop_err: None,
25             },
26         };
27 
28         let result = Ethernet2Slice::from_slice_without_fcs(slice)?;
29 
30         // cache the ether_type for later
31         let payload = result.payload();
32 
33         // set the new data
34         cursor.offset += result.header_len();
35         cursor.result.link = Some(Ethernet2(result));
36 
37         // continue parsing (if required)
38         match payload.ether_type {
39             IPV4 => Ok(cursor.slice_ip(payload.payload)),
40             IPV6 => Ok(cursor.slice_ip(payload.payload)),
41             VLAN_TAGGED_FRAME | PROVIDER_BRIDGING | VLAN_DOUBLE_TAGGED_FRAME => {
42                 Ok(cursor.slice_vlan(payload.payload))
43             }
44             _ => Ok(cursor.result),
45         }
46     }
47 
parse_from_ether_type(ether_type: EtherType, slice: &'a [u8]) -> LaxSlicedPacket<'a>48     pub fn parse_from_ether_type(ether_type: EtherType, slice: &'a [u8]) -> LaxSlicedPacket<'a> {
49         let cursor = LaxSlicedPacketCursor {
50             offset: 0,
51             result: LaxSlicedPacket {
52                 link: Some(LinkSlice::EtherPayload(EtherPayloadSlice {
53                     ether_type,
54                     payload: slice,
55                 })),
56                 vlan: None,
57                 net: None,
58                 transport: None,
59                 stop_err: None,
60             },
61         };
62         use ether_type::*;
63         match ether_type {
64             IPV4 => cursor.slice_ip(slice),
65             IPV6 => cursor.slice_ip(slice),
66             VLAN_TAGGED_FRAME | PROVIDER_BRIDGING | VLAN_DOUBLE_TAGGED_FRAME => {
67                 cursor.slice_vlan(slice)
68             }
69             _ => cursor.result,
70         }
71     }
72 
parse_from_ip( slice: &'a [u8], ) -> Result<LaxSlicedPacket<'a>, err::ip::LaxHeaderSliceError>73     pub fn parse_from_ip(
74         slice: &'a [u8],
75     ) -> Result<LaxSlicedPacket<'a>, err::ip::LaxHeaderSliceError> {
76         let (ip, stop_err) = LaxIpSlice::from_slice(slice)?;
77         let is_ip_v4 = match &ip {
78             LaxIpSlice::Ipv4(_) => true,
79             LaxIpSlice::Ipv6(_) => false,
80         };
81         let payload = ip.payload().clone();
82         let offset = (payload.payload.as_ptr() as usize) - (slice.as_ptr() as usize);
83         Ok(LaxSlicedPacketCursor {
84             offset,
85             result: LaxSlicedPacket {
86                 link: None,
87                 vlan: None,
88                 net: Some(ip.into()),
89                 transport: None,
90                 stop_err: stop_err.map(|(stop_err, stop_layer)| {
91                     use err::ipv6_exts::HeaderError as E;
92                     use err::ipv6_exts::HeaderSliceError as I;
93                     use err::packet::SliceError as O;
94                     (
95                         match stop_err {
96                             I::Len(l) => O::Len(l),
97                             I::Content(c) => match c {
98                                 E::HopByHopNotAtStart => O::Ipv6Exts(E::HopByHopNotAtStart),
99                                 E::IpAuth(auth) => {
100                                     if is_ip_v4 {
101                                         O::Ipv4Exts(auth)
102                                     } else {
103                                         O::Ipv6Exts(E::IpAuth(auth))
104                                     }
105                                 }
106                             },
107                         },
108                         stop_layer,
109                     )
110                 }),
111             },
112         }
113         .slice_transport(payload))
114     }
115 
slice_vlan(mut self, slice: &'a [u8]) -> LaxSlicedPacket<'a>116     pub fn slice_vlan(mut self, slice: &'a [u8]) -> LaxSlicedPacket<'a> {
117         use ether_type::*;
118         use VlanSlice::*;
119 
120         // cache the starting slice so the later combining
121         // of outer & inner vlan is defined behavior (for miri)
122         let outer_start_slice = slice;
123         let outer = match SingleVlanSlice::from_slice(slice) {
124             Ok(v) => v,
125             Err(err) => {
126                 self.result.stop_err = Some((
127                     SliceError::Len(err.add_offset(self.offset)),
128                     Layer::VlanHeader,
129                 ));
130                 return self.result;
131             }
132         };
133         self.result.vlan = Some(VlanSlice::SingleVlan(outer.clone()));
134         self.offset += outer.header_len();
135 
136         //check if it is a double vlan header
137         match outer.ether_type() {
138             //in case of a double vlan header continue with the inner
139             VLAN_TAGGED_FRAME | PROVIDER_BRIDGING | VLAN_DOUBLE_TAGGED_FRAME => {
140                 let inner = match SingleVlanSlice::from_slice(outer.payload_slice()) {
141                     Ok(v) => v,
142                     Err(err) => {
143                         self.result.stop_err = Some((
144                             SliceError::Len(err.add_offset(self.offset)),
145                             Layer::VlanHeader,
146                         ));
147                         return self.result;
148                     }
149                 };
150                 self.offset += inner.header_len();
151 
152                 let inner_ether_type = inner.ether_type();
153                 self.result.vlan = Some(DoubleVlan(DoubleVlanSlice {
154                     slice: outer_start_slice,
155                 }));
156 
157                 match inner_ether_type {
158                     IPV4 => self.slice_ip(inner.payload_slice()),
159                     IPV6 => self.slice_ip(inner.payload_slice()),
160                     _ => self.result,
161                 }
162             }
163             value => match value {
164                 IPV4 => self.slice_ip(outer.payload_slice()),
165                 IPV6 => self.slice_ip(outer.payload_slice()),
166                 _ => self.result,
167             },
168         }
169     }
170 
slice_ip(mut self, slice: &'a [u8]) -> LaxSlicedPacket<'a>171     pub fn slice_ip(mut self, slice: &'a [u8]) -> LaxSlicedPacket<'a> {
172         // ip slice
173         let ip = match LaxIpSlice::from_slice(slice) {
174             Ok(ip) => ip,
175             Err(e) => {
176                 use err::ip::LaxHeaderSliceError as I;
177                 use err::packet::SliceError as O;
178                 self.result.stop_err = Some(match e {
179                     I::Len(mut l) => {
180                         l.layer_start_offset += self.offset;
181                         (O::Len(l), Layer::IpHeader)
182                     }
183                     I::Content(c) => (O::Ip(c), Layer::IpHeader),
184                 });
185                 return self.result;
186             }
187         };
188         self.result.net = Some(ip.0.clone().into());
189 
190         // stop in case there was a stop error in the ip extension headers
191         if let Some((stop_err, stop_layer)) = ip.1 {
192             use err::ipv6_exts::HeaderError as E;
193             use err::ipv6_exts::HeaderSliceError as I;
194             use err::packet::SliceError as O;
195             self.result.stop_err = Some((
196                 match stop_err {
197                     I::Len(l) => O::Len(l.add_offset(self.offset)),
198                     I::Content(c) => match c {
199                         E::HopByHopNotAtStart => O::Ipv6Exts(E::HopByHopNotAtStart),
200                         E::IpAuth(auth) => match &ip.0 {
201                             LaxIpSlice::Ipv4(_) => O::Ipv4Exts(auth),
202                             LaxIpSlice::Ipv6(_) => O::Ipv6Exts(E::IpAuth(auth)),
203                         },
204                     },
205                 },
206                 stop_layer,
207             ));
208         }
209 
210         // move offset for the transport layers
211         let payload = ip.0.payload().clone();
212         self.offset += (payload.payload.as_ptr() as usize) - (slice.as_ptr() as usize);
213         self.slice_transport(payload)
214     }
215 
slice_transport(mut self, slice: LaxIpPayloadSlice<'a>) -> LaxSlicedPacket<'a>216     fn slice_transport(mut self, slice: LaxIpPayloadSlice<'a>) -> LaxSlicedPacket<'a> {
217         use err::packet::SliceError as O;
218         if slice.fragmented || self.result.stop_err.is_some() {
219             // if an error occured in an upper layer or the payload is fragmented
220             // stop here
221             return self.result;
222         }
223         match slice.ip_number {
224             ip_number::ICMP => match Icmpv4Slice::from_slice(slice.payload) {
225                 Ok(icmp) => {
226                     self.offset += icmp.slice().len();
227                     self.result.transport = Some(TransportSlice::Icmpv4(icmp));
228                 }
229                 Err(mut err) => {
230                     err.layer_start_offset += self.offset;
231                     err.len_source = slice.len_source;
232                     self.result.stop_err = Some((O::Len(err), Layer::Icmpv4));
233                 }
234             },
235             ip_number::UDP => match UdpSlice::from_slice_lax(slice.payload) {
236                 Ok(udp) => {
237                     self.offset += udp.slice().len();
238                     self.result.transport = Some(TransportSlice::Udp(udp));
239                 }
240                 Err(mut err) => {
241                     err.layer_start_offset += self.offset;
242                     err.len_source = slice.len_source;
243                     self.result.stop_err = Some((O::Len(err), Layer::UdpHeader));
244                 }
245             },
246             ip_number::TCP => match TcpSlice::from_slice(slice.payload) {
247                 Ok(tcp) => {
248                     self.offset += tcp.slice().len();
249                     self.result.transport = Some(TransportSlice::Tcp(tcp));
250                 }
251                 Err(err) => {
252                     use err::tcp::HeaderSliceError as I;
253                     self.result.stop_err = Some((
254                         match err {
255                             I::Len(mut l) => {
256                                 l.layer_start_offset += self.offset;
257                                 l.len_source = slice.len_source;
258                                 O::Len(l)
259                             }
260                             I::Content(c) => O::Tcp(c),
261                         },
262                         Layer::TcpHeader,
263                     ));
264                 }
265             },
266             ip_number::IPV6_ICMP => match Icmpv6Slice::from_slice(slice.payload) {
267                 Ok(icmp) => {
268                     self.offset += icmp.slice().len();
269                     self.result.transport = Some(TransportSlice::Icmpv6(icmp));
270                 }
271                 Err(mut err) => {
272                     err.layer_start_offset += self.offset;
273                     err.len_source = slice.len_source;
274                     self.result.stop_err = Some((O::Len(err), Layer::Icmpv6));
275                 }
276             },
277             _ => {}
278         }
279         self.result
280     }
281 }
282