mod fragment;
mod srh;
pub use self::fragment::*;
pub use self::srh::*;
use crate::packets::checksum::PseudoHeader;
use crate::packets::ip::{IpPacket, ProtocolNumber, DEFAULT_IP_TTL};
use crate::packets::types::{u16be, u32be};
use crate::packets::{EtherTypes, Ethernet, Internal, Packet};
use crate::{ensure, SizeOf};
use anyhow::{anyhow, Result};
use std::fmt;
use std::net::{IpAddr, Ipv6Addr};
use std::ptr::NonNull;
pub const IPV6_MIN_MTU: usize = 1280;
const DSCP: u32be = u32be(u32::to_be(0x0fc0_0000));
const ECN: u32be = u32be(u32::to_be(0x0030_0000));
const FLOW: u32be = u32be(u32::to_be(0xfffff));
pub struct Ipv6 {
envelope: Ethernet,
header: NonNull<Ipv6Header>,
offset: usize,
}
impl Ipv6 {
#[inline]
fn header(&self) -> &Ipv6Header {
unsafe { self.header.as_ref() }
}
#[inline]
fn header_mut(&mut self) -> &mut Ipv6Header {
unsafe { self.header.as_mut() }
}
#[inline]
pub fn version(&self) -> u8 {
let v: u32 = (self.header().version_to_flow_label & u32be::from(0xf000_0000)).into();
(v >> 28) as u8
}
#[inline]
pub fn dscp(&self) -> u8 {
let v: u32 = (self.header().version_to_flow_label & DSCP).into();
(v >> 22) as u8
}
#[inline]
pub fn set_dscp(&mut self, dscp: u8) {
self.header_mut().version_to_flow_label = (self.header().version_to_flow_label & !DSCP)
| (u32be::from(u32::from(dscp) << 22) & DSCP)
}
#[inline]
pub fn ecn(&self) -> u8 {
let v: u32 = (self.header().version_to_flow_label & ECN).into();
(v >> 20) as u8
}
#[inline]
pub fn set_ecn(&mut self, ecn: u8) {
self.header_mut().version_to_flow_label =
(self.header().version_to_flow_label & !ECN) | (u32be::from(u32::from(ecn) << 20) & ECN)
}
#[inline]
pub fn flow_label(&self) -> u32 {
(self.header().version_to_flow_label & FLOW).into()
}
#[inline]
pub fn set_flow_label(&mut self, flow_label: u32) {
self.header_mut().version_to_flow_label =
(self.header().version_to_flow_label & !FLOW) | (u32be::from(flow_label) & FLOW)
}
#[inline]
pub fn payload_length(&self) -> u16 {
self.header().payload_length.into()
}
#[inline]
fn set_payload_length(&mut self, payload_length: u16) {
self.header_mut().payload_length = payload_length.into();
}
#[inline]
pub fn hop_limit(&self) -> u8 {
self.header().hop_limit
}
#[inline]
pub fn set_hop_limit(&mut self, hop_limit: u8) {
self.header_mut().hop_limit = hop_limit;
}
#[inline]
pub fn src(&self) -> Ipv6Addr {
self.header().src
}
#[inline]
pub fn set_src(&mut self, src: Ipv6Addr) {
self.header_mut().src = src;
}
#[inline]
pub fn dst(&self) -> Ipv6Addr {
self.header().dst
}
#[inline]
pub fn set_dst(&mut self, dst: Ipv6Addr) {
self.header_mut().dst = dst;
}
}
impl fmt::Debug for Ipv6 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ipv6")
.field("src", &format!("{}", self.src()))
.field("dst", &format!("{}", self.dst()))
.field("dscp", &self.dscp())
.field("ecn", &self.ecn())
.field("flow_label", &self.flow_label())
.field("payload_length", &self.payload_length())
.field("next_header", &format!("{}", self.next_header()))
.field("hop_limit", &self.hop_limit())
.field("$offset", &self.offset())
.field("$len", &self.len())
.field("$header_len", &self.header_len())
.finish()
}
}
impl Packet for Ipv6 {
type Envelope = Ethernet;
#[inline]
fn envelope(&self) -> &Self::Envelope {
&self.envelope
}
#[inline]
fn envelope_mut(&mut self) -> &mut Self::Envelope {
&mut self.envelope
}
#[inline]
fn offset(&self) -> usize {
self.offset
}
#[inline]
fn header_len(&self) -> usize {
Ipv6Header::size_of()
}
#[inline]
unsafe fn clone(&self, internal: Internal) -> Self {
Ipv6 {
envelope: self.envelope.clone(internal),
header: self.header,
offset: self.offset,
}
}
#[inline]
fn try_parse(envelope: Self::Envelope, _internal: Internal) -> Result<Self> {
ensure!(
envelope.ether_type() == EtherTypes::Ipv6,
anyhow!("not an IPv6 packet.")
);
let mbuf = envelope.mbuf();
let offset = envelope.payload_offset();
let header = mbuf.read_data(offset)?;
Ok(Ipv6 {
envelope,
header,
offset,
})
}
#[inline]
fn try_push(mut envelope: Self::Envelope, _internal: Internal) -> Result<Self> {
let offset = envelope.payload_offset();
let mbuf = envelope.mbuf_mut();
mbuf.extend(offset, Ipv6Header::size_of())?;
let header = mbuf.write_data(offset, &Ipv6Header::default())?;
envelope.set_ether_type(EtherTypes::Ipv6);
Ok(Ipv6 {
envelope,
header,
offset,
})
}
#[inline]
fn deparse(self) -> Self::Envelope {
self.envelope
}
#[inline]
fn reconcile(&mut self) {
let len = self.payload_len() as u16;
self.set_payload_length(len);
}
}
impl IpPacket for Ipv6 {
#[inline]
fn next_protocol(&self) -> ProtocolNumber {
self.next_header()
}
#[inline]
fn set_next_protocol(&mut self, proto: ProtocolNumber) {
self.set_next_header(proto);
}
#[inline]
fn src(&self) -> IpAddr {
IpAddr::V6(self.src())
}
#[inline]
fn set_src(&mut self, src: IpAddr) -> Result<()> {
match src {
IpAddr::V6(addr) => {
self.set_src(addr);
Ok(())
}
_ => Err(anyhow!("source address must be IPv6.")),
}
}
#[inline]
fn dst(&self) -> IpAddr {
IpAddr::V6(self.dst())
}
#[inline]
fn set_dst(&mut self, dst: IpAddr) -> Result<()> {
match dst {
IpAddr::V6(addr) => {
self.set_dst(addr);
Ok(())
}
_ => Err(anyhow!("destination address must be IPv6.")),
}
}
#[inline]
fn pseudo_header(&self, packet_len: u16, protocol: ProtocolNumber) -> PseudoHeader {
PseudoHeader::V6 {
src: self.src(),
dst: self.dst(),
packet_len,
protocol,
}
}
#[inline]
fn truncate(&mut self, mtu: usize) -> Result<()> {
ensure!(
mtu >= IPV6_MIN_MTU,
anyhow!("MTU {} must be greater than {}.", mtu, IPV6_MIN_MTU)
);
let to_len = mtu + self.offset();
self.mbuf_mut().truncate(to_len)
}
}
impl Ipv6Packet for Ipv6 {
#[inline]
fn next_header(&self) -> ProtocolNumber {
ProtocolNumber::new(self.header().next_header)
}
#[inline]
fn set_next_header(&mut self, next_header: ProtocolNumber) {
self.header_mut().next_header = next_header.0;
}
}
pub trait Ipv6Packet: IpPacket {
fn next_header(&self) -> ProtocolNumber;
fn set_next_header(&mut self, next_header: ProtocolNumber);
}
#[derive(Clone, Copy, Debug, SizeOf)]
#[repr(C)]
struct Ipv6Header {
version_to_flow_label: u32be,
payload_length: u16be,
next_header: u8,
hop_limit: u8,
src: Ipv6Addr,
dst: Ipv6Addr,
}
impl Default for Ipv6Header {
fn default() -> Ipv6Header {
Ipv6Header {
version_to_flow_label: u32be::from(6 << 28),
payload_length: u16be::default(),
next_header: 0,
hop_limit: DEFAULT_IP_TTL,
src: Ipv6Addr::UNSPECIFIED,
dst: Ipv6Addr::UNSPECIFIED,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::packets::ip::ProtocolNumbers;
use crate::testils::byte_arrays::{IPV4_UDP_PACKET, IPV6_TCP_PACKET};
use crate::Mbuf;
#[test]
fn size_of_ipv6_header() {
assert_eq!(40, Ipv6Header::size_of());
}
#[capsule::test]
fn parse_ipv6_packet() {
let packet = Mbuf::from_bytes(&IPV6_TCP_PACKET).unwrap();
let ethernet = packet.parse::<Ethernet>().unwrap();
let ipv6 = ethernet.parse::<Ipv6>().unwrap();
assert_eq!(6, ipv6.version());
assert_eq!(0, ipv6.dscp());
assert_eq!(0, ipv6.ecn());
assert_eq!(0, ipv6.flow_label());
assert_eq!(24, ipv6.payload_len());
assert_eq!(ProtocolNumbers::Tcp, ipv6.next_header());
assert_eq!(2, ipv6.hop_limit());
assert_eq!("2001:db8:85a3::1", ipv6.src().to_string());
assert_eq!("2001:db8:85a3::8a2e:370:7334", ipv6.dst().to_string());
}
#[capsule::test]
fn parse_non_ipv6_packet() {
let packet = Mbuf::from_bytes(&IPV4_UDP_PACKET).unwrap();
let ethernet = packet.parse::<Ethernet>().unwrap();
assert!(ethernet.parse::<Ipv6>().is_err());
}
#[capsule::test]
fn parse_ipv6_setter_checks() {
let packet = Mbuf::from_bytes(&IPV6_TCP_PACKET).unwrap();
let ethernet = packet.parse::<Ethernet>().unwrap();
let mut ipv6 = ethernet.parse::<Ipv6>().unwrap();
assert_eq!(6, ipv6.version());
assert_eq!(0, ipv6.dscp());
assert_eq!(0, ipv6.ecn());
assert_eq!(0, ipv6.flow_label());
ipv6.set_dscp(10);
ipv6.set_ecn(3);
assert_eq!(6, ipv6.version());
assert_eq!(10, ipv6.dscp());
assert_eq!(3, ipv6.ecn());
assert_eq!(0, ipv6.flow_label());
}
#[capsule::test]
fn push_ipv6_packet() {
let packet = Mbuf::new().unwrap();
let ethernet = packet.push::<Ethernet>().unwrap();
let ipv6 = ethernet.push::<Ipv6>().unwrap();
assert_eq!(6, ipv6.version());
assert_eq!(Ipv6Header::size_of(), ipv6.len());
assert_eq!(EtherTypes::Ipv6, ipv6.envelope().ether_type());
}
#[capsule::test]
fn truncate_ipv6_packet() {
let mut packet = Mbuf::new().unwrap();
let _ = packet.extend(0, 1800);
let ethernet = packet.push::<Ethernet>().unwrap();
let mut ipv6 = ethernet.push::<Ipv6>().unwrap();
assert!(ipv6.truncate(1200).is_err());
assert!(ipv6.len() > 1500);
let _ = ipv6.truncate(1500);
assert_eq!(1500, ipv6.len());
}
}