nftnl-rs中get_tables_nlmsg与get_tables_cb函数使用的类型转换问题及参数疑惑
解决nftnl-rs中
get_tables_nlmsg和get_tables_cb的使用问题 看起来你误解了这两个函数的协作方式——get_tables_nlmsg是用来构建向内核查询表的Netlink请求消息,而get_tables_cb是用来解析内核返回的响应消息的。你直接拿着请求消息去调用回调函数,这肯定行不通,而且类型转换的问题也源于这个错误的用法。
先拆解你的问题:
1. 类型疑惑解答
首先,&libc::nlmsghdr是对nlmsghdr结构体的不可变引用,而*const libc::nlmsghdr是一个指向该结构体的原始指针。要从指针得到引用,你需要在unsafe块中确认指针的有效性(比如指向的内存确实是一个合法的nlmsghdr实例,且生命周期正确),然后解引用并取引用:
// 假设ptr是有效的*const libc::nlmsghdr let hdr: &libc::nlmsghdr = unsafe { &*ptr };
但这不是你当前问题的核心——核心是你没走完整的Netlink通信流程。
2. 正确的使用流程
要查询系统中已存在的nftables表,你需要:
- 创建Netlink套接字,与内核通信
- 用
get_tables_nlmsg生成查询请求 - 发送请求到内核,接收响应
- 遍历响应中的每个Netlink消息头,用
get_tables_cb解析出表名
下面是完整的可运行代码示例:
use std::collections::HashSet; use std::ffi::CString; use nftnl::{self, socket::Socket, nftnl_sys::libc}; fn dump_tables() -> Result<(), Box<dyn std::error::Error>> { // 1. 创建Netlink套接字,连接到nftables子系统 let mut socket = Socket::new(libc::NETLINK_NETFILTER)?; // 2. 生成查询表的Netlink请求消息 let req_buffer = nftnl::table::get_tables_nlmsg(0); // 3. 发送请求到内核,并接收响应 let resp_buffer = socket.send(&req_buffer)?; // 4. 遍历响应中的所有Netlink消息头,解析表名 let mut tables = HashSet::new(); let mut ptr = resp_buffer.as_ptr() as *const libc::nlmsghdr; // 循环处理每个Netlink消息(Netlink消息可能是多段的) while unsafe { libc::nlmsg_ok(ptr, resp_buffer.len()) } != 0 { // 安全转换为&nlmsghdr let hdr = unsafe { &*ptr }; // 调用回调函数解析表名到HashSet nftnl::table::get_tables_cb(hdr, &mut tables); // 移动到下一个消息头 ptr = unsafe { libc::nlmsg_next(ptr, resp_buffer.len()) }; } // 打印结果 println!("Existing tables: {:?}", tables); Ok(()) } fn main() -> Result<(), Box<dyn std::error::Error>> { dump_tables() }
3. 关键细节解释
Socket::new(libc::NETLINK_NETFILTER):创建与Netfilter子系统通信的Netlink套接字,这是和内核交互的必要步骤。socket.send(&req_buffer):把请求消息发给内核,返回内核的响应缓冲区。libc::nlmsg_ok和libc::nlmsg_next:Netlink的标准工具函数,用来遍历响应中的多个消息段(因为内核可能返回多个消息)。- 类型转换的
unsafe块:因为我们直接操作原始指针和C库函数,必须确保内存安全——这里的安全前提是resp_buffer是内核返回的合法Netlink消息,所以可以安全地转换为&nlmsghdr。
为什么你的原代码不行?
你直接把get_tables_nlmsg生成的请求缓冲区转成nlmsghdr去处理,但这个缓冲区里是你发给内核的查询请求,不是内核返回的包含表信息的响应。所以就算类型转换成功,也得不到任何有效数据。
内容的提问来源于stack exchange,提问作者la Fleur




