xenet_packet/
ipv6.rs

1//! An IPv6 packet abstraction.
2
3use crate::ip::IpNextLevelProtocol;
4
5use alloc::vec::Vec;
6
7use xenet_macro::packet;
8use xenet_macro_helper::types::*;
9
10use std::net::Ipv6Addr;
11
12#[cfg(feature = "serde")]
13use serde::{Deserialize, Serialize};
14
15/// IPv6 Header Length.
16pub const IPV6_HEADER_LEN: usize = MutableIpv6Packet::minimum_packet_size();
17
18/// Represents the IPv6 header.
19#[derive(Clone, Debug, PartialEq, Eq)]
20#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
21pub struct Ipv6Header {
22    pub version: u4,
23    pub traffic_class: u8,
24    pub flow_label: u20be,
25    pub payload_length: u16be,
26    pub next_header: IpNextLevelProtocol,
27    pub hop_limit: u8,
28    pub source: Ipv6Addr,
29    pub destination: Ipv6Addr,
30}
31
32impl Ipv6Header {
33    /// Construct an IPv6 header from a byte slice.
34    pub fn from_bytes(packet: &[u8]) -> Result<Ipv6Header, String> {
35        if packet.len() < IPV6_HEADER_LEN {
36            return Err("Packet is too small for IPv6 header".to_string());
37        }
38        match Ipv6Packet::new(packet) {
39            Some(ipv6_packet) => Ok(Ipv6Header {
40                version: ipv6_packet.get_version(),
41                traffic_class: ipv6_packet.get_traffic_class(),
42                flow_label: ipv6_packet.get_flow_label(),
43                payload_length: ipv6_packet.get_payload_length(),
44                next_header: ipv6_packet.get_next_header(),
45                hop_limit: ipv6_packet.get_hop_limit(),
46                source: ipv6_packet.get_source(),
47                destination: ipv6_packet.get_destination(),
48            }),
49            None => Err("Failed to parse IPv6 packet".to_string()),
50        }
51    }
52    /// Construct an IPv6 header from a Ipv6Packet.
53    pub(crate) fn from_packet(ipv6_packet: &Ipv6Packet) -> Ipv6Header {
54        Ipv6Header {
55            version: ipv6_packet.get_version(),
56            traffic_class: ipv6_packet.get_traffic_class(),
57            flow_label: ipv6_packet.get_flow_label(),
58            payload_length: ipv6_packet.get_payload_length(),
59            next_header: ipv6_packet.get_next_header(),
60            hop_limit: ipv6_packet.get_hop_limit(),
61            source: ipv6_packet.get_source(),
62            destination: ipv6_packet.get_destination(),
63        }
64    }
65}
66
67/// Represents an IPv6 Packet.
68#[packet]
69pub struct Ipv6 {
70    pub version: u4,
71    pub traffic_class: u8,
72    pub flow_label: u20be,
73    pub payload_length: u16be,
74    #[construct_with(u8)]
75    pub next_header: IpNextLevelProtocol,
76    pub hop_limit: u8,
77    #[construct_with(u16, u16, u16, u16, u16, u16, u16, u16)]
78    pub source: Ipv6Addr,
79    #[construct_with(u16, u16, u16, u16, u16, u16, u16, u16)]
80    pub destination: Ipv6Addr,
81    #[length = "payload_length"]
82    #[payload]
83    pub payload: Vec<u8>,
84}
85
86impl<'p> ExtensionIterable<'p> {
87    pub fn new(buf: &[u8]) -> ExtensionIterable {
88        ExtensionIterable { buf: buf }
89    }
90}
91
92/// Represents an IPv6 Extension.
93#[packet]
94pub struct Extension {
95    #[construct_with(u8)]
96    pub next_header: IpNextLevelProtocol,
97    pub hdr_ext_len: u8,
98    #[length_fn = "ipv6_extension_length"]
99    #[payload]
100    pub options: Vec<u8>,
101}
102
103fn ipv6_extension_length(ext: &ExtensionPacket) -> usize {
104    ext.get_hdr_ext_len() as usize * 8 + 8 - 2
105}
106
107/// Represents an IPv6 Hop-by-Hop Options.
108pub type HopByHop = Extension;
109/// A structure enabling manipulation of on the wire packets.
110pub type HopByHopPacket<'p> = ExtensionPacket<'p>;
111/// A structure enabling manipulation of on the wire packets.
112pub type MutableHopByHopPacket<'p> = MutableExtensionPacket<'p>;
113
114/// Represents an IPv6 Routing Extension.
115#[packet]
116pub struct Routing {
117    #[construct_with(u8)]
118    pub next_header: IpNextLevelProtocol,
119    pub hdr_ext_len: u8,
120    pub routing_type: u8,
121    pub segments_left: u8,
122    #[length_fn = "routing_extension_length"]
123    #[payload]
124    pub data: Vec<u8>,
125}
126
127fn routing_extension_length(ext: &RoutingPacket) -> usize {
128    ext.get_hdr_ext_len() as usize * 8 + 8 - 4
129}
130
131/// Represents an IPv6 Fragment Extension.
132#[packet]
133pub struct Fragment {
134    #[construct_with(u8)]
135    pub next_header: IpNextLevelProtocol,
136    pub reserved: u8,
137    pub fragment_offset_with_flags: u16be,
138    pub id: u32be,
139    #[length = "0"]
140    #[payload]
141    pub payload: Vec<u8>,
142}
143
144const FRAGMENT_FLAGS_MASK: u16 = 0x03;
145const FRAGMENT_FLAGS_MORE_FRAGMENTS: u16 = 0x01;
146const FRAGMENT_OFFSET_MASK: u16 = !FRAGMENT_FLAGS_MASK;
147
148impl<'p> FragmentPacket<'p> {
149    pub fn get_fragment_offset(&self) -> u16 {
150        self.get_fragment_offset_with_flags() & FRAGMENT_OFFSET_MASK
151    }
152
153    pub fn is_last_fragment(&self) -> bool {
154        (self.get_fragment_offset_with_flags() & FRAGMENT_FLAGS_MORE_FRAGMENTS) == 0
155    }
156}
157
158impl<'p> MutableFragmentPacket<'p> {
159    pub fn get_fragment_offset(&self) -> u16 {
160        self.get_fragment_offset_with_flags() & FRAGMENT_OFFSET_MASK
161    }
162
163    pub fn is_last_fragment(&self) -> bool {
164        (self.get_fragment_offset_with_flags() & FRAGMENT_FLAGS_MORE_FRAGMENTS) == 0
165    }
166
167    pub fn set_fragment_offset(&mut self, offset: u16) {
168        let fragment_offset_with_flags = self.get_fragment_offset_with_flags();
169
170        self.set_fragment_offset_with_flags(
171            (offset & FRAGMENT_OFFSET_MASK) | (fragment_offset_with_flags & FRAGMENT_FLAGS_MASK),
172        );
173    }
174
175    pub fn set_last_fragment(&mut self, is_last: bool) {
176        let fragment_offset_with_flags = self.get_fragment_offset_with_flags();
177
178        self.set_fragment_offset_with_flags(if is_last {
179            fragment_offset_with_flags & !FRAGMENT_FLAGS_MORE_FRAGMENTS
180        } else {
181            fragment_offset_with_flags | FRAGMENT_FLAGS_MORE_FRAGMENTS
182        });
183    }
184}
185
186/// Represents an Destination Options.
187pub type Destination = Extension;
188/// A structure enabling manipulation of on the wire packets.
189pub type DestinationPacket<'p> = ExtensionPacket<'p>;
190/// A structure enabling manipulation of on the wire packets.
191pub type MutableDestinationPacket<'p> = MutableExtensionPacket<'p>;
192
193#[test]
194fn ipv6_header_test() {
195    use crate::ip::IpNextLevelProtocol;
196    use crate::{MutablePacket, Packet, PacketSize};
197    use alloc::vec;
198
199    let mut packet = [0u8; 0x200];
200    {
201        let mut ip_header = MutableIpv6Packet::new(&mut packet[..]).unwrap();
202        ip_header.set_version(6);
203        assert_eq!(ip_header.get_version(), 6);
204
205        ip_header.set_traffic_class(17);
206        assert_eq!(ip_header.get_traffic_class(), 17);
207
208        ip_header.set_flow_label(0x10101);
209        assert_eq!(ip_header.get_flow_label(), 0x10101);
210
211        ip_header.set_payload_length(0x0101);
212        assert_eq!(ip_header.get_payload_length(), 0x0101);
213        assert_eq!(0x0101, ip_header.payload().len());
214
215        ip_header.set_next_header(IpNextLevelProtocol::Hopopt);
216        assert_eq!(ip_header.get_next_header(), IpNextLevelProtocol::Hopopt);
217
218        ip_header.set_hop_limit(1);
219        assert_eq!(ip_header.get_hop_limit(), 1);
220
221        let source = Ipv6Addr::new(0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001);
222        ip_header.set_source(source);
223        assert_eq!(ip_header.get_source(), source);
224
225        let dest = Ipv6Addr::new(0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001);
226        ip_header.set_destination(dest);
227        assert_eq!(ip_header.get_destination(), dest);
228
229        let mut pos = {
230            let mut hopopt = MutableHopByHopPacket::new(ip_header.payload_mut()).unwrap();
231
232            hopopt.set_next_header(IpNextLevelProtocol::Ipv6Opts);
233            assert_eq!(hopopt.get_next_header(), IpNextLevelProtocol::Ipv6Opts);
234
235            hopopt.set_hdr_ext_len(1);
236            assert_eq!(hopopt.get_hdr_ext_len(), 1);
237
238            hopopt.set_options(&[b'A'; 14][..]);
239            assert_eq!(hopopt.payload(), b"AAAAAAAAAAAAAA");
240
241            hopopt.packet_size()
242        };
243
244        pos += {
245            let mut dstopt =
246                MutableDestinationPacket::new(&mut ip_header.payload_mut()[pos..]).unwrap();
247
248            dstopt.set_next_header(IpNextLevelProtocol::Ipv6Route);
249            assert_eq!(dstopt.get_next_header(), IpNextLevelProtocol::Ipv6Route);
250
251            dstopt.set_hdr_ext_len(1);
252            assert_eq!(dstopt.get_hdr_ext_len(), 1);
253
254            dstopt.set_options(&[b'B'; 14][..]);
255            assert_eq!(dstopt.payload(), b"BBBBBBBBBBBBBB");
256
257            dstopt.packet_size()
258        };
259
260        pos += {
261            let mut routing =
262                MutableRoutingPacket::new(&mut ip_header.payload_mut()[pos..]).unwrap();
263
264            routing.set_next_header(IpNextLevelProtocol::Ipv6Frag);
265            assert_eq!(routing.get_next_header(), IpNextLevelProtocol::Ipv6Frag);
266
267            routing.set_hdr_ext_len(1);
268            assert_eq!(routing.get_hdr_ext_len(), 1);
269
270            routing.set_routing_type(4);
271            assert_eq!(routing.get_routing_type(), 4);
272
273            routing.set_segments_left(2);
274            assert_eq!(routing.get_segments_left(), 2);
275
276            routing.set_data(&[b'C'; 12][..]);
277            assert_eq!(routing.payload(), b"CCCCCCCCCCCC");
278
279            routing.packet_size()
280        };
281
282        pos += {
283            let mut frag = MutableFragmentPacket::new(&mut ip_header.payload_mut()[pos..]).unwrap();
284
285            frag.set_next_header(IpNextLevelProtocol::Udp);
286            assert_eq!(frag.get_next_header(), IpNextLevelProtocol::Udp);
287
288            frag.set_fragment_offset(1024);
289            assert_eq!(frag.get_fragment_offset(), 1024);
290
291            frag.set_last_fragment(false);
292            assert!(!frag.is_last_fragment());
293
294            frag.set_id(1234);
295            assert_eq!(frag.get_id(), 1234);
296
297            frag.packet_size()
298        };
299
300        assert_eq!(
301            ExtensionIterable::new(&ip_header.payload()[..pos])
302                .map(|ext| (
303                    ext.get_next_header(),
304                    ext.get_hdr_ext_len(),
305                    ext.packet_size()
306                ))
307                .collect::<Vec<_>>(),
308            vec![
309                (IpNextLevelProtocol::Ipv6Opts, 1, 16),
310                (IpNextLevelProtocol::Ipv6Route, 1, 16),
311                (IpNextLevelProtocol::Ipv6Frag, 1, 16),
312                (IpNextLevelProtocol::Udp, 0, 8),
313            ]
314        );
315    }
316
317    let ref_packet = [
318        0x61, /* ver/traffic class */
319        0x11, /* traffic class/flow label */
320        0x01, 0x01, /* flow label */
321        0x01, 0x01, /* payload length */
322        0x00, /* next header */
323        0x01, /* hop limit */
324        /* source ip */
325        0x01, 0x10, 0x10, 0x01, 0x01, 0x10, 0x10, 0x01, 0x01, 0x10, 0x10, 0x01, 0x01, 0x10, 0x10,
326        0x01, /* dest ip */
327        0x01, 0x10, 0x10, 0x01, 0x01, 0x10, 0x10, 0x01, 0x01, 0x10, 0x10, 0x01, 0x01, 0x10, 0x10,
328        0x01, /* Hop-by-Hop Options */
329        0x3c, // Next Header
330        0x01, // Hdr Ext Len
331        b'A', b'A', b'A', b'A', b'A', b'A', b'A', b'A', b'A', b'A', b'A', b'A', b'A', b'A',
332        /* Destination Options */
333        0x2b, // Next Header
334        0x01, // Hdr Ext Len
335        b'B', b'B', b'B', b'B', b'B', b'B', b'B', b'B', b'B', b'B', b'B', b'B', b'B', b'B',
336        /* Routing */
337        0x2c, // Next Header
338        0x01, // Hdr Ext Len
339        0x04, // Routing Type
340        0x02, // Segments Left
341        b'C', b'C', b'C', b'C', b'C', b'C', b'C', b'C', b'C', b'C', b'C', b'C',
342        /* Fragment */
343        0x11, // Next Header
344        0x00, // Reserved
345        0x04, 0x01, // Fragment Offset
346        0x00, 0x00, 0x04, 0xd2, // Identification
347    ];
348    assert_eq!(&ref_packet[..], &packet[..ref_packet.len()]);
349}