rpkt/ipv6/
mod.rs

1use std::fmt;
2
3use byteorder::{ByteOrder, NetworkEndian};
4
5use crate::ipv4::Ipv4Addr;
6
7// A full implementation of IPv6 includes implementation of the
8//    following extension headers:
9
10//       Hop-by-Hop Options
11//       Fragment
12//       Destination Options
13//       Routing
14//       Authentication
15//       Encapsulating Security Payload
16
17//    The first four are specified in this document (RFC8200); the last two are
18//    specified in [RFC4302] and [RFC4303], respectively.  The current list
19//    of IPv6 extension headers can be found at [IANA-EH].
20
21/// A sixteen-octet IPv6 address.
22#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
23pub struct Ipv6Addr(pub [u8; 16]);
24
25impl Ipv6Addr {
26    pub const UNSPECIFIED: Ipv6Addr = Ipv6Addr([0x00; 16]);
27
28    pub const LINK_LOCAL_ALL_NODES: Ipv6Addr = Ipv6Addr([
29        0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30        0x01,
31    ]);
32
33    pub const LINK_LOCAL_ALL_ROUTERS: Ipv6Addr = Ipv6Addr([
34        0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35        0x02,
36    ]);
37
38    pub const LOOPBACK: Ipv6Addr = Ipv6Addr([
39        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40        0x01,
41    ]);
42
43    const IPV4_MAPPED_PREFIX: [u8; 16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0];
44
45    pub const fn new(
46        a0: u16,
47        a1: u16,
48        a2: u16,
49        a3: u16,
50        a4: u16,
51        a5: u16,
52        a6: u16,
53        a7: u16,
54    ) -> Ipv6Addr {
55        Ipv6Addr([
56            (a0 >> 8) as u8,
57            a0 as u8,
58            (a1 >> 8) as u8,
59            a1 as u8,
60            (a2 >> 8) as u8,
61            a2 as u8,
62            (a3 >> 8) as u8,
63            a3 as u8,
64            (a4 >> 8) as u8,
65            a4 as u8,
66            (a5 >> 8) as u8,
67            a5 as u8,
68            (a6 >> 8) as u8,
69            a6 as u8,
70            (a7 >> 8) as u8,
71            a7 as u8,
72        ])
73    }
74
75    pub fn from_bytes(data: &[u8]) -> Ipv6Addr {
76        let mut bytes = [0; 16];
77        bytes.copy_from_slice(data);
78        Ipv6Addr(bytes)
79    }
80
81    pub fn from_parts(data: &[u16]) -> Ipv6Addr {
82        assert!(data.len() >= 8);
83        let mut bytes = [0; 16];
84        for (word_idx, chunk) in bytes.chunks_mut(2).enumerate() {
85            NetworkEndian::write_u16(chunk, data[word_idx]);
86        }
87        Ipv6Addr(bytes)
88    }
89
90    pub fn write_parts(&self, data: &mut [u16]) {
91        assert!(data.len() >= 8);
92        for (i, chunk) in self.0.chunks(2).enumerate() {
93            data[i] = NetworkEndian::read_u16(chunk);
94        }
95    }
96
97    pub const fn as_bytes(&self) -> &[u8] {
98        &self.0
99    }
100
101    pub fn is_unicast(&self) -> bool {
102        !(self.is_multicast() || self.is_unspecified())
103    }
104
105    pub const fn is_multicast(&self) -> bool {
106        self.0[0] == 0xff
107    }
108
109    pub fn is_unspecified(&self) -> bool {
110        *self == Self::UNSPECIFIED
111    }
112
113    pub fn is_link_local(&self) -> bool {
114        self.0[0..8] == [0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
115    }
116
117    pub fn is_loopback(&self) -> bool {
118        *self == Self::LOOPBACK
119    }
120
121    pub fn is_ipv4_mapped(&self) -> bool {
122        self.0[..12] == Self::IPV4_MAPPED_PREFIX[..12]
123    }
124
125    pub fn as_ipv4(&self) -> Option<Ipv4Addr> {
126        if self.is_ipv4_mapped() {
127            Some(Ipv4Addr::from_bytes(&self.0[12..]))
128        } else {
129            None
130        }
131    }
132
133    pub fn solicited_node(&self) -> Ipv6Addr {
134        assert!(self.is_unicast());
135        Ipv6Addr([
136            0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF,
137            self.0[13], self.0[14], self.0[15],
138        ])
139    }
140}
141
142impl From<::std::net::Ipv6Addr> for Ipv6Addr {
143    fn from(x: ::std::net::Ipv6Addr) -> Ipv6Addr {
144        Ipv6Addr(x.octets())
145    }
146}
147
148impl From<Ipv6Addr> for ::std::net::Ipv6Addr {
149    fn from(x: Ipv6Addr) -> ::std::net::Ipv6Addr {
150        x.into()
151    }
152}
153
154impl From<Ipv4Addr> for Ipv6Addr {
155    fn from(x: Ipv4Addr) -> Ipv6Addr {
156        let mut bytes = Self::IPV4_MAPPED_PREFIX;
157        (&mut bytes[12..16]).copy_from_slice(x.as_bytes());
158        Ipv6Addr(bytes)
159    }
160}
161
162impl fmt::Display for Ipv6Addr {
163    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164        if self.is_ipv4_mapped() {
165            return write!(
166                f,
167                "::ffff:{}.{}.{}.{}",
168                self.0[12 + 0],
169                self.0[12 + 1],
170                self.0[12 + 2],
171                self.0[12 + 3]
172            );
173        }
174
175        // See https://tools.ietf.org/html/rfc4291#section-2.2
176        enum State {
177            Head,
178            HeadBody,
179            Tail,
180            TailBody,
181        }
182        let mut words = [0u16; 8];
183        self.write_parts(&mut words);
184        let mut state = State::Head;
185        for word in words.iter() {
186            state = match (*word, &state) {
187                // Once a u16 equal to zero write a double colon and
188                // skip to the next non-zero u16.
189                (0, &State::Head) | (0, &State::HeadBody) => {
190                    write!(f, "::")?;
191                    State::Tail
192                }
193                // Continue iterating without writing any characters until
194                // we hit a non-zero value.
195                (0, &State::Tail) => State::Tail,
196                // When the state is Head or Tail write a u16 in hexadecimal
197                // without the leading colon if the value is not 0.
198                (_, &State::Head) => {
199                    write!(f, "{word:x}")?;
200                    State::HeadBody
201                }
202                (_, &State::Tail) => {
203                    write!(f, "{word:x}")?;
204                    State::TailBody
205                }
206                // Write the u16 with a leading colon when parsing a value
207                // that isn't the first in a section
208                (_, &State::HeadBody) | (_, &State::TailBody) => {
209                    write!(f, ":{word:x}")?;
210                    state
211                }
212            }
213        }
214        Ok(())
215    }
216}
217
218mod header;
219pub use header::{Ipv6Header, IPV6_HEADER_LEN};
220
221mod packet;
222pub use packet::Ipv6Packet;
223
224pub mod extentions;