重读TCP/IP(4)之IP协议及传输

IP

IPTCP/IP协议族中最为核心的协议,所有的TCP,UDP,ICMPIGMP数据都以IP数据报格式传输,IP协议是不可靠,无连接的,这是针对它的上层TCP来说的,不可靠指的是它不能保证IP数据能成功地到达目的地,它仅提供最好的传输服务,如果发生某种错误,如路由器缓存用完了,IP会丢弃该数据报,发送ICMP消息给信源端说不可达,也就仅此而已。无连接指的是IP并不唯护任何关于后续数据报的状态信息,每个数据报的处理是相互独立的,IP数据报可以不按顺序接收,每个数据报独立的选择路由路线,因此到达顺序不可知。数据在经过网络层时会对数据进行封装,也就是IP首部,在以太网帧中,IPv4头紧跟着以太网帧头,同时以太网帧头中的协议类型为0x0800.

IP首部

重读TCP/IP(4)之IP协议及传输_第1张图片

Version 版本 4bit 用来表明IP协议实现的版本号,当前为IPv4, 0100

Internet Header Length(IHL) 头部长度:占4bit 包头的长度是n*32 由于IPv4的包头可能有可变数量的可选项,所以这个字段可以用来确定ipv4中数据部分偏移位置。IP包头的最小长度为20字节,因此一般IHL的最小值是5,由于IHL4位,最大也就60个字节,目前最多是24个字节

Service Type服务类型: 定义IP封包在传送过程中要求的服务类型,共由8bit组成其中每个bit的组合分别代表不同的意思,4bit中只能置其中1bit,如果为0000则是一般的服务,实际上现在把前6位作为DSCP的应用比较多,统一作为一个优先级来操作。

000..... (Routine): 过程字段,占3位,设置了数据包的重要性,取值越大越重要
...0.... (Delay):     延迟字段, 0正常,1期待高的延迟
....0... (Throughput): 流量字段,0正常,1期待高的流量
.....0.. (Reliability):  可靠性字段,0正常,1期待高的可靠性
......0. (ECN-capable Transport):  显示拥塞指示传输字段,以显示源端是否支持拥塞指示,0不支持,1支持
.......0 (CN: Congestion Experienced):  拥塞预警字段,0正常,1拥塞

Total Length(TL)包长度: 长度包括包头和数据的总和,该字段占16bit,利用首部长度和总长度字段就可以知道IP数据报内容的起始位置和长度,长度最大达到65535字节,但是一般数据链路层会对它进行分段,以太网最大1514字节,主机也要求不能接收超过576字节的数据。由于TCP会把用户数据分段,因此IP的这个长度不会影响TCP,UDP的应用(RIP,TFTP,BOOTP,DNS,SNMP都限制用户数据报长度为512字节),实际上已经有8192字节的IP数据报了,包长度字段对于IP首部是必需的,因为以太网最小帧长为46字节,而IP数据可能会更短,如果没有包长度,IP层不知道这46字节中有多少是IP数据报的内容,哪些是以太网数据填充的内容,哪些是真实的IP数据。

Identification (ID)标识:每一个IP封包都有一个16bit的唯一识别码,当程序产生的九据要通过网络传送时都会拆散成封包形式发送,当封包要进行重组的的时候这个ID就是依据,证明他们是同一个数据报分段而来的,标识字段通常每发一份消息它的值就会加1.

Flags 标记:这个标记的作用在于是否分段及段偏移

000 (Reserved Fragment): 保留分段
.0.  (Don’t Fragment):  不分段,0表示包可以分段,1表示不能分割
..0  (More Fragment):  更多分段。当上一个值为0时,此值为0则为最后一个封包,1表示还有被分割的封包

Fragment Offset(FO) 分段偏移: IP 协议头格式规定当包被分段之后,由于网络情况及其它因素不会按顺序抵达接收端,因此包进行分段时会为各片段做好定位,以便在接收端可以根据这个定位重装这个封包,占 13bit 如果封包没有被分段 FO=0

Time to Live(TTL) 生存时间: 生存时间字段设置了数据报可以经过的最多路由器的个数,每过一个路由器TTL1,意味着数据包在网络上生存多久,当TTL0时,数据报就被丢弃,并发送ICMP消息通知源主机,占8

Protocol,PROT 协议:指明所使用的网络协议类型,占8位,常用协议:

00:  IP
01:   ICMP
02:   IGMP
06:   TCP
17:   UDP
27:   RDP
89:   OSPFIGP

Head Checksum 头部校验和:这个数值用来检错用的,用以确保封包正确无误的接收到,头部校验和只计算 IP 首部,不对数据进行计算, ICMP,IGMP,UDP,TCP 的校验和都包括数据, IP 协议头规定了校验和的计算方法:

 

首先把检验和字段设置为0
对首部中每16位进行二进制反码求和,结果存在校验和字段中
当接收端收到一份IP数据包时,同样对首部中每个16位进行二进制反码求和,由于接收方计算过程中包含了发送端的首部校验和,因此如果首部在传输过程中没有发生任何差错,那么接收方计算的结果应该为全1,如果不全1则错误,丢弃该IP包,但是不生成并错消息,由上层去发现丢的的数据报并进行重传,通常由TCP来做这事

Source Address 源地址: 发送 IP 数据包的 IP 地址。占 32bit

Destination Address 目的地址:接收IP数据包的IP址址。占32bit

Options+Padding 选项填充: 这两项很少使用,只有某些特殊的封包需要特定的控制才会用到

 

安全和处理限制: 用于军事领域
记录路径:让每个路由器都记下它的IP地址
时间戳:让每个路由器记来它的IP地址的时间
宽松的源站选路:为数据报指定一系列必需经过的IP地址
严格的源站选路:要求只能经过指定的这些IP地址,不能经过其它的地址,选路规定死了

选项字段以32bit为单位,不够用0填充,这也保证了IP首部始终为32bit的整数倍

IP头部如果没有选项为20个字节,TCP头部也是24个字节,当有选项时是24个字节。

具体实例分析:

重读TCP/IP(4)之IP协议及传输_第2张图片

1.         0x45:        4代表ipv4的版本号,5代表  5*4=20字节,包头长度单位为4字节

2.         0x00:        tos=0, 没有优先极区分

3.         0x0034:      总长度包括包头和数据总共52个字节,其中20字节IP头,20字节TCP头,12字节TCP选项

4.         0xbd17:       标识ID为48417

5.         0x4000:       010 00000  不分片,片偏移为0

6.         0x40:         TTL=64

7.         0x06:         协议为06指的是TCP

8.         0xf787:       首部校验和来保证数据(IP报头)的完整性,也仅仅是头部,数据不能保证,不可靠

9.         0xc0a80265:   源地址      192.168.2.101

10.        0xc0a8026f:   目的地址 192.168.2.111

校验和算法:

 

发送方: 将校验和字段设置为0,然后将IP包头按16bit分成多个单元,如包头长度不是16bit的整数倍,用0填充
        对各个单元采用反码求和运算(即高位溢出会加到低位),将得到的和的反码填入字段

接收方:将校验和字段设置为0,然后将IP包头按16bit分成多个单元,如包头长度不是16bit的整数倍,用0填充
       对各个单元采用反码求和运算,检查得到的是否符合全1
证明:
       假如发送端求的和为 sum_send, 那么校验码 checksum=2**16-1-sum_send
       当接收端收到包时 sum_receive=sum_send+checksum=2**16-1 即是全1了

校验和算法python实现:

 

#!/usr/bin/env python

def checksum(*aList):
    sum = 0x0
    for i in range(len(aList[0])):              #aList[0]=alist
        if i%2==0:
            aList[0][i]=aList[0][i]<<8          #奇数位左移8位成为高8位
    for i in aList[0]:
        sum=sum+i                               #求和
        sum=(sum>>16)+(sum&0xffff)              #循环相加,如果溢出加到低位
        result=2**16-1-sum                      #算反码=2**模-1-原码
        result=hex(result)                      #十六进制转换
    return result        

alist=[0x45,0x00,0x00,0x34,0xbd,0x17,0x40,0x00,0x40,0x06,0x00,0x00,0xc0,0xa8,0x02,0x65,0xc0,0xa8,0x02,0x6f]

print checksum(alist)
------------------------------------------
0xf787

IP分片

分段一般是由上层TCP来负责,但是如果数据包只在第三层,而没有牵扯到第四层,则会由IP自己来分片,如ICMP包,跟TCP无关,但又超过了以太网包1500总长,IP就会自动分片进行传输

ping –l 8192 192.168.1.100抓包如下:

重读TCP/IP(4)之IP协议及传输_第3张图片

由于以太网数据长度为46~1500,以太网承载IP的最大数据就是1500字节,可见IPTotal Length:1500,去掉头部20字节,数据长度为1480字节,由于我选择的是第二个包,因此它坐有片偏移1480,且Identification与上一个包是一样的,说明他们属于同一个数据包分片而来,Flags标识分片并未结束,因为数据总长为8192,现在只传了1480*2,这一切都是为了方便接收端重装这个数据包

IP数据传输

以太网工作在第二层,作用在同一个网络内部转发以太网帧,但如果源和目的的IP位于不同的网络,则必需经过路由器进行转发,路由器负责不同网络间的传输报文,通过路由表来决定最佳转发路径,以太网交换机是负责同一网络间的报文传输,能过学习源地址表进行端口转发,一般情况数据会先发至默认的网关,由网关进行外网的连接。

转发的过程:

将第二层的帧头和帧尾移除,解析出第三层报文

检查IP报文的目的IP地址,在路由表中查找

如果路由器找到最佳路径,则将第三层报文封装到新的二层帧中,目的MAC会改变,将帧转发出端口,在报文从原设备传输至目的设备的过程中,三层IP地址不会改为(除NAT)但是每一跳随着报文在路由器中被解封装和重新封装,二层链路地址会改变,封装格式也有可能改变,如以太网到串行链路或令牌环网等。

一个例子:在网络概述中我举的例子是同一网段中的web浏览,然而现在举的是不同的网段浏览网页,数据又是如何传输的呢,PC1192.168.1.10)浏览服务器PC2(192.168.4.10)上的网页:

PC1浏览器输入 http://192.168.4.10:8000/blog/

重读TCP/IP(4)之IP协议及传输_第4张图片

PC1作为发送主机,有着7层协议栈,当在浏览器中输入网址后,PC1开始封装包,由http get消息增加TCP头,再增加IP头,再增加Ethernet头的同时发送ARP,如果URL中的IP是同网段,则不需要默认网关,只需要在本地发送ARP广播,查询属于该IPMAC地址,如果URL中的IP不在同一网段,则PC1寻找默认网关,如果ARP缓存中有,则直接发数据给默认网关,如果没有,则发ARP寻找默认网关的MAC,得到R1的回复后,将报文转发至R1Fa0/0

R1作为路由器,只关心二三层,而不关心上层的数据,R1检查目的MAC是否 为自己,如果是则接收,不是则丢弃,R1识别出以太网类型为0x0800,意味着数据为IP数据包,R1解封装第二层的数据,查看第三层IP的目的IP,R1发现目的IP192.168.4.10不是自己的直连的网络,则查找自己的路由表,看看192.168.4.0的网段的下一跳是哪一个设备,路由表中指明192.168.4.0/24的下一跳是R2Fa0/0,于是决定把该报文从自己的Fa0/1口发送R2Fa0/0,由于是在以太网上,因此R1必需ARP解析出192.168.2.2MAC地址,这时R1需要重新封装第二层的数据帧,源为自己的MAC(00-20),而目的MAC指向R2Fa0/00B-31

R2作为路由器收到R1过来的包,同样寻找192.168.4.10是属于哪个网段的,下一跳是谁,当他检查了R1发过来的目的MAC为自己时,解封装,检查目的IP,查找路由表下一跳是192.168.3.2(R3S0/0),并从自己的串行口发出去,由于二层是点对点的串行链路,因此无需ARP直接用PPP封装传送数据到R3sS0/0

R3收到R2来的数据包,R3进行解封装PPP,取出目的IP地址发现是自己的直连以太网,即无需再发给路由器了,但还必需ARP解析出目的主机,PC2收到R3发来的ARP广播寻问192.168.4.10是谁时,PC2回给R3自己的MAC(0B-20)R3此时重新封装新的以太网帧并从自己的Fa0/0发出

PC2终于接收到了由PC1发来的get消息,解封装以太网帧,将IPv4报文传递给协议栈处理,解开IP头,解开TCP头,取出get消息,得知PC2想要获取自己服务器上的主页,随后需要对此信息进行确认,由于PC1发来的肖息除了IP是源主机的外,源MAC已经变成了R3Fa0/0,但这并不影响PC2进行返回确认,PC2可以根据源IP,重新找路由找到R3,再到R2,再到R1,最后回到PC1,二层MAC的改变并不影响三层数据的正确转发。

路由表

首先路由器会检查数据帧目标地址字段中的数据链路标识,如果它包含了路由器接口标识,那么路由器将从帧中剥离出数据包传递给网络层,在网络层,路由器检查目的IP地址,如果目标地址是路由器接口的IP地址或所有主机广播地址,则检查协议字段进行处理,如果不是自己接口的地址,则需要检查路由表,路由表至少必需包含两项

目标地址:这是路由器可以到达的网络地址

指向目标的指针:即下一跳路由器,要么指针指向路由器的直连目标网络,要么就指向直连网络内的另一台路由器地址,更接近目标网络一跳的路由器

Windows:  (R2)

目标网络                 网络掩码                 网关                  接口

192.168.4.0               255.255.255.0          192.168.2.2     192.168.2.1

Linux: (R3)

[root@]# ip route

192.168.4.0/24 via 192.168.3.2 dev eth0

Cisco: (R3)

192.168.1.0 255.255.255.0 via 192.168.3.1

参考:

TCP/IP协议卷1
TCP/IP路由技术第一卷 
https://community.emc.com/go/chinese
http://jianjian.blog.51cto.com/35031/4932/ 校验和计算

 

 

你可能感兴趣的:(路由,校验和,IP协议)