• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{err::Layer, LenSource};
2 
3 /// Error when different lengths are conflicting with each other (e.g. not
4 /// enough data in a slice to decode a header).
5 ///
6 /// This error is triggered whenever there is not enough data to decode
7 /// an element (e.g. if a slice is too small to decode an header) or
8 /// if a length that is inhered from an upper layer is too big for the
9 /// lower layer (e.g. length inherited from an IP header is too big to
10 /// be used as an ICMP packet length).
11 ///
12 /// When the error is caused by not enough data being available
13 /// `required_len > len` must be true. While when the length from
14 /// the upper layer is too big for the lower layer the inverse
15 /// (`required_len < len`) must be true.
16 ///
17 /// # Examples:
18 ///
19 /// An example for an error that could be returned when there is not enough
20 /// data available to decode an UDP header would be:
21 ///
22 /// ```
23 /// use etherparse::*;
24 ///
25 /// err::LenError{
26 ///     // Expected to have at least the length of an UDP header present:
27 ///     required_len: UdpHeader::LEN,
28 ///     // Could not decode the UDP header:
29 ///     layer: err::Layer::UdpHeader,
30 ///     // There was only 1 byte left (not enough for an UDP header):
31 ///     len: 1,
32 ///     // The provided length was determined by the total length field in the
33 ///     // IPv4 header:
34 ///     len_source: LenSource::Ipv4HeaderTotalLen,
35 ///     // Offset in bytes from the start of decoding (ethernet in this) case
36 ///     // to the expected UDP header start:
37 ///     layer_start_offset: Ethernet2Header::LEN + Ipv4Header::MIN_LEN
38 /// };
39 /// ```
40 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
41 pub struct LenError {
42     /// Expected minimum or maximum length conflicting with the
43     /// `len` value.
44     pub required_len: usize,
45 
46     /// Length limiting or exceeding the required length.
47     pub len: usize,
48 
49     /// Source of the outer length (e.g. Slice or a length specified by
50     /// an upper level protocol).
51     pub len_source: LenSource,
52 
53     /// Layer in which the length error was encountered.
54     pub layer: Layer,
55 
56     /// Offset from the start of the parsed data to the layer where the
57     /// length error occurred.
58     pub layer_start_offset: usize,
59 }
60 
61 impl LenError {
62     /// Adds an offset value to the `layer_start_offset` field.
63     #[inline]
add_offset(self, offset: usize) -> Self64     pub const fn add_offset(self, offset: usize) -> Self {
65         LenError {
66             required_len: self.required_len,
67             layer: self.layer,
68             len: self.len,
69             len_source: self.len_source,
70             layer_start_offset: self.layer_start_offset + offset,
71         }
72     }
73 }
74 
75 impl core::fmt::Display for LenError {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result76     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
77         let len_source: &'static str = {
78             use LenSource::*;
79             match self.len_source {
80                 Slice => "slice length",
81                 Ipv4HeaderTotalLen => "length calculated from the IPv4 header 'total length' field",
82                 Ipv6HeaderPayloadLen => {
83                     "length calculated from the IPv6 header 'payload length' field"
84                 }
85                 UdpHeaderLen => "length calculated from the UDP header 'length' field",
86                 TcpHeaderLen => "length calculated from the TCP header 'length' field",
87                 ArpAddrLengths => {
88                     "length calculated from the ARP 'hw_addr_size' & 'proto_addr_size' fields"
89                 }
90             }
91         };
92 
93         if self.required_len > self.len {
94             if self.layer_start_offset > 0 {
95                 write!(
96                     f,
97                     "{}: Not enough data to decode '{}'. {} byte(s) would be required, but only {} byte(s) are available based on the {} ('{}' starts at overall parsed byte {}).",
98                     self.layer.error_title(),
99                     self.layer,
100                     self.required_len,
101                     self.len,
102                     len_source,
103                     self.layer,
104                     self.layer_start_offset
105                 )
106             } else {
107                 write!(
108                     f,
109                     "{}: Not enough data to decode '{}'. {} byte(s) would be required, but only {} byte(s) are available based on the {}.",
110                     self.layer.error_title(),
111                     self.layer,
112                     self.required_len,
113                     self.len,
114                     len_source
115                 )
116             }
117         } else if self.layer_start_offset > 0 {
118             write!(
119                 f,
120                 "{}: Length of {} byte(s) is too big for an '{}' (maximum is {} bytes). The {} was used to determine the length ('{}' starts at overall parsed byte {}).",
121                 self.layer.error_title(),
122                 self.len,
123                 self.layer,
124                 self.required_len,
125                 len_source,
126                 self.layer,
127                 self.layer_start_offset
128             )
129         } else {
130             write!(
131                 f,
132                 "{}: Length of {} byte(s) is too big for an '{}' (maximum is {} bytes). The {} was used to determine the length.",
133                 self.layer.error_title(),
134                 self.len,
135                 self.layer,
136                 self.required_len,
137                 len_source
138             )
139         }
140     }
141 }
142 
143 #[cfg(feature = "std")]
144 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
145 impl std::error::Error for LenError {
source(&self) -> Option<&(dyn std::error::Error + 'static)>146     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
147         None
148     }
149 }
150 
151 #[cfg(test)]
152 mod test {
153     use super::*;
154     use alloc::format;
155     use std::{
156         collections::hash_map::DefaultHasher,
157         error::Error,
158         hash::{Hash, Hasher},
159     };
160 
161     #[test]
add_offset()162     fn add_offset() {
163         assert_eq!(
164             LenError {
165                 required_len: 2,
166                 layer: Layer::Icmpv4,
167                 len: 1,
168                 len_source: LenSource::Slice,
169                 layer_start_offset: 20,
170             }
171             .add_offset(100),
172             LenError {
173                 required_len: 2,
174                 layer: Layer::Icmpv4,
175                 len: 1,
176                 len_source: LenSource::Slice,
177                 layer_start_offset: 120,
178             }
179         );
180     }
181 
182     #[test]
debug()183     fn debug() {
184         assert_eq!(
185             format!(
186                 "{:?}",
187                 LenError {
188                     required_len: 2,
189                     layer: Layer::Ipv4Header,
190                     len: 1,
191                     len_source: LenSource::Slice,
192                     layer_start_offset: 0
193                 }
194             ),
195             format!(
196                 "LenError {{ required_len: {:?}, len: {:?}, len_source: {:?}, layer: {:?}, layer_start_offset: {:?} }}",
197                 2, 1, LenSource::Slice, Layer::Ipv4Header, 0
198             ),
199         );
200     }
201 
202     #[test]
clone_eq_hash()203     fn clone_eq_hash() {
204         let err = LenError {
205             required_len: 2,
206             layer: Layer::Icmpv4,
207             len: 1,
208             len_source: LenSource::Slice,
209             layer_start_offset: 20,
210         };
211         assert_eq!(err, err.clone());
212         let hash_a = {
213             let mut hasher = DefaultHasher::new();
214             err.hash(&mut hasher);
215             hasher.finish()
216         };
217         let hash_b = {
218             let mut hasher = DefaultHasher::new();
219             err.clone().hash(&mut hasher);
220             hasher.finish()
221         };
222         assert_eq!(hash_a, hash_b);
223     }
224 
225     #[test]
fmt()226     fn fmt() {
227         // len sources based tests (not enough data)
228         {
229             use crate::LenSource::*;
230             let len_source_tests = [
231                 (Slice, "IPv4 Header Error: Not enough data to decode 'IPv4 header'. 2 byte(s) would be required, but only 1 byte(s) are available based on the slice length."),
232                 (Ipv4HeaderTotalLen, "IPv4 Header Error: Not enough data to decode 'IPv4 header'. 2 byte(s) would be required, but only 1 byte(s) are available based on the length calculated from the IPv4 header 'total length' field."),
233                 (Ipv6HeaderPayloadLen, "IPv4 Header Error: Not enough data to decode 'IPv4 header'. 2 byte(s) would be required, but only 1 byte(s) are available based on the length calculated from the IPv6 header 'payload length' field."),
234                 (UdpHeaderLen, "IPv4 Header Error: Not enough data to decode 'IPv4 header'. 2 byte(s) would be required, but only 1 byte(s) are available based on the length calculated from the UDP header 'length' field."),
235                 (TcpHeaderLen, "IPv4 Header Error: Not enough data to decode 'IPv4 header'. 2 byte(s) would be required, but only 1 byte(s) are available based on the length calculated from the TCP header 'length' field."),
236             ];
237 
238             for test in len_source_tests {
239                 assert_eq!(
240                     test.1,
241                     format!(
242                         "{}",
243                         LenError {
244                             required_len: 2,
245                             layer: Layer::Ipv4Header,
246                             len: 1,
247                             len_source: test.0,
248                             layer_start_offset: 0
249                         }
250                     )
251                 );
252             }
253         }
254 
255         // start offset based test
256         assert_eq!(
257             "IPv4 Header Error: Not enough data to decode 'IPv4 header'. 2 byte(s) would be required, but only 1 byte(s) are available based on the slice length ('IPv4 header' starts at overall parsed byte 4).",
258             format!(
259                 "{}",
260                 LenError{
261                     required_len: 2,
262                     len: 1,
263                     len_source: LenSource::Slice,
264                     layer: Layer::Ipv4Header,
265                     layer_start_offset: 4
266                 }
267             )
268         );
269 
270         // len sources based tests (length too big)
271         {
272             use crate::LenSource::*;
273             let len_source_tests = [
274                 (Slice, "IPv4 Header Error: Length of 2 byte(s) is too big for an 'IPv4 header' (maximum is 1 bytes). The slice length was used to determine the length."),
275                 (Ipv4HeaderTotalLen, "IPv4 Header Error: Length of 2 byte(s) is too big for an 'IPv4 header' (maximum is 1 bytes). The length calculated from the IPv4 header 'total length' field was used to determine the length."),
276                 (Ipv6HeaderPayloadLen, "IPv4 Header Error: Length of 2 byte(s) is too big for an 'IPv4 header' (maximum is 1 bytes). The length calculated from the IPv6 header 'payload length' field was used to determine the length."),
277                 (UdpHeaderLen, "IPv4 Header Error: Length of 2 byte(s) is too big for an 'IPv4 header' (maximum is 1 bytes). The length calculated from the UDP header 'length' field was used to determine the length."),
278                 (TcpHeaderLen, "IPv4 Header Error: Length of 2 byte(s) is too big for an 'IPv4 header' (maximum is 1 bytes). The length calculated from the TCP header 'length' field was used to determine the length."),
279             ];
280 
281             for test in len_source_tests {
282                 assert_eq!(
283                     test.1,
284                     format!(
285                         "{}",
286                         LenError {
287                             required_len: 1,
288                             layer: Layer::Ipv4Header,
289                             len: 2,
290                             len_source: test.0,
291                             layer_start_offset: 0
292                         }
293                     )
294                 );
295             }
296         }
297 
298         // start offset based test
299         assert_eq!(
300             "IPv4 Header Error: Length of 2 byte(s) is too big for an 'IPv4 header' (maximum is 1 bytes). The slice length was used to determine the length ('IPv4 header' starts at overall parsed byte 4).",
301             format!(
302                 "{}",
303                 LenError{
304                     required_len: 1,
305                     len: 2,
306                     len_source: LenSource::Slice,
307                     layer: Layer::Ipv4Header,
308                     layer_start_offset: 4
309                 }
310             )
311         );
312     }
313 
314     #[cfg(feature = "std")]
315     #[test]
source()316     fn source() {
317         assert!(LenError {
318             required_len: 0,
319             len: 0,
320             len_source: LenSource::Slice,
321             layer: Layer::Ipv4Header,
322             layer_start_offset: 0
323         }
324         .source()
325         .is_none());
326     }
327 }
328