1 #![deny(missing_docs)] 2 3 use byteorder::{ByteOrder, NetworkEndian}; 4 use core::fmt; 5 6 use super::{Error, Result}; 7 use crate::wire::ip::pretty_print_ip_payload; 8 #[cfg(feature = "proto-ipv4")] 9 use crate::wire::ipv4; 10 11 pub use super::IpProtocol as Protocol; 12 13 /// Minimum MTU required of all links supporting IPv6. See [RFC 8200 § 5]. 14 /// 15 /// [RFC 8200 § 5]: https://tools.ietf.org/html/rfc8200#section-5 16 pub const MIN_MTU: usize = 1280; 17 18 /// Size of IPv6 adderess in octets. 19 /// 20 /// [RFC 8200 § 2]: https://www.rfc-editor.org/rfc/rfc4291#section-2 21 pub const ADDR_SIZE: usize = 16; 22 23 /// Size of IPv4-mapping prefix in octets. 24 /// 25 /// [RFC 8200 § 2]: https://www.rfc-editor.org/rfc/rfc4291#section-2 26 pub const IPV4_MAPPED_PREFIX_SIZE: usize = ADDR_SIZE - 4; // 4 == ipv4::ADDR_SIZE , cannot DRY here because of dependency on a IPv4 module which is behind the feature 27 28 /// A sixteen-octet IPv6 address. 29 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)] 30 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 31 pub struct Address(pub [u8; ADDR_SIZE]); 32 33 impl Address { 34 /// The [unspecified address]. 35 /// 36 /// [unspecified address]: https://tools.ietf.org/html/rfc4291#section-2.5.2 37 pub const UNSPECIFIED: Address = Address([0x00; ADDR_SIZE]); 38 39 /// The link-local [all nodes multicast address]. 40 /// 41 /// [all nodes multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7.1 42 pub const LINK_LOCAL_ALL_NODES: Address = Address([ 43 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 44 0x01, 45 ]); 46 47 /// The link-local [all routers multicast address]. 48 /// 49 /// [all routers multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7.1 50 pub const LINK_LOCAL_ALL_ROUTERS: Address = Address([ 51 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 52 0x02, 53 ]); 54 55 /// The [loopback address]. 56 /// 57 /// [loopback address]: https://tools.ietf.org/html/rfc4291#section-2.5.3 58 pub const LOOPBACK: Address = Address([ 59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60 0x01, 61 ]); 62 63 /// The prefix used in [IPv4-mapped addresses]. 64 /// 65 /// [IPv4-mapped addresses]: https://www.rfc-editor.org/rfc/rfc4291#section-2.5.5.2 66 pub const IPV4_MAPPED_PREFIX: [u8; IPV4_MAPPED_PREFIX_SIZE] = 67 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff]; 68 69 /// Construct an IPv6 address from parts. 70 #[allow(clippy::too_many_arguments)] new( a0: u16, a1: u16, a2: u16, a3: u16, a4: u16, a5: u16, a6: u16, a7: u16, ) -> Address71 pub const fn new( 72 a0: u16, 73 a1: u16, 74 a2: u16, 75 a3: u16, 76 a4: u16, 77 a5: u16, 78 a6: u16, 79 a7: u16, 80 ) -> Address { 81 Address([ 82 (a0 >> 8) as u8, 83 a0 as u8, 84 (a1 >> 8) as u8, 85 a1 as u8, 86 (a2 >> 8) as u8, 87 a2 as u8, 88 (a3 >> 8) as u8, 89 a3 as u8, 90 (a4 >> 8) as u8, 91 a4 as u8, 92 (a5 >> 8) as u8, 93 a5 as u8, 94 (a6 >> 8) as u8, 95 a6 as u8, 96 (a7 >> 8) as u8, 97 a7 as u8, 98 ]) 99 } 100 101 /// Construct an IPv6 address from a sequence of octets, in big-endian. 102 /// 103 /// # Panics 104 /// The function panics if `data` is not sixteen octets long. from_bytes(data: &[u8]) -> Address105 pub fn from_bytes(data: &[u8]) -> Address { 106 let mut bytes = [0; ADDR_SIZE]; 107 bytes.copy_from_slice(data); 108 Address(bytes) 109 } 110 111 /// Construct an IPv6 address from a sequence of words, in big-endian. 112 /// 113 /// # Panics 114 /// The function panics if `data` is not 8 words long. from_parts(data: &[u16]) -> Address115 pub fn from_parts(data: &[u16]) -> Address { 116 assert!(data.len() >= 8); 117 let mut bytes = [0; ADDR_SIZE]; 118 for (word_idx, chunk) in bytes.chunks_mut(2).enumerate() { 119 NetworkEndian::write_u16(chunk, data[word_idx]); 120 } 121 Address(bytes) 122 } 123 124 /// Write a IPv6 address to the given slice. 125 /// 126 /// # Panics 127 /// The function panics if `data` is not 8 words long. write_parts(&self, data: &mut [u16])128 pub fn write_parts(&self, data: &mut [u16]) { 129 assert!(data.len() >= 8); 130 for (i, chunk) in self.0.chunks(2).enumerate() { 131 data[i] = NetworkEndian::read_u16(chunk); 132 } 133 } 134 135 /// Return an IPv6 address as a sequence of octets, in big-endian. as_bytes(&self) -> &[u8]136 pub const fn as_bytes(&self) -> &[u8] { 137 &self.0 138 } 139 140 /// Query whether the IPv6 address is an [unicast address]. 141 /// 142 /// [unicast address]: https://tools.ietf.org/html/rfc4291#section-2.5 is_unicast(&self) -> bool143 pub fn is_unicast(&self) -> bool { 144 !(self.is_multicast() || self.is_unspecified()) 145 } 146 147 /// Query whether the IPv6 address is a [multicast address]. 148 /// 149 /// [multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7 is_multicast(&self) -> bool150 pub const fn is_multicast(&self) -> bool { 151 self.0[0] == 0xff 152 } 153 154 /// Query whether the IPv6 address is the [unspecified address]. 155 /// 156 /// [unspecified address]: https://tools.ietf.org/html/rfc4291#section-2.5.2 is_unspecified(&self) -> bool157 pub fn is_unspecified(&self) -> bool { 158 self.0 == [0x00; ADDR_SIZE] 159 } 160 161 /// Query whether the IPv6 address is in the [link-local] scope. 162 /// 163 /// [link-local]: https://tools.ietf.org/html/rfc4291#section-2.5.6 is_link_local(&self) -> bool164 pub fn is_link_local(&self) -> bool { 165 self.0[0..8] == [0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 166 } 167 168 /// Query whether the IPv6 address is the [loopback address]. 169 /// 170 /// [loopback address]: https://tools.ietf.org/html/rfc4291#section-2.5.3 is_loopback(&self) -> bool171 pub fn is_loopback(&self) -> bool { 172 *self == Self::LOOPBACK 173 } 174 175 /// Query whether the IPv6 address is an [IPv4 mapped IPv6 address]. 176 /// 177 /// [IPv4 mapped IPv6 address]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 is_ipv4_mapped(&self) -> bool178 pub fn is_ipv4_mapped(&self) -> bool { 179 self.0[..IPV4_MAPPED_PREFIX_SIZE] == Self::IPV4_MAPPED_PREFIX 180 } 181 182 #[cfg(feature = "proto-ipv4")] 183 /// Convert an IPv4 mapped IPv6 address to an IPv4 address. as_ipv4(&self) -> Option<ipv4::Address>184 pub fn as_ipv4(&self) -> Option<ipv4::Address> { 185 if self.is_ipv4_mapped() { 186 Some(ipv4::Address::from_bytes( 187 &self.0[IPV4_MAPPED_PREFIX_SIZE..], 188 )) 189 } else { 190 None 191 } 192 } 193 194 /// Helper function used to mask an address given a prefix. 195 /// 196 /// # Panics 197 /// This function panics if `mask` is greater than 128. mask(&self, mask: u8) -> [u8; ADDR_SIZE]198 pub(super) fn mask(&self, mask: u8) -> [u8; ADDR_SIZE] { 199 assert!(mask <= 128); 200 let mut bytes = [0u8; ADDR_SIZE]; 201 let idx = (mask as usize) / 8; 202 let modulus = (mask as usize) % 8; 203 let (first, second) = self.0.split_at(idx); 204 bytes[0..idx].copy_from_slice(first); 205 if idx < ADDR_SIZE { 206 let part = second[0]; 207 bytes[idx] = part & (!(0xff >> modulus) as u8); 208 } 209 bytes 210 } 211 212 /// The solicited node for the given unicast address. 213 /// 214 /// # Panics 215 /// This function panics if the given address is not 216 /// unicast. solicited_node(&self) -> Address217 pub fn solicited_node(&self) -> Address { 218 assert!(self.is_unicast()); 219 Address([ 220 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 221 self.0[13], self.0[14], self.0[15], 222 ]) 223 } 224 225 /// Convert to an `IpAddress`. 226 /// 227 /// Same as `.into()`, but works in `const`. into_address(self) -> super::IpAddress228 pub const fn into_address(self) -> super::IpAddress { 229 super::IpAddress::Ipv6(self) 230 } 231 } 232 233 #[cfg(feature = "std")] 234 impl From<::std::net::Ipv6Addr> for Address { from(x: ::std::net::Ipv6Addr) -> Address235 fn from(x: ::std::net::Ipv6Addr) -> Address { 236 Address(x.octets()) 237 } 238 } 239 240 #[cfg(feature = "std")] 241 impl From<Address> for ::std::net::Ipv6Addr { from(Address(x): Address) -> ::std::net::Ipv6Addr242 fn from(Address(x): Address) -> ::std::net::Ipv6Addr { 243 x.into() 244 } 245 } 246 247 impl fmt::Display for Address { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result248 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 249 if self.is_ipv4_mapped() { 250 return write!( 251 f, 252 "::ffff:{}.{}.{}.{}", 253 self.0[IPV4_MAPPED_PREFIX_SIZE + 0], 254 self.0[IPV4_MAPPED_PREFIX_SIZE + 1], 255 self.0[IPV4_MAPPED_PREFIX_SIZE + 2], 256 self.0[IPV4_MAPPED_PREFIX_SIZE + 3] 257 ); 258 } 259 260 // The string representation of an IPv6 address should 261 // collapse a series of 16 bit sections that evaluate 262 // to 0 to "::" 263 // 264 // See https://tools.ietf.org/html/rfc4291#section-2.2 265 // for details. 266 enum State { 267 Head, 268 HeadBody, 269 Tail, 270 TailBody, 271 } 272 let mut words = [0u16; 8]; 273 self.write_parts(&mut words); 274 let mut state = State::Head; 275 for word in words.iter() { 276 state = match (*word, &state) { 277 // Once a u16 equal to zero write a double colon and 278 // skip to the next non-zero u16. 279 (0, &State::Head) | (0, &State::HeadBody) => { 280 write!(f, "::")?; 281 State::Tail 282 } 283 // Continue iterating without writing any characters until 284 // we hit a non-zero value. 285 (0, &State::Tail) => State::Tail, 286 // When the state is Head or Tail write a u16 in hexadecimal 287 // without the leading colon if the value is not 0. 288 (_, &State::Head) => { 289 write!(f, "{word:x}")?; 290 State::HeadBody 291 } 292 (_, &State::Tail) => { 293 write!(f, "{word:x}")?; 294 State::TailBody 295 } 296 // Write the u16 with a leading colon when parsing a value 297 // that isn't the first in a section 298 (_, &State::HeadBody) | (_, &State::TailBody) => { 299 write!(f, ":{word:x}")?; 300 state 301 } 302 } 303 } 304 Ok(()) 305 } 306 } 307 308 #[cfg(feature = "proto-ipv4")] 309 /// Convert the given IPv4 address into a IPv4-mapped IPv6 address 310 impl From<ipv4::Address> for Address { from(address: ipv4::Address) -> Self311 fn from(address: ipv4::Address) -> Self { 312 let mut b = [0_u8; ADDR_SIZE]; 313 b[..Self::IPV4_MAPPED_PREFIX.len()].copy_from_slice(&Self::IPV4_MAPPED_PREFIX); 314 b[Self::IPV4_MAPPED_PREFIX.len()..].copy_from_slice(&address.0); 315 Self(b) 316 } 317 } 318 319 /// A specification of an IPv6 CIDR block, containing an address and a variable-length 320 /// subnet masking prefix length. 321 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)] 322 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 323 pub struct Cidr { 324 address: Address, 325 prefix_len: u8, 326 } 327 328 impl Cidr { 329 /// The [solicited node prefix]. 330 /// 331 /// [solicited node prefix]: https://tools.ietf.org/html/rfc4291#section-2.7.1 332 pub const SOLICITED_NODE_PREFIX: Cidr = Cidr { 333 address: Address([ 334 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 335 0x00, 0x00, 336 ]), 337 prefix_len: 104, 338 }; 339 340 /// Create an IPv6 CIDR block from the given address and prefix length. 341 /// 342 /// # Panics 343 /// This function panics if the prefix length is larger than 128. new(address: Address, prefix_len: u8) -> Cidr344 pub const fn new(address: Address, prefix_len: u8) -> Cidr { 345 assert!(prefix_len <= 128); 346 Cidr { 347 address, 348 prefix_len, 349 } 350 } 351 352 /// Return the address of this IPv6 CIDR block. address(&self) -> Address353 pub const fn address(&self) -> Address { 354 self.address 355 } 356 357 /// Return the prefix length of this IPv6 CIDR block. prefix_len(&self) -> u8358 pub const fn prefix_len(&self) -> u8 { 359 self.prefix_len 360 } 361 362 /// Query whether the subnetwork described by this IPv6 CIDR block contains 363 /// the given address. contains_addr(&self, addr: &Address) -> bool364 pub fn contains_addr(&self, addr: &Address) -> bool { 365 // right shift by 128 is not legal 366 if self.prefix_len == 0 { 367 return true; 368 } 369 370 self.address.mask(self.prefix_len) == addr.mask(self.prefix_len) 371 } 372 373 /// Query whether the subnetwork described by this IPV6 CIDR block contains 374 /// the subnetwork described by the given IPv6 CIDR block. contains_subnet(&self, subnet: &Cidr) -> bool375 pub fn contains_subnet(&self, subnet: &Cidr) -> bool { 376 self.prefix_len <= subnet.prefix_len && self.contains_addr(&subnet.address) 377 } 378 } 379 380 impl fmt::Display for Cidr { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result381 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 382 // https://tools.ietf.org/html/rfc4291#section-2.3 383 write!(f, "{}/{}", self.address, self.prefix_len) 384 } 385 } 386 387 /// A read/write wrapper around an Internet Protocol version 6 packet buffer. 388 #[derive(Debug, PartialEq, Eq, Clone)] 389 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 390 pub struct Packet<T: AsRef<[u8]>> { 391 buffer: T, 392 } 393 394 // Ranges and constants describing the IPv6 header 395 // 396 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 397 // |Version| Traffic Class | Flow Label | 398 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 399 // | Payload Length | Next Header | Hop Limit | 400 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 401 // | | 402 // + + 403 // | | 404 // + Source Address + 405 // | | 406 // + + 407 // | | 408 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 409 // | | 410 // + + 411 // | | 412 // + Destination Address + 413 // | | 414 // + + 415 // | | 416 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 417 // 418 // See https://tools.ietf.org/html/rfc2460#section-3 for details. 419 mod field { 420 use crate::wire::field::*; 421 // 4-bit version number, 8-bit traffic class, and the 422 // 20-bit flow label. 423 pub const VER_TC_FLOW: Field = 0..4; 424 // 16-bit value representing the length of the payload. 425 // Note: Options are included in this length. 426 pub const LENGTH: Field = 4..6; 427 // 8-bit value identifying the type of header following this 428 // one. Note: The same numbers are used in IPv4. 429 pub const NXT_HDR: usize = 6; 430 // 8-bit value decremented by each node that forwards this 431 // packet. The packet is discarded when the value is 0. 432 pub const HOP_LIMIT: usize = 7; 433 // IPv6 address of the source node. 434 pub const SRC_ADDR: Field = 8..24; 435 // IPv6 address of the destination node. 436 pub const DST_ADDR: Field = 24..40; 437 } 438 439 /// Length of an IPv6 header. 440 pub const HEADER_LEN: usize = field::DST_ADDR.end; 441 442 impl<T: AsRef<[u8]>> Packet<T> { 443 /// Create a raw octet buffer with an IPv6 packet structure. 444 #[inline] new_unchecked(buffer: T) -> Packet<T>445 pub const fn new_unchecked(buffer: T) -> Packet<T> { 446 Packet { buffer } 447 } 448 449 /// Shorthand for a combination of [new_unchecked] and [check_len]. 450 /// 451 /// [new_unchecked]: #method.new_unchecked 452 /// [check_len]: #method.check_len 453 #[inline] new_checked(buffer: T) -> Result<Packet<T>>454 pub fn new_checked(buffer: T) -> Result<Packet<T>> { 455 let packet = Self::new_unchecked(buffer); 456 packet.check_len()?; 457 Ok(packet) 458 } 459 460 /// Ensure that no accessor method will panic if called. 461 /// Returns `Err(Error)` if the buffer is too short. 462 /// 463 /// The result of this check is invalidated by calling [set_payload_len]. 464 /// 465 /// [set_payload_len]: #method.set_payload_len 466 #[inline] check_len(&self) -> Result<()>467 pub fn check_len(&self) -> Result<()> { 468 let len = self.buffer.as_ref().len(); 469 if len < field::DST_ADDR.end || len < self.total_len() { 470 Err(Error) 471 } else { 472 Ok(()) 473 } 474 } 475 476 /// Consume the packet, returning the underlying buffer. 477 #[inline] into_inner(self) -> T478 pub fn into_inner(self) -> T { 479 self.buffer 480 } 481 482 /// Return the header length. 483 #[inline] header_len(&self) -> usize484 pub const fn header_len(&self) -> usize { 485 // This is not a strictly necessary function, but it makes 486 // code more readable. 487 field::DST_ADDR.end 488 } 489 490 /// Return the version field. 491 #[inline] version(&self) -> u8492 pub fn version(&self) -> u8 { 493 let data = self.buffer.as_ref(); 494 data[field::VER_TC_FLOW.start] >> 4 495 } 496 497 /// Return the traffic class. 498 #[inline] traffic_class(&self) -> u8499 pub fn traffic_class(&self) -> u8 { 500 let data = self.buffer.as_ref(); 501 ((NetworkEndian::read_u16(&data[0..2]) & 0x0ff0) >> 4) as u8 502 } 503 504 /// Return the flow label field. 505 #[inline] flow_label(&self) -> u32506 pub fn flow_label(&self) -> u32 { 507 let data = self.buffer.as_ref(); 508 NetworkEndian::read_u24(&data[1..4]) & 0x000fffff 509 } 510 511 /// Return the payload length field. 512 #[inline] payload_len(&self) -> u16513 pub fn payload_len(&self) -> u16 { 514 let data = self.buffer.as_ref(); 515 NetworkEndian::read_u16(&data[field::LENGTH]) 516 } 517 518 /// Return the payload length added to the known header length. 519 #[inline] total_len(&self) -> usize520 pub fn total_len(&self) -> usize { 521 self.header_len() + self.payload_len() as usize 522 } 523 524 /// Return the next header field. 525 #[inline] next_header(&self) -> Protocol526 pub fn next_header(&self) -> Protocol { 527 let data = self.buffer.as_ref(); 528 Protocol::from(data[field::NXT_HDR]) 529 } 530 531 /// Return the hop limit field. 532 #[inline] hop_limit(&self) -> u8533 pub fn hop_limit(&self) -> u8 { 534 let data = self.buffer.as_ref(); 535 data[field::HOP_LIMIT] 536 } 537 538 /// Return the source address field. 539 #[inline] src_addr(&self) -> Address540 pub fn src_addr(&self) -> Address { 541 let data = self.buffer.as_ref(); 542 Address::from_bytes(&data[field::SRC_ADDR]) 543 } 544 545 /// Return the destination address field. 546 #[inline] dst_addr(&self) -> Address547 pub fn dst_addr(&self) -> Address { 548 let data = self.buffer.as_ref(); 549 Address::from_bytes(&data[field::DST_ADDR]) 550 } 551 } 552 553 impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> { 554 /// Return a pointer to the payload. 555 #[inline] payload(&self) -> &'a [u8]556 pub fn payload(&self) -> &'a [u8] { 557 let data = self.buffer.as_ref(); 558 let range = self.header_len()..self.total_len(); 559 &data[range] 560 } 561 } 562 563 impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> { 564 /// Set the version field. 565 #[inline] set_version(&mut self, value: u8)566 pub fn set_version(&mut self, value: u8) { 567 let data = self.buffer.as_mut(); 568 // Make sure to retain the lower order bits which contain 569 // the higher order bits of the traffic class 570 data[0] = (data[0] & 0x0f) | ((value & 0x0f) << 4); 571 } 572 573 /// Set the traffic class field. 574 #[inline] set_traffic_class(&mut self, value: u8)575 pub fn set_traffic_class(&mut self, value: u8) { 576 let data = self.buffer.as_mut(); 577 // Put the higher order 4-bits of value in the lower order 578 // 4-bits of the first byte 579 data[0] = (data[0] & 0xf0) | ((value & 0xf0) >> 4); 580 // Put the lower order 4-bits of value in the higher order 581 // 4-bits of the second byte 582 data[1] = (data[1] & 0x0f) | ((value & 0x0f) << 4); 583 } 584 585 /// Set the flow label field. 586 #[inline] set_flow_label(&mut self, value: u32)587 pub fn set_flow_label(&mut self, value: u32) { 588 let data = self.buffer.as_mut(); 589 // Retain the lower order 4-bits of the traffic class 590 let raw = (((data[1] & 0xf0) as u32) << 16) | (value & 0x0fffff); 591 NetworkEndian::write_u24(&mut data[1..4], raw); 592 } 593 594 /// Set the payload length field. 595 #[inline] set_payload_len(&mut self, value: u16)596 pub fn set_payload_len(&mut self, value: u16) { 597 let data = self.buffer.as_mut(); 598 NetworkEndian::write_u16(&mut data[field::LENGTH], value); 599 } 600 601 /// Set the next header field. 602 #[inline] set_next_header(&mut self, value: Protocol)603 pub fn set_next_header(&mut self, value: Protocol) { 604 let data = self.buffer.as_mut(); 605 data[field::NXT_HDR] = value.into(); 606 } 607 608 /// Set the hop limit field. 609 #[inline] set_hop_limit(&mut self, value: u8)610 pub fn set_hop_limit(&mut self, value: u8) { 611 let data = self.buffer.as_mut(); 612 data[field::HOP_LIMIT] = value; 613 } 614 615 /// Set the source address field. 616 #[inline] set_src_addr(&mut self, value: Address)617 pub fn set_src_addr(&mut self, value: Address) { 618 let data = self.buffer.as_mut(); 619 data[field::SRC_ADDR].copy_from_slice(value.as_bytes()); 620 } 621 622 /// Set the destination address field. 623 #[inline] set_dst_addr(&mut self, value: Address)624 pub fn set_dst_addr(&mut self, value: Address) { 625 let data = self.buffer.as_mut(); 626 data[field::DST_ADDR].copy_from_slice(value.as_bytes()); 627 } 628 629 /// Return a mutable pointer to the payload. 630 #[inline] payload_mut(&mut self) -> &mut [u8]631 pub fn payload_mut(&mut self) -> &mut [u8] { 632 let range = self.header_len()..self.total_len(); 633 let data = self.buffer.as_mut(); 634 &mut data[range] 635 } 636 } 637 638 impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result639 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 640 match Repr::parse(self) { 641 Ok(repr) => write!(f, "{repr}"), 642 Err(err) => { 643 write!(f, "IPv6 ({err})")?; 644 Ok(()) 645 } 646 } 647 } 648 } 649 650 impl<T: AsRef<[u8]>> AsRef<[u8]> for Packet<T> { as_ref(&self) -> &[u8]651 fn as_ref(&self) -> &[u8] { 652 self.buffer.as_ref() 653 } 654 } 655 656 /// A high-level representation of an Internet Protocol version 6 packet header. 657 #[derive(Debug, PartialEq, Eq, Clone, Copy)] 658 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 659 pub struct Repr { 660 /// IPv6 address of the source node. 661 pub src_addr: Address, 662 /// IPv6 address of the destination node. 663 pub dst_addr: Address, 664 /// Protocol contained in the next header. 665 pub next_header: Protocol, 666 /// Length of the payload including the extension headers. 667 pub payload_len: usize, 668 /// The 8-bit hop limit field. 669 pub hop_limit: u8, 670 } 671 672 impl Repr { 673 /// Parse an Internet Protocol version 6 packet and return a high-level representation. parse<T: AsRef<[u8]> + ?Sized>(packet: &Packet<&T>) -> Result<Repr>674 pub fn parse<T: AsRef<[u8]> + ?Sized>(packet: &Packet<&T>) -> Result<Repr> { 675 // Ensure basic accessors will work 676 packet.check_len()?; 677 if packet.version() != 6 { 678 return Err(Error); 679 } 680 Ok(Repr { 681 src_addr: packet.src_addr(), 682 dst_addr: packet.dst_addr(), 683 next_header: packet.next_header(), 684 payload_len: packet.payload_len() as usize, 685 hop_limit: packet.hop_limit(), 686 }) 687 } 688 689 /// Return the length of a header that will be emitted from this high-level representation. buffer_len(&self) -> usize690 pub const fn buffer_len(&self) -> usize { 691 // This function is not strictly necessary, but it can make client code more readable. 692 field::DST_ADDR.end 693 } 694 695 /// Emit a high-level representation into an Internet Protocol version 6 packet. emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>)696 pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>) { 697 // Make no assumptions about the original state of the packet buffer. 698 // Make sure to set every byte. 699 packet.set_version(6); 700 packet.set_traffic_class(0); 701 packet.set_flow_label(0); 702 packet.set_payload_len(self.payload_len as u16); 703 packet.set_hop_limit(self.hop_limit); 704 packet.set_next_header(self.next_header); 705 packet.set_src_addr(self.src_addr); 706 packet.set_dst_addr(self.dst_addr); 707 } 708 } 709 710 impl fmt::Display for Repr { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result711 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 712 write!( 713 f, 714 "IPv6 src={} dst={} nxt_hdr={} hop_limit={}", 715 self.src_addr, self.dst_addr, self.next_header, self.hop_limit 716 ) 717 } 718 } 719 720 use crate::wire::pretty_print::{PrettyIndent, PrettyPrint}; 721 722 // TODO: This is very similar to the implementation for IPv4. Make 723 // a way to have less copy and pasted code here. 724 impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> { pretty_print( buffer: &dyn AsRef<[u8]>, f: &mut fmt::Formatter, indent: &mut PrettyIndent, ) -> fmt::Result725 fn pretty_print( 726 buffer: &dyn AsRef<[u8]>, 727 f: &mut fmt::Formatter, 728 indent: &mut PrettyIndent, 729 ) -> fmt::Result { 730 let (ip_repr, payload) = match Packet::new_checked(buffer) { 731 Err(err) => return write!(f, "{indent}({err})"), 732 Ok(ip_packet) => match Repr::parse(&ip_packet) { 733 Err(_) => return Ok(()), 734 Ok(ip_repr) => { 735 write!(f, "{indent}{ip_repr}")?; 736 (ip_repr, ip_packet.payload()) 737 } 738 }, 739 }; 740 741 pretty_print_ip_payload(f, indent, ip_repr, payload) 742 } 743 } 744 745 #[cfg(test)] 746 mod test { 747 use super::Error; 748 use super::{Address, Cidr}; 749 use super::{Packet, Protocol, Repr}; 750 use crate::wire::pretty_print::PrettyPrinter; 751 752 #[cfg(feature = "proto-ipv4")] 753 use crate::wire::ipv4::Address as Ipv4Address; 754 755 static LINK_LOCAL_ADDR: Address = Address([ 756 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 757 0x01, 758 ]); 759 #[test] test_basic_multicast()760 fn test_basic_multicast() { 761 assert!(!Address::LINK_LOCAL_ALL_ROUTERS.is_unspecified()); 762 assert!(Address::LINK_LOCAL_ALL_ROUTERS.is_multicast()); 763 assert!(!Address::LINK_LOCAL_ALL_ROUTERS.is_link_local()); 764 assert!(!Address::LINK_LOCAL_ALL_ROUTERS.is_loopback()); 765 assert!(!Address::LINK_LOCAL_ALL_NODES.is_unspecified()); 766 assert!(Address::LINK_LOCAL_ALL_NODES.is_multicast()); 767 assert!(!Address::LINK_LOCAL_ALL_NODES.is_link_local()); 768 assert!(!Address::LINK_LOCAL_ALL_NODES.is_loopback()); 769 } 770 771 #[test] test_basic_link_local()772 fn test_basic_link_local() { 773 assert!(!LINK_LOCAL_ADDR.is_unspecified()); 774 assert!(!LINK_LOCAL_ADDR.is_multicast()); 775 assert!(LINK_LOCAL_ADDR.is_link_local()); 776 assert!(!LINK_LOCAL_ADDR.is_loopback()); 777 } 778 779 #[test] test_basic_loopback()780 fn test_basic_loopback() { 781 assert!(!Address::LOOPBACK.is_unspecified()); 782 assert!(!Address::LOOPBACK.is_multicast()); 783 assert!(!Address::LOOPBACK.is_link_local()); 784 assert!(Address::LOOPBACK.is_loopback()); 785 } 786 787 #[test] test_address_format()788 fn test_address_format() { 789 assert_eq!("ff02::1", format!("{}", Address::LINK_LOCAL_ALL_NODES)); 790 assert_eq!("fe80::1", format!("{LINK_LOCAL_ADDR}")); 791 assert_eq!( 792 "fe80::7f00:0:1", 793 format!( 794 "{}", 795 Address::new(0xfe80, 0, 0, 0, 0, 0x7f00, 0x0000, 0x0001) 796 ) 797 ); 798 assert_eq!("::", format!("{}", Address::UNSPECIFIED)); 799 assert_eq!("::1", format!("{}", Address::LOOPBACK)); 800 801 #[cfg(feature = "proto-ipv4")] 802 assert_eq!( 803 "::ffff:192.168.1.1", 804 format!("{}", Address::from(Ipv4Address::new(192, 168, 1, 1))) 805 ); 806 } 807 808 #[test] test_new()809 fn test_new() { 810 assert_eq!( 811 Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1), 812 Address::LINK_LOCAL_ALL_NODES 813 ); 814 assert_eq!( 815 Address::new(0xff02, 0, 0, 0, 0, 0, 0, 2), 816 Address::LINK_LOCAL_ALL_ROUTERS 817 ); 818 assert_eq!(Address::new(0, 0, 0, 0, 0, 0, 0, 1), Address::LOOPBACK); 819 assert_eq!(Address::new(0, 0, 0, 0, 0, 0, 0, 0), Address::UNSPECIFIED); 820 assert_eq!(Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1), LINK_LOCAL_ADDR); 821 } 822 823 #[test] test_from_parts()824 fn test_from_parts() { 825 assert_eq!( 826 Address::from_parts(&[0xff02, 0, 0, 0, 0, 0, 0, 1]), 827 Address::LINK_LOCAL_ALL_NODES 828 ); 829 assert_eq!( 830 Address::from_parts(&[0xff02, 0, 0, 0, 0, 0, 0, 2]), 831 Address::LINK_LOCAL_ALL_ROUTERS 832 ); 833 assert_eq!( 834 Address::from_parts(&[0, 0, 0, 0, 0, 0, 0, 1]), 835 Address::LOOPBACK 836 ); 837 assert_eq!( 838 Address::from_parts(&[0, 0, 0, 0, 0, 0, 0, 0]), 839 Address::UNSPECIFIED 840 ); 841 assert_eq!( 842 Address::from_parts(&[0xfe80, 0, 0, 0, 0, 0, 0, 1]), 843 LINK_LOCAL_ADDR 844 ); 845 } 846 847 #[test] test_write_parts()848 fn test_write_parts() { 849 let mut bytes = [0u16; 8]; 850 { 851 Address::LOOPBACK.write_parts(&mut bytes); 852 assert_eq!(Address::LOOPBACK, Address::from_parts(&bytes)); 853 } 854 { 855 Address::LINK_LOCAL_ALL_ROUTERS.write_parts(&mut bytes); 856 assert_eq!(Address::LINK_LOCAL_ALL_ROUTERS, Address::from_parts(&bytes)); 857 } 858 { 859 LINK_LOCAL_ADDR.write_parts(&mut bytes); 860 assert_eq!(LINK_LOCAL_ADDR, Address::from_parts(&bytes)); 861 } 862 } 863 864 #[test] test_mask()865 fn test_mask() { 866 let addr = Address::new(0x0123, 0x4567, 0x89ab, 0, 0, 0, 0, 1); 867 assert_eq!( 868 addr.mask(11), 869 [0x01, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 870 ); 871 assert_eq!( 872 addr.mask(15), 873 [0x01, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 874 ); 875 assert_eq!( 876 addr.mask(26), 877 [0x01, 0x23, 0x45, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 878 ); 879 assert_eq!( 880 addr.mask(128), 881 [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] 882 ); 883 assert_eq!( 884 addr.mask(127), 885 [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 886 ); 887 } 888 889 #[cfg(feature = "proto-ipv4")] 890 #[test] test_is_ipv4_mapped()891 fn test_is_ipv4_mapped() { 892 assert!(!Address::UNSPECIFIED.is_ipv4_mapped()); 893 assert!(Address::from(Ipv4Address::new(192, 168, 1, 1)).is_ipv4_mapped()); 894 } 895 896 #[cfg(feature = "proto-ipv4")] 897 #[test] test_as_ipv4()898 fn test_as_ipv4() { 899 assert_eq!(None, Address::UNSPECIFIED.as_ipv4()); 900 901 let ipv4 = Ipv4Address::new(192, 168, 1, 1); 902 assert_eq!(Some(ipv4), Address::from(ipv4).as_ipv4()); 903 } 904 905 #[cfg(feature = "proto-ipv4")] 906 #[test] test_from_ipv4_address()907 fn test_from_ipv4_address() { 908 assert_eq!( 909 Address([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 168, 1, 1]), 910 Address::from(Ipv4Address::new(192, 168, 1, 1)) 911 ); 912 assert_eq!( 913 Address([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 222, 1, 41, 90]), 914 Address::from(Ipv4Address::new(222, 1, 41, 90)) 915 ); 916 } 917 918 #[test] test_cidr()919 fn test_cidr() { 920 // fe80::1/56 921 // 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 922 // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 923 let cidr = Cidr::new(LINK_LOCAL_ADDR, 56); 924 925 let inside_subnet = [ 926 // fe80::2 927 [ 928 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 929 0x00, 0x02, 930 ], 931 // fe80::1122:3344:5566:7788 932 [ 933 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 934 0x77, 0x88, 935 ], 936 // fe80::ff00:0:0:0 937 [ 938 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 939 0x00, 0x00, 940 ], 941 // fe80::ff 942 [ 943 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 944 0x00, 0xff, 945 ], 946 ]; 947 948 let outside_subnet = [ 949 // fe80:0:0:101::1 950 [ 951 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 952 0x00, 0x01, 953 ], 954 // ::1 955 [ 956 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 957 0x00, 0x01, 958 ], 959 // ff02::1 960 [ 961 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 962 0x00, 0x01, 963 ], 964 // ff02::2 965 [ 966 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 967 0x00, 0x02, 968 ], 969 ]; 970 971 let subnets = [ 972 // fe80::ffff:ffff:ffff:ffff/65 973 ( 974 [ 975 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 976 0xff, 0xff, 0xff, 977 ], 978 65, 979 ), 980 // fe80::1/128 981 ( 982 [ 983 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 984 0x00, 0x00, 0x01, 985 ], 986 128, 987 ), 988 // fe80::1234:5678/96 989 ( 990 [ 991 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 992 0x34, 0x56, 0x78, 993 ], 994 96, 995 ), 996 ]; 997 998 let not_subnets = [ 999 // fe80::101:ffff:ffff:ffff:ffff/55 1000 ( 1001 [ 1002 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 1003 0xff, 0xff, 0xff, 1004 ], 1005 55, 1006 ), 1007 // fe80::101:ffff:ffff:ffff:ffff/56 1008 ( 1009 [ 1010 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 1011 0xff, 0xff, 0xff, 1012 ], 1013 56, 1014 ), 1015 // fe80::101:ffff:ffff:ffff:ffff/57 1016 ( 1017 [ 1018 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 1019 0xff, 0xff, 0xff, 1020 ], 1021 57, 1022 ), 1023 // ::1/128 1024 ( 1025 [ 1026 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1027 0x00, 0x00, 0x01, 1028 ], 1029 128, 1030 ), 1031 ]; 1032 1033 for addr in inside_subnet.iter().map(|a| Address::from_bytes(a)) { 1034 assert!(cidr.contains_addr(&addr)); 1035 } 1036 1037 for addr in outside_subnet.iter().map(|a| Address::from_bytes(a)) { 1038 assert!(!cidr.contains_addr(&addr)); 1039 } 1040 1041 for subnet in subnets.iter().map(|&(a, p)| Cidr::new(Address(a), p)) { 1042 assert!(cidr.contains_subnet(&subnet)); 1043 } 1044 1045 for subnet in not_subnets.iter().map(|&(a, p)| Cidr::new(Address(a), p)) { 1046 assert!(!cidr.contains_subnet(&subnet)); 1047 } 1048 1049 let cidr_without_prefix = Cidr::new(LINK_LOCAL_ADDR, 0); 1050 assert!(cidr_without_prefix.contains_addr(&Address::LOOPBACK)); 1051 } 1052 1053 #[test] 1054 #[should_panic(expected = "length")] test_from_bytes_too_long()1055 fn test_from_bytes_too_long() { 1056 let _ = Address::from_bytes(&[0u8; 15]); 1057 } 1058 1059 #[test] 1060 #[should_panic(expected = "data.len() >= 8")] test_from_parts_too_long()1061 fn test_from_parts_too_long() { 1062 let _ = Address::from_parts(&[0u16; 7]); 1063 } 1064 1065 static REPR_PACKET_BYTES: [u8; 52] = [ 1066 0x60, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x11, 0x40, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 1067 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 1068 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 1069 0x0c, 0x02, 0x4e, 0xff, 0xff, 0xff, 0xff, 1070 ]; 1071 static REPR_PAYLOAD_BYTES: [u8; 12] = [ 1072 0x00, 0x01, 0x00, 0x02, 0x00, 0x0c, 0x02, 0x4e, 0xff, 0xff, 0xff, 0xff, 1073 ]; 1074 packet_repr() -> Repr1075 const fn packet_repr() -> Repr { 1076 Repr { 1077 src_addr: Address([ 1078 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1079 0x00, 0x01, 1080 ]), 1081 dst_addr: Address::LINK_LOCAL_ALL_NODES, 1082 next_header: Protocol::Udp, 1083 payload_len: 12, 1084 hop_limit: 64, 1085 } 1086 } 1087 1088 #[test] test_packet_deconstruction()1089 fn test_packet_deconstruction() { 1090 let packet = Packet::new_unchecked(&REPR_PACKET_BYTES[..]); 1091 assert_eq!(packet.check_len(), Ok(())); 1092 assert_eq!(packet.version(), 6); 1093 assert_eq!(packet.traffic_class(), 0); 1094 assert_eq!(packet.flow_label(), 0); 1095 assert_eq!(packet.total_len(), 0x34); 1096 assert_eq!(packet.payload_len() as usize, REPR_PAYLOAD_BYTES.len()); 1097 assert_eq!(packet.next_header(), Protocol::Udp); 1098 assert_eq!(packet.hop_limit(), 0x40); 1099 assert_eq!( 1100 packet.src_addr(), 1101 Address([ 1102 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1103 0x00, 0x01 1104 ]) 1105 ); 1106 assert_eq!(packet.dst_addr(), Address::LINK_LOCAL_ALL_NODES); 1107 assert_eq!(packet.payload(), &REPR_PAYLOAD_BYTES[..]); 1108 } 1109 1110 #[test] test_packet_construction()1111 fn test_packet_construction() { 1112 let mut bytes = [0xff; 52]; 1113 let mut packet = Packet::new_unchecked(&mut bytes[..]); 1114 // Version, Traffic Class, and Flow Label are not 1115 // byte aligned. make sure the setters and getters 1116 // do not interfere with each other. 1117 packet.set_version(6); 1118 assert_eq!(packet.version(), 6); 1119 packet.set_traffic_class(0x99); 1120 assert_eq!(packet.version(), 6); 1121 assert_eq!(packet.traffic_class(), 0x99); 1122 packet.set_flow_label(0x54321); 1123 assert_eq!(packet.traffic_class(), 0x99); 1124 assert_eq!(packet.flow_label(), 0x54321); 1125 packet.set_payload_len(0xc); 1126 packet.set_next_header(Protocol::Udp); 1127 packet.set_hop_limit(0xfe); 1128 packet.set_src_addr(Address::LINK_LOCAL_ALL_ROUTERS); 1129 packet.set_dst_addr(Address::LINK_LOCAL_ALL_NODES); 1130 packet 1131 .payload_mut() 1132 .copy_from_slice(&REPR_PAYLOAD_BYTES[..]); 1133 let mut expected_bytes = [ 1134 0x69, 0x95, 0x43, 0x21, 0x00, 0x0c, 0x11, 0xfe, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 1135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x02, 0x00, 0x00, 1136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 1137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1138 ]; 1139 let start = expected_bytes.len() - REPR_PAYLOAD_BYTES.len(); 1140 expected_bytes[start..].copy_from_slice(&REPR_PAYLOAD_BYTES[..]); 1141 assert_eq!(packet.check_len(), Ok(())); 1142 assert_eq!(&*packet.into_inner(), &expected_bytes[..]); 1143 } 1144 1145 #[test] test_overlong()1146 fn test_overlong() { 1147 let mut bytes = vec![]; 1148 bytes.extend(&REPR_PACKET_BYTES[..]); 1149 bytes.push(0); 1150 1151 assert_eq!( 1152 Packet::new_unchecked(&bytes).payload().len(), 1153 REPR_PAYLOAD_BYTES.len() 1154 ); 1155 assert_eq!( 1156 Packet::new_unchecked(&mut bytes).payload_mut().len(), 1157 REPR_PAYLOAD_BYTES.len() 1158 ); 1159 } 1160 1161 #[test] test_total_len_overflow()1162 fn test_total_len_overflow() { 1163 let mut bytes = vec![]; 1164 bytes.extend(&REPR_PACKET_BYTES[..]); 1165 Packet::new_unchecked(&mut bytes).set_payload_len(0x80); 1166 1167 assert_eq!(Packet::new_checked(&bytes).unwrap_err(), Error); 1168 } 1169 1170 #[test] test_repr_parse_valid()1171 fn test_repr_parse_valid() { 1172 let packet = Packet::new_unchecked(&REPR_PACKET_BYTES[..]); 1173 let repr = Repr::parse(&packet).unwrap(); 1174 assert_eq!(repr, packet_repr()); 1175 } 1176 1177 #[test] test_repr_parse_bad_version()1178 fn test_repr_parse_bad_version() { 1179 let mut bytes = vec![0; 40]; 1180 let mut packet = Packet::new_unchecked(&mut bytes[..]); 1181 packet.set_version(4); 1182 packet.set_payload_len(0); 1183 let packet = Packet::new_unchecked(&*packet.into_inner()); 1184 assert_eq!(Repr::parse(&packet), Err(Error)); 1185 } 1186 1187 #[test] test_repr_parse_smaller_than_header()1188 fn test_repr_parse_smaller_than_header() { 1189 let mut bytes = vec![0; 40]; 1190 let mut packet = Packet::new_unchecked(&mut bytes[..]); 1191 packet.set_version(6); 1192 packet.set_payload_len(39); 1193 let packet = Packet::new_unchecked(&*packet.into_inner()); 1194 assert_eq!(Repr::parse(&packet), Err(Error)); 1195 } 1196 1197 #[test] test_repr_parse_smaller_than_payload()1198 fn test_repr_parse_smaller_than_payload() { 1199 let mut bytes = vec![0; 40]; 1200 let mut packet = Packet::new_unchecked(&mut bytes[..]); 1201 packet.set_version(6); 1202 packet.set_payload_len(1); 1203 let packet = Packet::new_unchecked(&*packet.into_inner()); 1204 assert_eq!(Repr::parse(&packet), Err(Error)); 1205 } 1206 1207 #[test] test_basic_repr_emit()1208 fn test_basic_repr_emit() { 1209 let repr = packet_repr(); 1210 let mut bytes = vec![0xff; repr.buffer_len() + REPR_PAYLOAD_BYTES.len()]; 1211 let mut packet = Packet::new_unchecked(&mut bytes); 1212 repr.emit(&mut packet); 1213 packet.payload_mut().copy_from_slice(&REPR_PAYLOAD_BYTES); 1214 assert_eq!(&*packet.into_inner(), &REPR_PACKET_BYTES[..]); 1215 } 1216 1217 #[test] test_pretty_print()1218 fn test_pretty_print() { 1219 assert_eq!( 1220 format!( 1221 "{}", 1222 PrettyPrinter::<Packet<&'static [u8]>>::new("\n", &&REPR_PACKET_BYTES[..]) 1223 ), 1224 "\nIPv6 src=fe80::1 dst=ff02::1 nxt_hdr=UDP hop_limit=64\n \\ UDP src=1 dst=2 len=4" 1225 ); 1226 } 1227 } 1228