Rust网络过滤库nftnl-sys的使用:高效操作Linux netfilter规则集的Rust绑定
Rust网络过滤库nftnl-sys的使用:高效操作Linux netfilter规则集的Rust绑定
nftnl-sys是libnftnl的低级FFI绑定,libnftnl是一个用户空间库,提供对内核nf_tables子系统的低级netlink编程接口(API)。
链接到libmnl和libnftnl
默认情况下,此crate使用pkg-config查找并链接到其C依赖项libmnl和libnftnl。要手动配置查找这些库的位置,请设置环境变量LIBMNL_LIB_DIR和LIBNFTNL_LIB_DIR指向libmnl.so(或libmnl.a)和libnftnl.so(或libnftnl.a)所在的目录。
选择libnftnl版本
此crate具有大多数libnftnl版本的绑定。所有绑定都由bindgen通过此存储库中的generate_bindings.sh脚本生成。
只能通过此crate暴露一个版本的libnftnl。默认情况下,crate导出最旧支持版本的绑定(libnftnl-1.0.6)。要获取较新版本,请激活相应功能。有关可用功能/版本,请参见Cargo.toml。
例如,要获取libnftnl-1.0.9的绑定,请像这样依赖此crate:
[dependencies]
nftnl-sys = { version = "0.1", features = ["nftnl-1-0-9"] }
完整示例代码
以下是一个更完整的nftnl-sys使用示例,展示了如何创建表、链和规则:
use nftnl_sys as nftnl;
use std::ptr;
use std::os::raw::c_int;
use libc::{AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP};
fn main() -> Result<(), String> {
unsafe {
// 创建netlink套接字
let sock = libc::socket(AF_NETLINK, SOCK_RAW | libc::SOCK_CLOEXEC, NETLINK_NETFILTER as c_int);
if sock < 0 {
return Err("Failed to create socket".to_string());
}
// 绑定套接字
let mut addr = libc::sockaddr_nl {
nl_family: AF_NETLINK as u16,
nl_pad: 0,
nl_pid: 0,
nl_groups: 0,
};
if libc::bind(sock, &addr as *const _ as *const _, std::mem::size_of_val(&addr) as u32) < 0 {
return Err("Failed to bind socket".to_string());
}
// 创建批处理
let batch = nftnl::nftnl_batch_alloc();
if batch.is_null() {
return Err("Failed to allocate batch".to_string());
}
// 创建表
let table = nftnl::nftnl_table_alloc();
nftnl::nftnl_table_set(table, nftnl::NFTNL_TABLE_NAME, "mytable\0".as_ptr() as *const _);
nftnl::nftnl_table_set_u32(table, nftnl::NFTNL_TABLE_FAMILY, nftnl::NFPROTO_IPV4 as u32);
// 创建链
let chain = nftnl::nftnl_chain_alloc();
nftnl::nftnl_chain_set(chain, nftnl::NFTNL_CHAIN_NAME, "mychain\0".as_ptr() as *const _);
nftnl::nftnl_chain_set(chain, nftnl::NFTNL_CHAIN_TABLE, "mytable\0".as_ptr() as *const _);
nftnl::nftnl_chain_set_u32(chain, nftnl::NFTNL_CHAIN_FAMILY, nftnl::NFPROTO_IPV4 as u32);
nftnl::nftnl_chain_set_u32(chain, nftnl::NFTNL_CHAIN_TYPE, nftnl::NFT_CHAIN_T_FILTER as u32);
nftnl::nftnl_chain_set_u32(chain, nftnl::NFTNL_CHAIN_HOOKNUM, 0); // 输入钩子
nftnl::nftnl_chain_set_u32(chain, nftnl::NFTNL_CHAIN_PRIO, 0); // 优先级
// 创建规则
let rule = nftnl::nftnl_rule_alloc();
nftnl::nftnl_rule_set(rule, nftnl::NFTNL_RULE_TABLE, "mytable\0".as_ptr() as *const _);
nftnl::nftnl_rule_set(rule, nftnl::NFTNL_RULE_CHAIN, "mychain\0".as_ptr() as *const _);
nftnl::nftnl_rule_set_u32(rule, nftnl::NFTNL_RULE_FAMILY, nftnl::NFPROTO_IPV4 as u32);
// 添加计数器表达式
let expr = nftnl::nftnl_expr_alloc("counter\0".as_ptr() as *const _);
nftnl::nftnl_rule_add_expr(rule, expr);
// 构建并发送netlink消息
let mut nlh = nftnl::nftnl_nlmsg_build_hdr(
ptr::null_mut(),
nftnl::NFT_MSG_NEWTABLE as u16,
nftnl::NFPROTO_IPV4 as u16,
0,
0
);
nftnl::nftnl_table_nlmsg_build_payload(nlh, table);
// 清理资源
nftnl::nftnl_table_free(table);
nftnl::nftnl_chain_free(chain);
nftnl::nftnl_rule_free(rule);
nftnl::nftnl_batch_free(batch);
libc::close(sock);
}
Ok(())
}
这个完整示例展示了如何使用nftnl-sys:
- 创建netlink套接字
- 创建批处理对象
- 创建表、链和规则
- 添加计数器表达式
- 构建netlink消息
- 清理资源
注意:实际使用时需要添加更多的错误处理和规则配置。完整实现还需要处理netlink消息的发送和接收。
License: MIT/Apache-2.0
Rust网络过滤库nftnl-sys的使用指南
简介
nftnl-sys是Rust对Linux netfilter用户空间库(libnftnl)的低级绑定,允许开发者高效操作Linux netfilter规则集。它提供了与Linux内核网络过滤子系统交互的能力,是构建防火墙、NAT等网络工具的基础。
主要特性
- 提供对nftables规则的完全控制
- 支持创建、修改和删除规则集
- 低开销、高性能的网络过滤操作
- 与Linux内核netfilter子系统直接交互
使用方法
添加依赖
在Cargo.toml中添加:
[dependencies]
nftnl-sys = "0.1"
libc = "0.2"
基本示例
use nftnl_sys as nftnl;
use libc::{c_void, c_char, size_t};
fn main() {
// 创建新的规则集
let batch = unsafe { nftnl::nftnl_batch_alloc() };
// 创建新表
let table = unsafe { nftnl::nftnl_table_alloc() };
unsafe {
nftnl::nftnl_table_set_u8(table, nftnl::NFTNL_TABLE_FAMILY as u16, libc::AF_INET as u8);
nftnl::nftnl_table_set_str(table, nftnl::NFTNL_TABLE_NAME as u16, b"mytable\0".as_ptr() as *const c_char);
}
// 将表添加到batch
unsafe {
nftnl::nftnl_batch_begin(batch, nftnl::NFTNL_MSG_NEWTABLE as i32);
nftnl::nftnl_batch_table_add(batch, nftnl::NFTNL_MSG_NEWTABLE as i32, table);
nftnl::nftnl_batch_end(batch, nftnl::NFTNL_MSG_NEWTABLE as i32);
}
// 清理资源
unsafe {
nftnl::nftnl_table_free(table);
nftnl::nftnl_batch_free(batch);
}
}
创建规则链示例
fn create_chain() {
let batch = unsafe { nftnl::nftnl_batch_alloc() };
let chain = unsafe { nftnl::nftnl_chain_alloc() };
unsafe {
// 设置链属性
nftnl::nftnl_chain_set_u8(chain, nftnl::NFTNL_CHAIN_FAMILY as u16, libc::AF_INET as u8);
nftnl::nftnl_chain_set_str(chain, nftnl::NFTNL_CHAIN_TABLE as u16, b"mytable\0".as_ptr() as *const c_char);
nftnl::nftnl_chain_set_str(chain, nftnl::NFTNL_CHAIN_NAME as u16, b"input\0".as_ptr() as *const c_char);
// 添加到batch
nftnl::nftnl_batch_begin(batch, nftnl::NFTNL_MSG_NEWCHAIN as i32);
nftnl::nftnl_batch_chain_add(batch, nftnl::NFTNL_MSG_NEWCHAIN as i32, chain);
nftnl::nftnl_batch_end(batch, nftnl::NFTNL_MSG_NEWCHAIN as i32);
}
// 发送到内核netlink接口
// 这里需要实现netlink通信代码
unsafe {
nftnl::nftnl_chain_free(chain);
nftnl::nftnl_batch_free(batch);
}
}
高级用法
创建过滤规则
fn create_filter_rule() {
let rule = unsafe { nftnl::nftnl_rule_alloc() };
unsafe {
// 设置规则基本属性
nftnl::nftnl_rule_set_u8(rule, nftnl::NFTNL_RULE_FAMILY as u16, libc::AF_INET as u8);
nftnl::nftnl_rule_set_str(rule, nftnl::NFTNL_RULE_TABLE as u16, b"mytable\0".as_ptr() as *const c_char);
nftnl::nftnl_rule_set_str(rule, nftnl::NFTNL_RULE_CHAIN as u16, b"input\0".as_ptr() as *const c_char);
// 添加匹配条件 (例如匹配TCP端口80)
let expr = nftnl::nftnl_expr_alloc("match");
// 这里需要设置expr的具体参数...
// 添加动作 (例如接受数据包)
let expr_action = nftnl::nftnl_expr_alloc("target");
// 这里需要设置expr_action的具体参数...
// 将表达式添加到规则
nftnl::nftnl_rule_add_expr(rule, expr);
nftnl::nftnl_rule_add_expr(rule, expr_action);
}
// 将规则添加到batch并发送到内核...
unsafe {
nftnl::nftnl_rule_free(rule);
}
}
完整示例demo
以下是一个完整的nftnl-sys使用示例,展示了如何创建表、链和规则:
use nftnl_sys as nftnl;
use libc::{c_char, c_void, AF_INET};
fn main() -> Result<(), String> {
// 1. 创建batch对象
let batch = unsafe { nftnl::nftnl_batch_alloc() };
if batch.is_null() {
return Err("Failed to allocate batch".to_string());
}
// 2. 创建并配置表
let table = unsafe { nftnl::nftnl_table_alloc() };
if table.is_null() {
unsafe { nftnl::nftnl_batch_free(batch) };
return Err("Failed to allocate table".to_string());
}
unsafe {
nftnl::nftnl_table_set_u8(table, nftnl::NFTNL_TABLE_FAMILY as u16, AF_INET as u8);
nftnl::nftnl_table_set_str(table, nftnl::NFTNL_TABLE_NAME as u16, b"mytable\0".as_ptr() as *const c_char);
}
// 3. 创建并配置链
let chain = unsafe { nftnl::nftnl_chain_alloc() };
if chain.is_null() {
unsafe {
nftnl::nftnl_table_free(table);
nftnl::nftnl_batch_free(batch);
}
return Err("Failed to allocate chain".to_string());
}
unsafe {
nftnl::nftnl_chain_set_u8(chain, nftnl::NFTNL_CHAIN_FAMILY as u16, AF_INET as u8);
nftnl::nftnl_chain_set_str(chain, nftnl::NFTNL_CHAIN_TABLE as u16, b"mytable\0".as_ptr() as *const c_char);
nftnl::nftnl_chain_set_str(chain, nftnl::NFTNL_CHAIN_NAME as u16, b"input\0".as_ptr() as *const c_char);
}
// 4. 创建并配置规则
let rule = unsafe { nftnl::nftnl_rule_alloc() };
if rule.is_null() {
unsafe {
nftnl::nftnl_chain_free(chain);
nftnl::nftnl_table_free(table);
nftnl::nftnl_batch_free(batch);
}
return Err("Failed to allocate rule".to_string());
}
unsafe {
nftnl::nftnl_rule_set_u8(rule, nftnl::NFTNL_RULE_FAMILY as u16, AF_INET as u8);
nftnl::nftnl_rule_set_str(rule, nftnl::NFTNL_RULE_TABLE as u16, b"mytable\0".as_ptr() as *const c_char);
nftnl::nftnl_rule_set_str(rule, nftnl::NFTNL_RULE_CHAIN as u16, b"input\0".as_ptr() as *const c_char);
// 添加匹配TCP端口80的表达式
let expr = nftnl::nftnl_expr_alloc(b"match\0".as_ptr() as *const c_char);
if expr.is_null() {
nftnl::nftnl_rule_free(rule);
nftnl::nftnl_chain_free(chain);
nftnl::nftnl_table_free(table);
nftnl::nftnl_batch_free(batch);
return Err("Failed to allocate match expression".to_string());
}
// 这里需要配置具体的匹配参数
// ...
// 添加接受数据包的动作
let expr_action = nftnl::nftnl_expr_alloc(b"target\0".as_ptr() as *const c_char);
if expr_action.is_null() {
nftnl::nftnl_expr_free(expr);
nftnl::nftnl_rule_free(rule);
nftnl::nftnl_chain_free(chain);
nftnl::nftnl_table_free(table);
nftnl::nftnl_batch_free(batch);
return Err("Failed to allocate target expression".to_string());
}
// 这里需要配置具体的动作参数
// ...
nftnl::nftnl_rule_add_expr(rule, expr);
nftnl::nftnl_rule_add_expr(rule, expr_action);
}
// 5. 将所有对象添加到batch
unsafe {
// 添加表
nftnl::nftnl_batch_begin(batch, nftnl::NFTNL_MSG_NEWTABLE as i32);
nftnl::nftnl_batch_table_add(batch, nftnl::NFTNL_MSG_NEWTABLE as i32, table);
nftnl::nftnl_batch_end(batch, nftnl::NFTNL_MSG_NEWTABLE as i32);
// 添加链
nftnl::nftnl_batch_begin(batch, nftnl::NFTNL_MSG_NEWCHAIN as i32);
nftnl::nftnl_batch_chain_add(batch, nftnl::NFTNL_MSG_NEWCHAIN as i32, chain);
nftnl::nftnl_batch_end(batch, nftnl::NFTNL_MSG_NEWCHAIN as i32);
// 添加规则
nftnl::nftnl_batch_begin(batch, nftnl::NFTNL_MSG_NEWRULE as i32);
nftnl::nftnl_batch_rule_add(batch, nftnl::NFTNL_MSG_NEWRULE as i32, rule);
nftnl::nftnl_batch_end(batch, nftnl::NFTNL_MSG_NEWRULE as i32);
}
// 6. 这里应该添加将batch发送到内核的代码
// 通常使用netlink socket发送
// 7. 清理资源
unsafe {
nftnl::nftnl_rule_free(rule);
nftnl::nftnl_chain_free(chain);
nftnl::nftnl_table_free(table);
nftnl::nftnl_batch_free(batch);
}
Ok(())
}
注意事项
- nftnl-sys是低级绑定,使用时需要熟悉Linux netfilter的工作原理
- 所有操作都需要unsafe块
- 需要正确处理内存管理,避免内存泄漏
- 需要root权限才能修改netfilter规则集
- 错误处理非常重要,应检查每个API调用的返回值
性能建议
- 使用batch操作减少内核上下文切换
- 复用已分配的nftnl对象
- 尽量减少规则更新频率
- 使用nftnl提供的批处理接口