use crate::ip::IpNextHeaderProtocol;
use alloc::vec::Vec;
use pnet_macros::packet;
use pnet_macros_support::types::*;
use pnet_base::core_net::Ipv6Addr;
#[packet]
pub struct Ipv6 {
pub version: u4,
pub traffic_class: u8,
pub flow_label: u20be,
pub payload_length: u16be,
#[construct_with(u8)]
pub next_header: IpNextHeaderProtocol,
pub hop_limit: u8,
#[construct_with(u16, u16, u16, u16, u16, u16, u16, u16)]
pub source: Ipv6Addr,
#[construct_with(u16, u16, u16, u16, u16, u16, u16, u16)]
pub destination: Ipv6Addr,
#[length = "payload_length"]
#[payload]
pub payload: Vec<u8>,
}
impl<'p> ExtensionIterable<'p> {
pub fn new(buf: &[u8]) -> ExtensionIterable {
ExtensionIterable { buf: buf }
}
}
#[packet]
pub struct Extension {
#[construct_with(u8)]
pub next_header: IpNextHeaderProtocol,
pub hdr_ext_len: u8,
#[length_fn = "ipv6_extension_length"]
#[payload]
pub options: Vec<u8>,
}
fn ipv6_extension_length(ext: &ExtensionPacket) -> usize {
ext.get_hdr_ext_len() as usize * 8 + 8 - 2
}
pub type HopByHop = Extension;
pub type HopByHopPacket<'p> = ExtensionPacket<'p>;
pub type MutableHopByHopPacket<'p> = MutableExtensionPacket<'p>;
#[packet]
pub struct Routing {
#[construct_with(u8)]
pub next_header: IpNextHeaderProtocol,
pub hdr_ext_len: u8,
pub routing_type: u8,
pub segments_left: u8,
#[length_fn = "routing_extension_length"]
#[payload]
pub data: Vec<u8>,
}
fn routing_extension_length(ext: &RoutingPacket) -> usize {
ext.get_hdr_ext_len() as usize * 8 + 8 - 4
}
#[packet]
pub struct Fragment {
#[construct_with(u8)]
pub next_header: IpNextHeaderProtocol,
pub reserved: u8,
pub fragment_offset_with_flags: u16be,
pub id: u32be,
#[length = "0"]
#[payload]
pub payload: Vec<u8>,
}
const FRAGMENT_FLAGS_MASK: u16 = 0x03;
const FRAGMENT_FLAGS_MORE_FRAGMENTS: u16 = 0x01;
const FRAGMENT_OFFSET_MASK: u16 = !FRAGMENT_FLAGS_MASK;
impl<'p> FragmentPacket<'p> {
pub fn get_fragment_offset(&self) -> u16 {
self.get_fragment_offset_with_flags() & FRAGMENT_OFFSET_MASK
}
pub fn is_last_fragment(&self) -> bool {
(self.get_fragment_offset_with_flags() & FRAGMENT_FLAGS_MORE_FRAGMENTS) == 0
}
}
impl<'p> MutableFragmentPacket<'p> {
pub fn get_fragment_offset(&self) -> u16 {
self.get_fragment_offset_with_flags() & FRAGMENT_OFFSET_MASK
}
pub fn is_last_fragment(&self) -> bool {
(self.get_fragment_offset_with_flags() & FRAGMENT_FLAGS_MORE_FRAGMENTS) == 0
}
pub fn set_fragment_offset(&mut self, offset: u16) {
let fragment_offset_with_flags = self.get_fragment_offset_with_flags();
self.set_fragment_offset_with_flags(
(offset & FRAGMENT_OFFSET_MASK) | (fragment_offset_with_flags & FRAGMENT_FLAGS_MASK),
);
}
pub fn set_last_fragment(&mut self, is_last: bool) {
let fragment_offset_with_flags = self.get_fragment_offset_with_flags();
self.set_fragment_offset_with_flags(if is_last {
fragment_offset_with_flags & !FRAGMENT_FLAGS_MORE_FRAGMENTS
} else {
fragment_offset_with_flags | FRAGMENT_FLAGS_MORE_FRAGMENTS
});
}
}
pub type Destination = Extension;
pub type DestinationPacket<'p> = ExtensionPacket<'p>;
pub type MutableDestinationPacket<'p> = MutableExtensionPacket<'p>;
#[test]
fn ipv6_header_test() {
use crate::ip::IpNextHeaderProtocols;
use crate::{MutablePacket, Packet, PacketSize};
use alloc::vec;
let mut packet = [0u8; 0x200];
{
let mut ip_header = MutableIpv6Packet::new(&mut packet[..]).unwrap();
ip_header.set_version(6);
assert_eq!(ip_header.get_version(), 6);
ip_header.set_traffic_class(17);
assert_eq!(ip_header.get_traffic_class(), 17);
ip_header.set_flow_label(0x10101);
assert_eq!(ip_header.get_flow_label(), 0x10101);
ip_header.set_payload_length(0x0101);
assert_eq!(ip_header.get_payload_length(), 0x0101);
assert_eq!(0x0101, ip_header.payload().len());
ip_header.set_next_header(IpNextHeaderProtocols::Hopopt);
assert_eq!(ip_header.get_next_header(), IpNextHeaderProtocols::Hopopt);
ip_header.set_hop_limit(1);
assert_eq!(ip_header.get_hop_limit(), 1);
let source = Ipv6Addr::new(0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001);
ip_header.set_source(source);
assert_eq!(ip_header.get_source(), source);
let dest = Ipv6Addr::new(0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001);
ip_header.set_destination(dest);
assert_eq!(ip_header.get_destination(), dest);
let mut pos = {
let mut hopopt = MutableHopByHopPacket::new(ip_header.payload_mut()).unwrap();
hopopt.set_next_header(IpNextHeaderProtocols::Ipv6Opts);
assert_eq!(hopopt.get_next_header(), IpNextHeaderProtocols::Ipv6Opts);
hopopt.set_hdr_ext_len(1);
assert_eq!(hopopt.get_hdr_ext_len(), 1);
hopopt.set_options(&[b'A'; 14][..]);
assert_eq!(hopopt.payload(), b"AAAAAAAAAAAAAA");
hopopt.packet_size()
};
pos += {
let mut dstopt =
MutableDestinationPacket::new(&mut ip_header.payload_mut()[pos..]).unwrap();
dstopt.set_next_header(IpNextHeaderProtocols::Ipv6Route);
assert_eq!(dstopt.get_next_header(), IpNextHeaderProtocols::Ipv6Route);
dstopt.set_hdr_ext_len(1);
assert_eq!(dstopt.get_hdr_ext_len(), 1);
dstopt.set_options(&[b'B'; 14][..]);
assert_eq!(dstopt.payload(), b"BBBBBBBBBBBBBB");
dstopt.packet_size()
};
pos += {
let mut routing =
MutableRoutingPacket::new(&mut ip_header.payload_mut()[pos..]).unwrap();
routing.set_next_header(IpNextHeaderProtocols::Ipv6Frag);
assert_eq!(routing.get_next_header(), IpNextHeaderProtocols::Ipv6Frag);
routing.set_hdr_ext_len(1);
assert_eq!(routing.get_hdr_ext_len(), 1);
routing.set_routing_type(4);
assert_eq!(routing.get_routing_type(), 4);
routing.set_segments_left(2);
assert_eq!(routing.get_segments_left(), 2);
routing.set_data(&[b'C'; 12][..]);
assert_eq!(routing.payload(), b"CCCCCCCCCCCC");
routing.packet_size()
};
pos += {
let mut frag = MutableFragmentPacket::new(&mut ip_header.payload_mut()[pos..]).unwrap();
frag.set_next_header(IpNextHeaderProtocols::Udp);
assert_eq!(frag.get_next_header(), IpNextHeaderProtocols::Udp);
frag.set_fragment_offset(1024);
assert_eq!(frag.get_fragment_offset(), 1024);
frag.set_last_fragment(false);
assert!(!frag.is_last_fragment());
frag.set_id(1234);
assert_eq!(frag.get_id(), 1234);
frag.packet_size()
};
assert_eq!(
ExtensionIterable::new(&ip_header.payload()[..pos])
.map(|ext| (
ext.get_next_header(),
ext.get_hdr_ext_len(),
ext.packet_size()
))
.collect::<Vec<_>>(),
vec![
(IpNextHeaderProtocols::Ipv6Opts, 1, 16),
(IpNextHeaderProtocols::Ipv6Route, 1, 16),
(IpNextHeaderProtocols::Ipv6Frag, 1, 16),
(IpNextHeaderProtocols::Udp, 0, 8),
]
);
}
let ref_packet = [0x61, 0x11, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x10, 0x10, 0x01,
0x01, 0x10, 0x10, 0x01,
0x01, 0x10, 0x10, 0x01,
0x01, 0x10, 0x10, 0x01,
0x01, 0x10, 0x10, 0x01,
0x01, 0x10, 0x10, 0x01,
0x01, 0x10, 0x10, 0x01,
0x01, 0x10, 0x10, 0x01,
0x3c, 0x01, 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',
0x2b, 0x01, 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',
0x2c, 0x01, 0x04, 0x02, b'C', b'C', b'C', b'C', b'C', b'C', b'C', b'C',
b'C', b'C', b'C', b'C',
0x11, 0x00, 0x04, 0x01, 0x00, 0x00, 0x04, 0xd2 ];
assert_eq!(&ref_packet[..], &packet[..ref_packet.len()]);
}