Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/alexforster/pdu

Small, fast, and correct L2/L3/L4 packet parser.
https://github.com/alexforster/pdu

parser rust rustlang

Last synced: 5 days ago
JSON representation

Small, fast, and correct L2/L3/L4 packet parser.

Awesome Lists containing this project

README

        

# pdu

Small, fast, and correct L2/L3/L4 packet parser.

**Author:** Alex Forster \

**License:** Apache-2.0

[![build status](https://travis-ci.org/alexforster/pdu.svg?branch=master)](https://travis-ci.org/alexforster/pdu)
[![crates.io version](https://img.shields.io/crates/v/pdu.svg)](https://crates.io/crates/pdu)
[![docs.rs](https://docs.rs/pdu/badge.svg)](https://docs.rs/pdu)

#### Small

* Fully-featured `no_std` support
* No Crate dependencies and no macros
* Internet protocols only: application-layer protocols are out of scope

#### Fast

* Lazy parsing: only the fields that you access are parsed
* Zero-copy construction: no heap allocations are performed

#### Correct

* Tested against [Wireshark](https://www.wireshark.org/docs/man-pages/tshark.html) to ensure all packet fields are parsed correctly
* Fuzzed using [Honggfuzz](https://github.com/google/honggfuzz) to ensure invalid input does not cause panics
* Does not use any `unsafe` code

## Supported Protocols

The following protocol hierarchy can be parsed with this library:

* Ethernet (including vlan)
* ARP
* IPv4 (including options)
* TCP (including options)
* UDP
* ICMP
* GREv0
* ...Ethernet, IPv4, IPv6...
* IPv6 (including extension headers)
* TCP (including options)
* UDP
* ICMPv6
* GREv0
* ...Ethernet, IPv4, IPv6...

In addition, unrecognized upper protocols are accessible as bytes via `Raw`
enum variants.

## Getting Started

#### `Cargo.toml`

```toml
[dependencies]
pdu = "1.1"
```

#### Examples

```rust
use pdu::*;

// parse a layer 2 (Ethernet) packet using EthernetPdu::new()

fn main() {
let packet: &[u8] = &[
0x68, 0x5b, 0x35, 0xc0, 0x61, 0xb6, 0x00, 0x1d, 0x09, 0x94, 0x65, 0x38, 0x08, 0x00, 0x45, 0x00, 0x00,
0x3b, 0x2d, 0xfd, 0x00, 0x00, 0x40, 0x11, 0xbc, 0x43, 0x83, 0xb3, 0xc4, 0x2e, 0x83, 0xb3, 0xc4, 0xdc,
0x18, 0xdb, 0x18, 0xdb, 0x00, 0x27, 0xe0, 0x3e, 0x05, 0x1d, 0x07, 0x15, 0x08, 0x07, 0x65, 0x78, 0x61,
0x6d, 0x70, 0x6c, 0x65, 0x08, 0x07, 0x74, 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x08, 0x01, 0x31, 0x0a,
0x04, 0x1e, 0xcc, 0xe2, 0x51,
];

match EthernetPdu::new(&packet) {
Ok(ethernet_pdu) => {
println!("[ethernet] destination_address: {:x?}", ethernet_pdu.destination_address().as_ref());
println!("[ethernet] source_address: {:x?}", ethernet_pdu.source_address().as_ref());
println!("[ethernet] ethertype: 0x{:04x}", ethernet_pdu.ethertype());
if let Some(vlan) = ethernet_pdu.vlan() {
println!("[ethernet] vlan: 0x{:04x}", vlan);
}
// upper-layer protocols can be accessed via the inner() method
match ethernet_pdu.inner() {
Ok(Ethernet::Ipv4(ipv4_pdu)) => {
println!("[ipv4] source_address: {:x?}", ipv4_pdu.source_address().as_ref());
println!("[ipv4] destination_address: {:x?}", ipv4_pdu.destination_address().as_ref());
println!("[ipv4] protocol: 0x{:02x}", ipv4_pdu.protocol());
// upper-layer protocols can be accessed via the inner() method (not shown)
}
Ok(Ethernet::Ipv6(ipv6_pdu)) => {
println!("[ipv6] source_address: {:x?}", ipv6_pdu.source_address().as_ref());
println!("[ipv6] destination_address: {:x?}", ipv6_pdu.destination_address().as_ref());
println!("[ipv6] protocol: 0x{:02x}", ipv6_pdu.computed_protocol());
// upper-layer protocols can be accessed via the inner() method (not shown)
}
Ok(other) => {
panic!("Unexpected protocol {:?}", other);
}
Err(e) => {
panic!("EthernetPdu::inner() parser failure: {:?}", e);
}
}
}
Err(e) => {
panic!("EthernetPdu::new() parser failure: {:?}", e);
}
}
}
```

```rust
use pdu::*;

// parse a layer 3 (IP) packet using Ip::new()

fn main() {
let packet: &[u8] = &[
0x45, 0x00, 0x00, 0x3b, 0x2d, 0xfd, 0x00, 0x00, 0x40, 0x11, 0xbc, 0x43, 0x83, 0xb3, 0xc4, 0x2e, 0x83, 0xb3,
0xc4, 0xdc, 0x18, 0xdb, 0x18, 0xdb, 0x00, 0x27, 0xe0, 0x3e, 0x05, 0x1d, 0x07, 0x15, 0x08, 0x07, 0x65, 0x78,
0x61, 0x6d, 0x70, 0x6c, 0x65, 0x08, 0x07, 0x74, 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x08, 0x01, 0x31, 0x0a,
0x04, 0x1e, 0xcc, 0xe2, 0x51,
];

match Ip::new(&packet) {
Ok(Ip::Ipv4(ipv4_pdu)) => {
println!("[ipv4] source_address: {:x?}", ipv4_pdu.source_address().as_ref());
println!("[ipv4] destination_address: {:x?}", ipv4_pdu.destination_address().as_ref());
println!("[ipv4] protocol: 0x{:02x}", ipv4_pdu.protocol());
// upper-layer protocols can be accessed via the inner() method (not shown)
}
Ok(Ip::Ipv6(ipv6_pdu)) => {
println!("[ipv6] source_address: {:x?}", ipv6_pdu.source_address().as_ref());
println!("[ipv6] destination_address: {:x?}", ipv6_pdu.destination_address().as_ref());
println!("[ipv6] protocol: 0x{:02x}", ipv6_pdu.computed_protocol());
// upper-layer protocols can be accessed via the inner() method (not shown)
}
Err(e) => {
panic!("Ip::new() parser failure: {:?}", e);
}
}
}
```