Rust网络过滤库nftnl的使用,nftnl提供高性能Netlink通信接口实现Linux防火墙规则管理
Rust网络过滤库nftnl的使用
nftnl是libnftnl
的安全抽象库,提供了对内核nf_tables子系统的低级用户空间访问。它是iptables防火墙的继任者nftables的管理工具,可用于创建和删除表、链、集合和规则。
特点
- 提供高性能的Netlink通信接口
- 直接与内核nf_tables子系统交互
- 允许创建、修改和删除防火墙规则
- 支持表(table)、链(chain)、集合(set)和规则(rule)的管理
使用示例
以下是一个使用nftnl管理nftables规则的完整示例:
use nftnl::{Batch, Chain, Hook, Rule, Table, Verdict};
use nftnl_sys as sys;
fn main() -> Result<(), String> {
// 创建一个新的批处理对象
let mut batch = Batch::new();
// 创建一个新的表
let table = Table::new("my_table", sys::NFT_TABLE_FAMILY_IP);
batch.add(&table, nftnl::MsgType::Add)?;
// 创建一个新的输入链
let chain = Chain::new(
"my_input_chain",
table.clone(),
Hook::Input,
sys::NFPROTO_IPV4,
0,
);
batch.add(&chain, nftnl::MsgType::Add)?;
// 创建一个规则,允许来自127.0.0.1的流量
let mut rule = Rule::new(
chain.clone(),
sys::NFPROTO_IPV4,
);
// 设置规则表达式
rule.add_expr(
&nftnl::expr::Payload::new_ip_src().map_err(|e| e.to_string())?
)?;
rule.add_expr(
&nftnl::expr::Cmp::new_eq(
std::net::Ipv4Addr::new(127, 0, 0, 1).into(),
).map_err(|e| e.to_string())?
)?;
rule.add_expr(
&nftnl::expr::Verdict::new(Verdict::Accept)
)?;
batch.add(&rule, nftnl::MsgType::Add)?;
// 执行批处理操作
batch.send()?;
Ok(())
}
完整示例扩展
以下是一个更完整的示例,展示如何创建表、链、规则,并执行删除操作:
use nftnl::{Batch, Chain, Hook, Rule, Table, Verdict};
use nftnl_sys as sys;
fn main() -> Result<(), String> {
// 创建批处理对象
let mut batch = Batch::new();
// 1. 创建表和链
let table = Table::new("demo_table", sys::NFT_TABLE_FAMILY_IP);
batch.add(&table, nftnl::MsgType::Add)?;
let input_chain = Chain::new(
"demo_input_chain",
table.clone(),
Hook::Input,
sys::NFPROTO_IPV4,
0,
);
batch.add(&input_chain, nftnl::MsgType::Add)?;
// 2. 添加规则 - 允许本地回环
let mut loopback_rule = Rule::new(input_chain.clone(), sys::NFPROTO_IPV4);
loopback_rule.add_expr(
&nftnl::expr::Payload::new_ip_src().map_err(|e| e.to_string())?
)?;
loopback_rule.add_expr(
&nftnl::expr::Cmp::new_eq(
std::net::Ipv4Addr::new(127, 0, 0, 1).into(),
).map_err(|e| e.to_string())?
)?;
loopback_rule.add_expr(&nftnl::expr::Verdict::new(Verdict::Accept))?;
batch.add(&loopback_rule, nftnl::MsgType::Add)?;
// 3. 添加规则 - 丢弃所有其他流量
let mut drop_rule = Rule::new(input_chain.clone(), sys::NFPROTO_IPV4);
drop_rule.add_expr(&nftnl::expr::Verdict::new(Verdict::Drop))?;
batch.add(&drop_rule, nftnl::MsgType::Add)?;
// 执行添加操作
batch.send()?;
// 4. 清理 - 删除规则、链和表
let mut cleanup_batch = Batch::new();
cleanup_batch.add(&loopback_rule, nftnl::MsgType::Del)?;
cleanup_batch.add(&drop_rule, nftnl::MsgType::Del)?;
cleanup_batch.add(&input_chain, nftnl::MsgType::Del)?;
cleanup_batch.add(&table, nftnl::MsgType::Del)?;
cleanup_batch.send()?;
Ok(())
}
注意事项
- 当前库的API还不够完善,添加和删除netfilter条目可能不够简单优雅
- nftables本身是低级别且高度可定制的,过度简化可能不合适
- 实现主要基于试错,可能存在某些使用方式不符合预期
- 许多
libnftnl
功能尚未覆盖
许可证
MIT或Apache-2.0双重许可
依赖版本选择
与对应的sys crate(nftnl-sys
)具有相同的功能,版本选择方式相同。
1 回复
Rust网络过滤库nftnl的使用指南
概述
nftnl是一个Rust库,提供了高性能的Netlink通信接口,用于管理Linux防火墙规则(nftables)。它是libnftnl的Rust绑定,允许开发者以类型安全的方式与Linux内核的netfilter子系统交互。
主要特性
- 类型安全的Rust接口
- 高性能Netlink通信
- 支持nftables的所有主要功能
- 异步友好的设计
安装
在Cargo.toml中添加依赖:
[dependencies]
nftnl = "0.1"
基本使用方法
1. 创建nftnl上下文
use nftnl::{Batch, Socket};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut socket = Socket::new()?;
let mut batch = Batch::new();
// 在这里添加规则
socket.send(&batch)?;
Ok(())
}
2. 添加简单规则
use nftnl::{Batch, Socket, Rule, Table, Chain, Expr};
fn add_drop_rule() -> Result<(), Box<dyn std::error::Error>> {
let mut socket = Socket::new()?;
let mut batch = Batch::new();
// 创建表
let table = Table::new("filter")
.family(nftnl::Family::IP)
.create();
// 创建链
let chain = Chain::new("input")
.table("filter")
.hook(nftnl::Hook::Input)
.priority(0)
.policy(nftnl::ChainPolicy::Drop)
.create();
// 创建规则
let mut rule = Rule::new()
.table("filter")
.chain("input")
.create();
// 添加表达式 - 丢弃所有TCP流量
rule.add_expr(Expr::meta(nftnl::MetaKey::L4PROTO, nftnl::Register::REG_1));
rule.add_expr(Expr::cmp(nftnl::Register::REG_1, nftnl::CmpOp::Eq, libc::IPPROTO_TCP as u32));
rule.add_expr(Expr::verdict(nftnl::Verdict::Drop));
batch.add(&table);
batch.add(&chain);
batch.add(&rule);
socket.send(&batch)?;
Ok(())
}
3. 列出当前规则
use nftnl::{Socket, UserData};
fn list_rules() -> Result<(), Box<dyn std::error::Error>> {
let mut socket = Socket::new()?;
// 设置回调处理接收到的规则
let callback = |msg: &nftnl::Message| {
println!("Received rule: {:?}", msg);
true // 继续接收
};
// 查询所有规则
let mut msg = nftnl::Message::new(nftnl::MsgType::GetRule);
msg.set_family(nftnl::Family::IP);
socket.send_msg(&msg)?;
socket.recv_msgs(callback)?;
Ok(())
}
高级用法
1. 使用批处理优化性能
use nftnl::{Batch, Socket};
fn batch_operations() -> Result<(), Box<dyn std::error::Error>> {
let mut socket = Socket::new()?;
let mut batch = Batch::new();
// 批处理开始
batch.begin();
// 添加多个操作...
// 批处理结束并提交
batch.end();
socket.send(&batch)?;
Ok(())
}
2. 处理异步事件
use nftnl::{Socket, PollFd};
use std::os::unix::io::AsRawFd;
async fn async_monitor() -> Result<(), Box<dyn std::error::Error>> {
let socket = Socket::new?;
let fd = PollFd::new(socket.as_raw_fd());
// 使用async_std或tokio等异步运行时监听事件
loop {
// 等待事件
// async_std::task::block_on(fd.readable()).await?;
// 处理接收到的消息
let callback = |msg: &nftnl::Message| {
println!("Event received: {:?}", msg);
true
};
socket.recv_msgs(callback)?;
}
}
注意事项
- 需要root权限才能修改防火墙规则
- 错误处理很重要 - 错误的规则可能导致网络中断
- 生产环境中建议使用事务或批处理来确保规则的一致性
- 考虑使用
libc
crate来处理协议常量(如libc::IPPROTO_TCP
)
完整示例
下面是一个完整的防火墙规则管理示例,包含创建表、链、添加规则和列出规则的功能:
use nftnl::{Batch, Socket, Rule, Table, Chain, Expr, Message, MsgType, Family, MetaKey, Register, CmpOp, Verdict, Hook, ChainPolicy};
use libc;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. 初始化Socket和Batch
let mut socket = Socket::new()?;
let mut batch = Batch::new();
// 2. 创建表和链
let table = Table::new("rust_filter")
.family(Family::IP)
.create();
let input_chain = Chain::new("input")
.table("rust_filter")
.hook(Hook::Input)
.priority(0)
.policy(ChainPolicy::Accept)
.create();
// 3. 添加规则 - 丢弃所有ICMP流量(ping)
let mut drop_icmp = Rule::new()
.table("rust_filter")
.chain("input")
.create();
drop_icmp.add_expr(Expr::meta(MetaKey::L4PROTO, Register::REG_1));
drop_icmp.add_expr(Expr::cmp(Register::REG_1, CmpOp::Eq, libc::IPPROTO_ICMP as u32));
drop_icmp.add_expr(Expr::verdict(Verdict::Drop));
// 4. 添加规则 - 允许SSH端口(22)
let mut allow_ssh = Rule::new()
.table("rust_filter")
.chain("input")
.create();
allow_ssh.add_expr(Expr::meta(MetaKey::L4PROTO, Register::REG_1));
allow_ssh.add_expr(Expr::cmp(Register::REG_1, CmpOp::Eq, libc::IPPROTO_TCP as u32));
allow_ssh.add_expr(Expr::payload(nftnl::Payload::TransportHeader, 2, Register::REG_1)); // 目标端口
allow_ssh.add_expr(Expr::cmp(Register::REG_1, CmpOp::Eq, 22)); // 端口22
allow_ssh.add_expr(Expr::verdict(Verdict::Accept));
// 5. 批量添加所有规则
batch.add(&table);
batch.add(&input_chain);
batch.add(&drop_icmp);
batch.add(&allow_ssh);
// 6. 提交规则
socket.send(&batch)?;
// 7. 列出当前规则
println!("Current rules:");
let callback = |msg: &Message| {
println!("{:?}", msg);
true
};
let mut msg = Message::new(MsgType::GetRule);
msg.set_family(Family::IP);
socket.send_msg(&msg)?;
socket.recv_msgs(callback)?;
Ok(())
}
这个完整示例展示了如何使用nftnl库:
- 创建一个名为"rust_filter"的表
- 添加一个input链
- 添加两条规则:一条阻止所有ICMP流量,另一条允许TCP端口22(SSH)
- 批量提交所有更改
- 列出当前规则进行验证
实际使用时,可以根据需要调整规则条件和操作,构建更复杂的防火墙配置。