skb中的端口信息与tcpdump的端口信息不匹配

问题描述

我在功能__netif_receive_skb_core() /net/core/dev.c 文件中捕获了网络数据包。我解析数据包并获取src_portdest_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_portfast_node->org_srcportfast_node->org_destport%u printk的说明符。)
但是您必须考虑到TCPUDP标头中的 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_headertransport_header必须在您通过ip_hdr() / tcp_hdr() / udp_hdr()访问标题时设置,否则返回的指针可能是无效。


此外,您还必须注意如何在内核内部的不同位置分配内存。
__netif_receive_skb_core() atomic 上下文中执行,因此您不能在这里睡觉。 GFP_KERNEL标志允许kmalloc()休眠,因此您有一个错误。将GFP_KERNEL更改为GFP_ATOMIC