#linux-networking #linux #header #packet-header #packet #osi

network-types

Rust 结构体表示 Linux 中的网络相关类型

6 个版本

0.0.6 2024 年 6 月 4 日
0.0.5 2023 年 11 月 30 日
0.0.4 2023 年 1 月 9 日
0.0.3 2022 年 12 月 29 日
0.0.2 2022 年 11 月 28 日

#1#osi

Download history 318/week @ 2024-03-13 738/week @ 2024-03-20 346/week @ 2024-03-27 551/week @ 2024-04-03 345/week @ 2024-04-10 226/week @ 2024-04-17 188/week @ 2024-04-24 181/week @ 2024-05-01 217/week @ 2024-05-08 220/week @ 2024-05-15 165/week @ 2024-05-22 278/week @ 2024-05-29 432/week @ 2024-06-05 408/week @ 2024-06-12 312/week @ 2024-06-19 223/week @ 2024-06-26

每月 1,470 次下载

MIT 许可证

39KB
781

network-types

表示网络协议头部(在第 2、3 和 4 层)的 Rust 结构体。

该包是 no_std,这使得它非常适合使用 Aya 编写的 eBPF 程序。

示例

一个示例,用于记录关于入站数据包的地址和端口的 XDP 程序

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)
}

命名约定

在命名结构体和字段时,我们尽量遵守以下原则

  • 使用 CamelCase,即使对于通常全大写的名称(例如,Icmp 而不是 ICMP)。这是 std::net 模块使用的约定。
  • 当字段名称(由 RFC 或其他标准指定)包含空格时,请用 _ 替换。通常,使用 snake_case 为字段名称。
  • 缩短以下冗长的名称
    • source -> src
    • destination -> dst
    • address -> addr

功能标志

Serde 支持可以通过 serde 功能标志启用。它打算与像 bincode 这样的二进制序列化库一起使用,这些库利用 Serde 的基础设施。

请注意,启用 Serde 时会丢失 no_std 支持。

许可证:MIT

依赖项

~170KB