You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

nftnl-rs中get_tables_nlmsg与get_tables_cb函数使用的类型转换问题及参数疑惑

解决nftnl-rs中get_tables_nlmsgget_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_oklibc::nlmsg_next:Netlink的标准工具函数,用来遍历响应中的多个消息段(因为内核可能返回多个消息)。
  • 类型转换的unsafe块:因为我们直接操作原始指针和C库函数,必须确保内存安全——这里的安全前提是resp_buffer是内核返回的合法Netlink消息,所以可以安全地转换为&nlmsghdr

为什么你的原代码不行?

你直接把get_tables_nlmsg生成的请求缓冲区转成nlmsghdr去处理,但这个缓冲区里是你发给内核的查询请求,不是内核返回的包含表信息的响应。所以就算类型转换成功,也得不到任何有效数据。

内容的提问来源于stack exchange,提问作者la Fleur

火山引擎 最新活动