crafter 0.3.0

Packet-level network interaction for Rust tools and agents.
Documentation
use super::{
    IpDefrag, IpDefragConfig, IpDefragEvictionReason, IpDefragMetadata, IpDefragOverlapStatus,
    IpFragment, IpFragmentConfig, IpFragmentFamily, IpFragmentMetadata, IpFragmentRange,
    IpFragmentReason,
};
use crate::wire::record::{BackendKind, PacketOrigin, PacketRecord};
use crate::wire::transform::PacketTransform;
use crate::Raw;

fn record(payload: &'static str) -> PacketRecord {
    PacketRecord::new(Raw::from(payload))
        .with_origin(PacketOrigin::Generated)
        .with_backend(BackendKind::Memory)
        .with_interface("lo")
}

#[test]
fn ip_defrag_passes_records_through_initially() {
    let input = record("payload");
    let expected_summary = input.packet().summary();
    let expected_metadata = input.metadata().clone();
    let mut transform = IpDefrag::new();

    let output = transform.defrag_record(input).unwrap();

    assert_eq!(transform.name(), "ip-defrag");
    assert_eq!(transform.input_count(), 1);
    assert_eq!(transform.emitted_count(), 1);
    assert_eq!(output.len(), 1);
    assert_eq!(output.records()[0].packet().summary(), expected_summary);
    assert_eq!(output.records()[0].metadata(), &expected_metadata);
}

#[test]
fn ip_fragment_passes_records_through_initially() {
    let input = record("payload");
    let expected_summary = input.packet().summary();
    let expected_metadata = input.metadata().clone();
    let mut transform = IpFragment::new(1280);

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

    assert_eq!(transform.name(), "ip-fragment");
    assert_eq!(transform.config().mtu(), 1280);
    assert_eq!(transform.input_count(), 1);
    assert_eq!(transform.emitted_count(), 1);
    assert_eq!(output.len(), 1);
    assert_eq!(output.records()[0].packet().summary(), expected_summary);
    assert_eq!(output.records()[0].metadata(), &expected_metadata);
}

#[test]
fn ip_defrag_config_exposes_passthrough_policy() {
    let config = IpDefragConfig::new().pass_non_fragments(false);
    let transform = IpDefrag::new().with_config(config);

    assert!(!transform.config().emits_non_fragments());
}

#[test]
fn ip_fragment_config_exposes_mtu_and_df_policy() {
    let config = IpFragmentConfig::new(1500).honor_dont_fragment(false);
    let transform = IpFragment::with_config(config);

    assert_eq!(transform.config().mtu(), 1500);
    assert!(!transform.config().honors_dont_fragment());
}

#[test]
fn ip_fragment_metadata_exposes_emission_details() {
    let metadata = IpFragmentMetadata::new(
        IpFragmentFamily::Ipv6,
        1280,
        0xfeed_beef,
        4,
        false,
        5,
        4,
        IpFragmentRange::new(32, 48),
    )
    .with_original_len(2048)
    .with_reason(IpFragmentReason::Fragmented);

    assert_eq!(metadata.family(), IpFragmentFamily::Ipv6);
    assert_eq!(metadata.family().version(), 6);
    assert_eq!(metadata.family().label(), "ipv6");
    assert_eq!(metadata.mtu(), 1280);
    assert_eq!(metadata.identification(), 0xfeed_beef);
    assert_eq!(metadata.fragment_offset(), 4);
    assert_eq!(metadata.fragment_offset_bytes(), 32);
    assert!(!metadata.more_fragments());
    assert_eq!(metadata.fragment_count(), 5);
    assert_eq!(metadata.emitted_index(), 4);
    assert_eq!(metadata.byte_range(), IpFragmentRange::new(32, 48));
    assert_eq!(metadata.byte_range().len(), 16);
    assert_eq!(metadata.original_len(), Some(2048));
    assert_eq!(metadata.reason(), Some(&IpFragmentReason::Fragmented));
}

#[test]
fn ip_defrag_metadata_exposes_overlap_duplicates_and_eviction() {
    let metadata = IpDefragMetadata::new(IpFragmentFamily::Ipv4, 0x1234)
        .with_datagram_key("192.0.2.1>198.51.100.1 proto=17 id=0x1234")
        .with_fragment_count(3)
        .with_duplicate_count(2)
        .with_overlap_status(IpDefragOverlapStatus::Conflicting)
        .with_byte_range(IpFragmentRange::new(0, 24))
        .with_byte_range(IpFragmentRange::new(16, 40))
        .with_total_len(60)
        .with_eviction_reason(IpDefragEvictionReason::Conflict);

    assert_eq!(metadata.family(), IpFragmentFamily::Ipv4);
    assert_eq!(metadata.identification(), 0x1234);
    assert_eq!(
        metadata.datagram_key(),
        Some("192.0.2.1>198.51.100.1 proto=17 id=0x1234")
    );
    assert_eq!(metadata.fragment_count(), 3);
    assert_eq!(metadata.duplicate_count(), 2);
    assert_eq!(
        metadata.overlap_status(),
        IpDefragOverlapStatus::Conflicting
    );
    assert!(metadata.overlap_status().has_overlap());
    assert!(metadata.has_conflict());
    assert_eq!(
        metadata.byte_ranges(),
        &[IpFragmentRange::new(0, 24), IpFragmentRange::new(16, 40)]
    );
    assert_eq!(metadata.total_len(), Some(60));
    assert_eq!(
        metadata.eviction_reason(),
        Some(&IpDefragEvictionReason::Conflict)
    );
    assert!(!metadata.timed_out());
}