network_types/
lib.rs

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