1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
use crate::{err::Layer, LenSource};

/// Error when different lengths are conflicting with each other (e.g. not
/// enough data in a slice to decode a header).
///
/// This error is triggered whenever there is not enough data to decode
/// an element (e.g. if a slice is too small to decode an header) or
/// if a length that is inhered from an upper layer is too big for the
/// lower layer (e.g. length inherited from an IP header is too big to
/// be used as an ICMP packet length).
///
/// When the error is caused by not enough data being available
/// `required_len > len` must be true. While when the length from
/// the upper layer is too big for the lower layer the inverse
/// (`required_len < len`) must be true.
///
/// # Examples:
///
/// An example for an error that could be returned when there is not enough
/// data available to decode an UDP header would be:
///
/// ```
/// use etherparse::*;
///
/// err::LenError{
///     // Expected to have at least the length of an UDP header present:
///     required_len: UdpHeader::LEN,
///     // Could not decode the UDP header:
///     layer: err::Layer::UdpHeader,
///     // There was only 1 byte left (not enough for an UDP header):
///     len: 1,
///     // The provided length was determined by the total length field in the
///     // IPv4 header:
///     len_source: LenSource::Ipv4HeaderTotalLen,
///     // Offset in bytes from the start of decoding (ethernet in this) case
///     // to the expected UDP header start:
///     layer_start_offset: Ethernet2Header::LEN + Ipv4Header::MIN_LEN
/// };
/// ```
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct LenError {
    /// Expected minimum or maximum length conflicting with the
    /// `len` value.
    pub required_len: usize,

    /// Length limiting or exceeding the required length.
    pub len: usize,

    /// Source of the outer length (e.g. Slice or a length specified by
    /// an upper level protocol).
    pub len_source: LenSource,

    /// Layer in which the length error was encountered.
    pub layer: Layer,

    /// Offset from the start of the parsed data to the layer where the
    /// length error occurred.
    pub layer_start_offset: usize,
}

impl LenError {
    /// Adds an offset value to the `layer_start_offset` field.
    #[inline]
    pub const fn add_offset(self, offset: usize) -> Self {
        LenError {
            required_len: self.required_len,
            layer: self.layer,
            len: self.len,
            len_source: self.len_source,
            layer_start_offset: self.layer_start_offset + offset,
        }
    }
}

impl core::fmt::Display for LenError {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        let len_source: &'static str = {
            use LenSource::*;
            match self.len_source {
                Slice => "slice length",
                Ipv4HeaderTotalLen => "length calculated from the IPv4 header 'total length' field",
                Ipv6HeaderPayloadLen => {
                    "length calculated from the IPv6 header 'payload length' field"
                }
                UdpHeaderLen => "length calculated from the UDP header 'length' field",
                TcpHeaderLen => "length calculated from the TCP header 'length' field",
            }
        };

        if self.required_len > self.len {
            if self.layer_start_offset > 0 {
                write!(
                    f,
                    "{}: Not enough data to decode '{}'. {} byte(s) would be required, but only {} byte(s) are available based on the {} ('{}' starts at overall parsed byte {}).",
                    self.layer.error_title(),
                    self.layer,
                    self.required_len,
                    self.len,
                    len_source,
                    self.layer,
                    self.layer_start_offset
                )
            } else {
                write!(
                    f,
                    "{}: Not enough data to decode '{}'. {} byte(s) would be required, but only {} byte(s) are available based on the {}.",
                    self.layer.error_title(),
                    self.layer,
                    self.required_len,
                    self.len,
                    len_source
                )
            }
        } else if self.layer_start_offset > 0 {
            write!(
                f,
                "{}: Length of {} byte(s) is too big for an '{}' (maximum is {} bytes). The {} was used to determine the length ('{}' starts at overall parsed byte {}).",
                self.layer.error_title(),
                self.len,
                self.layer,
                self.required_len,
                len_source,
                self.layer,
                self.layer_start_offset
            )
        } else {
            write!(
                f,
                "{}: Length of {} byte(s) is too big for an '{}' (maximum is {} bytes). The {} was used to determine the length.",
                self.layer.error_title(),
                self.len,
                self.layer,
                self.required_len,
                len_source
            )
        }
    }
}

#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl std::error::Error for LenError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use alloc::format;
    use std::{
        collections::hash_map::DefaultHasher,
        error::Error,
        hash::{Hash, Hasher},
    };

    #[test]
    fn add_offset() {
        assert_eq!(
            LenError {
                required_len: 2,
                layer: Layer::Icmpv4,
                len: 1,
                len_source: LenSource::Slice,
                layer_start_offset: 20,
            }
            .add_offset(100),
            LenError {
                required_len: 2,
                layer: Layer::Icmpv4,
                len: 1,
                len_source: LenSource::Slice,
                layer_start_offset: 120,
            }
        );
    }

    #[test]
    fn debug() {
        assert_eq!(
            format!(
                "{:?}",
                LenError {
                    required_len: 2,
                    layer: Layer::Ipv4Header,
                    len: 1,
                    len_source: LenSource::Slice,
                    layer_start_offset: 0
                }
            ),
            format!(
                "LenError {{ required_len: {:?}, len: {:?}, len_source: {:?}, layer: {:?}, layer_start_offset: {:?} }}",
                2, 1, LenSource::Slice, Layer::Ipv4Header, 0
            ),
        );
    }

    #[test]
    fn clone_eq_hash() {
        let err = LenError {
            required_len: 2,
            layer: Layer::Icmpv4,
            len: 1,
            len_source: LenSource::Slice,
            layer_start_offset: 20,
        };
        assert_eq!(err, err.clone());
        let hash_a = {
            let mut hasher = DefaultHasher::new();
            err.hash(&mut hasher);
            hasher.finish()
        };
        let hash_b = {
            let mut hasher = DefaultHasher::new();
            err.clone().hash(&mut hasher);
            hasher.finish()
        };
        assert_eq!(hash_a, hash_b);
    }

    #[test]
    fn fmt() {
        // len sources based tests (not enough data)
        {
            use crate::LenSource::*;
            let len_source_tests = [
                (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."),
                (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."),
                (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."),
                (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."),
                (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."),
            ];

            for test in len_source_tests {
                assert_eq!(
                    test.1,
                    format!(
                        "{}",
                        LenError {
                            required_len: 2,
                            layer: Layer::Ipv4Header,
                            len: 1,
                            len_source: test.0,
                            layer_start_offset: 0
                        }
                    )
                );
            }
        }

        // start offset based test
        assert_eq!(
            "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).",
            format!(
                "{}",
                LenError{
                    required_len: 2,
                    len: 1,
                    len_source: LenSource::Slice,
                    layer: Layer::Ipv4Header,
                    layer_start_offset: 4
                }
            )
        );

        // len sources based tests (length too big)
        {
            use crate::LenSource::*;
            let len_source_tests = [
                (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."),
                (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."),
                (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."),
                (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."),
                (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."),
            ];

            for test in len_source_tests {
                assert_eq!(
                    test.1,
                    format!(
                        "{}",
                        LenError {
                            required_len: 1,
                            layer: Layer::Ipv4Header,
                            len: 2,
                            len_source: test.0,
                            layer_start_offset: 0
                        }
                    )
                );
            }
        }

        // start offset based test
        assert_eq!(
            "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).",
            format!(
                "{}",
                LenError{
                    required_len: 1,
                    len: 2,
                    len_source: LenSource::Slice,
                    layer: Layer::Ipv4Header,
                    layer_start_offset: 4
                }
            )
        );
    }

    #[cfg(feature = "std")]
    #[test]
    fn source() {
        assert!(LenError {
            required_len: 0,
            len: 0,
            len_source: LenSource::Slice,
            layer: Layer::Ipv4Header,
            layer_start_offset: 0
        }
        .source()
        .is_none());
    }
}