network-types 0.0.1

Rust structs representing network-related types in Linux.
Documentation

network-types

Rust structs representing network-related types (on Layer 2, 3 and 4) in Linux.

The crate is no_std and the structures are fully compatible with the ones provided by the Linux kernel, which makes it a great fit for eBPF programs written with Aya.

Example with Aya

This crate can be used for parsing packet headers in TC classifier and XDP.

A small example of an XDP program logging information about addresses and ports for incoming packets:

#![no_std]
#![no_main]

use aya_bpf::{bindings::xdp_action, macros::xdp, programs::XdpContext};
use aya_log_ebpf::info;

use core::mem;
use network_types::{
    l2::ethernet::{EthHdr, ETH_HDR_LEN},
    l3::{
        ip::{Ipv4Hdr, IPV4_HDR_LEN},
        L3Protocol,
    },
    l4::{tcp::TcpHdr, udp::UdpHdr, L4Protocol},
};

#[xdp]
pub fn xdp_firewall(ctx: XdpContext) -> u32 {
    match try_xdp_firewall(ctx) {
        Ok(ret) => ret,
        Err(_) => xdp_action::XDP_PASS,
    }
}

#[inline(always)]
unsafe fn ptr_at<T>(ctx: &XdpContext, offset: usize) -> Result<*const T, ()> {
    let start = ctx.data();
    let end = ctx.data_end();
    let len = mem::size_of::<T>();

    if start + offset + len > end {
        return Err(());
    }

    Ok((start + offset) as *const T)
}

fn try_xdp_firewall(ctx: XdpContext) -> Result<u32, ()> {
    let ethhdr: *const EthHdr = unsafe { ptr_at(&ctx, 0)? };
    match unsafe { *ethhdr }.protocol()? {
        L3Protocol::Ipv4 => {}
        _ => return Ok(xdp_action::XDP_PASS),
    }

    let ipv4hdr: *const Ipv4Hdr = unsafe { ptr_at(&ctx, ETH_HDR_LEN)? };
    let saddr = unsafe { *ipv4hdr }.saddr_from_be();

    let sport = match unsafe { *ipv4hdr }.protocol()? {
        L4Protocol::Tcp => {
            let tcphdr: *const TcpHdr =
                unsafe { ptr_at(&ctx, ETH_HDR_LEN + IPV4_HDR_LEN) }?;
            u16::from_be(unsafe { *tcphdr }.source)
        }
        L4Protocol::Udp => {
            let udphdr: *const UdpHdr =
                unsafe { ptr_at(&ctx, ETH_HDR_LEN + IPV4_HDR_LEN) }?;
            u16::from_be(unsafe { *udphdr }.source)
        }
        _ => return Err(()),
    };

    info!(&ctx, "SRC IP: {}, SRC PORT: {}", saddr, sport);

    Ok(xdp_action::XDP_PASS)
}

#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
    unsafe { core::hint::unreachable_unchecked() }
}