• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::*;
2 use core::slice::from_raw_parts;
3 
4 /// Allows iterating over the IPv6 extension headers present in an [Ipv6ExtensionsSlice].
5 #[derive(Clone, Debug, Eq, PartialEq)]
6 pub struct Ipv6ExtensionSliceIter<'a> {
7     pub(crate) next_header: IpNumber,
8     pub(crate) rest: &'a [u8],
9 }
10 
11 impl Default for Ipv6ExtensionSliceIter<'_> {
default() -> Self12     fn default() -> Self {
13         Ipv6ExtensionSliceIter {
14             // don't use 0 as this is the reserved value
15             // for the hop by hop header
16             next_header: IpNumber::IPV6_NO_NEXT_HEADER,
17             rest: &[],
18         }
19     }
20 }
21 
22 impl<'a> Iterator for Ipv6ExtensionSliceIter<'a> {
23     type Item = Ipv6ExtensionSlice<'a>;
24 
next(&mut self) -> Option<Ipv6ExtensionSlice<'a>>25     fn next(&mut self) -> Option<Ipv6ExtensionSlice<'a>> {
26         use ip_number::*;
27         use Ipv6ExtensionSlice::*;
28 
29         match self.next_header {
30             // Note on the unsafe calls:
31             //
32             // As the slice contents & length were previously checked by
33             // Ipv6ExtensionsSlice::from_slice the content does not have to be
34             // rechecked.
35             IPV6_HOP_BY_HOP => unsafe {
36                 let slice = Ipv6RawExtHeaderSlice::from_slice_unchecked(self.rest);
37                 let len = slice.slice().len();
38                 self.rest = from_raw_parts(self.rest.as_ptr().add(len), self.rest.len() - len);
39                 self.next_header = slice.next_header();
40                 Some(HopByHop(slice))
41             },
42             IPV6_ROUTE => unsafe {
43                 let slice = Ipv6RawExtHeaderSlice::from_slice_unchecked(self.rest);
44                 let len = slice.slice().len();
45                 self.rest = from_raw_parts(self.rest.as_ptr().add(len), self.rest.len() - len);
46                 self.next_header = slice.next_header();
47                 Some(Routing(slice))
48             },
49             IPV6_DEST_OPTIONS => unsafe {
50                 let slice = Ipv6RawExtHeaderSlice::from_slice_unchecked(self.rest);
51                 let len = slice.slice().len();
52                 self.rest = from_raw_parts(self.rest.as_ptr().add(len), self.rest.len() - len);
53                 self.next_header = slice.next_header();
54                 Some(DestinationOptions(slice))
55             },
56             IPV6_FRAG => unsafe {
57                 let slice = Ipv6FragmentHeaderSlice::from_slice_unchecked(self.rest);
58                 let len = slice.slice().len();
59                 self.rest = from_raw_parts(self.rest.as_ptr().add(len), self.rest.len() - len);
60                 self.next_header = slice.next_header();
61 
62                 Some(Fragment(slice))
63             },
64             AUTH => unsafe {
65                 let slice = IpAuthHeaderSlice::from_slice_unchecked(self.rest);
66                 let len = slice.slice().len();
67                 self.rest = from_raw_parts(self.rest.as_ptr().add(len), self.rest.len() - len);
68                 self.next_header = slice.next_header();
69                 Some(Authentication(slice))
70             },
71             // done parsing, the next header is not a known/supported header extension
72             _ => None,
73         }
74     }
75 }
76 
77 #[cfg(test)]
78 mod test {
79     use super::ipv6_exts_test_helpers::*;
80     use super::*;
81     use crate::ip_number::*;
82     use crate::test_gens::*;
83     use alloc::borrow::ToOwned;
84     use proptest::prelude::*;
85 
86     #[test]
into_iter()87     fn into_iter() {
88         let a: Ipv6ExtensionsSlice = Default::default();
89         let mut iter = a.into_iter();
90         assert_eq!(None, iter.next());
91     }
92 
93     proptest! {
94         #[test]
95         fn next(
96             header_size in any::<u8>(),
97             post_header in ip_number_any()
98                 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
99                     |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
100                 )
101         ) {
102             /// Run a test with the given ip numbers
103             fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8]) {
104                 // setup test payload
105                 let e = ExtensionTestPayload::new(
106                     ip_numbers,
107                     header_sizes
108                 );
109 
110                 // a hop by hop header that is not at the start triggers an error
111                 if false == e.ip_numbers[1..].iter().any(|&x| x == IPV6_HOP_BY_HOP) {
112                     // normal read
113                     let (header, _, _) = Ipv6ExtensionsSlice::from_slice(ip_numbers[0], e.slice()).unwrap();
114                     let mut iter = header.into_iter();
115                     let mut slice = e.slice();
116 
117                     // go through all expected headers
118                     for i in 0..e.ip_numbers.len() - 1 {
119                         use Ipv6ExtensionSlice::*;
120 
121                         // iterate and check all results
122                         let next = iter.next().unwrap();
123                         match e.ip_numbers[i] {
124                             IPV6_HOP_BY_HOP => {
125                                 let header = Ipv6RawExtHeaderSlice::from_slice(slice).unwrap();
126                                 assert_eq!(next, HopByHop(header.clone()));
127                                 slice = &slice[header.slice().len()..];
128                             },
129                             IPV6_ROUTE => {
130                                 let header = Ipv6RawExtHeaderSlice::from_slice(slice).unwrap();
131                                 assert_eq!(next, Routing(header.clone()));
132                                 slice = &slice[header.slice().len()..];
133                             },
134                             IPV6_DEST_OPTIONS => {
135                                 let header = Ipv6RawExtHeaderSlice::from_slice(slice).unwrap();
136                                 assert_eq!(next, DestinationOptions(header.clone()));
137                                 slice = &slice[header.slice().len()..];
138                             }
139                             IPV6_FRAG => {
140                                 let header = Ipv6FragmentHeaderSlice::from_slice(slice).unwrap();
141                                 assert_eq!(next, Fragment(header.clone()));
142                                 slice = &slice[header.slice().len()..];
143                             },
144                             AUTH => {
145                                 let header = IpAuthHeaderSlice::from_slice(slice).unwrap();
146                                 assert_eq!(next, Authentication(header.clone()));
147                                 slice = &slice[header.slice().len()..];
148                             },
149                             _ => unreachable!()
150                         }
151                     }
152 
153                     // expect that all headers have been visited
154                     assert_eq!(None, iter.next());
155                 }
156             }
157 
158             // test the parsing of different extension header combinations
159             for first_header in &EXTENSION_KNOWN_IP_NUMBERS {
160 
161                 // single header parsing
162                 run_test(
163                     &[*first_header, post_header],
164                     &[header_size],
165                 );
166 
167                 for second_header in &EXTENSION_KNOWN_IP_NUMBERS {
168 
169                     // double header parsing
170                     run_test(
171                         &[*first_header, *second_header, post_header],
172                         &[header_size],
173                     );
174 
175                     for third_header in &EXTENSION_KNOWN_IP_NUMBERS {
176                         // tripple header parsing
177                         run_test(
178                             &[*first_header, *second_header, *third_header, post_header],
179                             &[header_size],
180                         );
181                     }
182                 }
183             }
184         }
185     }
186 
187     #[test]
debug()188     fn debug() {
189         use alloc::format;
190 
191         let a: Ipv6ExtensionSliceIter = Default::default();
192         assert_eq!(
193             format!(
194                 "Ipv6ExtensionSliceIter {{ next_header: {:?}, rest: [] }}",
195                 IpNumber(59)
196             ),
197             format!("{:?}", a)
198         );
199     }
200 
201     #[test]
clone_eq()202     fn clone_eq() {
203         let a: Ipv6ExtensionSliceIter = Default::default();
204         assert_eq!(a.clone(), a);
205     }
206 
207     #[test]
default()208     fn default() {
209         let mut a: Ipv6ExtensionSliceIter = Default::default();
210         assert_eq!(None, a.next());
211     }
212 }
213