从数据包数据中获取 IP 版本

Posted

技术标签:

【中文标题】从数据包数据中获取 IP 版本【英文标题】:Get IP version from packet data 【发布时间】:2021-06-18 07:45:56 【问题描述】:

pcap回调函数返回IP头和数据如下:

void packet_handler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data);

我的理解是 pkt_data 的前 4 位是 IP 版本,我可以从中确定它是 IPv4 还是 IPv6。但是,我尝试了几种不同的方法来读取前 4 位,但我得到的数据没有意义。

例如,我定义了如下结构:

struct ipdata 
    u_char version : 4;
    u_char dontcare : 4;
;

然后我尝试使用此代码获取 ip 版本:

ipdata* pipdata;
pipdata = (ipdata*) pkt_data;
ip_ver = pipdata->version;
printf(" %d ", ip_ver);

上述方法打印的值是 3、6、9、8 和 12。如果我在 Wireshark 中同时观察流量,我发现大部分数据包都是 IPv6。

做过这件事的人能否解释一下我将如何阅读 IP 版本?

【问题讨论】:

“没有意义”是什么意思?你得到了什么价值观? 你的“几种不同的方式”是什么?请发帖Minimal, Reproducible Example。 IP 版本应该从它下面的层知道。仅仅从第一个字节获取它是不可靠的。 嗯,第一个数据可能是ETHERNET地址。 Programming with pcapTCPDUMP/LIBPCAP public repository 感谢您的所有回复。我添加了一种尝试获取前 4 位和我看到的输出的方法。 【参考方案1】:

找出答案。 npcap返回整个以太网包,所以前14个字节是以太网头:

/* Length of the Ethernet Header (Data Link Layer) */
#define ETHERNET_HEADER_LEN 14 

/* Ethernet addresses are 6 bytes */
#define ETHER_ADDR_LEN  6

/* Ethernet header */
struct sniff_ethernet 
    u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address (i.e. Destination MAC Address) */
    u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address (i.e. Source MAC Address) */
    u_short ether_type; /* IP? ARP? RARP? etc */
;

你可以通过查看上面结构中的ether_type而不是IP头中的版本来判断它是IPv4还是IPv6数据包,例如:

/* Common ethernet types in Hex*/
#define ETHERNET_TYPE_IPv4 0x0800
#define ETHERNET_TYPE_IPv6 0x86DD

u_short eth_type;
ethernet = (struct sniff_ethernet*)(pkt_data);
eth_type = ntohs(ethernet->ether_type);

if (eth_type == ETHERNET_TYPE_IPv4) 
    ipv4_handler(pkt_data);

else if (eth_type == ETHERNET_TYPE_IPv6)

    ipv6_handler(pkt_data);

IP 标头在以太网标头之后开始,因此您可以使用以下 IPv6 数据包示例的代码来获取它:

/* IPv6 header */
typedef struct ipv6_header

    unsigned int
        version : 4,
        traffic_class : 8,
        flow_label : 20;
    uint16_t length;
    uint8_t  next_header;
    uint8_t  hop_limit;
    struct in6_addr saddr;
    struct in6_addr daddr;
 ipv6_header;

const ipv6_header* iph;

iph = (ipv6_header*)(pkt_data + ETHERNET_HEADER_LEN);

从那里您可以访问有关 IP 标头的版本和其他信息。有关更多信息,请参阅此帖子:Getting Npcap IPv6 source and destination addresses

【讨论】:

以上是关于从数据包数据中获取 IP 版本的主要内容,如果未能解决你的问题,请参考以下文章

C# 使用 tcp/ip 从 Minecraft 服务器获取数据包

为啥tcp服务器可以获取客户端的ip?

网络层IP数据包和ARP协议转发原理

确定哪个 IP 地址收到了数据包

[na]ip数据包格式

网络层协议介绍及概述