You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C语言中使用NETFILTER正确打印点分十进制格式IP地址

问题解决方法

你当前打印的是IP地址对应的32位网络字节序整数,内核的printk已经提供了专门的IPv4地址格式化符,不需要手动拆分字节,修改方法非常简单:

方案1:使用内核内置格式化符(推荐)

直接用%pI4格式占位符,参数传入IP地址变量的指针即可,该格式化符会自动处理网络字节序,输出标准点分十进制格式,仅需要修改hook_func函数中printk对应的代码:

unsigned int hook_func(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) {
    struct iphdr *ip_header = (struct iphdr *)skb_network_header(skb);
    // 直接用%pI4格式化,传入saddr和daddr的地址
    printk(KERN_INFO "IPs: %pI4 \t to \t %pI4 \n", &ip_header->saddr, &ip_header->daddr);
    return NF_ACCEPT;   
}

重新编译加载模块后,dmesg就能看到类似IPs: 192.168.1.2 to 192.168.1.3的正常输出。

方案2:手动拆分字节

如果你需要自己处理IP地址的每个分段,可以用位运算+字节掩码拆分,注意需要先把网络字节序转为CPU的主机字节序,使用该方案需要额外引入头文件#include <linux/inet.h>:

unsigned int hook_func(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) {
    struct iphdr *ip_header = (struct iphdr *)skb_network_header(skb);
    // 转主机字节序
    unsigned int src_ip = ntohl(ip_header->saddr);
    unsigned int dst_ip = ntohl(ip_header->daddr);
    
    printk(KERN_INFO "IPs: %u.%u.%u.%u \t to \t %u.%u.%u.%u \n",
        (src_ip >> 24) & 0xFF,
        (src_ip >> 16) & 0xFF,
        (src_ip >> 8) & 0xFF,
        src_ip & 0xFF,
        (dst_ip >> 24) & 0xFF,
        (dst_ip >> 16) & 0xFF,
        (dst_ip >> 8) & 0xFF,
        dst_ip & 0xFF
    );
    return NF_ACCEPT;   
}

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 07:15:03