如何在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
相关产品推荐
相关产品推荐

