etherparse/transport/
tcp_options_iterator.rs

1use crate::*;
2
3/// Allows iterating over the options after a TCP header.
4#[derive(Clone, Eq, PartialEq)]
5pub struct TcpOptionsIterator<'a> {
6    pub(crate) options: &'a [u8],
7}
8
9impl<'a> TcpOptionsIterator<'a> {
10    /// Creates an options iterator from a slice containing encoded tcp options.
11    pub fn from_slice(options: &'a [u8]) -> TcpOptionsIterator<'a> {
12        TcpOptionsIterator { options }
13    }
14
15    /// Returns the non processed part of the options slice.
16    pub fn rest(&self) -> &'a [u8] {
17        self.options
18    }
19}
20
21impl Iterator for TcpOptionsIterator<'_> {
22    type Item = Result<TcpOptionElement, TcpOptionReadError>;
23
24    fn next(&mut self) -> Option<Self::Item> {
25        use crate::TcpOptionElement::*;
26        use crate::TcpOptionReadError::*;
27
28        let expect_specific_size =
29            |expected_size: u8, slice: &[u8]| -> Result<(), TcpOptionReadError> {
30                let id = slice[0];
31                if slice.len() < expected_size as usize {
32                    Err(UnexpectedEndOfSlice {
33                        option_id: id,
34                        expected_len: expected_size,
35                        actual_len: slice.len(),
36                    })
37                } else if slice[1] != expected_size {
38                    Err(UnexpectedSize {
39                        option_id: slice[0],
40                        size: slice[1],
41                    })
42                } else {
43                    Ok(())
44                }
45            };
46
47        if self.options.is_empty() {
48            None
49        } else {
50            //first determine the result
51            use tcp_option::*;
52            let result = match self.options[0] {
53                //end
54                KIND_END => None,
55                KIND_NOOP => {
56                    self.options = &self.options[1..];
57                    Some(Ok(Noop))
58                }
59                KIND_MAXIMUM_SEGMENT_SIZE => {
60                    match expect_specific_size(LEN_MAXIMUM_SEGMENT_SIZE, self.options) {
61                        Err(value) => Some(Err(value)),
62                        _ => {
63                            // SAFETY:
64                            // Safe as the slice size is checked beforehand to be at
65                            // least of size LEN_MAXIMUM_SEGMENT_SIZE (4).
66                            let value =
67                                unsafe { get_unchecked_be_u16(self.options.as_ptr().add(2)) };
68                            self.options = &self.options[4..];
69                            Some(Ok(MaximumSegmentSize(value)))
70                        }
71                    }
72                }
73                KIND_WINDOW_SCALE => match expect_specific_size(LEN_WINDOW_SCALE, self.options) {
74                    Err(value) => Some(Err(value)),
75                    _ => {
76                        let value = self.options[2];
77                        self.options = &self.options[3..];
78                        Some(Ok(WindowScale(value)))
79                    }
80                },
81                KIND_SELECTIVE_ACK_PERMITTED => {
82                    match expect_specific_size(LEN_SELECTIVE_ACK_PERMITTED, self.options) {
83                        Err(value) => Some(Err(value)),
84                        _ => {
85                            self.options = &self.options[2..];
86                            Some(Ok(SelectiveAcknowledgementPermitted))
87                        }
88                    }
89                }
90                KIND_SELECTIVE_ACK => {
91                    //check that the length field can be read
92                    if self.options.len() < 2 {
93                        Some(Err(UnexpectedEndOfSlice {
94                            option_id: self.options[0],
95                            expected_len: 2,
96                            actual_len: self.options.len(),
97                        }))
98                    } else {
99                        //check that the length is an allowed one for this option
100                        let len = self.options[1];
101                        if len != 10 && len != 18 && len != 26 && len != 34 {
102                            Some(Err(UnexpectedSize {
103                                option_id: self.options[0],
104                                size: len,
105                            }))
106                        } else if self.options.len() < (len as usize) {
107                            Some(Err(UnexpectedEndOfSlice {
108                                option_id: self.options[0],
109                                expected_len: len,
110                                actual_len: self.options.len(),
111                            }))
112                        } else {
113                            let mut acks: [Option<(u32, u32)>; 3] = [None; 3];
114                            // SAFETY:
115                            // This is safe as above the len is checked
116                            // to be at least 10 and the slice len is
117                            // checked to be at least len bytes.
118                            let first = unsafe {
119                                (
120                                    get_unchecked_be_u32(self.options.as_ptr().add(2)),
121                                    get_unchecked_be_u32(self.options.as_ptr().add(6)),
122                                )
123                            };
124                            for (i, item) in acks.iter_mut().enumerate().take(3) {
125                                let offset = 2 + 8 + (i * 8);
126                                // SAFETY:
127                                // len can only be 10, 18, 26 or 34
128                                // therefore if the offset is smaller then the
129                                // len, then at least 8 bytes can be read.
130                                unsafe {
131                                    if offset < (len as usize) {
132                                        *item = Some((
133                                            get_unchecked_be_u32(self.options.as_ptr().add(offset)),
134                                            get_unchecked_be_u32(
135                                                self.options.as_ptr().add(offset + 4),
136                                            ),
137                                        ));
138                                    }
139                                }
140                            }
141                            //iterate the options
142                            self.options = &self.options[len as usize..];
143                            Some(Ok(SelectiveAcknowledgement(first, acks)))
144                        }
145                    }
146                }
147                KIND_TIMESTAMP => {
148                    match expect_specific_size(LEN_TIMESTAMP, self.options) {
149                        Err(value) => Some(Err(value)),
150
151                        _ => unsafe {
152                            let t = Timestamp(
153                                // SAFETY:
154                                // Safe as the len first gets checked to be equal
155                                // LEN_TIMESTAMP (10).
156                                get_unchecked_be_u32(self.options.as_ptr().add(2)),
157                                get_unchecked_be_u32(self.options.as_ptr().add(6)),
158                            );
159                            self.options = &self.options[10..];
160                            Some(Ok(t))
161                        },
162                    }
163                }
164
165                //unknown id
166                _ => Some(Err(UnknownId(self.options[0]))),
167            };
168
169            //in case the result was an error or the end move the slice to an end position
170            match result {
171                None | Some(Err(_)) => {
172                    let len = self.options.len();
173                    self.options = &self.options[len..len];
174                }
175                _ => {}
176            }
177
178            //finally return the result
179            result
180        }
181    }
182}
183
184impl core::fmt::Debug for TcpOptionsIterator<'_> {
185    fn fmt(&self, fmt: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
186        let mut list = fmt.debug_list();
187
188        // create a copy and iterate over all elements
189        for it in self.clone() {
190            match it {
191                Ok(e) => {
192                    list.entry(&e);
193                }
194                Err(e) => {
195                    list.entry(&Result::<(), TcpOptionReadError>::Err(e.clone()));
196                }
197            }
198        }
199
200        list.finish()
201    }
202}
203
204#[cfg(test)]
205mod test {
206    use crate::{tcp_option::*, *};
207    use alloc::format;
208
209    #[test]
210    fn debug() {
211        use tcp_option::*;
212        #[rustfmt::skip]
213        assert_eq!(
214            "[MaximumSegmentSize(0), WindowScale(0)]",
215            format!(
216                "{:?}",
217                TcpOptionsIterator::from_slice(&[
218                    KIND_MAXIMUM_SEGMENT_SIZE, 4, 0, 0,
219                    KIND_WINDOW_SCALE, 3, 0,
220                    KIND_END,
221                ])
222            )
223        );
224        #[rustfmt::skip]
225        assert_eq!(
226            "[MaximumSegmentSize(0), Err(UnexpectedSize { option_id: 3, size: 0 })]",
227            format!(
228                "{:?}",
229                TcpOptionsIterator::from_slice(&[
230                    KIND_MAXIMUM_SEGMENT_SIZE, 4, 0, 0,
231                    KIND_WINDOW_SCALE, 0, 0, 0,
232                ])
233            )
234        );
235    }
236
237    #[test]
238    fn clone_eq() {
239        use tcp_option::*;
240        let it = TcpOptionsIterator::from_slice(&[KIND_END]);
241        assert_eq!(it, it.clone());
242    }
243
244    #[test]
245    fn from_slice_and_rest() {
246        let buffer = [KIND_NOOP, KIND_NOOP, KIND_MAXIMUM_SEGMENT_SIZE, 4];
247        let it = TcpOptionsIterator::from_slice(&buffer);
248        assert_eq!(it.rest(), &buffer[..]);
249    }
250
251    #[test]
252    #[rustfmt::skip]
253    fn next() {
254        use crate::TcpOptionElement::*;
255
256        // ok test
257        {
258            fn expect_elements(buffer: &[u8], expected: &[TcpOptionElement]) {
259                // options iterator via from_slice()
260                let mut it = TcpOptionsIterator::from_slice(buffer);
261                for element in expected.iter() {
262                    assert_eq!(element, &it.next().unwrap().unwrap());
263                }
264        
265                //expect no more elements
266                assert_eq!(None, it.next());
267                assert_eq!(0, it.rest().len());
268            }
269
270            // nop & max segment size
271            #[rustfmt::skip]
272            expect_elements(&[
273                    KIND_NOOP, 
274                    KIND_NOOP,
275                    KIND_MAXIMUM_SEGMENT_SIZE, 4, 
276                    0, 1,
277                    KIND_WINDOW_SCALE, 3, 2,
278                    KIND_SELECTIVE_ACK_PERMITTED, 2,
279                    KIND_SELECTIVE_ACK, 10,
280                    0, 0, 0, 10,
281                    0, 0, 0, 11,
282                    KIND_SELECTIVE_ACK, 18, 
283                    0, 0, 0, 12,
284                    0, 0, 0, 13,
285                    0, 0, 0, 14,
286                    0, 0, 0, 15,
287                    KIND_SELECTIVE_ACK, 26, 
288                    0, 0, 0, 16,
289                    0, 0, 0, 17,
290                    0, 0, 0, 18,
291                    0, 0, 0, 19,
292                    0, 0, 0, 20,
293                    0, 0, 0, 21,
294                    KIND_SELECTIVE_ACK, 34, 
295                    0, 0, 0, 22,
296                    0, 0, 0, 23,
297                    0, 0, 0, 24,
298                    0, 0, 0, 25,
299                    0, 0, 0, 26,
300                    0, 0, 0, 27,
301                    0, 0, 0, 28,
302                    0, 0, 0, 29,
303                    KIND_TIMESTAMP, 10, 
304                    0, 0, 0, 30, 
305                    0, 0, 0, 31,
306                    KIND_END, 0, 0, 0, 0
307                ],
308                &[
309                    Noop,
310                    Noop,
311                    MaximumSegmentSize(1),
312                    WindowScale(2),
313                    SelectiveAcknowledgementPermitted,
314                    SelectiveAcknowledgement((10,11), [None, None, None]),
315                    SelectiveAcknowledgement((12,13), [Some((14,15)), None, None]),
316                    SelectiveAcknowledgement((16,17), [Some((18,19)), Some((20,21)), None]),
317                    SelectiveAcknowledgement((22,23), [Some((24,25)), Some((26,27)), Some((28,29))]),
318                    Timestamp(30,31)
319                ]
320            );
321        }
322
323        // unknown id
324        {
325            let data = [255, 2, 0, 0, 0,
326                0, 0, 0, 0, 0, //10
327                0, 0, 0, 0, 0,
328                0, 0, 0, 0, 0, //20
329                0, 0, 0, 0, 0,
330                0, 0, 0, 0, 0, //30
331                0, 0, 0, 0];
332            let mut it = TcpOptionsIterator::from_slice(&data);
333            assert_eq!(Some(Err(TcpOptionReadError::UnknownId(255))), it.next());
334            
335            //expect the iterator slice to be moved to the end
336            assert_eq!(0, it.rest().len());
337            assert_eq!(None, it.next());
338            assert_eq!(0, it.rest().len());
339        }
340
341        // unexpected end of slice
342        {
343            fn expect_unexpected_eos(slice: &[u8]) {
344                for i in 1..slice.len()-1 {
345                    let mut it = TcpOptionsIterator::from_slice(&slice[..i]);
346                    assert_eq!(
347                        Some(
348                            Err(
349                                TcpOptionReadError::UnexpectedEndOfSlice{
350                                    option_id: slice[0],
351                                    expected_len: match slice[0] {
352                                        KIND_MAXIMUM_SEGMENT_SIZE => 4,
353                                        KIND_WINDOW_SCALE => 3,
354                                        KIND_SELECTIVE_ACK_PERMITTED => 2,
355                                        KIND_SELECTIVE_ACK => if i < 2 {
356                                            // the inial check only checks if there
357                                            // is enough data to read the length field
358                                            2
359                                        } else {
360                                            slice[1]
361                                        },
362                                        KIND_TIMESTAMP => 10,
363                                        _ => panic!("not part of the tests"),
364                                    },
365                                    actual_len: i
366                                }
367                            )
368                        ),
369                        it.next()
370                    );
371                    //expect the iterator slice to be moved to the end
372                    assert_eq!(0, it.rest().len());
373                    assert_eq!(None, it.next());
374                }
375            }
376
377            expect_unexpected_eos(&[KIND_MAXIMUM_SEGMENT_SIZE, 4, 0, 0]);
378            expect_unexpected_eos(&[KIND_WINDOW_SCALE, 3, 0]);
379            expect_unexpected_eos(&[KIND_MAXIMUM_SEGMENT_SIZE, 4, 0, 0]);
380            expect_unexpected_eos(&[KIND_SELECTIVE_ACK_PERMITTED, 2]);
381            expect_unexpected_eos(&[KIND_SELECTIVE_ACK, 10, 0, 0, 0,
382                                    0, 0, 0, 0, 0]);
383            expect_unexpected_eos(&[KIND_SELECTIVE_ACK, 18, 0, 0, 0,
384                                    0, 0, 0, 0, 0,
385                                    0, 0, 0, 0, 0,
386                                    0, 0, 0]);
387            expect_unexpected_eos(&[KIND_SELECTIVE_ACK, 26, 0, 0, 0,
388                                    0, 0, 0, 0, 0,
389                                    0, 0, 0, 0, 0,
390                                    0, 0, 0, 0, 0,
391                                    0, 0, 0, 0, 0,
392                                    0]);
393            expect_unexpected_eos(&[KIND_SELECTIVE_ACK, 34, 0, 0, 0,
394                                    0, 0, 0, 0, 0, //10
395                                    0, 0, 0, 0, 0,
396                                    0, 0, 0, 0, 0, //20
397                                    0, 0, 0, 0, 0,
398                                    0, 0, 0, 0, 0, //30
399                                    0, 0, 0, 0]);
400            expect_unexpected_eos(&[KIND_TIMESTAMP, 10, 0, 0, 0,
401                                    0, 0, 0, 0, 0]);
402        }
403
404        // unexpected option size error 
405        {
406            fn expect_unexpected_size(id: u8, size: u8) {
407                let data = [
408                    id, size, 0, 0, 0, 0, 0, 0, 0, 0, //10
409                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20
410                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30
411                    0, 0, 0, 0,
412                ];
413                let mut it = TcpOptionsIterator::from_slice(&data);
414                assert_eq!(
415                    Some(Err(TcpOptionReadError::UnexpectedSize {
416                        option_id: data[0],
417                        size: data[1]
418                    })),
419                    it.next()
420                );
421                //expect the iterator slice to be moved to the end
422                assert_eq!(0, it.rest().len());
423                assert_eq!(None, it.next());
424                assert_eq!(0, it.rest().len());
425            }
426            expect_unexpected_size(KIND_MAXIMUM_SEGMENT_SIZE, 3);
427            expect_unexpected_size(KIND_MAXIMUM_SEGMENT_SIZE, 5);
428        
429            expect_unexpected_size(KIND_WINDOW_SCALE, 2);
430            expect_unexpected_size(KIND_WINDOW_SCALE, 4);
431        
432            expect_unexpected_size(KIND_MAXIMUM_SEGMENT_SIZE, 3);
433            expect_unexpected_size(KIND_MAXIMUM_SEGMENT_SIZE, 5);
434        
435            expect_unexpected_size(KIND_SELECTIVE_ACK_PERMITTED, 1);
436            expect_unexpected_size(KIND_SELECTIVE_ACK_PERMITTED, 3);
437        
438            expect_unexpected_size(KIND_SELECTIVE_ACK, 9);
439            expect_unexpected_size(KIND_SELECTIVE_ACK, 11);
440        
441            expect_unexpected_size(KIND_SELECTIVE_ACK, 17);
442            expect_unexpected_size(KIND_SELECTIVE_ACK, 19);
443        
444            expect_unexpected_size(KIND_SELECTIVE_ACK, 25);
445            expect_unexpected_size(KIND_SELECTIVE_ACK, 27);
446        
447            expect_unexpected_size(KIND_SELECTIVE_ACK, 33);
448            expect_unexpected_size(KIND_SELECTIVE_ACK, 35);
449        
450            expect_unexpected_size(KIND_TIMESTAMP, 9);
451            expect_unexpected_size(KIND_TIMESTAMP, 11);
452        }
453    }
454}