libpacket/
ipv6.rs

1// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! An IPv6 packet abstraction.
10
11use crate::ip::IpNextHeaderProtocol;
12use crate::{types::*, Packet};
13use std::net::Ipv6Addr;
14
15/// Represents an IPv6 Packet.
16#[derive(Debug, Packet)]
17pub struct Ipv6 {
18    pub version: u4,
19    pub traffic_class: u8,
20    pub flow_label: u20be,
21    pub payload_length: u16be,
22    #[construct_with(u8)]
23    pub next_header: IpNextHeaderProtocol,
24    pub hop_limit: u8,
25    #[construct_with(u16, u16, u16, u16, u16, u16, u16, u16)]
26    pub source: Ipv6Addr,
27    #[construct_with(u16, u16, u16, u16, u16, u16, u16, u16)]
28    pub destination: Ipv6Addr,
29    #[length = "payload_length"]
30    #[payload]
31    pub payload: Vec<u8>,
32}
33
34impl<'p> ExtensionIterable<'p> {
35    pub fn new(buf: &[u8]) -> ExtensionIterable {
36        ExtensionIterable { buf: buf }
37    }
38}
39
40/// Represents an IPv6 Extension.
41#[derive(Debug, Packet)]
42pub struct Extension {
43    #[construct_with(u8)]
44    pub next_header: IpNextHeaderProtocol,
45    pub hdr_ext_len: u8,
46    #[length = "ipv6_extension_length(hdr_ext_len)"]
47    #[payload]
48    pub options: Vec<u8>,
49}
50
51fn ipv6_extension_length(hdr_ext_len: u8) -> usize {
52    hdr_ext_len as usize * 8 + 8 - 2
53}
54
55/// Represents an IPv6 Hop-by-Hop Options.
56pub type HopByHop = Extension;
57/// A structure enabling manipulation of on the wire packets.
58pub type HopByHopPacket<'p> = ExtensionPacket<'p>;
59/// A structure enabling manipulation of on the wire packets.
60pub type MutableHopByHopPacket<'p> = MutableExtensionPacket<'p>;
61
62/// Represents an IPv6 Routing Extension.
63#[derive(Debug, Packet)]
64pub struct Routing {
65    #[construct_with(u8)]
66    pub next_header: IpNextHeaderProtocol,
67    pub hdr_ext_len: u8,
68    pub routing_type: u8,
69    pub segments_left: u8,
70    #[length = "routing_extension_length(hdr_ext_len)"]
71    #[payload]
72    pub data: Vec<u8>,
73}
74
75fn routing_extension_length(hdr_ext_len: u8) -> usize {
76    hdr_ext_len as usize * 8 + 8 - 4
77}
78
79/// Represents an IPv6 Fragment Extension.
80#[derive(Debug, Packet)]
81pub struct Fragment {
82    #[construct_with(u8)]
83    pub next_header: IpNextHeaderProtocol,
84    pub reserved: u8,
85    pub fragment_offset_with_flags: u16be,
86    pub id: u32be,
87    #[length = "0"]
88    #[payload]
89    pub payload: Vec<u8>,
90}
91
92const FRAGMENT_FLAGS_MASK: u16 = 0x03;
93const FRAGMENT_FLAGS_MORE_FRAGMENTS: u16 = 0x01;
94const FRAGMENT_OFFSET_MASK: u16 = !FRAGMENT_FLAGS_MASK;
95
96impl<'p> FragmentPacket<'p> {
97    pub fn get_fragment_offset(&self) -> u16 {
98        self.get_fragment_offset_with_flags() & FRAGMENT_OFFSET_MASK
99    }
100
101    pub fn is_last_fragment(&self) -> bool {
102        (self.get_fragment_offset_with_flags() & FRAGMENT_FLAGS_MORE_FRAGMENTS) == 0
103    }
104}
105
106impl<'p> MutableFragmentPacket<'p> {
107    pub fn get_fragment_offset(&self) -> u16 {
108        self.get_fragment_offset_with_flags() & FRAGMENT_OFFSET_MASK
109    }
110
111    pub fn is_last_fragment(&self) -> bool {
112        (self.get_fragment_offset_with_flags() & FRAGMENT_FLAGS_MORE_FRAGMENTS) == 0
113    }
114
115    pub fn set_fragment_offset(&mut self, offset: u16) {
116        let fragment_offset_with_flags = self.get_fragment_offset_with_flags();
117
118        self.set_fragment_offset_with_flags(
119            (offset & FRAGMENT_OFFSET_MASK) | (fragment_offset_with_flags & FRAGMENT_FLAGS_MASK),
120        );
121    }
122
123    pub fn set_last_fragment(&mut self, is_last: bool) {
124        let fragment_offset_with_flags = self.get_fragment_offset_with_flags();
125
126        self.set_fragment_offset_with_flags(if is_last {
127            fragment_offset_with_flags & !FRAGMENT_FLAGS_MORE_FRAGMENTS
128        } else {
129            fragment_offset_with_flags | FRAGMENT_FLAGS_MORE_FRAGMENTS
130        });
131    }
132}
133
134/// Represents an Destination Options.
135pub type Destination = Extension;
136/// A structure enabling manipulation of on the wire packets.
137pub type DestinationPacket<'p> = ExtensionPacket<'p>;
138/// A structure enabling manipulation of on the wire packets.
139pub type MutableDestinationPacket<'p> = MutableExtensionPacket<'p>;
140
141#[test]
142fn ipv6_header_test() {
143    use crate::ip::IpNextHeaderProtocols;
144    use crate::{MutablePacket, Packet, PacketSize};
145
146    let mut packet = [0u8; 0x200];
147    {
148        let mut ip_header = MutableIpv6Packet::new(&mut packet[..]).unwrap();
149        ip_header.set_version(6);
150        assert_eq!(ip_header.get_version(), 6);
151
152        ip_header.set_traffic_class(17);
153        assert_eq!(ip_header.get_traffic_class(), 17);
154
155        ip_header.set_flow_label(0x10101);
156        assert_eq!(ip_header.get_flow_label(), 0x10101);
157
158        ip_header.set_payload_length(0x0101);
159        assert_eq!(ip_header.get_payload_length(), 0x0101);
160        assert_eq!(0x0101, ip_header.payload().len());
161
162        ip_header.set_next_header(IpNextHeaderProtocols::Hopopt);
163        assert_eq!(ip_header.get_next_header(), IpNextHeaderProtocols::Hopopt);
164
165        ip_header.set_hop_limit(1);
166        assert_eq!(ip_header.get_hop_limit(), 1);
167
168        let source = Ipv6Addr::new(0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001);
169        ip_header.set_source(source);
170        assert_eq!(ip_header.get_source(), source);
171
172        let dest = Ipv6Addr::new(0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001);
173        ip_header.set_destination(dest);
174        assert_eq!(ip_header.get_destination(), dest);
175
176        let mut pos = {
177            let mut hopopt = MutableHopByHopPacket::new(ip_header.payload_mut()).unwrap();
178
179            hopopt.set_next_header(IpNextHeaderProtocols::Ipv6Opts);
180            assert_eq!(hopopt.get_next_header(), IpNextHeaderProtocols::Ipv6Opts);
181
182            hopopt.set_hdr_ext_len(1);
183            assert_eq!(hopopt.get_hdr_ext_len(), 1);
184
185            hopopt.set_options(&[b'A'; 14][..]);
186            assert_eq!(hopopt.payload(), b"AAAAAAAAAAAAAA");
187
188            hopopt.packet_size()
189        };
190
191        pos += {
192            let mut dstopt =
193                MutableDestinationPacket::new(&mut ip_header.payload_mut()[pos..]).unwrap();
194
195            dstopt.set_next_header(IpNextHeaderProtocols::Ipv6Route);
196            assert_eq!(dstopt.get_next_header(), IpNextHeaderProtocols::Ipv6Route);
197
198            dstopt.set_hdr_ext_len(1);
199            assert_eq!(dstopt.get_hdr_ext_len(), 1);
200
201            dstopt.set_options(&[b'B'; 14][..]);
202            assert_eq!(dstopt.payload(), b"BBBBBBBBBBBBBB");
203
204            dstopt.packet_size()
205        };
206
207        pos += {
208            let mut routing =
209                MutableRoutingPacket::new(&mut ip_header.payload_mut()[pos..]).unwrap();
210
211            routing.set_next_header(IpNextHeaderProtocols::Ipv6Frag);
212            assert_eq!(routing.get_next_header(), IpNextHeaderProtocols::Ipv6Frag);
213
214            routing.set_hdr_ext_len(1);
215            assert_eq!(routing.get_hdr_ext_len(), 1);
216
217            routing.set_routing_type(4);
218            assert_eq!(routing.get_routing_type(), 4);
219
220            routing.set_segments_left(2);
221            assert_eq!(routing.get_segments_left(), 2);
222
223            routing.set_data(&[b'C'; 12][..]);
224            assert_eq!(routing.payload(), b"CCCCCCCCCCCC");
225
226            routing.packet_size()
227        };
228
229        pos += {
230            let mut frag = MutableFragmentPacket::new(&mut ip_header.payload_mut()[pos..]).unwrap();
231
232            frag.set_next_header(IpNextHeaderProtocols::Udp);
233            assert_eq!(frag.get_next_header(), IpNextHeaderProtocols::Udp);
234
235            frag.set_fragment_offset(1024);
236            assert_eq!(frag.get_fragment_offset(), 1024);
237
238            frag.set_last_fragment(false);
239            assert!(!frag.is_last_fragment());
240
241            frag.set_id(1234);
242            assert_eq!(frag.get_id(), 1234);
243
244            frag.packet_size()
245        };
246
247        assert_eq!(
248            ExtensionIterable::new(&ip_header.payload()[..pos])
249                .map(|ext| (
250                    ext.get_next_header(),
251                    ext.get_hdr_ext_len(),
252                    ext.packet_size()
253                ))
254                .collect::<Vec<_>>(),
255            vec![
256                (IpNextHeaderProtocols::Ipv6Opts, 1, 16),
257                (IpNextHeaderProtocols::Ipv6Route, 1, 16),
258                (IpNextHeaderProtocols::Ipv6Frag, 1, 16),
259                (IpNextHeaderProtocols::Udp, 0, 8),
260            ]
261        );
262    }
263
264    let ref_packet = [
265        0x61, /* ver/traffic class */
266        0x11, /* traffic class/flow label */
267        0x01, 0x01, /* flow label */
268        0x01, 0x01, /* payload length */
269        0x00, /* next header */
270        0x01, /* hop limit */
271        /* source ip */
272        0x01, 0x10, 0x10, 0x01, 0x01, 0x10, 0x10, 0x01, 0x01, 0x10, 0x10, 0x01, 0x01, 0x10, 0x10,
273        0x01, /* dest ip */
274        0x01, 0x10, 0x10, 0x01, 0x01, 0x10, 0x10, 0x01, 0x01, 0x10, 0x10, 0x01, 0x01, 0x10, 0x10,
275        0x01, /* Hop-by-Hop Options */
276        0x3c, // Next Header
277        0x01, // Hdr Ext Len
278        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',
279        /* Destination Options */
280        0x2b, // Next Header
281        0x01, // Hdr Ext Len
282        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',
283        /* Routing */
284        0x2c, // Next Header
285        0x01, // Hdr Ext Len
286        0x04, // Routing Type
287        0x02, // Segments Left
288        b'C', b'C', b'C', b'C', b'C', b'C', b'C', b'C', b'C', b'C', b'C', b'C',
289        /* Fragment */
290        0x11, // Next Header
291        0x00, // Reserved
292        0x04, 0x01, // Fragment Offset
293        0x00, 0x00, 0x04, 0xd2, // Identification
294    ];
295    assert_eq!(&ref_packet[..], &packet[..ref_packet.len()]);
296}