问题描述
我在功能__netif_receive_skb_core()
的 /net/core/dev.c 文件中捕获了网络数据包。我解析数据包并获取src_port
,dest_port
等。我在任何接口上都使用了tcpdump。但是tcpdump的端口信息与我获取的端口信息不匹配。我不明白为什么。
orig_dev = skb->dev;
eth = eth_hdr(skb);
__be16 src_port = 0,dest_port = 0;
if (skb->protocol == htons(ETH_P_IP))
{
ih = ip_hdr(skb);
proto_num = ih->protocol;
switch (ih->protocol)
{
case IPPROTO_TCP:
{
struct tcphdr *th = tcp_hdr(skb);
src_port = th->source;
dest_port = th->dest;
break;
}
case IPPROTO_UDP:
{
struct udphdr *uh = udp_hdr(skb);
src_port = uh->source;
dest_port = uh->dest;
break;
}
default:
src_port = 0;
dest_port = 0;
}
fast_node = NULL;
fast_node = (struct fast_pktlist *)kzalloc(sizeof(*fast_node),GFP_KERNEL);
if (fast_node)
{
fast_node->protocol_num = proto_num;
strcpy(fast_node->in_interface,orig_dev->name);
fast_node->orgsrc_ip = ih->saddr;
fast_node->orgdest_ip = ih->daddr;
memcpy(fast_node->orgsrc_mac,eth->h_source,6);
fast_node->org_srcport = src_port;
fast_node->org_destport = dest_port;
INIT_LIST_HEAD(&fast_node->_list);
list_add_tail(&fast_node->_list,&FAST_HEAD);
}
else
{
printk("can not allocate memory at line number = %d\n",__LINE__);
}
}
解决方法
我看不到在何处以及如何打印或比较端口(也许您在某处使用src_port
打印dest_port
和fast_node->org_srcport
或fast_node->org_destport
和%u
printk
的说明符。)
但是您必须考虑到TCP和UDP标头中的 port 都是1字节字段(长度为2字节),因此它为endianness 。具体是网络字节顺序。
这就是为什么在打印时按主机字节顺序查看端口的原因,应该使用特殊功能来交换字节-ntohs()
-网络主机短。粗略地说,“短”表示该函数是针对2字节变量的。
所以最后,如果您需要打印端口,应该是这样的:
printk(KERN_INFO "sport:%u dport:%u\n",ntohs(src_port),ntohs(dest_port));
,如果需要比较:
if (ntohs(dest_port) == 53)
BTW network_header
和transport_header
必须在您通过ip_hdr()
/ tcp_hdr()
/ udp_hdr()
访问标题时设置,否则返回的指针可能是无效。
此外,您还必须注意如何在内核内部的不同位置分配内存。__netif_receive_skb_core()
在 atomic 上下文中执行,因此您不能在这里睡觉。 GFP_KERNEL
标志允许kmalloc()
休眠,因此您有一个错误。将GFP_KERNEL
更改为GFP_ATOMIC
。