代码目的不明确?

时间:2016-12-11 00:09:42

标签: c ipv4 bit-fields packets raw-sockets

我正在学习Linux中的原始套接字编程,在教程中我注意到了这段代码的巧合:

struct ipheader {
 unsigned char      iph_ihl:5, iph_ver:4; //<--------------These
 unsigned char      iph_tos;
 unsigned short int iph_len;
 unsigned short int iph_ident;
 unsigned char      iph_flag;
 unsigned short int iph_offset;
 unsigned char      iph_ttl;
 unsigned char      iph_protocol;
 unsigned short int iph_chksum;
 unsigned int       iph_sourceip;
 unsigned int       iph_destip;
};

iph_ver保存IP为4,iph_ihl保存标头长度,设置为5.由于标头长度用4字节字描述,实际标头长度为是5×4 = 20个字节。 20个字节是最小长度。话虽如此,我很好奇这个结构中的位字段(iph_veriph_ihl是否具体为4和5,因为它将是IPv4,IP头的长度为20个字节。但是我不确定它们的位域如何对它们的值产生任何影响或相关性。任何解释都将不胜感激。

代码链接:http://www.tenouk.com/Module43a.html

1 个答案:

答案 0 :(得分:3)

本教程中的代码片段实际上是错误的!

以下是IP数据包标头的正确定义:

/*
 * Structure of an internet header, naked of options.
 *
 * We declare ip_len and ip_off to be short, rather than u_short
 * pragmatically since otherwise unsigned comparisons can result
 * against negative integers quite easily, and fail in subtle ways.
 */
struct ip {
#if BYTE_ORDER == LITTLE_ENDIAN 
    u_char  ip_hl:4,        /* header length */
            ip_v:4;         /* version */
#endif
#if BYTE_ORDER == BIG_ENDIAN 
    u_char  ip_v:4,         /* version */
            ip_hl:4;        /* header length */
#endif
    u_char  ip_tos;         /* type of service */
    short   ip_len;         /* total length */
    u_short ip_id;          /* identification */
    short   ip_off;         /* fragment offset field */
#define IP_DF 0x4000        /* dont fragment flag */
#define IP_MF 0x2000        /* more fragments flag */
    u_char  ip_ttl;         /* time to live */
    u_char  ip_p;           /* protocol */
    u_short ip_sum;         /* checksum */
    struct  in_addr ip_src,ip_dst;  /* source and dest address */
};

如您所见,ip_hlip_v都是4位宽的位域。字段的实际名称无关紧要,只是它们在数据包标题中的位置。

它们根据平台以不同的顺序定义,因为编译器根据字节顺序分配不同的位域。实际上,这种行为在C标准中没有规定,但似乎在各个平台上都是一致的。