on
Linux服务器 - 2.IP协议详解
IP协议是TCP/IP协议族的核心协议,也是socket网络编程的基础之一。本文将从IP头部信息和IP数据报的路由和转发两个方面探讨IP协议。
1. IP服务的特点
IP协议为上层协议提供无状态、无连接、不可靠的服务。
无状态(stateless)是指IP通信双方不同步传输数据的状态信息,因此所有IP数据报的发送、传输和接收都是相互独立、没有上下文关系的。缺点是无法处理乱序和重复的IP数据报,优点是简单、高效。
无连接(connectionless)是指IP通信双方都不长久地维持对方的任何信息。这样上层协议每次发送数据都必须指定对方IP地址。
不可靠 是指IP协议不能保证IP数据报准确地到达接收端。发送端的IP模块一旦检测到IP数据报发送失败,就通知上层协议发送失败,而不会试图重传。
2. IPv4头部结构
| 4位版本号 | 4位头部长度 | 8位服务类型(TOS) | 16位总长度(字节数) | ||||||||||||||||||||||||||||
| 16位标识 | 3位标志 | 13位片偏移 | |||||||||||||||||||||||||||||
| 8位生存时间(TTL) | 8位协议 | 16位头部校验和 | |||||||||||||||||||||||||||||
| 32位源端IP地址 | |||||||||||||||||||||||||||||||
| 32位目的端IP地址 | |||||||||||||||||||||||||||||||
| 可选,最多40字节 | |||||||||||||||||||||||||||||||
4位版本号(version)指定IP协议版本。对IPv4来说,其值是4。
4位头部长度(header length)标识该IP头部有多少个32bit(4字节)。因为4位最大能表示15,所以IP头部最长是60字节。
8位服务类型(Type of Service, TOS)包含一个3位的优先权字段(现在已经被忽略),4位的TOS字段和1位保留字段(必须置0)。4位的TOS字段分别表示:最小延时、最大吞吐量、最高可靠性和最小费用,其中最大有一个能置1。
16位总长度(total length)是指整个IP数据报的长度,以字节为单位,因此IP数据报的最大长度为65535(216-1)字节。但是由于MTU的限制,长度超过MTU的数据报都将被分片传输,所以实际传输的IP数据报(分片)长度远小于最大值。接下来3个字段描述如何分片。
16位标识(identification)唯一地标识主机发送的每一个数据报。其初始值由系统随机生成,每发送一个数据报,其值就加1。该值在数据报分片时被复制到每个分片中,因此同一个数据报的所有分片具有相同的标识值。
3位标志字段的第一位保留。第二位(Don’t Fragment,DF)表示“禁止分片”。如果设置了这个位,IP模块将不对数据报进行分片,此时,如果数据报长度超过MTU的话,IP模块将丢弃该数据报并返回一个ICMP差错报文。第三位(More Fragment,MF)表示“更多分片”。除了数据报的最后一个分片外,其他分片都要把它置1。
13位分片偏移(fragmentation offset)是分片相对原始IP数据报开始处(仅指数据部分)的偏移。实际的偏移值是该值左移3位(乘8)后得到的。由于这个原因,除了最后一个分片外,每个IP分片的数据部分的长度必须是8的整数倍。
8位生存时间(Time To Live,TTL)是数据报到达目的地之前允许经过的路由器跳数。TTL值被发送端设置(常见是64)。数据报在转发过程中每经过一个路由,该值就被路由器减1。当TTL值减为0时,路由器将丢弃数据报,并向源端发送一个ICMP差错报文。TTL值可以防止数据报陷入路由循环。
8位协议(protocal)用来区分上层协议。其中,ICMP是1,TCP是6,UDP是17。
16位头部校验和(header checksum)由发送端填充,接收端对其使用CRC算法以检验IP数据报头部是否在传输过程中被损坏。
32位源端IP地址和目的端IP地址用来标识数据报的发送端和接收端。
最后一个选项字段(option)是可变长的可选信息,这部分最多包含40字节。可用的IP选项包括:
- 记录路由(record route),告诉数据报途径的所有路由器都将自己的IP地址填入IP头部的选项部分,这样我们可以追踪数据报的传递路径。
- 时间戳(timestamp),告诉每个路由器都将数据报被转发的时间填入IP头部的选项部分,这样就可以测量途径路由之间数据报的传输时间。
- 松散源路由选择(loose source routing),指定一个路由器IP地址列表,数据报发送过程中必须经过其中所有的路由器。
- 严格源路由选择(strict source routing),和松散源路由选择类似,不过数据报只能经过被指定的路由器。
3. IP分片
当IP数据报的长度超过帧的MTU时,它将被分片传输。分片可能发生在发送端,也可能发生在中转路由器上,而且可能在传输过程中被多次分片,但只有在最终的目标机器上才会被重新组装。
IP头部中有三个字段用于给IP分片和重组:数据报标识、标志和片偏移。一个IP数据报的每个分片都有自己的IP头部,她们具有相同的标识值,但具有不同的片偏移。并且除了最后一个分片外,其他分片都将设置MF标志。此外,每个分片的IP头部的总长度字段将被设置位该分片的长度。
以太网帧的MTU是1500字节,因此它携带的IP数据报的数据部分最多是1480字节。
4. IP路由
IP协议的一个核心任务是数据报的路由,即决定发送数据报到目标机器的路径。以下是IP模块的基本工作流程:

当IP模块接收到来自数据链路层的IP数据报时,先对该数据报的头部做CRC校验,确认无误后再具体分析头部信息。
如果该IP数据报的头部设置了源站选路选项(松散源路由选择或严格源路由选择),则IP模块转发该数据报。如果该IP数据报的目标IP地址是本机的IP地址,或者是广播地址,则该数据报是发送给本机的,IP模块根据数据报头部的协议字段将他派发给上层应用。如果该数据报不是发送给本机的,则转发该数据报。
数据报的转发首先检测系统是否允许转发,如果不允许,IP模块就将该数据报丢弃。如果允许,将对该数据报执行一些操作后,将数据报输出。
IP数据报应该发送至哪个下一跳路由,以及经过那个网卡来发送,就是IP路由过程。
路由机制
使用route命令或netstat命令可以查看路由表,以下是路由表实例:
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 192.168.1.1 0.0.0.0 UG 100 0 0 enp0s3
link-local * 255.255.0.0 U 1000 0 0 enp0s3
该路由表包含8个字段,含义如下:
- Destination 目标网络或主机
- Gateway 网关地址,*表示目标和本机在同一个网络,不需要路由
- Genmask 网络掩码
- Flags 路由项标志,常见有如下5种:
U,该路由项是活动的
H,该路由项的目标是一台主机
G,该路由项的目标是网关
D,该路由项是由重定向生成的
M,该路由项被重定向修改过 - Metric 路由距离,即到达指定网络所需的中转数
- Ref 路由项被引用的次数(Linux未使用)
- Use 该路由项被使用的次数
- Iface 该路由项对应的输出网卡接口
路由表更新
路由表必须能够更新,以反映网络连接的变化,这样IP模块才能准确、高效地转发数据报。route命令可以修改路由表,以下是几个例子:
$ sudo route add -host XXX.XXX.XXX.XXX dev eth0
$ sudo route del -net XXX.XXX.XXX.XXX netmask 255.255.255.0
$ sudo route del default
$ sudo route add default gw XXX.XXX.XXX.XXX dev eth0
通过route命令或其他工具手动修改路由表,是静态的路由更新方式。对于大型的路由器,通常通过BGP、RIP、OSPF等协议来发现路径,并更新自己的路由表。