使用位域解析网络数据包

Posted

技术标签:

【中文标题】使用位域解析网络数据包【英文标题】:Using bitfields for parsing network packets 【发布时间】:2017-07-02 01:09:56 【问题描述】:

我有一份吃力不讨好的工作是编写 IPv6 标头解析器。

我想知道是否可以使用位域解析出版本、流量类别和流量控制标签。

我写了一些测试代码。在 x86 系统上执行我得到了意想不到的结果。

#include <stdint.h>
#include <stdio.h>

typedef struct __attribute__ ((__packed__)) 
        uint32_t                flow_label:20;
        uint32_t                traffic_class:8;
        uint32_t                ip_version:4;
 test_t;

int main(int argc, char **argv)

        uint8_t data[] =  0x60, 0x00, 0x00, 0x00 ;
        test_t  *ipv6 = (void *)data;

        printf("Size is %zu, version %u, traffic class %u, flow label %u\n", sizeof(test_t), ipv6->ip_version, ipv6->traffic_class, ipv6->flow_label);

我希望第一个 nibble 在 ip_version 中可用,但似乎没有,相反我得到:

Size is 4, version 0, traffic class 0, flow label 96

或倒置场序

Size is 4, version 0, traffic class 6, flow label 0

谁能解释为什么会这样?

【问题讨论】:

从调试的角度来看,使用uint8_t data[] = 0x12, 0x34, 0x56, 0x78 ;"version %X, traffic class %X, flow label %X" 深入了解问题。 顺便说一句,"flow label 0" 中具有小端位/字节顺序 isfirst 半字节,因为该顺序中的第一个半字节从 0x60 开始为 0 【参考方案1】:

对于位域,它的实现取决于它们的布局方式。您最好声明一个 32 位字段作为数据包的开头并使用位移来提取相关字段。

uint8_t ipver = data[0] >> 4;
uint8_t tclass = ((data[0] & 0xf) << 4) | (data[1] >> 4);
uint32_t flowlbl = (((uint32_t)data[1] & 0xf) << 16) | ((uint32_t)data[2] << 8) | data[3];

确实,即使是 Linux netinet/ip6.h 标头也不使用 ipv6 标头的位字段:

struct ip6_hdr
  
    union
      
    struct ip6_hdrctl
      
        uint32_t ip6_un1_flow;   /* 4 bits version, 8 bits TC,
                    20 bits flow-ID */
        uint16_t ip6_un1_plen;   /* payload length */
        uint8_t  ip6_un1_nxt;    /* next header */
        uint8_t  ip6_un1_hlim;   /* hop limit */
       ip6_un1; 
    uint8_t ip6_un2_vfc;       /* 4 bits version, top 4 bits tclass */
       ip6_ctlun;
    struct in6_addr ip6_src;      /* source address */
    struct in6_addr ip6_dst;      /* destination address */
  ;

【讨论】:

我已经看到用于解析 IPv4 数据包的结构使用两个 4 位位字段来表示标头和版本。我相信 OpenBSD 可以做到这一点。我想知道什么能始终如一地工作,但更复杂的位域会失败 @ArranCudbard-Bell 这可能与位域占用一个字节的一部分和另一个字节的一部分有关。

以上是关于使用位域解析网络数据包的主要内容,如果未能解决你的问题,请参考以下文章

一文教你如何用C代码解析一段网络数据包?含代码

Qt6网络抓包工具项目实战2.9网络数据解析并显示

2-ipv6基础知识之-数据包

一个通用网络协议数据解析

java怎么解析Wireshark抓包文件

《Wireshark数据包分析实战》(三)地址解析协议(ARP)