struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD) //网络字节序
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos;
__be16 tot_len;
__be16 id;
__be16 frag_off;
__u8 ttl;
__u8 protocol;
__sum16 check;
__be32 saddr;
__be32 daddr;
};
45 00 00 29 38 13 40 00 40 06 7d 60 c0 a8 02 0a c0 a8 02 01
(1) “45”,其中“4”是IP协议的版本(Version),说明是IP4。“5”是IHL位,表示IP头部的长度,是一个4bit字段,最大就是1111了,IP头部的最大长度就是60字节。而这里为“5”,说明是20字节。IP包头最小长度为20字节(IP头长度包含选项)
(2) “00”,服务类型(Type of Service)。这个8bit字段由3bit的优先权子字段(现在已经被忽略),4 bit的TOS子字段以及1 bit的未用字段(现在为0)构成.4 bit的TOS子字段包含:最小延时、最大吞吐量、最高可靠性以及最小费用构成,这四个1bit位最多只能有一个为1,本例中都为0,表示是一般服务
(3) “00 29”,IP数据报文总长,包含头部以及数据,这里表示41字节。这41字节由20字节的IP头部以及21字节的TCP头构成(最后的一个字节为数据)
(7) “40”这个字节就是TTL(Time To Live)了,表示一个IP数据流的生命周期,用Ping显示的结果,能得到TTL的值。每次IP数据包经过一个路由器的时候TTL就减一,当减到0时,这个数据包就消亡了。这也时Tracert的原理。本例中为“40”,转换为十进制就是64了
.ttl = IPDEFTTL; 缺省的IP包生存期为64
(8) “06”,这个字节表示传输层的协议类型
//Protocols
#define IPPROTO_IP 0 /* dummy for IP */
#define IPPROTO_ICMP 1 /* control message protocol */
#define IPPROTO_IGMP 2 /* internet group management protocol */
#define IPPROTO_GGP 3 /* gateway^2 (deprecated) */
#define IPPROTO_TCP 6 /* tcp */
#define IPPROTO_PUP 12 /* pup */
#define IPPROTO_UDP 17 /* user datagram protocol */
#define IPPROTO_IDP 22 /* xns idp */
#define IPPROTO_ND 77 /* UNOFFICIAL net disk proto */
#define IPPROTO_RAW 255 /* raw IP packet */
#define IPPROTO_MAX 256
(9) “7d 60”这个16bit是头校验和(Header Checksum)
(10) “c0 a8 02 0a”,这个是源地址
(11) “c0 a8 02 01”,这个是目标地址
IP校验和
/*
buffer:IP首部的起始地址
size:IP首部的大小
*/
SHORT checksum(USHORT* buffer, int size)
{
unsigned long cksum = 0;
while(size>1)
{
cksum += ntohs(*buffer++);
size -= sizeof(USHORT);
}
if(size)
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16);
return (USHORT)(~cksum);
}
- 把校验和字段清零
- 对每16位进行二进制反码求和,反码求和的意思是先对每16位求和,再将得到的和转为反码
(cksum >> 16) + (cksum & 0xffff):将高16位与低16位相加
cksum += (cksum >> 16):第一步相加可能产生进位
举例
45 00 00 31
89 F5 00 00
6E 06 00 00(校验字段)
C0 A8 01 0A -> 192.168.1.10
C0 A8 04 0C -> 192.168.4.12
4500 + 0031 + 89F5 + 0000 + 6e06+ 0000 + C0A8 + 010A + C0A8 + 040C = 2 C392
0002 + C392 = C394
~22C7 = 3C6B
注:校验和计算时需要主机序;计算完的校验和需要转换成网络序