IPV4协议头固定部分20字节
IPV6协议头固定大小部分为40个字节
通过一个抓包,分析IP头部的校验和如何计算
1-1:version 4位
1-2:头长 4位 此四位表示的是有多少个32位,即有多少个4字节。
第一个字节45,二进制是0100 0101,即可看到前四位表示版本是4,后5位表示头部长度是20个字节,5*4=20.
计算校验和的方法,是将校验和置0,即图中的91 2a, 然后将头部数据每两个字节为一组,进行相加运算,如果结果大于两个字节,再将结果中每两个字节为一组进行加运算,最后得到两个字节的和,将这个和取反,即为IP头部校验和。这个例子相加结果是26ed3, 分两部分加后为6ed5, 取反(即用15去减每一位)得到912a.
TCP/IP详解一书中提到的是所有双字节先取反,再求和,计算结果是一样的,79123 -> 912a.
------------------------------------------------------------------
下面看下编程时用到的地址结构,及其转化。
表示地址的结构体,IPV4的sockaddr_in 是16个字节,其中后8个字节是填充位。
struct sockaddr_in {
sa_family_t sin_family; /* Address family 2字节 */
unsigned short int sin_port; /* Port number 2字节 */
struct in_addr sin_addr; /* Internet address 4字节 */
/* Pad to size of `struct sockaddr'. 8字节*/
unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
sizeof(unsigned short int) - sizeof(struct in_addr)];
};
其中sin_addr是一个联合体。
IPV6的sockaddr_in6为28字节
struct sockaddr_in6 {
unsigned short intsin6_family; /* AF_INET6 2字节*/
__be16 sin6_port; /* Transport layer port # 2字节 */
__be32 sin6_flowinfo; /* IPv6 flow information 4字节*/
struct in6_addrsin6_addr; /* IPv6 address 16字节*/
__u32 sin6_scope_id; /* scope id (new in RFC2553) 4字节 */
};
它们最终要转化的sockaddr为16字节,
struct sockaddr {
sa_family_t sa_family; /* address family, AF_xxx*/
char sa_data[14];/* 14 bytes of protocol address
*/
};
所以IPV4地址结构在转换后会有溢出的部分,但用指针访问依然可以。