Rust网络类型库network-types的使用,高效处理多种网络协议和数据格式转换
Rust网络类型库network-types的使用,高效处理多种网络协议和数据格式转换
network-types
是用于表示网络协议头(Layer 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)? };
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() };
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)? };
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
) - 当字段名称(由RFC或其他标准指定)包含空格时,用
_
替换它们 - 缩短以下冗长的名称:
source
->src
destination
->dst
address
->addr
功能标志
可以通过serde
功能标志启用Serde支持。它旨在与像bincode这样的二进制序列化库一起使用,这些库利用Serde的基础设施。
请注意,启用Serde时会失去no_std
支持。
完整示例代码
// 完整示例展示了如何使用network-types解析网络包
use network_types::{
eth::{EthHdr, EtherType},
ip::{Ipv4Hdr, IpProto},
tcp::TcpHdr,
};
// 假设我们有一个原始网络数据包
let raw_packet: &[u8] = get_raw_packet_from_network();
// 解析以太网头
let eth_header = unsafe { &*(raw_packet.as_ptr() as *const EthHdr) };
match eth_header.ether_type {
EtherType::Ipv4 => {
// 解析IPv4头
let ipv4_offset = EthHdr::LEN;
let ipv4_header = unsafe {
&*(raw_packet.as_ptr().add(ipv4_offset) as *const Ipv4Hdr)
};
println!("Source IP: {:?}", ipv4_header.src_addr());
println!("Destination IP: {:?}", ipv4_header.dst_addr());
match ipv4_header.proto {
IpProto::Tcp => {
// 解析TCP头
let tcp_offset = ipv4_offset + Ipv4Hdr::LEN;
let tcp_header = unsafe {
&*(raw_packet.as_ptr().add(tcp_offset) as *const TcpHdr)
};
println!("Source Port: {}", tcp_header.source);
println!("Destination Port: {}", tcp_header.dest);
}
_ => println!("Not a TCP packet"),
}
}
_ => println!("Not an IPv4 packet"),
}
许可证: MIT
1 回复
Rust网络类型库network-types的使用指南
network-types
是一个Rust库,提供了高效处理多种网络协议和数据格式转换的功能。它简化了网络编程中常见的数据类型处理和协议转换任务。
主要特性
- 支持多种网络协议的标准数据类型
- 提供高效的数据格式转换功能
- 类型安全的网络数据处理
- 零拷贝解析和序列化支持
安装
在Cargo.toml中添加依赖:
[dependencies]
network-types = "0.7"
基本用法
1. IP地址处理
use network_types::ip::{Ipv4Addr, Ipv6Addr};
fn main() {
let ipv4 = Ipv4Addr::new(192, 168, 1, 1);
let ipv6 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1);
println!("IPv4: {}", ipv4);
println!("IPv6: {}", ipv6);
// 从字符串解析
let ipv4_from_str: Ipv4Addr = "10.0.0.1".parse().unwrap();
println!("Parsed IPv4: {}", ipv4_from_str);
}
2. MAC地址处理
use network_types::ethernet::MacAddr;
fn main() {
let mac = MacAddr::new(0x00, 0x11, 0x22, 0x33, 0x44, 0x55);
println!("MAC Address: {}", mac);
// 从字节数组创建
let bytes = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff];
let mac_from_bytes = MacAddr::from_bytes(&bytes);
println!("MAC from bytes: {}", mac_from_bytes);
}
3. 协议数据包处理
use network_types::{
ethernet::{EthHdr, EtherType},
ip::{Ipv4Hdr, Protocol},
};
fn build_ethernet_frame() {
let eth_hdr = EthHdr {
dst: MacAddr::new(0x00, 0x11, 0x22, 0x33, 0x44, 0x55),
src: MacAddr::new(0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff),
ether_type: EtherType::IPV4,
};
let ip极客 = Ipv4Hdr {
version_ihl: 0x45,
tos: 0,
total_len: 100,
id: 0x1234,
flags_frag_off: 0,
ttl: 64,
protocol: Protocol::TCP,
csum: 0,
src: Ipv4Addr::new(192, 168, 1, 1),
dst: Ipv4Addr::new(192, 168, 1, 2),
};
// 计算校验和
let ip_hdr = ip_hdr.with_csum();
println!("Ethernet Header: {:?}", eth_hdr);
println!("IP Header: {:?}", ip_hdr);
}
4. 数据格式转换
use network_types::convert::{NetworkEndian, ToNetwork};
fn convert_to_network_bytes() {
let value: u32 = 0x12345678;
let network_bytes = value.to_network::<NetworkEndian>();
println!("Original: 0x{:x}", value);
println!("Network bytes: {:?}", network_bytes);
// 从网络字节序转换回来
let host_value = u32::from_network::<NetworkEndian>(network_bytes);
println!("Converted back: 0x{:x}", host_value);
}
高级用法
1. 自定义协议处理
use network_types::{
ethernet::EthHdr,
ip::{Ipv4Hdr, Protocol},
tcp::TcpHdr,
udp::UdpHdr,
convert::AsBytes,
};
fn process_packet(packet: &[u8]) {
// 解析以太网头部
let eth_hdr = EthHdr::from_bytes(&packet[..14]).unwrap();
match eth_hdr.ether_type {
EtherType::IPV4 => {
let ip_hdr = Ipv4Hdr::from_bytes(&packet[14..34]).unwrap();
match ip_hdr.protocol {
Protocol::TCP => {
let tcp_hdr = TcpHdr::from_bytes(&packet[34..54]).unwrap();
println!("TCP Packet: {:?}", tcp_hdr);
},
Protocol::UDP => {
let udp_hdr = UdpHdr极客::from_bytes(&packet[34..42]).unwrap();
println!("UDP Packet: {:?}", udp_hdr);
},
_ => println!("Other IP protocol"),
}
},
_ => println!("Non-IPv4 packet"),
}
}
2. 零拷贝解析
use network_types::{
ip::Ipv4Hdr,
tcp::TcpHdr,
convert::FromBytes,
};
fn zero_copy_parse(packet: &[极客u8]) {
// 使用零拷贝方式解析IP头部
let (ip_hdr, ip_rest) = Ipv4Hdr::from_bytes_prefix(packet).unwrap();
if ip_hdr.protocol == Protocol::TCP {
// 零拷贝解析TCP头部
let (tcp_hdr, _) = TcpHdr::from_bytes_prefix(ip_rest).unwrap();
println!("TCP Header without copy: {:?}", tcp_hdr);
}
}
性能提示
- 尽可能使用零拷贝解析方法(
from_bytes_prefix
) - 批量处理数据时重用缓冲区
- 对于热路径代码,考虑使用
unsafe
版本的方法(如果性能分析表明有必要)
network-types
库为Rust网络编程提供了强大而高效的类型支持,特别适合需要处理多种网络协议和数据格式转换的应用场景。