• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::*;
2 
3 /// Allows iterating over the options after a TCP header.
4 #[derive(Clone, Eq, PartialEq)]
5 pub struct TcpOptionsIterator<'a> {
6     pub(crate) options: &'a [u8],
7 }
8 
9 impl<'a> TcpOptionsIterator<'a> {
10     /// Creates an options iterator from a slice containing encoded tcp options.
from_slice(options: &'a [u8]) -> TcpOptionsIterator<'a>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.
rest(&self) -> &'a [u8]16     pub fn rest(&self) -> &'a [u8] {
17         self.options
18     }
19 }
20 
21 impl Iterator for TcpOptionsIterator<'_> {
22     type Item = Result<TcpOptionElement, TcpOptionReadError>;
23 
next(&mut self) -> Option<Self::Item>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 
184 impl core::fmt::Debug for TcpOptionsIterator<'_> {
fmt(&self, fmt: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error>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)]
205 mod test {
206     use crate::{tcp_option::*, *};
207     use alloc::format;
208 
209     #[test]
debug()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]
clone_eq()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]
from_slice_and_rest()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]
next()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 }
455