• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 | IPV6 => cursor.slice_ip(slice),
65             VLAN_TAGGED_FRAME | PROVIDER_BRIDGING | VLAN_DOUBLE_TAGGED_FRAME => {
66                 cursor.slice_vlan(slice)
67             }
68             ARP => cursor.slice_arp(slice),
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_arp(mut self, slice: &'a [u8]) -> LaxSlicedPacket<'a>171     pub fn slice_arp(mut self, slice: &'a [u8]) -> LaxSlicedPacket<'a> {
172         let arp = match ArpPacketSlice::from_slice(slice) {
173             Ok(arp) => arp,
174             Err(mut e) => {
175                 e.layer_start_offset += self.offset;
176                 self.result.stop_err = Some((err::packet::SliceError::Len(e), Layer::Arp));
177                 return self.result;
178             }
179         };
180         self.result.net = Some(LaxNetSlice::Arp(arp));
181         self.result
182     }
183 
slice_ip(mut self, slice: &'a [u8]) -> LaxSlicedPacket<'a>184     pub fn slice_ip(mut self, slice: &'a [u8]) -> LaxSlicedPacket<'a> {
185         // ip slice
186         let ip = match LaxIpSlice::from_slice(slice) {
187             Ok(ip) => ip,
188             Err(e) => {
189                 use err::ip::LaxHeaderSliceError as I;
190                 use err::packet::SliceError as O;
191                 self.result.stop_err = Some(match e {
192                     I::Len(mut l) => {
193                         l.layer_start_offset += self.offset;
194                         (O::Len(l), Layer::IpHeader)
195                     }
196                     I::Content(c) => (O::Ip(c), Layer::IpHeader),
197                 });
198                 return self.result;
199             }
200         };
201         self.result.net = Some(ip.0.clone().into());
202 
203         // stop in case there was a stop error in the ip extension headers
204         if let Some((stop_err, stop_layer)) = ip.1 {
205             use err::ipv6_exts::HeaderError as E;
206             use err::ipv6_exts::HeaderSliceError as I;
207             use err::packet::SliceError as O;
208             self.result.stop_err = Some((
209                 match stop_err {
210                     I::Len(l) => O::Len(l.add_offset(self.offset)),
211                     I::Content(c) => match c {
212                         E::HopByHopNotAtStart => O::Ipv6Exts(E::HopByHopNotAtStart),
213                         E::IpAuth(auth) => match &ip.0 {
214                             LaxIpSlice::Ipv4(_) => O::Ipv4Exts(auth),
215                             LaxIpSlice::Ipv6(_) => O::Ipv6Exts(E::IpAuth(auth)),
216                         },
217                     },
218                 },
219                 stop_layer,
220             ));
221         }
222 
223         // move offset for the transport layers
224         let payload = ip.0.payload().clone();
225         self.offset += (payload.payload.as_ptr() as usize) - (slice.as_ptr() as usize);
226         self.slice_transport(payload)
227     }
228 
slice_transport(mut self, slice: LaxIpPayloadSlice<'a>) -> LaxSlicedPacket<'a>229     fn slice_transport(mut self, slice: LaxIpPayloadSlice<'a>) -> LaxSlicedPacket<'a> {
230         use err::packet::SliceError as O;
231         if slice.fragmented || self.result.stop_err.is_some() {
232             // if an error occured in an upper layer or the payload is fragmented
233             // stop here
234             return self.result;
235         }
236         match slice.ip_number {
237             ip_number::ICMP => match Icmpv4Slice::from_slice(slice.payload) {
238                 Ok(icmp) => {
239                     self.offset += icmp.slice().len();
240                     self.result.transport = Some(TransportSlice::Icmpv4(icmp));
241                 }
242                 Err(mut err) => {
243                     err.layer_start_offset += self.offset;
244                     err.len_source = slice.len_source;
245                     self.result.stop_err = Some((O::Len(err), Layer::Icmpv4));
246                 }
247             },
248             ip_number::UDP => match UdpSlice::from_slice_lax(slice.payload) {
249                 Ok(udp) => {
250                     self.offset += udp.slice().len();
251                     self.result.transport = Some(TransportSlice::Udp(udp));
252                 }
253                 Err(mut err) => {
254                     err.layer_start_offset += self.offset;
255                     err.len_source = slice.len_source;
256                     self.result.stop_err = Some((O::Len(err), Layer::UdpHeader));
257                 }
258             },
259             ip_number::TCP => match TcpSlice::from_slice(slice.payload) {
260                 Ok(tcp) => {
261                     self.offset += tcp.slice().len();
262                     self.result.transport = Some(TransportSlice::Tcp(tcp));
263                 }
264                 Err(err) => {
265                     use err::tcp::HeaderSliceError as I;
266                     self.result.stop_err = Some((
267                         match err {
268                             I::Len(mut l) => {
269                                 l.layer_start_offset += self.offset;
270                                 l.len_source = slice.len_source;
271                                 O::Len(l)
272                             }
273                             I::Content(c) => O::Tcp(c),
274                         },
275                         Layer::TcpHeader,
276                     ));
277                 }
278             },
279             ip_number::IPV6_ICMP => match Icmpv6Slice::from_slice(slice.payload) {
280                 Ok(icmp) => {
281                     self.offset += icmp.slice().len();
282                     self.result.transport = Some(TransportSlice::Icmpv6(icmp));
283                 }
284                 Err(mut err) => {
285                     err.layer_start_offset += self.offset;
286                     err.len_source = slice.len_source;
287                     self.result.stop_err = Some((O::Len(err), Layer::Icmpv6));
288                 }
289             },
290             _ => {}
291         }
292         self.result
293     }
294 }
295