#packet #networking #packets #raw-sockets #protocols #network-protocol #ethernet

no-std zero-packet

A zero-copy Rust library that builds and parses network packets in-place

10 releases

0.1.0 Jul 20, 2024
0.0.9 Jul 15, 2024

#643 in Network programming

MIT license

210KB
4.5K SLoC

zero-packet

crates.io MIT docs.rs

Super simple library to efficiently build and parse network packets in-place with zero overhead.

No async, no allocations, no dependencies, no std, no unsafe. It simply cannot be easier.

Use zero-packet if you are working with raw sockets, low-level networking, or something similar.

Supported

You can build and parse a wide variety of packets of arbitrary complexity.

  • Ethernet II
    • Optional
      • VLAN tagging
      • Double tagging
  • ARP
  • IPv4
  • IPv6
    • Extension headers
      • Hop-by-Hop Options
      • Routing
      • Fragment
      • Authentication Header
      • Destination Options (1st and 2nd)
  • IP-in-IP
    • Encapsulation
      • IPv4 in IPv4
      • IPv4 in IPv6
      • IPv6 in IPv4
      • IPv6 in IPv6
  • ICMPv4
  • ICMPv6
  • TCP
  • UDP

Usage

Getting started

Install via your command line:

cargo add zero-packet

Or add the following to your Cargo.toml:

[dependencies]
zero-packet = "0.1.0"

PacketBuilder

If you want to create network packets manually and efficiently, look no further.

// Raw packet that we will mutate in-place.
// Ethernet header (14 bytes) + IPv4 header (20 bytes) + UDP header (8 bytes) = 42 bytes.
let mut buffer = [0u8; 64]

// Some random payload (11 bytes).
let payload = b"Hello, UDP!";

// PacketBuilder is a zero-copy packet builder.
// Using the typestate pattern, a state machine is implemented at compile-time.
// The state machine ensures that the package is built structurally correct.
let mut packet_builder = PacketBuilder::new(&mut buffer);

// Sets Ethernet, IPv4 and UDP header fields.
// Optional: add payload to the packet.
// Encapsulates everything in the given byte slice.
let packet: &[u8] = packet_builder
    .ethernet(src_mac, dest_mac, ethertype)?
    .ipv4(version, ihl, dscp, ecn, total_length, id, flags, fragment_offset, ttl, protocol, src_ip, dest_ip)?
    .udp(src_ip, src_port, dest_ip, dest_port, length, Some(payload))?
    .build();

PacketParser

Parsing any received byte slice for which we don't know ahead of time what type of packet it is.

// Some byte slice that we have received.
// We don't know yet what it contains.
let packet = [..];

// PacketParser is a zero-copy packet parser.
// The `parse` method recognizes which protocol headers are present.
let parsed = PacketParser::parse(&packet)?;

// Now it is as easy as this.
if let Some(ethernet) = parsed.ethernet {
    let ethertype = ethernet.ethertype();
    // ...
}

// Or this.
if let Some(ipv4) = parsed.ipv4 {
    let src_ip = ipv4.src_ip();
    // ...
}

// Alternatively, just manually read headers directly.
// By adjusting the index of the slice you can find different headers.
if let Some(tcp) = TcpReader::new(&packet)? {
    let src_port = tcp.src_port();
    // ...
}

No runtime deps