使用位域解析网络数据包
Using bitfields for parsing network packets
我有一份吃力不讨好的编写 IPv6 header 解析器的工作。
我想知道是否可以使用位域解析版本、流量 class 和流量控制标签。
我写了一些测试代码。在 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);
}
我希望第一个半字节在 ip_version 中可用,但似乎没有,相反我得到:
Size is 4, version 0, traffic class 0, flow label 96
或反转字段顺序
Size is 4, version 0, traffic class 6, flow label 0
谁能解释为什么会这样?
对于位域,它的实现取决于它们的布局方式。您最好为数据包的开头声明一个 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 header 也没有为 ipv6 使用位字段 header:
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 */
};
我有一份吃力不讨好的编写 IPv6 header 解析器的工作。
我想知道是否可以使用位域解析版本、流量 class 和流量控制标签。
我写了一些测试代码。在 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);
}
我希望第一个半字节在 ip_version 中可用,但似乎没有,相反我得到:
Size is 4, version 0, traffic class 0, flow label 96
或反转字段顺序
Size is 4, version 0, traffic class 6, flow label 0
谁能解释为什么会这样?
对于位域,它的实现取决于它们的布局方式。您最好为数据包的开头声明一个 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 header 也没有为 ipv6 使用位字段 header:
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 */
};