use alloc::vec::Vec;
use core::borrow::Borrow;
use core::fmt::{self, Debug, Formatter};
use core::ops::Range;
use internet_checksum::Checksum;
use log::debug;
use net_types::ip::{GenericOverIp, IpAddress, Ipv4, Ipv4Addr, Ipv6Addr};
use packet::records::options::{OptionSequenceBuilder, OptionsRaw};
use packet::records::RecordsIter;
use packet::{
BufferAlloc, BufferProvider, BufferView, BufferViewMut, EmptyBuf, FragmentedBytesMut, FromRaw,
GrowBufferMut, InnerPacketBuilder, MaybeParsed, PacketBuilder, PacketConstraints,
ParsablePacket, ParseMetadata, ReusableBuffer, SerializeError, SerializeTarget, Serializer,
};
use zerocopy::byteorder::network_endian::U16;
use zerocopy::{
FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, SplitByteSliceMut, Unaligned,
};
use crate::error::{IpParseError, IpParseResult, ParseError};
use crate::ip::{
DscpAndEcn, FragmentOffset, IpExt, IpPacketBuilder, IpProto, Ipv4Proto, Ipv6Proto, Nat64Error,
Nat64TranslationResult,
};
use crate::ipv6::Ipv6PacketBuilder;
use crate::tcp::{TcpParseArgs, TcpSegment};
use crate::udp::{UdpPacket, UdpParseArgs};
pub(crate) use self::inner::IPV4_MIN_HDR_LEN;
use self::options::{Ipv4Option, Ipv4OptionsImpl};
pub const HDR_PREFIX_LEN: usize = 20;
pub const MAX_HDR_LEN: usize = 60;
pub const MAX_OPTIONS_LEN: usize = MAX_HDR_LEN - HDR_PREFIX_LEN;
const IPV4_FRAGMENT_DATA_BYTE_RANGE: Range<usize> = 4..8;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
pub enum Ipv4FragmentType {
InitialFragment,
NonInitialFragment,
}
#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
#[repr(C)]
pub struct HeaderPrefix {
version_ihl: u8,
dscp_and_ecn: DscpAndEcn,
total_len: U16,
id: U16,
flags_frag_off: [u8; 2],
ttl: u8,
proto: u8,
hdr_checksum: [u8; 2],
src_ip: Ipv4Addr,
dst_ip: Ipv4Addr,
}
const IP_VERSION: u8 = 4;
const VERSION_OFFSET: u8 = 4;
const IHL_MASK: u8 = 0xF;
const IHL_MAX: u8 = (1 << VERSION_OFFSET) - 1;
const FLAGS_OFFSET: u8 = 13;
const FLAGS_MAX: u8 = (1 << (16 - FLAGS_OFFSET)) - 1;
const FRAG_OFF_MAX: u16 = (1 << FLAGS_OFFSET) - 1;
impl HeaderPrefix {
#[allow(clippy::too_many_arguments)]
fn new(
ihl: u8,
dscp_and_ecn: DscpAndEcn,
total_len: u16,
id: u16,
flags: u8,
frag_off: u16,
ttl: u8,
proto: u8,
hdr_checksum: [u8; 2],
src_ip: Ipv4Addr,
dst_ip: Ipv4Addr,
) -> HeaderPrefix {
debug_assert!(ihl <= IHL_MAX);
debug_assert!(flags <= FLAGS_MAX);
debug_assert!(frag_off <= FRAG_OFF_MAX);
HeaderPrefix {
version_ihl: (IP_VERSION << VERSION_OFFSET) | ihl,
dscp_and_ecn,
total_len: U16::new(total_len),
id: U16::new(id),
flags_frag_off: ((u16::from(flags) << FLAGS_OFFSET) | frag_off).to_be_bytes(),
ttl,
proto,
src_ip,
dst_ip,
hdr_checksum,
}
}
fn version(&self) -> u8 {
self.version_ihl >> VERSION_OFFSET
}
pub(crate) fn ihl(&self) -> u8 {
self.version_ihl & IHL_MASK
}
pub(crate) fn mf_flag(&self) -> bool {
self.flags_frag_off[0] & (1 << ((FLAGS_OFFSET - 8) + MF_FLAG_OFFSET)) > 0
}
}
pub trait Ipv4Header {
fn get_header_prefix(&self) -> &HeaderPrefix;
fn dscp_and_ecn(&self) -> DscpAndEcn {
self.get_header_prefix().dscp_and_ecn
}
fn id(&self) -> u16 {
self.get_header_prefix().id.get()
}
fn df_flag(&self) -> bool {
self.get_header_prefix().flags_frag_off[0] & (1 << (5 + DF_FLAG_OFFSET)) > 0
}
fn mf_flag(&self) -> bool {
self.get_header_prefix().mf_flag()
}
fn fragment_offset(&self) -> FragmentOffset {
FragmentOffset::new_with_lsb(U16::from_bytes(self.get_header_prefix().flags_frag_off).get())
}
fn fragment_type(&self) -> Ipv4FragmentType {
match self.fragment_offset().into_raw() {
0 => Ipv4FragmentType::InitialFragment,
_ => Ipv4FragmentType::NonInitialFragment,
}
}
fn ttl(&self) -> u8 {
self.get_header_prefix().ttl
}
fn proto(&self) -> Ipv4Proto {
Ipv4Proto::from(self.get_header_prefix().proto)
}
fn src_ip(&self) -> Ipv4Addr {
self.get_header_prefix().src_ip
}
fn dst_ip(&self) -> Ipv4Addr {
self.get_header_prefix().dst_ip
}
fn builder(&self) -> Ipv4PacketBuilder {
let mut s = Ipv4PacketBuilder {
id: self.id(),
dscp_and_ecn: self.dscp_and_ecn(),
flags: 0,
frag_off: self.fragment_offset().into_raw(),
ttl: self.ttl(),
proto: self.get_header_prefix().proto.into(),
src_ip: self.src_ip(),
dst_ip: self.dst_ip(),
};
s.df_flag(self.df_flag());
s.mf_flag(self.mf_flag());
s
}
}
pub struct Ipv4OnlyMeta {
pub id: u16,
pub fragment_type: Ipv4FragmentType,
}
pub struct Ipv4Packet<B> {
hdr_prefix: Ref<B, HeaderPrefix>,
options: Options<B>,
body: B,
}
impl<B: SplitByteSlice, I: IpExt> GenericOverIp<I> for Ipv4Packet<B> {
type Type = <I as IpExt>::Packet<B>;
}
impl<B: SplitByteSlice> Ipv4Header for Ipv4Packet<B> {
fn get_header_prefix(&self) -> &HeaderPrefix {
&self.hdr_prefix
}
}
impl<B: SplitByteSlice> ParsablePacket<B, ()> for Ipv4Packet<B> {
type Error = IpParseError<Ipv4>;
fn parse_metadata(&self) -> ParseMetadata {
let header_len = Ref::bytes(&self.hdr_prefix).len() + self.options.bytes().len();
ParseMetadata::from_packet(header_len, self.body.len(), 0)
}
fn parse<BV: BufferView<B>>(buffer: BV, _args: ()) -> IpParseResult<Ipv4, Self> {
Ipv4PacketRaw::<B>::parse(buffer, ()).and_then(Ipv4Packet::try_from_raw)
}
}
impl<B: SplitByteSlice> FromRaw<Ipv4PacketRaw<B>, ()> for Ipv4Packet<B> {
type Error = IpParseError<Ipv4>;
fn try_from_raw_with(raw: Ipv4PacketRaw<B>, _args: ()) -> Result<Self, Self::Error> {
let hdr_prefix = raw.hdr_prefix;
let hdr_bytes = (hdr_prefix.ihl() * 4) as usize;
if hdr_bytes < HDR_PREFIX_LEN {
return debug_err!(Err(ParseError::Format.into()), "invalid IHL: {}", hdr_prefix.ihl());
}
let options = match raw.options {
MaybeParsed::Incomplete(_) => {
return debug_err!(Err(ParseError::Format.into()), "Incomplete options");
}
MaybeParsed::Complete(unchecked) => Options::try_from_raw(unchecked)
.map_err(|e| debug_err!(e, "malformed options: {:?}", e))?,
};
if hdr_prefix.version() != 4 {
return debug_err!(
Err(ParseError::Format.into()),
"unexpected IP version: {}",
hdr_prefix.version()
);
}
let body = match raw.body {
MaybeParsed::Incomplete(_) => {
if hdr_prefix.mf_flag() {
return debug_err!(
Err(ParseError::NotSupported.into()),
"fragmentation not supported"
);
} else {
return debug_err!(Err(ParseError::Format.into()), "Incomplete body");
}
}
MaybeParsed::Complete(bytes) => bytes,
};
let packet = Ipv4Packet { hdr_prefix, options, body };
if packet.compute_header_checksum() != [0, 0] {
return debug_err!(Err(ParseError::Checksum.into()), "invalid checksum");
}
Ok(packet)
}
}
fn compute_header_checksum(hdr_prefix: &[u8], options: &[u8]) -> [u8; 2] {
let mut c = Checksum::new();
c.add_bytes(hdr_prefix);
c.add_bytes(options);
c.checksum()
}
impl<B: SplitByteSlice> Ipv4Packet<B> {
pub fn iter_options(&self) -> impl Iterator<Item = Ipv4Option<'_>> {
self.options.iter()
}
fn compute_header_checksum(&self) -> [u8; 2] {
compute_header_checksum(Ref::bytes(&self.hdr_prefix), self.options.bytes())
}
pub fn body(&self) -> &[u8] {
&self.body
}
pub fn header_len(&self) -> usize {
Ref::bytes(&self.hdr_prefix).len() + self.options.bytes().len()
}
pub fn copy_header_bytes_for_fragment(&self) -> Vec<u8> {
let expected_bytes_len = self.header_len();
let mut bytes = Vec::with_capacity(expected_bytes_len);
bytes.extend_from_slice(Ref::bytes(&self.hdr_prefix));
bytes.extend_from_slice(self.options.bytes());
assert_eq!(bytes.len(), expected_bytes_len);
bytes[IPV4_FRAGMENT_DATA_BYTE_RANGE].copy_from_slice(&[0; 4][..]);
bytes
}
pub fn nat64_translate(
&self,
v6_src_addr: Ipv6Addr,
v6_dst_addr: Ipv6Addr,
) -> Nat64TranslationResult<impl Serializer<Buffer = EmptyBuf> + Debug + '_, Nat64Error> {
#[derive(Debug)]
enum Nat64Serializer<T, U, O> {
Tcp(T),
Udp(U),
Other(O),
}
impl<T, U, O> Serializer for Nat64Serializer<T, U, O>
where
T: Serializer<Buffer = EmptyBuf>,
U: Serializer<Buffer = EmptyBuf>,
O: Serializer<Buffer = EmptyBuf>,
{
type Buffer = EmptyBuf;
fn serialize<B, P>(
self,
outer: PacketConstraints,
provider: P,
) -> Result<B, (SerializeError<P::Error>, Self)>
where
B: GrowBufferMut,
P: BufferProvider<Self::Buffer, B>,
{
match self {
Nat64Serializer::Tcp(serializer) => serializer
.serialize(outer, provider)
.map_err(|(err, ser)| (err, Nat64Serializer::Tcp(ser))),
Nat64Serializer::Udp(serializer) => serializer
.serialize(outer, provider)
.map_err(|(err, ser)| (err, Nat64Serializer::Udp(ser))),
Nat64Serializer::Other(serializer) => serializer
.serialize(outer, provider)
.map_err(|(err, ser)| (err, Nat64Serializer::Other(ser))),
}
}
fn serialize_new_buf<B: ReusableBuffer, A: BufferAlloc<B>>(
&self,
outer: PacketConstraints,
alloc: A,
) -> Result<B, SerializeError<A::Error>> {
match self {
Nat64Serializer::Tcp(serializer) => serializer.serialize_new_buf(outer, alloc),
Nat64Serializer::Udp(serializer) => serializer.serialize_new_buf(outer, alloc),
Nat64Serializer::Other(serializer) => {
serializer.serialize_new_buf(outer, alloc)
}
}
}
}
let v6_builder = |v6_proto| {
let mut builder =
Ipv6PacketBuilder::new(v6_src_addr, v6_dst_addr, self.ttl(), v6_proto);
builder.dscp_and_ecn(self.dscp_and_ecn());
builder.flowlabel(0);
builder
};
match self.proto() {
Ipv4Proto::Igmp => {
Nat64TranslationResult::Drop
}
Ipv4Proto::Proto(IpProto::Tcp) => {
let v6_pkt_builder = v6_builder(Ipv6Proto::Proto(IpProto::Tcp));
let args = TcpParseArgs::new(self.src_ip(), self.dst_ip());
match TcpSegment::parse(&mut self.body.as_bytes(), args) {
Ok(tcp) => {
let tcp_serializer =
Nat64Serializer::Tcp(tcp.into_serializer(v6_src_addr, v6_dst_addr));
Nat64TranslationResult::Forward(tcp_serializer.encapsulate(v6_pkt_builder))
}
Err(msg) => {
debug!("Parsing of TCP segment failed: {:?}", msg);
let common_serializer =
Nat64Serializer::Other(self.body().into_serializer());
Nat64TranslationResult::Forward(
common_serializer.encapsulate(v6_pkt_builder),
)
}
}
}
Ipv4Proto::Proto(IpProto::Udp) => {
let v6_pkt_builder = v6_builder(Ipv6Proto::Proto(IpProto::Udp));
let args = UdpParseArgs::new(self.src_ip(), self.dst_ip());
match UdpPacket::parse(&mut self.body.as_bytes(), args) {
Ok(udp) => {
let udp_serializer =
Nat64Serializer::Udp(udp.into_serializer(v6_src_addr, v6_dst_addr));
Nat64TranslationResult::Forward(udp_serializer.encapsulate(v6_pkt_builder))
}
Err(msg) => {
debug!("Parsing of UDP packet failed: {:?}", msg);
let common_serializer =
Nat64Serializer::Other(self.body().into_serializer());
Nat64TranslationResult::Forward(
common_serializer.encapsulate(v6_pkt_builder),
)
}
}
}
Ipv4Proto::Icmp => Nat64TranslationResult::Err(Nat64Error::NotImplemented),
Ipv4Proto::Other(val) => {
let v6_pkt_builder = v6_builder(Ipv6Proto::Other(val));
let common_serializer = Nat64Serializer::Other(self.body().into_serializer());
Nat64TranslationResult::Forward(common_serializer.encapsulate(v6_pkt_builder))
}
Ipv4Proto::Proto(IpProto::Reserved) => Nat64TranslationResult::Drop,
}
}
pub fn to_vec(&self) -> Vec<u8> {
let Ipv4Packet { hdr_prefix, options, body } = self;
let mut buf = Vec::with_capacity(
Ref::bytes(&hdr_prefix).len() + options.bytes().len() + body.as_bytes().len(),
);
buf.extend(Ref::bytes(&hdr_prefix));
buf.extend(options.bytes());
buf.extend(body.as_bytes());
buf
}
}
impl<B: SplitByteSliceMut> Ipv4Packet<B> {
pub fn set_src_ip_and_update_checksum(&mut self, addr: Ipv4Addr) {
let old_bytes = self.hdr_prefix.src_ip.bytes();
self.hdr_prefix.hdr_checksum =
internet_checksum::update(self.hdr_prefix.hdr_checksum, &old_bytes, addr.bytes());
self.hdr_prefix.src_ip = addr;
}
pub fn set_dst_ip_and_update_checksum(&mut self, addr: Ipv4Addr) {
let old_bytes = self.hdr_prefix.dst_ip.bytes();
self.hdr_prefix.hdr_checksum =
internet_checksum::update(self.hdr_prefix.hdr_checksum, &old_bytes, addr.bytes());
self.hdr_prefix.dst_ip = addr;
}
pub fn set_ttl(&mut self, ttl: u8) {
let old_bytes = [self.hdr_prefix.ttl, self.hdr_prefix.proto];
let new_bytes = [ttl, self.hdr_prefix.proto];
self.hdr_prefix.hdr_checksum =
internet_checksum::update(self.hdr_prefix.hdr_checksum, &old_bytes, &new_bytes);
self.hdr_prefix.ttl = ttl;
}
pub fn body_mut(&mut self) -> &mut [u8] {
&mut self.body
}
}
impl<B> Debug for Ipv4Packet<B>
where
B: SplitByteSlice,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("Ipv4Packet")
.field("src_ip", &self.src_ip())
.field("dst_ip", &self.dst_ip())
.field("id", &self.id())
.field("ttl", &self.ttl())
.field("proto", &self.proto())
.field("frag_off", &self.fragment_offset())
.field("dscp", &self.dscp_and_ecn().dscp())
.field("ecn", &self.dscp_and_ecn().ecn())
.field("mf_flag", &self.mf_flag())
.field("df_flag", &self.df_flag())
.field("body", &alloc::format!("<{} bytes>", self.body.len()))
.finish()
}
}
pub struct Ipv4PacketRaw<B> {
hdr_prefix: Ref<B, HeaderPrefix>,
options: MaybeParsed<OptionsRaw<B, Ipv4OptionsImpl>, B>,
body: MaybeParsed<B, B>,
}
impl<B: SplitByteSlice> Ipv4Header for Ipv4PacketRaw<B> {
fn get_header_prefix(&self) -> &HeaderPrefix {
&self.hdr_prefix
}
}
impl<B: SplitByteSlice> ParsablePacket<B, ()> for Ipv4PacketRaw<B> {
type Error = IpParseError<Ipv4>;
fn parse_metadata(&self) -> ParseMetadata {
let header_len = Ref::bytes(&self.hdr_prefix).len() + self.options.len();
ParseMetadata::from_packet(header_len, self.body.len(), 0)
}
fn parse<BV: BufferView<B>>(mut buffer: BV, _args: ()) -> IpParseResult<Ipv4, Self> {
let hdr_prefix = buffer
.take_obj_front::<HeaderPrefix>()
.ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for header"))?;
let hdr_bytes = (hdr_prefix.ihl() * 4) as usize;
let options = MaybeParsed::take_from_buffer_with(
&mut buffer,
hdr_bytes.saturating_sub(HDR_PREFIX_LEN),
OptionsRaw::new,
);
let total_len: usize = hdr_prefix.total_len.get().into();
let body_len = total_len.saturating_sub(hdr_bytes);
if buffer.len() > body_len {
let _: B = buffer.take_back(buffer.len() - body_len).unwrap();
}
let body = MaybeParsed::new_with_min_len(buffer.into_rest(), body_len);
Ok(Self { hdr_prefix, options, body })
}
}
impl<B> Ipv4PacketRaw<B> {
pub fn options(&self) -> &MaybeParsed<OptionsRaw<B, Ipv4OptionsImpl>, B> {
&self.options
}
}
impl<B: SplitByteSlice> Ipv4PacketRaw<B> {
pub fn body(&self) -> MaybeParsed<&[u8], &[u8]> {
self.body.as_ref().map(|b| b.deref()).map_incomplete(|b| b.deref())
}
pub fn into_body(self) -> MaybeParsed<B, B> {
self.body
}
}
impl<B: SplitByteSliceMut> Ipv4PacketRaw<B> {
pub fn set_src_ip_and_update_checksum(&mut self, addr: Ipv4Addr) {
let old_bytes = self.hdr_prefix.src_ip.bytes();
self.hdr_prefix.hdr_checksum =
internet_checksum::update(self.hdr_prefix.hdr_checksum, &old_bytes, addr.bytes());
self.hdr_prefix.src_ip = addr;
}
pub fn set_dst_ip_and_update_checksum(&mut self, addr: Ipv4Addr) {
let old_bytes = self.hdr_prefix.dst_ip.bytes();
self.hdr_prefix.hdr_checksum =
internet_checksum::update(self.hdr_prefix.hdr_checksum, &old_bytes, addr.bytes());
self.hdr_prefix.dst_ip = addr;
}
}
pub type Options<B> = packet::records::options::Options<B, Ipv4OptionsImpl>;
#[derive(Debug)]
pub struct Ipv4OptionsTooLongError;
#[derive(Debug, Clone)]
pub struct Ipv4PacketBuilderWithOptions<'a, I> {
prefix_builder: Ipv4PacketBuilder,
options: OptionSequenceBuilder<Ipv4Option<'a>, I>,
}
impl<'a, I> Ipv4PacketBuilderWithOptions<'a, I>
where
I: Iterator + Clone,
I::Item: Borrow<Ipv4Option<'a>>,
{
pub fn new<T: IntoIterator<IntoIter = I>>(
prefix_builder: Ipv4PacketBuilder,
options: T,
) -> Result<Ipv4PacketBuilderWithOptions<'a, I>, Ipv4OptionsTooLongError> {
let options = OptionSequenceBuilder::new(options.into_iter());
if options.serialized_len() > MAX_OPTIONS_LEN {
return Err(Ipv4OptionsTooLongError);
}
Ok(Ipv4PacketBuilderWithOptions { prefix_builder, options })
}
fn aligned_options_len(&self) -> usize {
crate::utils::round_to_next_multiple_of_four(self.options.serialized_len())
}
pub fn prefix_builder(&self) -> &Ipv4PacketBuilder {
&self.prefix_builder
}
pub fn prefix_builder_mut(&mut self) -> &mut Ipv4PacketBuilder {
&mut self.prefix_builder
}
pub fn options(&self) -> &I {
self.options.records()
}
pub fn with_fragment_options(
self,
first_fragment: bool,
) -> Ipv4PacketBuilderWithOptions<'a, impl Iterator<Item: Borrow<Ipv4Option<'a>>> + Clone> {
let Self { prefix_builder, options } = self;
Ipv4PacketBuilderWithOptions {
prefix_builder,
options: OptionSequenceBuilder::new(
options
.records()
.clone()
.filter(move |opt| first_fragment || opt.borrow().copied()),
),
}
}
}
impl<'a, B> Ipv4PacketBuilderWithOptions<'a, RecordsIter<'a, B, Ipv4OptionsImpl>> {
pub fn new_with_records_iter(
prefix_builder: Ipv4PacketBuilder,
iter: RecordsIter<'a, B, Ipv4OptionsImpl>,
) -> Self {
Self { prefix_builder, options: OptionSequenceBuilder::new(iter) }
}
}
impl<'a, I> PacketBuilder for Ipv4PacketBuilderWithOptions<'a, I>
where
I: Iterator + Clone,
I::Item: Borrow<Ipv4Option<'a>>,
{
fn constraints(&self) -> PacketConstraints {
let header_len = IPV4_MIN_HDR_LEN + self.aligned_options_len();
assert_eq!(header_len % 4, 0);
PacketConstraints::new(header_len, 0, 0, (1 << 16) - 1 - header_len)
}
fn serialize(&self, target: &mut SerializeTarget<'_>, body: FragmentedBytesMut<'_, '_>) {
let opt_len = self.aligned_options_len();
let mut header = &mut &mut target.header[..];
let opts = header.take_back_zero(opt_len).expect("too few bytes for Ipv4 options");
let Ipv4PacketBuilderWithOptions { prefix_builder, options } = self;
options.serialize_into(opts);
prefix_builder.serialize(target, body);
}
}
impl<'a, Item> IpPacketBuilder<Ipv4>
for Ipv4PacketBuilderWithOptions<'a, core::slice::Iter<'a, Item>>
where
Item: Debug,
&'a Item: Borrow<Ipv4Option<'a>>,
{
fn new(src_ip: Ipv4Addr, dst_ip: Ipv4Addr, ttl: u8, proto: Ipv4Proto) -> Self {
Ipv4PacketBuilderWithOptions::new(
Ipv4PacketBuilder::new(src_ip, dst_ip, ttl, proto),
[].iter(),
)
.expect("packet builder with no options should be valid")
}
fn src_ip(&self) -> Ipv4Addr {
self.prefix_builder.src_ip
}
fn set_src_ip(&mut self, addr: Ipv4Addr) {
self.prefix_builder.set_src_ip(addr);
}
fn dst_ip(&self) -> Ipv4Addr {
self.prefix_builder.dst_ip
}
fn set_dst_ip(&mut self, addr: Ipv4Addr) {
self.prefix_builder.set_dst_ip(addr);
}
fn proto(&self) -> Ipv4Proto {
self.prefix_builder.proto
}
fn set_dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
self.prefix_builder.set_dscp_and_ecn(dscp_and_ecn)
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Ipv4PacketBuilder {
id: u16,
dscp_and_ecn: DscpAndEcn,
flags: u8,
frag_off: u16,
ttl: u8,
proto: Ipv4Proto,
src_ip: Ipv4Addr,
dst_ip: Ipv4Addr,
}
impl Ipv4PacketBuilder {
pub fn new<S: Into<Ipv4Addr>, D: Into<Ipv4Addr>>(
src_ip: S,
dst_ip: D,
ttl: u8,
proto: Ipv4Proto,
) -> Ipv4PacketBuilder {
Ipv4PacketBuilder {
id: 0,
dscp_and_ecn: DscpAndEcn::default(),
flags: 0,
frag_off: 0,
ttl,
proto: proto,
src_ip: src_ip.into(),
dst_ip: dst_ip.into(),
}
}
pub fn dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
self.dscp_and_ecn = dscp_and_ecn;
}
pub fn id(&mut self, id: u16) {
self.id = id
}
pub fn df_flag(&mut self, df: bool) {
if df {
self.flags |= 1 << DF_FLAG_OFFSET;
} else {
self.flags &= !(1 << DF_FLAG_OFFSET);
}
}
pub fn mf_flag(&mut self, mf: bool) {
if mf {
self.flags |= 1 << MF_FLAG_OFFSET;
} else {
self.flags &= !(1 << MF_FLAG_OFFSET);
}
}
pub fn fragment_offset(&mut self, fragment_offset: FragmentOffset) {
self.frag_off = fragment_offset.into_raw();
}
pub fn read_df_flag(&self) -> bool {
(self.flags & (1 << DF_FLAG_OFFSET)) != 0
}
}
impl PacketBuilder for Ipv4PacketBuilder {
fn constraints(&self) -> PacketConstraints {
PacketConstraints::new(IPV4_MIN_HDR_LEN, 0, 0, (1 << 16) - 1 - IPV4_MIN_HDR_LEN)
}
fn serialize(&self, target: &mut SerializeTarget<'_>, body: FragmentedBytesMut<'_, '_>) {
let total_len = target.header.len() + body.len();
assert_eq!(target.header.len() % 4, 0);
let ihl: u8 = u8::try_from(target.header.len() / 4).expect("Header too large");
let id = if ((self.flags & (1 << DF_FLAG_OFFSET)) == 0)
|| ((self.flags & (1 << MF_FLAG_OFFSET)) == 1)
|| (self.frag_off > 0)
{
self.id
} else {
0
};
let mut hdr_prefix = HeaderPrefix::new(
ihl,
self.dscp_and_ecn,
{
debug_assert!(total_len <= core::u16::MAX as usize);
total_len as u16
},
id,
self.flags,
self.frag_off,
self.ttl,
self.proto.into(),
[0, 0], self.src_ip,
self.dst_ip,
);
let options = &target.header[HDR_PREFIX_LEN..];
let checksum = compute_header_checksum(hdr_prefix.as_bytes(), options);
hdr_prefix.hdr_checksum = checksum;
let mut header = &mut target.header;
header.write_obj_front(&hdr_prefix).expect("too few bytes for IPv4 header prefix");
}
}
impl IpPacketBuilder<Ipv4> for Ipv4PacketBuilder {
fn new(src_ip: Ipv4Addr, dst_ip: Ipv4Addr, ttl: u8, proto: Ipv4Proto) -> Self {
Ipv4PacketBuilder::new(src_ip, dst_ip, ttl, proto)
}
fn src_ip(&self) -> Ipv4Addr {
self.src_ip
}
fn set_src_ip(&mut self, addr: Ipv4Addr) {
self.src_ip = addr;
}
fn dst_ip(&self) -> Ipv4Addr {
self.dst_ip
}
fn set_dst_ip(&mut self, addr: Ipv4Addr) {
self.dst_ip = addr;
}
fn proto(&self) -> Ipv4Proto {
self.proto
}
fn set_dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
self.dscp_and_ecn = dscp_and_ecn;
}
}
const DF_FLAG_OFFSET: u8 = 1;
const MF_FLAG_OFFSET: u8 = 0;
pub(crate) fn reassemble_fragmented_packet<
B: SplitByteSliceMut,
BV: BufferViewMut<B>,
I: Iterator<Item = Vec<u8>>,
>(
mut buffer: BV,
header: Vec<u8>,
body_fragments: I,
) -> IpParseResult<Ipv4, ()> {
let bytes = buffer.as_mut();
bytes[0..header.len()].copy_from_slice(&header[..]);
let mut byte_count = header.len();
for p in body_fragments {
bytes[byte_count..byte_count + p.len()].copy_from_slice(&p[..]);
byte_count += p.len();
}
if byte_count > usize::from(core::u16::MAX) {
return debug_err!(
Err(ParseError::Format.into()),
"fragmented packet length of {} bytes is too large",
byte_count
);
}
let mut header = Ref::<_, HeaderPrefix>::from_prefix(bytes).unwrap().0;
header.total_len.set(u16::try_from(byte_count).unwrap());
header.flags_frag_off = [0; 2];
header.hdr_checksum = [0; 2];
header.hdr_checksum = compute_header_checksum(header.as_bytes(), &[]);
Ok(())
}
pub mod options {
use byteorder::{ByteOrder, NetworkEndian};
use packet::records::options::{
OptionBuilder, OptionLayout, OptionParseErr, OptionParseLayout, OptionsImpl,
};
use packet::BufferViewMut;
use zerocopy::byteorder::network_endian::U16;
const OPTION_KIND_EOL: u8 = 0;
const OPTION_KIND_NOP: u8 = 1;
const OPTION_KIND_RTRALRT: u8 = 148;
const OPTION_RTRALRT_LEN: usize = 2;
#[derive(PartialEq, Eq, Debug, Clone)]
#[allow(missing_docs)]
pub enum Ipv4Option<'a> {
RouterAlert { data: u16 },
Unrecognized { kind: u8, data: &'a [u8] },
}
impl<'a> Ipv4Option<'a> {
pub fn copied(&self) -> bool {
match self {
Ipv4Option::RouterAlert { .. } => true,
Ipv4Option::Unrecognized { kind, .. } => *kind & (1 << 7) != 0,
}
}
}
#[derive(Debug, Clone)]
pub struct Ipv4OptionsImpl;
impl OptionLayout for Ipv4OptionsImpl {
type KindLenField = u8;
}
impl OptionParseLayout for Ipv4OptionsImpl {
type Error = OptionParseErr;
const END_OF_OPTIONS: Option<u8> = Some(0);
const NOP: Option<u8> = Some(1);
}
impl OptionsImpl for Ipv4OptionsImpl {
type Option<'a> = Ipv4Option<'a>;
fn parse<'a>(kind: u8, data: &'a [u8]) -> Result<Option<Ipv4Option<'a>>, OptionParseErr> {
match kind {
self::OPTION_KIND_EOL | self::OPTION_KIND_NOP => {
unreachable!("records::options::Options promises to handle EOL and NOP")
}
self::OPTION_KIND_RTRALRT => {
if data.len() == OPTION_RTRALRT_LEN {
Ok(Some(Ipv4Option::RouterAlert { data: NetworkEndian::read_u16(data) }))
} else {
Err(OptionParseErr)
}
}
kind => {
if data.len() > 38 {
Err(OptionParseErr)
} else {
Ok(Some(Ipv4Option::Unrecognized { kind, data }))
}
}
}
}
}
impl<'a> OptionBuilder for Ipv4Option<'a> {
type Layout = Ipv4OptionsImpl;
fn serialized_len(&self) -> usize {
match self {
Ipv4Option::RouterAlert { .. } => OPTION_RTRALRT_LEN,
Ipv4Option::Unrecognized { data, .. } => data.len(),
}
}
fn option_kind(&self) -> u8 {
match self {
Ipv4Option::RouterAlert { .. } => OPTION_KIND_RTRALRT,
Ipv4Option::Unrecognized { kind, .. } => *kind,
}
}
fn serialize_into(&self, mut buffer: &mut [u8]) {
match self {
Ipv4Option::Unrecognized { data, .. } => buffer.copy_from_slice(data),
Ipv4Option::RouterAlert { data } => {
(&mut buffer).write_obj_front(&U16::new(*data)).unwrap()
}
};
}
}
#[cfg(test)]
mod test {
use packet::records::options::Options;
use packet::records::RecordBuilder;
use super::*;
#[test]
fn test_serialize_router_alert() {
let mut buffer = [0u8; 4];
let option = Ipv4Option::RouterAlert { data: 0 };
<Ipv4Option<'_> as RecordBuilder>::serialize_into(&option, &mut buffer);
assert_eq!(buffer[0], 148);
assert_eq!(buffer[1], 4);
assert_eq!(buffer[2], 0);
assert_eq!(buffer[3], 0);
}
#[test]
fn test_parse_router_alert() {
let mut buffer: Vec<u8> = vec![148, 4, 0, 0];
let options = Options::<_, Ipv4OptionsImpl>::parse(buffer.as_mut()).unwrap();
let rtralt = options.iter().next().unwrap();
assert_eq!(rtralt, Ipv4Option::RouterAlert { data: 0 });
}
}
}
mod inner {
pub const IPV4_MIN_HDR_LEN: usize = super::HDR_PREFIX_LEN;
}
pub mod testutil {
pub use super::inner::IPV4_MIN_HDR_LEN;
pub const IPV4_TTL_OFFSET: usize = 8;
pub const IPV4_CHECKSUM_OFFSET: usize = 10;
}
#[cfg(test)]
mod tests {
use net_types::ethernet::Mac;
use packet::{Buf, FragmentedBuffer, ParseBuffer};
use super::*;
use crate::ethernet::{
EtherType, EthernetFrame, EthernetFrameBuilder, EthernetFrameLengthCheck,
ETHERNET_MIN_BODY_LEN_NO_TAG,
};
use crate::testutil::*;
const DEFAULT_SRC_MAC: Mac = Mac::new([1, 2, 3, 4, 5, 6]);
const DEFAULT_DST_MAC: Mac = Mac::new([7, 8, 9, 0, 1, 2]);
const DEFAULT_SRC_IP: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
const DEFAULT_DST_IP: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
const DEFAULT_V6_SRC_IP: Ipv6Addr = Ipv6Addr::new([0x2001, 0x0db8, 0, 0, 0, 0, 0, 1]);
const DEFAULT_V6_DST_IP: Ipv6Addr = Ipv6Addr::new([0x2001, 0x0db8, 0, 0, 0, 0, 0, 2]);
#[test]
fn test_parse_serialize_full_tcp() {
use crate::testdata::tls_client_hello_v4::*;
let mut buf = ETHERNET_FRAME.bytes;
let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
verify_ethernet_frame(&frame, ETHERNET_FRAME);
let mut body = frame.body();
let packet = body.parse::<Ipv4Packet<_>>().unwrap();
verify_ipv4_packet(&packet, IPV4_PACKET);
let buffer = packet
.body()
.into_serializer()
.encapsulate(packet.builder())
.encapsulate(frame.builder())
.serialize_vec_outer()
.unwrap();
assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
assert_eq!(&packet.to_vec()[..], IPV4_PACKET.bytes);
}
#[test]
fn test_parse_serialize_full_udp() {
use crate::testdata::dns_request_v4::*;
let mut buf = ETHERNET_FRAME.bytes;
let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
verify_ethernet_frame(&frame, ETHERNET_FRAME);
let mut body = frame.body();
let packet = body.parse::<Ipv4Packet<_>>().unwrap();
verify_ipv4_packet(&packet, IPV4_PACKET);
let buffer = packet
.body()
.into_serializer()
.encapsulate(packet.builder())
.encapsulate(frame.builder())
.serialize_vec_outer()
.unwrap();
assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
assert_eq!(&packet.to_vec()[..], IPV4_PACKET.bytes);
}
#[test]
fn test_parse_serialize_with_options() {
use crate::testdata::igmpv2_membership::report::*;
let mut buf = IP_PACKET_BYTES;
let packet = buf.parse::<Ipv4Packet<_>>().unwrap();
assert_eq!(packet.iter_options().count(), 1);
assert_eq!(&packet.to_vec()[..], IP_PACKET_BYTES);
}
fn hdr_prefix_to_bytes(hdr_prefix: HeaderPrefix) -> [u8; 20] {
zerocopy::transmute!(hdr_prefix)
}
fn new_hdr_prefix() -> HeaderPrefix {
HeaderPrefix::new(
5,
DscpAndEcn::default(),
20,
0x0102,
0,
0,
0x03,
IpProto::Tcp.into(),
[0xa6, 0xcf],
DEFAULT_SRC_IP,
DEFAULT_DST_IP,
)
}
#[test]
fn test_parse() {
let mut bytes = &hdr_prefix_to_bytes(new_hdr_prefix())[..];
let packet = bytes.parse::<Ipv4Packet<_>>().unwrap();
assert_eq!(packet.id(), 0x0102);
assert_eq!(packet.ttl(), 0x03);
assert_eq!(packet.proto(), IpProto::Tcp.into());
assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
assert_eq!(packet.body(), []);
}
#[test]
fn test_parse_padding() {
let mut buffer = Buf::new(Vec::new(), ..)
.encapsulate(Ipv4PacketBuilder::new(
DEFAULT_DST_IP,
DEFAULT_DST_IP,
0,
IpProto::Tcp.into(),
))
.encapsulate(EthernetFrameBuilder::new(
DEFAULT_SRC_MAC,
DEFAULT_DST_MAC,
EtherType::Ipv4,
ETHERNET_MIN_BODY_LEN_NO_TAG,
))
.serialize_vec_outer()
.unwrap();
let _: EthernetFrame<_> =
buffer.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
assert_eq!(buffer.len(), 46);
let packet = buffer.parse::<Ipv4Packet<_>>().unwrap();
assert_eq!(packet.body().len(), 0);
assert_eq!(buffer.len(), 0);
}
#[test]
fn test_parse_error() {
let mut hdr_prefix = new_hdr_prefix();
hdr_prefix.version_ihl = (5 << 4) | 5;
assert_eq!(
(&hdr_prefix_to_bytes(hdr_prefix)[..]).parse::<Ipv4Packet<_>>().unwrap_err(),
ParseError::Format.into()
);
let mut hdr_prefix = new_hdr_prefix();
hdr_prefix.version_ihl = (4 << 4) | 4;
assert_eq!(
(&hdr_prefix_to_bytes(hdr_prefix)[..]).parse::<Ipv4Packet<_>>().unwrap_err(),
ParseError::Format.into()
);
let mut hdr_prefix = new_hdr_prefix();
hdr_prefix.version_ihl = (4 << 4) | 6;
assert_eq!(
(&hdr_prefix_to_bytes(hdr_prefix)[..]).parse::<Ipv4Packet<_>>().unwrap_err(),
ParseError::Format.into()
);
}
fn new_builder() -> Ipv4PacketBuilder {
Ipv4PacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, 64, IpProto::Tcp.into())
}
#[test]
fn test_fragment_type() {
fn test_fragment_type_helper(fragment_offset: u16, expect_fragment_type: Ipv4FragmentType) {
let mut builder = new_builder();
builder.fragment_offset(FragmentOffset::new(fragment_offset).unwrap());
let mut buf = [0; IPV4_MIN_HDR_LEN]
.into_serializer()
.encapsulate(builder)
.serialize_vec_outer()
.unwrap();
let packet = buf.parse::<Ipv4Packet<_>>().unwrap();
assert_eq!(packet.fragment_type(), expect_fragment_type);
}
test_fragment_type_helper(0x0000, Ipv4FragmentType::InitialFragment);
test_fragment_type_helper(0x0008, Ipv4FragmentType::NonInitialFragment);
}
#[test]
fn test_serialize() {
let mut builder = new_builder();
builder.dscp_and_ecn(DscpAndEcn::new(0x12, 3));
builder.id(0x0405);
builder.df_flag(true);
builder.mf_flag(true);
builder.fragment_offset(FragmentOffset::new(0x0607).unwrap());
let mut buf = (&[0, 1, 2, 3, 3, 4, 5, 7, 8, 9])
.into_serializer()
.encapsulate(builder)
.serialize_vec_outer()
.unwrap();
assert_eq!(
buf.as_ref(),
[
69, 75, 0, 30, 4, 5, 102, 7, 64, 6, 0, 112, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 3,
4, 5, 7, 8, 9
]
);
let packet = buf.parse::<Ipv4Packet<_>>().unwrap();
assert_eq!(packet.dscp_and_ecn().dscp(), 0x12);
assert_eq!(packet.dscp_and_ecn().ecn(), 3);
assert_eq!(packet.id(), 0x0405);
assert!(packet.df_flag());
assert!(packet.mf_flag());
assert_eq!(packet.fragment_offset().into_raw(), 0x0607);
assert_eq!(packet.fragment_type(), Ipv4FragmentType::NonInitialFragment);
}
#[test]
fn test_serialize_id_unset() {
let mut builder = new_builder();
builder.id(0x0405);
builder.df_flag(true);
let mut buf = (&[0, 1, 2, 3, 3, 4, 5, 7, 8, 9])
.into_serializer()
.encapsulate(builder)
.serialize_vec_outer()
.unwrap();
let packet = buf.parse::<Ipv4Packet<_>>().unwrap();
assert_eq!(packet.id(), 0);
assert!(packet.df_flag());
assert_eq!(packet.mf_flag(), false);
assert_eq!(packet.fragment_offset().into_raw(), 0);
assert_eq!(packet.fragment_type(), Ipv4FragmentType::InitialFragment);
}
#[test]
fn test_serialize_zeroes() {
let mut buf_0 = [0; IPV4_MIN_HDR_LEN];
let _: Buf<&mut [u8]> = Buf::new(&mut buf_0[..], IPV4_MIN_HDR_LEN..)
.encapsulate(new_builder())
.serialize_vec_outer()
.unwrap()
.unwrap_a();
let mut buf_1 = [0xFF; IPV4_MIN_HDR_LEN];
let _: Buf<&mut [u8]> = Buf::new(&mut buf_1[..], IPV4_MIN_HDR_LEN..)
.encapsulate(new_builder())
.serialize_vec_outer()
.unwrap()
.unwrap_a();
assert_eq!(buf_0, buf_1);
}
#[test]
#[should_panic(expected = "(SizeLimitExceeded, Nested { inner: Buf { buf:")]
fn test_serialize_panic_packet_length() {
let _: Buf<&mut [u8]> = Buf::new(&mut [0; (1 << 16) - IPV4_MIN_HDR_LEN][..], ..)
.encapsulate(new_builder())
.serialize_vec_outer()
.unwrap()
.unwrap_a();
}
#[test]
fn test_copy_header_bytes_for_fragment() {
let hdr_prefix = new_hdr_prefix();
let mut bytes = hdr_prefix_to_bytes(hdr_prefix);
let mut buf = &bytes[..];
let packet = buf.parse::<Ipv4Packet<_>>().unwrap();
let copied_bytes = packet.copy_header_bytes_for_fragment();
bytes[IPV4_FRAGMENT_DATA_BYTE_RANGE].copy_from_slice(&[0; 4][..]);
assert_eq!(&copied_bytes[..], &bytes[..]);
}
#[test]
fn test_partial_parsing() {
use core::ops::Deref as _;
let mut hdr_prefix = new_hdr_prefix();
hdr_prefix.total_len = U16::new(256);
let mut bytes = hdr_prefix_to_bytes(hdr_prefix)[..].to_owned();
const PAYLOAD: &[u8] = &[1, 2, 3, 4, 5];
bytes.extend(PAYLOAD);
let mut buf = &bytes[..];
let packet = buf.parse::<Ipv4PacketRaw<_>>().unwrap();
let Ipv4PacketRaw { hdr_prefix, options, body } = &packet;
assert_eq!(Ref::bytes(&hdr_prefix), &bytes[0..20]);
assert_eq!(options.as_ref().complete().unwrap().deref(), []);
assert_eq!(body, &MaybeParsed::Incomplete(PAYLOAD));
assert!(Ipv4Packet::try_from_raw(packet).is_err());
let mut hdr_prefix = new_hdr_prefix();
hdr_prefix.version_ihl = (4 << 4) | 10;
let bytes = hdr_prefix_to_bytes(hdr_prefix);
let mut buf = &bytes[..];
let packet = buf.parse::<Ipv4PacketRaw<_>>().unwrap();
let Ipv4PacketRaw { hdr_prefix, options, body } = &packet;
assert_eq!(Ref::bytes(&hdr_prefix), bytes);
assert_eq!(options.as_ref().incomplete().unwrap(), &[]);
assert_eq!(body.complete().unwrap(), []);
assert!(Ipv4Packet::try_from_raw(packet).is_err());
let hdr_prefix = new_hdr_prefix();
let bytes = &hdr_prefix_to_bytes(hdr_prefix);
let mut buf = &bytes[0..10];
assert!(buf.parse::<Ipv4PacketRaw<_>>().is_err());
}
fn create_ipv4_and_ipv6_builders(
proto_v4: Ipv4Proto,
proto_v6: Ipv6Proto,
) -> (Ipv4PacketBuilder, Ipv6PacketBuilder) {
const IP_DSCP_AND_ECN: DscpAndEcn = DscpAndEcn::new(0x12, 3);
const IP_TTL: u8 = 64;
let mut ipv4_builder =
Ipv4PacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, IP_TTL, proto_v4);
ipv4_builder.dscp_and_ecn(IP_DSCP_AND_ECN);
ipv4_builder.id(0x0405);
ipv4_builder.df_flag(true);
ipv4_builder.mf_flag(false);
ipv4_builder.fragment_offset(FragmentOffset::ZERO);
let mut ipv6_builder =
Ipv6PacketBuilder::new(DEFAULT_V6_SRC_IP, DEFAULT_V6_DST_IP, IP_TTL, proto_v6);
ipv6_builder.dscp_and_ecn(IP_DSCP_AND_ECN);
ipv6_builder.flowlabel(0);
(ipv4_builder, ipv6_builder)
}
fn create_tcp_ipv4_and_ipv6_pkt(
) -> (packet::Either<EmptyBuf, Buf<Vec<u8>>>, packet::Either<EmptyBuf, Buf<Vec<u8>>>) {
use crate::tcp::TcpSegmentBuilder;
use core::num::NonZeroU16;
let tcp_src_port: NonZeroU16 = NonZeroU16::new(20).unwrap();
let tcp_dst_port: NonZeroU16 = NonZeroU16::new(30).unwrap();
const TCP_SEQ_NUM: u32 = 4321;
const TCP_ACK_NUM: Option<u32> = Some(1234);
const TCP_WINDOW_SIZE: u16 = 12345;
const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
let (ipv4_builder, ipv6_builder) =
create_ipv4_and_ipv6_builders(IpProto::Tcp.into(), IpProto::Tcp.into());
let tcp_builder = TcpSegmentBuilder::new(
DEFAULT_SRC_IP,
DEFAULT_DST_IP,
tcp_src_port,
tcp_dst_port,
TCP_SEQ_NUM,
TCP_ACK_NUM,
TCP_WINDOW_SIZE,
);
let v4_pkt_buf = (&PAYLOAD)
.into_serializer()
.encapsulate(tcp_builder)
.encapsulate(ipv4_builder)
.serialize_vec_outer()
.unwrap();
let v6_tcp_builder = TcpSegmentBuilder::new(
DEFAULT_V6_SRC_IP,
DEFAULT_V6_DST_IP,
tcp_src_port,
tcp_dst_port,
TCP_SEQ_NUM,
TCP_ACK_NUM,
TCP_WINDOW_SIZE,
);
let v6_pkt_buf = (&PAYLOAD)
.into_serializer()
.encapsulate(v6_tcp_builder)
.encapsulate(ipv6_builder)
.serialize_vec_outer()
.unwrap();
(v4_pkt_buf, v6_pkt_buf)
}
#[test]
fn test_nat64_translate_tcp() {
let (mut v4_pkt_buf, expected_v6_pkt_buf) = create_tcp_ipv4_and_ipv6_pkt();
let parsed_v4_packet = v4_pkt_buf.parse::<Ipv4Packet<_>>().unwrap();
let nat64_translation_result =
parsed_v4_packet.nat64_translate(DEFAULT_V6_SRC_IP, DEFAULT_V6_DST_IP);
let serializable_pkt = match nat64_translation_result {
Nat64TranslationResult::Forward(s) => s,
_ => panic!("Nat64TranslationResult not of Forward type!"),
};
let translated_v6_pkt_buf = serializable_pkt.serialize_vec_outer().unwrap();
assert_eq!(
expected_v6_pkt_buf.to_flattened_vec(),
translated_v6_pkt_buf.to_flattened_vec()
);
}
fn create_udp_ipv4_and_ipv6_pkt(
) -> (packet::Either<EmptyBuf, Buf<Vec<u8>>>, packet::Either<EmptyBuf, Buf<Vec<u8>>>) {
use crate::udp::UdpPacketBuilder;
use core::num::NonZeroU16;
let udp_src_port: NonZeroU16 = NonZeroU16::new(35000).unwrap();
let udp_dst_port: NonZeroU16 = NonZeroU16::new(53).unwrap();
const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
let (ipv4_builder, ipv6_builder) =
create_ipv4_and_ipv6_builders(IpProto::Udp.into(), IpProto::Udp.into());
let udp_builder =
UdpPacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, Some(udp_src_port), udp_dst_port);
let v4_pkt_buf = (&PAYLOAD)
.into_serializer()
.encapsulate(udp_builder)
.encapsulate(ipv4_builder)
.serialize_vec_outer()
.unwrap();
let v6_udp_builder = UdpPacketBuilder::new(
DEFAULT_V6_SRC_IP,
DEFAULT_V6_DST_IP,
Some(udp_src_port),
udp_dst_port,
);
let v6_pkt_buf = (&PAYLOAD)
.into_serializer()
.encapsulate(v6_udp_builder)
.encapsulate(ipv6_builder)
.serialize_vec_outer()
.unwrap();
(v4_pkt_buf, v6_pkt_buf)
}
#[test]
fn test_nat64_translate_udp() {
let (mut v4_pkt_buf, expected_v6_pkt_buf) = create_udp_ipv4_and_ipv6_pkt();
let parsed_v4_packet = v4_pkt_buf.parse::<Ipv4Packet<_>>().unwrap();
let nat64_translation_result =
parsed_v4_packet.nat64_translate(DEFAULT_V6_SRC_IP, DEFAULT_V6_DST_IP);
let serializable_pkt = match nat64_translation_result {
Nat64TranslationResult::Forward(s) => s,
_ => panic!(
"Nat64TranslationResult not of Forward type: {:?} ",
nat64_translation_result
),
};
let translated_v6_pkt_buf = serializable_pkt.serialize_vec_outer().unwrap();
assert_eq!(
expected_v6_pkt_buf.to_flattened_vec(),
translated_v6_pkt_buf.to_flattened_vec()
);
}
#[test]
fn test_nat64_translate_non_tcp_udp_icmp() {
const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
let (ipv4_builder, ipv6_builder) =
create_ipv4_and_ipv6_builders(Ipv4Proto::Other(50), Ipv6Proto::Other(50));
let mut v4_pkt_buf =
(&PAYLOAD).into_serializer().encapsulate(ipv4_builder).serialize_vec_outer().unwrap();
let expected_v6_pkt_buf =
(&PAYLOAD).into_serializer().encapsulate(ipv6_builder).serialize_vec_outer().unwrap();
let translated_v6_pkt_buf = {
let parsed_v4_packet = v4_pkt_buf.parse::<Ipv4Packet<_>>().unwrap();
let nat64_translation_result =
parsed_v4_packet.nat64_translate(DEFAULT_V6_SRC_IP, DEFAULT_V6_DST_IP);
let serializable_pkt = match nat64_translation_result {
Nat64TranslationResult::Forward(s) => s,
_ => panic!(
"Nat64TranslationResult not of Forward type: {:?} ",
nat64_translation_result
),
};
let translated_buf = serializable_pkt.serialize_vec_outer().unwrap();
translated_buf
};
assert_eq!(
expected_v6_pkt_buf.to_flattened_vec(),
translated_v6_pkt_buf.to_flattened_vec()
);
}
}