skb 中的端口信息与 tcpdump 的不匹配
Port information in skb doesn't match with the tcpdump's one
我在 /net/core/dev.c 文件中的函数 __netif_receive_skb_core()
中捕获网络数据包。我解析数据包并获取 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
).
的说明符
但是你必须考虑到 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_header
和 transport_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
.
我在 /net/core/dev.c 文件中的函数 __netif_receive_skb_core()
中捕获网络数据包。我解析数据包并获取 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
).
的说明符
但是你必须考虑到 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_header
和 transport_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
.