zero_packet/network/extensions/
routing.rs

1use core::fmt;
2
3/// The minimum length of a Routing extension header.
4pub const ROUTING_HEADER_MIN_LEN: usize = 8;
5
6/// Writes the Routing extension header fields.
7pub struct RoutingHeaderWriter<'a> {
8    pub bytes: &'a mut [u8],
9}
10
11impl<'a> RoutingHeaderWriter<'a> {
12    /// Creates a new `RoutingHeaderWriter` from the given data slice.
13    #[inline]
14    pub fn new(bytes: &'a mut [u8]) -> Result<Self, &'static str> {
15        if bytes.len() < ROUTING_HEADER_MIN_LEN {
16            return Err("Slice is too short to contain a Routing extension header.");
17        }
18
19        Ok(Self { bytes })
20    }
21
22    /// Returns the total header length in bytes.
23    #[inline]
24    pub fn header_len(&self) -> usize {
25        (self.bytes[1] as usize + 1) * 8
26    }
27
28    /// Sets the next header field.
29    ///
30    /// Specifies the type of the next header.
31    #[inline]
32    pub fn set_next_header(&mut self, next_header: u8) {
33        self.bytes[0] = next_header;
34    }
35
36    /// Sets the header extension length field.
37    ///
38    /// Length of the header in 8 bytes, not including the first 8 bytes.
39    /// 
40    /// E.g. Header length = (header_ext_len + 1) * 8.
41    #[inline]
42    pub fn set_header_ext_len(&mut self, header_ext_len: u8) {
43        self.bytes[1] = header_ext_len;
44    }
45
46    /// Sets the routing type field.
47    ///
48    /// Value between 0 and 255, see IANA:
49    /// - 0: deprecated, since it enabled DoS attacks.
50    /// - 1: deprecated, used for the Nimrod project by DARPA.
51    /// - 2: allowed, limited version of type 0, used for Mobile IPv6.
52    /// - 3: allowed, RPL Source Route Header for low-power and lossy networks.
53    /// - 4: allowed, Segment Routing Header (SHR).
54    #[inline]
55    pub fn set_routing_type(&mut self, routing_type: u8) {
56        self.bytes[2] = routing_type;
57    }
58
59    /// Sets the segments left field.
60    ///
61    /// Number of nodes this packet has to visit before reaching its final destination.
62    #[inline]
63    pub fn set_segments_left(&mut self, segments_left: u8) {
64        self.bytes[3] = segments_left;
65    }
66
67    /// Sets the data field.
68    ///
69    /// The data field is a variable-length field.
70    ///
71    /// The first 4 bytes are reserved with zeroes.
72    ///
73    /// If you set data then set blocks of 8 bytes.
74    #[inline]
75    pub fn set_data(&mut self, data: &[u8]) -> Result<(), &'static str> {
76        if data.len() < 4 {
77            return Err("Type-specific data must be at least 4 bytes long.");
78        }
79
80        let extension_len = self.bytes[1] as usize * 8;
81
82        if extension_len != data.len() {
83            return Err("Type-specific data length must match the header extension length.");
84        }
85
86        let start_offset = 8;
87        let end_offset = start_offset + data.len();
88
89        if end_offset > self.bytes.len() {
90            return Err("Type-specific data exceeds the allocated header length.");
91        }
92
93        self.bytes[start_offset..end_offset].copy_from_slice(data);
94
95        Ok(())
96    }
97}
98
99/// Reads the Routing extension header fields.
100pub struct RoutingHeaderReader<'a> {
101    pub bytes: &'a [u8],
102}
103
104impl<'a> RoutingHeaderReader<'a> {
105    /// Creates a new `RoutingHeaderReader` from the given data slice.
106    #[inline]
107    pub fn new(bytes: &'a [u8]) -> Result<Self, &'static str> {
108        if bytes.len() < ROUTING_HEADER_MIN_LEN {
109            return Err("Slice is too short to contain a Routing extension header.");
110        }
111
112        Ok(Self { bytes })
113    }
114
115    /// Returns the next header field.
116    ///
117    /// Specifies the type of the next header.
118    #[inline]
119    pub fn next_header(&self) -> u8 {
120        self.bytes[0]
121    }
122
123    /// Returns the header extension length field.
124    ///
125    /// Length of the header in 8 bytes, not including the first 8 bytes.
126    /// 
127    /// E.g. Header length = (header_ext_len + 1) * 8.
128    #[inline]
129    pub fn header_ext_len(&self) -> u8 {
130        self.bytes[1]
131    }
132
133    /// Returns the routing type field.
134    ///
135    /// Value between 0 and 255, see IANA:
136    /// - 0: deprecated, since it enabled DoS attacks.
137    /// - 1: deprecated, used for the Nimrod project by DARPA.
138    /// - 2: allowed, limited version of type 0, used for Mobile IPv6.
139    /// - 3: allowed, RPL Source Route Header for low-power and lossy networks.
140    /// - 4: allowed, Segment Routing Header (SHR).
141    #[inline]
142    pub fn routing_type(&self) -> u8 {
143        self.bytes[2]
144    }
145
146    /// Returns the segments left field.
147    ///
148    /// Number of nodes this packet has to visit before reaching its final destination.
149    #[inline]
150    pub fn segments_left(&self) -> u8 {
151        self.bytes[3]
152    }
153
154    /// Returns the data field.
155    #[inline]
156    pub fn data(&self) -> &[u8] {
157        let start = 4;
158        let end = self.header_len();
159        &self.bytes[start..end]
160    }
161
162    /// Returns the total header length in bytes.
163    #[inline]
164    pub fn header_len(&self) -> usize {
165        (self.bytes[1] as usize + 1) * 8
166    }
167
168    /// Returns a reference to the header.
169    /// 
170    /// May fail if the indicated header length exceeds the allocated buffer.
171    #[inline]
172    pub fn header(&self) -> Result<&'a [u8], &'static str> {
173        let end = self.header_len();
174
175        if end > self.bytes.len() {
176            return Err("Indicated IPv6 routing header length exceeds the allocated buffer.");
177        }
178
179        Ok(&self.bytes[..end])
180    }
181
182    /// Returns a reference to the payload.
183    /// 
184    /// May fail if the indicated header length exceeds the allocated buffer.
185    #[inline]
186    pub fn payload(&self) -> Result<&'a [u8], &'static str> {
187        let start = self.header_len();
188
189        if start > self.bytes.len() {
190            return Err("Indicated IPv6 routing header length exceeds the allocated buffer.");
191        }
192
193        Ok(&self.bytes[self.header_len()..])
194    }
195}
196
197impl fmt::Debug for RoutingHeaderReader<'_> {
198    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199        f.debug_struct("RoutingExtensionHeader")
200            .field("next_header", &self.next_header())
201            .field("header_ext_len", &self.header_ext_len())
202            .field("routing_type", &self.routing_type())
203            .field("segments_left", &self.segments_left())
204            .field("data", &self.data())
205            .finish()
206    }
207}
208
209#[cfg(test)]
210pub mod tests {
211    use super::*;
212
213    #[test]
214    fn getters_and_setters() {
215        // Raw packet.
216        let mut bytes = [0u8; 16];
217
218        // Random values.
219        let next_header = 6;
220        let header_ext_len = 1; // (header_ext_len + 1) * 8 = 16
221        let routing_type = 2;
222        let segments_left = 3;
223        let data = [4, 5, 6, 7, 8, 9, 10, 11];
224
225        // Write the Routing extension header.
226        let mut writer = RoutingHeaderWriter::new(&mut bytes).unwrap();
227        writer.set_next_header(next_header);
228        writer.set_header_ext_len(header_ext_len);
229        writer.set_routing_type(routing_type);
230        writer.set_segments_left(segments_left);
231        writer.set_data(&data).unwrap();
232
233        // Read the Routing extension header.
234        let reader = RoutingHeaderReader::new(&bytes).unwrap();
235        assert_eq!(reader.next_header(), next_header);
236        assert_eq!(reader.header_ext_len(), header_ext_len);
237        assert_eq!(reader.routing_type(), routing_type);
238        assert_eq!(reader.segments_left(), segments_left);
239        assert_eq!(reader.data(), [0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11]);
240    }
241}