Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add etherparse-defrag #92

Merged
merged 14 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

# etherparse

A zero allocation library for parsing & writing a bunch of packet based protocols (EthernetII, IPv4, IPv6, UDP, TCP ...).
A zero allocation supporting library for parsing & writing a bunch of packet based protocols (EthernetII, IPv4, IPv6, UDP, TCP ...).

Currently supported are:
* Ethernet II
Expand All @@ -17,13 +17,15 @@ Currently supported are:
* TCP
* ICMP & ICMPv6 (not all message types are supported)

Reconstruction of fragmented IP packets is also supported, but requires allocations.

## Usage

Add the following to your `Cargo.toml`:

```toml
[dependencies]
etherparse = "0.15"
etherparse = "0.16"
```

## What is etherparse?
Expand All @@ -32,7 +34,7 @@ Etherparse is intended to provide the basic network parsing functions that allow
Some key points are:

* It is completely written in Rust and thoroughly tested.
* Special attention has been paid to not use allocations or syscalls.
* Special attention has been paid to not use allocations or syscalls except in the "defragmentation" code.
* The package is still in development and can & will still change.
* The current focus of development is on the most popular protocols in the internet & transport layer.

Expand Down
4 changes: 2 additions & 2 deletions etherparse/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "etherparse"
version = "0.15.0"
version = "0.16.0"
authors = ["Julian Schmid <[email protected]>"]
edition = "2021"
repository = "https://github.com/JulianSchmid/etherparse"
Expand All @@ -26,7 +26,7 @@ std = ["arrayvec/std"]
arrayvec = { version = "0.7.2", default-features = false }

[dev-dependencies]
proptest = "1.0.0"
proptest = "1.4.0"

[package.metadata.docs.rs]
all-features = true
Expand Down
78 changes: 78 additions & 0 deletions etherparse/examples/ip_defrag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use etherparse::*;

fn main() {
// setup some network data to parse
let builder = PacketBuilder::ethernet2(
// source mac
[1, 2, 3, 4, 5, 6],
// destination mac
[7, 8, 9, 10, 11, 12],
)
.ip(IpHeaders::Ipv4(
Ipv4Header {
total_len: 0, // will be overwritten by builder
identification: 1234,
dont_fragment: false,
more_fragments: true,
fragment_offset: IpFragOffset::try_new(1024 / 8).unwrap(),
time_to_live: 20,
protocol: IpNumber::UDP,
header_checksum: 0, // will be overwritten by builder
source: [1, 2, 3, 4],
destination: [2, 3, 4, 5],
..Default::default()
},
Default::default(),
))
.udp(
21, // source port
1234, // desitnation port
);

// payload of the udp packet
let payload = [1, 2, 3, 4, 5, 6, 7, 8];

// get some memory to store the serialized data
let mut serialized = Vec::<u8>::with_capacity(builder.size(payload.len()));
builder.write(&mut serialized, &payload).unwrap();

// pool that manages the different fragmented packets & the different memory buffers for re-assembly
let mut ip_defrag_pool = defrag::IpDefragPool::<(), ()>::new();

// slice the packet into the different header components
let sliced_packet = match SlicedPacket::from_ethernet(&serialized) {
Err(err) => {
println!("Err {:?}", err);
return;
}
Ok(v) => v,
};

// constructed
if sliced_packet.is_ip_payload_fragmented() {
let defrag_result = ip_defrag_pool.process_sliced_packet(&sliced_packet, (), ());
match defrag_result {
Ok(Some(finished)) => {
println!(
"Successfully reconstructed fragmented IP packet ({} bytes, protocol {:?})",
finished.payload.len(),
finished.ip_number,
);

// continue parsing the payload
// ... fill in your code here

// IMPORTANT: After done return the finished packet buffer to avoid unneeded allocations
ip_defrag_pool.return_buf(finished);
}
Ok(None) => {
println!(
"Received a fragmented packet, but the reconstruction was not yet finished"
);
}
Err(err) => {
println!("Error reconstructing fragmented IPv4 packet: {err}");
}
}
}
}
1 change: 1 addition & 0 deletions etherparse/src/checksum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,7 @@ pub mod u64_16bit_word {

proptest! {
#[test]
#[cfg_attr(miri, ignore)] // vec allocation reduces miri runspeed too much
fn u32_u16_comparison(
data in proptest::collection::vec(any::<u8>(), 0..0xfffusize)
) {
Expand Down
1 change: 1 addition & 0 deletions etherparse/src/compositions_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,7 @@ impl ComponentTest {
proptest! {
///Test that all known packet compositions are parsed correctly.
#[test]
#[cfg_attr(miri, ignore)] // vec allocation reduces miri runspeed too much
fn test_compositions(ref eth in ethernet_2_unknown(),
ref vlan_outer in vlan_single_unknown(),
ref vlan_inner in vlan_single_unknown(),
Expand Down
Loading
Loading