1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
//! Rust structs representing network protocol headers (on Layer 2, 3 and 4).
//!
//! The crate is [no_std](https://docs.rust-embedded.org/book/intro/no-std.html),
//! which makes it a great fit for [eBPF](https://ebpf.io/) programs written
//! with [Aya](https://aya-rs.dev/).
//!
//! # Examples
//!
//! An example of an [XDP program](https://aya-rs.dev/book/start/) logging
//! information about addresses and ports for incoming packets:
//!
//! ```rust
//! use core::mem;
//!
//! use aya_ebpf::{bindings::xdp_action, macros::xdp, programs::XdpContext};
//! use aya_log_ebpf::info;
//!
//! use network_types::{
//! eth::{EthHdr, EtherType},
//! ip::{Ipv4Hdr, Ipv6Hdr, IpProto},
//! tcp::TcpHdr,
//! udp::UdpHdr,
//! };
//!
//! #[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 }.ether_type {
//! EtherType::Ipv4 => {
//! let ipv4hdr: *const Ipv4Hdr = unsafe { ptr_at(&ctx, EthHdr::LEN)? };
//! let source_addr = unsafe { (*ipv4hdr).src_addr };
//!
//! let source_port = match unsafe { (*ipv4hdr).proto } {
//! IpProto::Tcp => {
//! let tcphdr: *const TcpHdr =
//! unsafe { ptr_at(&ctx, EthHdr::LEN + Ipv4Hdr::LEN) }?;
//! u16::from_be(unsafe { (*tcphdr).source })
//! }
//! IpProto::Udp => {
//! let udphdr: *const UdpHdr =
//! unsafe { ptr_at(&ctx, EthHdr::LEN + Ipv4Hdr::LEN) }?;
//! u16::from_be(unsafe { (*udphdr).source })
//! }
//! _ => return Ok(xdp_action::XDP_PASS),
//! };
//!
//! info!(&ctx, "SRC IP: {:i}, SRC PORT: {}", source_addr, source_port);
//! }
//! EtherType::Ipv6 => {
//! let ipv6hdr: *const Ipv6Hdr = unsafe { ptr_at(&ctx, EthHdr::LEN)? };
//! let source_addr = unsafe { (*ipv6hdr).src_addr.in6_u.u6_addr8 };
//!
//! let source_port = match unsafe { (*ipv6hdr).next_hdr } {
//! IpProto::Tcp => {
//! let tcphdr: *const TcpHdr =
//! unsafe { ptr_at(&ctx, EthHdr::LEN + Ipv6Hdr::LEN) }?;
//! u16::from_be(unsafe { (*tcphdr).source })
//! }
//! IpProto::Udp => {
//! let udphdr: *const UdpHdr =
//! unsafe { ptr_at(&ctx, EthHdr::LEN + Ipv6Hdr::LEN) }?;
//! u16::from_be(unsafe { (*udphdr).source })
//! }
//! _ => return Ok(xdp_action::XDP_PASS),
//! };
//!
//! info!(&ctx, "SRC IP: {:i}, SRC PORT: {}", source_addr, source_port);
//! }
//! _ => {},
//! }
//!
//! Ok(xdp_action::XDP_PASS)
//! }
//! ```
//!
//! # Naming conventions
//!
//! When naming stucts and fields, we are trying to stick to the following
//! principles:
//!
//! * Use `CamelCase`, even for names which normally would be all uppercase
//! (e.g. `Icmp` instead of `ICMP`). This is the convention used by the
//! [std::net](https://doc.rust-lang.org/std/net/index.html) module.
//! * Where field names (specified by RFCs or other standards) contain spaces,
//! replace them with `_`. In general, use `snake_case` for field names.
//! * Shorten the following verbose names:
//! * `source` -> `src`
//! * `destination` -> `dst`
//! * `address` -> `addr`
//!
//! # Feature flags
//!
//! [Serde](https://serde.rs) support can be enabled through the `serde`
//! feature flag. It is intended to be used with binary serialization libraries
//! like [`bincode`](https://crates.io/crates/bincode) that leverage Serde's
//! infrastructure.
//!
//! Note that `no_std` support is lost when enabling Serde.
#![cfg_attr(not(feature = "std"), no_std)]
pub mod bitfield;
pub mod eth;
pub mod icmp;
pub mod ip;
pub mod tcp;
pub mod udp;
pub mod vxlan;