网络协议 -- IP协议

IP协议是TCP/IP协议族中最核心的协议。所有的TCP、UDP、ICMP、IGMP数据都以IP数据报的格式传输。

IP协议是不可靠、无连接的:

  • 不可靠表示IP协议不能保证IP数据报能成功的到达目的地。IP仅提供传输服务,任何可靠性的要求都必须由上层来提供(如TCP)。如果传输过程发生错误,IP协议简单的丢弃该数据报,然后发送ICMP消息给发送端。

  • 无连接表示IP协议不维护任何关于后续数据报的状态信息,每个数据报都是相互独立的。这也说明,IP数据报可能不是按照发送顺序被接收到的,很有可能后发送的数据被先收到。

一、IP首部

IP数据报的格式如图:
网络协议 -- IP协议_第1张图片

  • 4位版本:标识目前采用的IP协议的版本号。IPv4为0100, IPv6为0110

  • 4位首部长度:用于标识首部的长度,单位为4字节,所以首部的最大长度为15*4字节=60字节

  • 8位服务类型:包括3bit的优先权字段(已被忽略),4bit的TOS字段,1bit的始终为0的未使用位。

  • 16位总长度(字节数):整个IP数据报的长度。数据报中数据内容的长度=总长度 - 首部长度

  • 16位标识:唯一地标识主机发送的每一份数据报。IP数据报的最大长度可达65535字节,但大多数链路层都会对它进行分片。由于TCP本身会把用户数据分成若干片,因此这个字段一般来说不会影响到TCP。

  • 3位标志:用于IP数据报分片。该字段第1bit不使用,第2bit是DF(Don't Fragment)位,DF位设为1时表明IP不对该数据包分片。第3bit是MF(More Fragments)位,当对数据包分片时,除了最后一片外,其他每个组成数据报的片都要把此位设为1。

  • 13位偏移:用于IP数据报分片。单位为8字节。表示该片相对于原始数据报开始处的位置,能表示的最大偏移为 2 13 2^{13} 213*8=65536字节。

另外,数据报被分片之后,每个片的总长度要更改为该片的长度值。IP层分片是透明的,但是即使只丢失一片数据也要重传整个数据报,因为IP层本身没有超时重传的机制。

  • 8位生存时间(TTL):设置数据报可以经过的最多路由器数量,每经过一个路由器,该值就减去1。当该值为0时,数据报就被丢弃。通常初始值为32或64.

  • 8位协议:表示上层传输层所用的协议类型。1表示ICMP协议,2表示IGMP协议,6表示TCP协议,17表示UDP协议。

  • 16位首部校验和:用于对IP首部的正确性进行校验,但不包括数据部分,这点不同于TCP和UDP的首部校验和。

  • 32位源IP地址:发送端的32bit的IP地址。

  • 32位目的IP地址:接收端的32bit的IP地址。

  • 选项:可变长度的可选信息。如果首部不含“选项字段”,则IP首部长度为20字节。

二、IP首部校验和

  • 发送端对IP数据报的校验和的计算步骤:
  1. 把IP数据报的校验和字段置为0;
  2. 把首部看成以16位为单位的数字组成,依次进行二进制反码求和;
  3. 把求和得到的结果取反。
  4. 将第2、3步得到的2个字节数据存入首部校验和。
  • 接收端对IP数据报的校验和的校验步骤:
  1. 把首部看成以16位为单位的数字组成,依次进行二进制反码求和;
  2. 把求和得到的结果取反码。
  3. 如果结果为0,则表示检验和校验通过,IP报文没有被修改过。

三、使用代码计算校验和

通过wireshark抓取一帧数据报,如图:
网络协议 -- IP协议_第2张图片

以该数据报的IP首部为基础,使用C++代码来验证IP首部校验和的计算步骤和校验步骤:

#include 


// GetChecksum函数用于实现上面所说的计算步骤中的第2步、第3步:
// 把首部看成以16位(2字节)为单位的数字组成,依次进行二进制反码求和,
// 但实际的算法实现上需要考虑取和溢出时的改进计算方法(见函数内部注释)
//
unsigned short GetChecksum(unsigned short* ip_header, int size) {
	assert(sizeof(unsigned short) == 2);

	// 为什么使用unsigned long(4字节)?
	// 因为虽然首部校验和只占16位(2个字节),但执行“以16位(2字节)为单位的二进制反码数据”求和操作得到的checksum可能会超过16位(2字节),
	// 所以这里用4个字节的unsigned long来接收相加得到的结果,后面再进行处理。
	//
	unsigned long checksum = 0;

	while (size > 1) {
		checksum += *ip_header; // 因为都是正数,所以反码与原码相同;故直接相加求和
		ip_header++; // ip_header为unsigned short类型的指针每次按2个字节相加

		size -= 2;
	}
	// 执行到这:checksum = 0x2850c

	// IP首部如果不包含“选项”字段,则为20字节,偶数;如果包含了“选项”,则字节数就可能为奇数了,
	// 这里针对字节数为奇数的情况进行处理。
	// 注:示例main函数中构造的ip_header不含有“选项”
	//
	if (size == 1) {
		checksum += *(unsigned char*)ip_header;
	}

	// 因为上面相加之后的结果大于2个字节,所以执行额外的处理步骤:
	// checksum >> 16 右移16位
	// 即除以2的16次方(0xffff),就是去除右边的2个字节,如:0x2850c >> 16 = 0x2
	//
	// checksum & 0xffff 位运算,得到后2个字节
	// 如:0x2850c & 0xffff = 0x850c
	//
	// checksum = 0x2 + 0x850c = 0x850e
	//
	checksum = (checksum >> 16) + (checksum & 0xffff);

	// 假如还大于2个字节,再次将多余的字节和checksum相加。
	checksum += (checksum >> 16);

	// 求和得到的结果的取反
	return (unsigned short)(~checksum);
}


int main()
{
	// 将上面wirkshark抓的数据包的IP头部,使用char数组,按字节构造出来
	//
	unsigned char ip_header[20] = {
		0x45, // 4位版本+4位首部长度
		0x00, // 8位服务类型(TOS)
		0x00, 0x1c,  // 16位总长度(字节数)
		0x50, 0xaa,  // 16位标识
		0x00, 0x00,  // 3位标志+13位片偏移
		0xff, // 8位生存时间(TTL)
		0x01, // 8位协议
		0xf1, 0x7a, // 16位首部校验和
		0xc0, 0xa8, 0x2e, 0x55, // 32位源IP地址
		0xee, 0x73, 0x9c, 0x4a  // 32位目的IP地址
	};


	// 第1步:把IP数据包的校验和字段置为0;
	//
	ip_header[10] = 0x00;
	ip_header[11] = 0x00;

	// 第2、3步计算校验和
	//
	unsigned short checksum = GetChecksum((unsigned short*)ip_header, sizeof(ip_header));

	printf("%02hhx %02hhx\n", *(char*)(&checksum), *((char*)(&checksum) + 1));

	// 第4步:将第2、3步得到的2个字节数据存入首部校验和
	//
	ip_header[10] = *(char*)(&checksum);
	ip_header[11] = *((char*)(&checksum) + 1);


	// 模拟接收到IP包之后,对IP首部的校验和进行校验
	//
	unsigned short checksum_check = GetChecksum((unsigned short*)ip_header, sizeof(ip_header));
	
	if (checksum_check == 0) {
		printf("checksum check successful!\n");
	}
	else {
		printf("checksum check failed!\n");
	}

    return 0;
}

四、IP校验和的设计原理

我们将IP首部进行简化来讲解IP校验和的设计原理,假设IP首部只有6个字节,第5,6字节存放校验和:
网络协议 -- IP协议_第3张图片

计算校验和时第5,6字节置为0,校验和等于:A+B+0,然后取反,即:
这里写图片描述

接收端收到之后校验步骤为:求校验和(不同的是:校验和位不置0),若此时求得校验和为0,则校验通过。即:
网络协议 -- IP协议_第4张图片

《TCP/IP详解 卷1:协议》在线阅读地址:http://www.52im.net/topic-tcpipvol1.html

你可能感兴趣的:(☆,网络编程,网络协议)