crafter 0.3.0

Packet-level network interaction for Rust tools and agents.
Documentation
use std::net::{Ipv4Addr, Ipv6Addr};

use super::{IpFragment, IpFragmentFamily, IpFragmentRange, IpFragmentReason};
use crate::wire::record::PacketRecord;
use crate::{Ipv4, Ipv6, Ipv6FragmentHeader, Raw, IPPROTO_TCP, IPPROTO_UDP};

fn ipv4_source() -> Ipv4Addr {
    Ipv4Addr::new(192, 0, 2, 24)
}

fn ipv4_destination() -> Ipv4Addr {
    Ipv4Addr::new(198, 51, 100, 24)
}

fn ipv6_source() -> Ipv6Addr {
    "2001:db8:24::1".parse().unwrap()
}

fn ipv6_destination() -> Ipv6Addr {
    "2001:db8:24::2".parse().unwrap()
}

#[test]
fn ipv4_single_emission_attaches_fragment_metadata() {
    let record = PacketRecord::new(
        Ipv4::with_addresses(ipv4_source(), ipv4_destination())
            .protocol(IPPROTO_UDP)
            .identification(0x2457)
            / Raw::from_bytes(b"abcdefghijklmnop"),
    );
    let mut transform = IpFragment::new(1500);

    let output = transform.fragment_record(record).unwrap();

    assert_eq!(output.len(), 1);
    let metadata = output.records()[0].metadata().ip_fragment_metadata();
    assert_eq!(metadata.len(), 1);
    let metadata = &metadata[0];
    assert_eq!(metadata.family(), IpFragmentFamily::Ipv4);
    assert_eq!(metadata.mtu(), 1500);
    assert_eq!(metadata.identification(), 0x2457);
    assert_eq!(metadata.fragment_offset(), 0);
    assert_eq!(metadata.fragment_offset_bytes(), 0);
    assert!(!metadata.more_fragments());
    assert_eq!(metadata.fragment_count(), 1);
    assert_eq!(metadata.fragment_index(), 0);
    assert_eq!(metadata.emitted_index(), 0);
    assert_eq!(metadata.byte_range(), IpFragmentRange::new(0, 16));
    assert_eq!(metadata.original_len(), Some(16));
    assert_eq!(metadata.reason(), Some(&IpFragmentReason::AlreadyFits));
}

#[test]
fn ipv4_fragment_emission_records_offset_range_and_more_fragments() {
    let record = PacketRecord::new(
        Ipv4::with_addresses(ipv4_source(), ipv4_destination())
            .protocol(IPPROTO_TCP)
            .identification(0x2468)
            .fragment_offset(3)
            .more_fragments(true)
            / Raw::from_bytes(b"qrstuvwx"),
    );
    let mut transform = IpFragment::new(576);

    let output = transform.fragment_record(record).unwrap();

    let metadata = &output.records()[0].metadata().ip_fragment_metadata()[0];
    assert_eq!(metadata.family(), IpFragmentFamily::Ipv4);
    assert_eq!(metadata.mtu(), 576);
    assert_eq!(metadata.identification(), 0x2468);
    assert_eq!(metadata.fragment_offset(), 3);
    assert_eq!(metadata.fragment_offset_bytes(), 24);
    assert!(metadata.more_fragments());
    assert_eq!(metadata.fragment_count(), 1);
    assert_eq!(metadata.fragment_index(), 0);
    assert_eq!(metadata.byte_range(), IpFragmentRange::new(24, 32));
    assert_eq!(metadata.original_len(), Some(8));
    assert_eq!(metadata.reason(), Some(&IpFragmentReason::Fragmented));
}

#[test]
fn ipv6_fragment_header_emission_attaches_fragment_metadata() {
    let record = PacketRecord::new(
        Ipv6::new()
            .src(ipv6_source())
            .dst(ipv6_destination())
            .next_header(crate::IPPROTO_IPV6_FRAGMENT)
            / Ipv6FragmentHeader::new()
                .next_header(IPPROTO_UDP)
                .identification(0x1020_3040)
                .fragment_offset(2)
                .more_fragments(true)
            / Raw::from_bytes(b"abcdefgh"),
    );
    let mut transform = IpFragment::new(1280);

    let output = transform.fragment_record(record).unwrap();

    let metadata = &output.records()[0].metadata().ip_fragment_metadata()[0];
    assert_eq!(metadata.family(), IpFragmentFamily::Ipv6);
    assert_eq!(metadata.mtu(), 1280);
    assert_eq!(metadata.identification(), 0x1020_3040);
    assert_eq!(metadata.fragment_offset(), 2);
    assert_eq!(metadata.fragment_offset_bytes(), 16);
    assert!(metadata.more_fragments());
    assert_eq!(metadata.fragment_count(), 1);
    assert_eq!(metadata.fragment_index(), 0);
    assert_eq!(metadata.byte_range(), IpFragmentRange::new(16, 24));
    assert_eq!(metadata.original_len(), Some(8));
    assert_eq!(metadata.reason(), Some(&IpFragmentReason::Fragmented));
}