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

Port information in skb doesn't match with the tcpdump's one

我在 /net/core/dev.c 文件中的函数 __netif_receive_skb_core() 中捕获网络数据包。我解析数据包并获取 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_portdest_portfast_node->org_srcportfast_node->org_destport%u printk).
的说明符 但是你必须考虑到 port in TCP and UDP headers is none 1-byte field (it has 2 bytes length), so it has endianness。特别是网络字节顺序。
这就是为什么要在打印时以主机字节顺序查看端口,您应该使用特殊函数来交换字节 - ntohs() - network-to-host-short。粗略地说,“短”意味着该函数适用于 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() 访问 headers 时设置,否则返回的指针可能无效。


此外,您还必须注意如何在内核中的不同位置分配内存。
__netif_receive_skb_core()atomic 上下文中执行,所以你不能在这里睡觉。 GFP_KERNEL flag allows some sleeping for kmalloc(), thus you have a bug. Change GFP_KERNEL to GFP_ATOMIC.