zero_packet/network/
ipv6.rs

1use super::extensions::headers::ExtensionHeaders;
2use crate::misc::bytes_to_ipv6;
3use core::{fmt, str::from_utf8};
4
5/// The length of an IPv6 header in bytes.
6pub const IPV6_HEADER_LEN: usize = 40;
7
8/// Writes IPv6 header fields.
9pub struct IPv6Writer<'a> {
10    pub bytes: &'a mut [u8],
11}
12
13impl<'a> IPv6Writer<'a> {
14    /// Creates a new `IPv6Writer` from the given data slice.
15    #[inline]
16    pub fn new(bytes: &'a mut [u8]) -> Result<Self, &'static str> {
17        if bytes.len() < IPV6_HEADER_LEN {
18            return Err("Slice is too short to contain an IPv6 header.");
19        }
20
21        Ok(Self { bytes })
22    }
23
24    /// Returns the actual header length in bytes.
25    #[inline]
26    pub fn header_len(&self) -> usize {
27        IPV6_HEADER_LEN
28    }
29
30    /// Sets the version field.
31    ///
32    /// Indicates the IP version number. Should be set to 6.
33    #[inline]
34    pub fn set_version(&mut self, version: u8) {
35        self.bytes[0] = (self.bytes[0] & 0x0F) | (version << 4);
36    }
37
38    /// Sets the traffic class field.
39    ///
40    /// Specifies the priority of the packet.
41    #[inline]
42    pub fn set_traffic_class(&mut self, traffic_class: u8) {
43        self.bytes[0] = (self.bytes[0] & 0xF0) | (traffic_class >> 4);
44        self.bytes[1] = (self.bytes[1] & 0x0F) | (traffic_class << 4);
45    }
46
47    /// Sets the flow label field.
48    ///
49    /// Identifies packets belonging to the same flow (group of packets).
50    #[inline]
51    pub fn set_flow_label(&mut self, flow_label: u32) {
52        self.bytes[1] = (self.bytes[1] & 0xF0) | ((flow_label >> 16) as u8);
53        self.bytes[2] = (flow_label >> 8) as u8;
54        self.bytes[3] = flow_label as u8;
55    }
56
57    /// Sets the payload length field.
58    ///
59    /// Specifies the length of the payload in bytes.
60    #[inline]
61    pub fn set_payload_length(&mut self, payload_length: u16) {
62        self.bytes[4] = (payload_length >> 8) as u8;
63        self.bytes[5] = payload_length as u8;
64    }
65
66    /// Sets the next header field.
67    ///
68    /// Specifies the type of the next header, usually a transport protocol.
69    ///
70    /// Shares the same values as the protocol field in an IPv4 header.
71    #[inline]
72    pub fn set_next_header(&mut self, next_header: u8) {
73        self.bytes[6] = next_header;
74    }
75
76    /// Sets the hop limit field.
77    ///
78    /// Replaces the time-to-live field in IPv4.
79    ///
80    /// The value is decremented each time the packet is forwarded by a router.
81    ///
82    /// When the value reaches 0, the packet is discarded, unless it has reached its destination.
83    #[inline]
84    pub fn set_hop_limit(&mut self, hop_limit: u8) {
85        self.bytes[7] = hop_limit;
86    }
87
88    /// Sets the source address field.
89    ///
90    /// Unicast IPv6 address of the sender.
91    #[inline]
92    pub fn set_src_addr(&mut self, src_addr: &[u8; 16]) {
93        self.bytes[8] = src_addr[0];
94        self.bytes[9] = src_addr[1];
95        self.bytes[10] = src_addr[2];
96        self.bytes[11] = src_addr[3];
97        self.bytes[12] = src_addr[4];
98        self.bytes[13] = src_addr[5];
99        self.bytes[14] = src_addr[6];
100        self.bytes[15] = src_addr[7];
101        self.bytes[16] = src_addr[8];
102        self.bytes[17] = src_addr[9];
103        self.bytes[18] = src_addr[10];
104        self.bytes[19] = src_addr[11];
105        self.bytes[20] = src_addr[12];
106        self.bytes[21] = src_addr[13];
107        self.bytes[22] = src_addr[14];
108        self.bytes[23] = src_addr[15];
109    }
110
111    /// Sets the destination address field.
112    ///
113    /// Unicast or multicast IPv6 address of the intended recipient.
114    #[inline]
115    pub fn set_dest_addr(&mut self, dest_addr: &[u8; 16]) {
116        self.bytes[24] = dest_addr[0];
117        self.bytes[25] = dest_addr[1];
118        self.bytes[26] = dest_addr[2];
119        self.bytes[27] = dest_addr[3];
120        self.bytes[28] = dest_addr[4];
121        self.bytes[29] = dest_addr[5];
122        self.bytes[30] = dest_addr[6];
123        self.bytes[31] = dest_addr[7];
124        self.bytes[32] = dest_addr[8];
125        self.bytes[33] = dest_addr[9];
126        self.bytes[34] = dest_addr[10];
127        self.bytes[35] = dest_addr[11];
128        self.bytes[36] = dest_addr[12];
129        self.bytes[37] = dest_addr[13];
130        self.bytes[38] = dest_addr[14];
131        self.bytes[39] = dest_addr[15];
132    }
133}
134
135/// Reads IPv6 header fields.
136///
137/// May contain extension headers.
138pub struct IPv6Reader<'a> {
139    pub bytes: &'a [u8],
140    pub extension_headers: Option<ExtensionHeaders<'a>>,
141    pub extension_headers_len: usize,
142}
143
144impl<'a> IPv6Reader<'a> {
145    /// Creates a new `IPv6Reader` from the given data slice.
146    #[inline]
147    pub fn new(bytes: &'a [u8]) -> Result<Self, &'static str> {
148        if bytes.len() < IPV6_HEADER_LEN {
149            return Err("Slice is too short to contain an IPv6 header.");
150        }
151
152        let mut reader = Self {
153            bytes,
154            extension_headers: None,
155            extension_headers_len: 0,
156        };
157
158        // Constructs a struct containing all extension headers, if there are any.
159        let extension_headers = ExtensionHeaders::parse(reader.payload(), reader.next_header())?;
160
161        if let Some(extension_headers) = extension_headers {
162            reader.extension_headers_len = extension_headers.total_headers_len;
163            reader.extension_headers = Some(extension_headers);
164        }
165
166        Ok(reader)
167    }
168
169    /// Returns the version field.
170    ///
171    /// Indicates the IP version number. Should be set to 6.
172    #[inline]
173    pub fn version(&self) -> u8 {
174        self.bytes[0] >> 4
175    }
176
177    /// Returns the traffic class field.
178    ///
179    /// Specifies the priority of the packet.
180    #[inline]
181    pub fn traffic_class(&self) -> u8 {
182        ((self.bytes[0] & 0x0F) << 4) | (self.bytes[1] >> 4)
183    }
184
185    /// Returns the flow label field.
186    ///
187    /// Identifies packets belonging to the same flow (group of packets).
188    #[inline]
189    pub fn flow_label(&self) -> u32 {
190        ((self.bytes[1] as u32 & 0x0F) << 16)
191            | ((self.bytes[2] as u32) << 8)
192            | (self.bytes[3] as u32)
193    }
194
195    /// Returns the payload length field.
196    ///
197    /// Specifies the length of the payload in bytes.
198    #[inline]
199    pub fn payload_length(&self) -> u16 {
200        ((self.bytes[4] as u16) << 8) | (self.bytes[5] as u16)
201    }
202
203    /// Returns the next header field.
204    ///
205    /// Specifies the type of the next header, usually a transport protocol.
206    ///
207    /// Shares the same values as the protocol field in an IPv4 header.
208    #[inline]
209    pub fn next_header(&self) -> u8 {
210        self.bytes[6]
211    }
212
213    /// Returns the final next header field, which is the encapsulated protocol.
214    ///
215    /// If there are extension headers, the last next header in the chain is returned.
216    ///
217    /// Otherwise, the next header field of the IPv6 header is returned.
218    #[inline]
219    pub fn final_next_header(&self) -> u8 {
220        let mut next_header = self.next_header();
221
222        if let Some(extension_headers) = &self.extension_headers {
223            next_header = extension_headers.final_next_header;
224        }
225
226        next_header
227    }
228
229    /// Returns the hop limit field.
230    ///
231    /// Replaces the time-to-live field in IPv4.
232    ///
233    /// The value is decremented each time the packet is forwarded by a router.
234    ///
235    /// When the value reaches 0, the packet is discarded, unless it has reached its destination.
236    #[inline]
237    pub fn hop_limit(&self) -> u8 {
238        self.bytes[7]
239    }
240
241    /// Returns the source address field.
242    ///
243    /// Unicast IPv6 address of the sender.
244    #[inline]
245    pub fn src_addr(&self) -> &[u8] {
246        &self.bytes[8..24]
247    }
248
249    /// Returns the destination address field.
250    ///
251    /// Unicast or multicast IPv6 address of the intended recipient.
252    #[inline]
253    pub fn dest_addr(&self) -> &[u8] {
254        &self.bytes[24..40]
255    }
256
257    /// Returns the actual header length in bytes.
258    ///
259    /// Does not include extension headers.
260    #[inline]
261    pub fn header_len(&self) -> usize {
262        IPV6_HEADER_LEN
263    }
264
265    /// Returns a reference to the header.
266    #[inline]
267    pub fn header(&self) -> &'a [u8] {
268        &self.bytes[..self.header_len()]
269    }
270
271    /// Returns a reference to the payload.
272    ///
273    /// May contain extension headers.
274    #[inline]
275    pub fn payload(&self) -> &'a [u8] {
276        &self.bytes[self.header_len()..]
277    }
278
279    /// Returns the payload after the extension headers.
280    ///
281    /// This is the encapsulated protocol (e.g. TCP, UDP).
282    #[inline]
283    pub fn upper_layer_payload(&self) -> &'a [u8] {
284        &self.bytes[self.header_len() + self.extension_headers_len..]
285    }
286}
287
288impl fmt::Debug for IPv6Reader<'_> {
289    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
290        let mut s_buf = [0u8; 39];
291        let s_len = bytes_to_ipv6(self.src_addr(), &mut s_buf);
292        let s_hex = from_utf8(&s_buf[..s_len]).unwrap();
293        let mut d_buf = [0u8; 39];
294        let d_len = bytes_to_ipv6(self.dest_addr(), &mut d_buf);
295        let d_hex = from_utf8(&d_buf[..d_len]).unwrap();
296        f.debug_struct("IPv6Packet")
297            .field("version", &self.version())
298            .field("traffic_class", &self.traffic_class())
299            .field("flow_label", &self.flow_label())
300            .field("payload_length", &self.payload_length())
301            .field("next_header", &self.next_header())
302            .field("hop_limit", &self.hop_limit())
303            .field("src_addr", &s_hex)
304            .field("dest_addr", &d_hex)
305            .field("extension_headers", &self.extension_headers)
306            .field("extension_headers_len", &self.extension_headers_len)
307            .finish()
308    }
309}
310
311#[cfg(test)]
312mod tests {
313    use super::*;
314
315    #[test]
316    fn getters_and_setters() {
317        // Raw packet.
318        let mut bytes = [0u8; 40];
319
320        // Random values.
321        let version = 6;
322        let traffic_class = 5;
323        let flow_label = 4;
324        let payload_length = 3;
325        let next_header = 2;
326        let hop_limit = 1;
327        let src_addr = [
328            0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70,
329            0x73, 0x34,
330        ];
331        let dest_addr = [
332            0x20, 0x01, 0x0d, 0xb8, 0x83, 0xa3, 0x00, 0x00, 0x50, 0x00, 0x81, 0x2e, 0x03, 0x70,
333            0x73, 0x32,
334        ];
335
336        // Create a IPv6 packet writer.
337        let mut writer = IPv6Writer::new(&mut bytes).unwrap();
338
339        // Set the fields.
340        writer.set_version(version);
341        writer.set_traffic_class(traffic_class);
342        writer.set_flow_label(flow_label);
343        writer.set_payload_length(payload_length);
344        writer.set_next_header(next_header);
345        writer.set_hop_limit(hop_limit);
346        writer.set_src_addr(&src_addr);
347        writer.set_dest_addr(&dest_addr);
348
349        // Create a IPv6 packet reader.
350        let reader = IPv6Reader::new(&bytes).unwrap();
351
352        // Check the fields.
353        assert_eq!(reader.version(), version);
354        assert_eq!(reader.traffic_class(), traffic_class);
355        assert_eq!(reader.flow_label(), flow_label);
356        assert_eq!(reader.payload_length(), payload_length);
357        assert_eq!(reader.next_header(), next_header);
358        assert_eq!(reader.hop_limit(), hop_limit);
359        assert_eq!(reader.src_addr(), &src_addr);
360        assert_eq!(reader.dest_addr(), &dest_addr);
361    }
362}