第6章:IP(Internet Protocol)
网际协议
一、导读
1.1 本章学习目标
第6章是全书的核心章节,深入讲解IP(网际协议)——Internet的基础协议。IP负责将数据报从源主机路由到目的主机,是整个TCP/IP协议族的核心。理解IP的工作原理,是理解整个Internet运作方式的前提。
本章的核心学习目标包括:
- 掌握IP数据报的完整格式:每个字段的含义、取值范围和作用
- 理解IP路由的基本原理:路由器如何根据目的IP和路由表选择下一跳
- 深入理解IP分片与重组:什么情况下分片、分片如何标识和重组
- 掌握TTL(生存时间)的作用:为什么需要TTL、TTL如何防止数据报无限循环
- 理解IP校验和的计算方法:为什么只校验头部、校验和如何更新
- 学会使用工具分析IP数据报:tcpdump、Wireshark、ip route等
1.2 为什么本章如此重要
IP是Internet的核心协议。每一台连接到Internet的设备——无论是服务器、PC、手机还是IoT设备——都必须实现IP协议。IP定义了数据报的格式和路由规则,是所有上层协议(TCP、UDP、ICMP等)的基础。
理解IP对于以下方面至关重要:
- 网络编程:理解套接字API背后的数据传输机制
- 网络故障排查:分析路由问题、MTU问题、TTL问题
- 网络安全:理解IP欺骗、源路由攻击等安全威胁
- 网络优化:理解分片对性能的影响、路径MTU发现
1.3 核心问题引导
在阅读本章时,请带着以下问题思考:
IP数据报头部为什么没有"长度"字段来标识数据部分的长度?它如何知道数据部分有多长?
TTL为什么是"跳数"而不是"时间"?每跳减1比每秒减1有什么优势?
IP分片在哪里发生?在哪里重组?为什么这样设计?
路由器转发数据报时,需要修改IP头部的哪些字段?为什么?
如果IP数据报在传输过程中丢失了一个分片,会发生什么?
IP协议是"不可靠"的,具体指什么?它不做哪些事情?
二、核心概念详解
2.1 IP数据报格式
IPv4数据报由头部和数据两部分组成。头部分为固定部分(20字节)和可选部分(可变长)。
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options (if IHL > 5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data ... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+2.1.1 各字段详解
| 字段 | 长度 | 说明 |
|---|---|---|
| Version | 4位 | IP版本号,IPv4为4 |
| IHL | 4位 | 头部长度(以4字节为单位),最小5(20字节) |
| TOS | 8位 | 服务类型(DSCP+ECN),用于QoS |
| Total Length | 16位 | 数据报总长度(头部+数据),最大65535字节 |
| Identification | 16位 | 标识字段,用于分片重组 |
| Flags | 3位 | DF(不分片)、MF(更多分片) |
| Fragment Offset | 13位 | 分片偏移量(以8字节为单位) |
| TTL | 8位 | 生存时间,每跳减1,减到0则丢弃 |
| Protocol | 8位 | 上层协议(6=TCP, 17=UDP, 1=ICMP) |
| Header Checksum | 16位 | 头部校验和 |
| Source Address | 32位 | 源IP地址 |
| Destination Address | 32位 | 目的IP地址 |
| Options | 可变 | 可选字段(记录路由、时间戳等) |
2.1.2 Total Length与数据部分长度
IP数据报没有直接的"数据长度"字段,但可以通过 Total Length - IHL×4 计算得出:
Total Length = 1500, IHL = 5 (20字节)
数据部分长度 = 1500 - 20 = 1480字节2.2 IP路由
IP路由是路由器根据目的IP地址选择下一跳的过程。
2.2.1 路由表
每台主机和路由器都维护一个路由表。路由表的每个条目包含:
| 字段 | 说明 |
|---|---|
| 目的网络 | 目的IP地址的网络前缀 |
| 子网掩码 | 网络前缀的长度 |
| 下一跳 | 下一个路由器的IP地址 |
| 接口 | 发送数据报的网络接口 |
| 度量值 | 路由的优先级(cost) |
# Linux查看路由表
ip route show
# default via 192.168.1.1 dev eth0
# 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.100
# 10.0.0.0/8 via 192.168.1.1 dev eth02.2.2 路由查找过程
路由器收到IP数据报后:
提取目的IP地址
用路由表中每个条目的子网掩码与目的IP做AND运算
如果结果匹配该条目的目的网络,则该条目是一个候选
在所有候选条目中选择最长前缀匹配的条目
将数据报从该条目的接口发送给下一跳
目的IP: 10.1.1.50
路由表:
10.0.0.0/8 → 接口A(匹配,前缀长度8)
10.1.0.0/16 → 接口B(匹配,前缀长度16)
10.1.1.0/24 → 接口C(匹配,前缀长度24)← 最长前缀匹配
选择接口C2.2.3 路由器转发时的字段修改
路由器转发数据报时,需要修改以下IP头部字段:
| 字段 | 操作 | 原因 |
|---|---|---|
| TTL | 减1 | 记录跳数,防止无限循环 |
| Header Checksum | 重新计算 | TTL改变导致校验和失效 |
| 链路层帧头 | 替换 | 新的源MAC和目的MAC |
| 链路层FCS | 重新计算 | 帧内容改变 |
以下字段保持不变:
- Source Address、Destination Address
- Protocol、Total Length(除非分片)
- Identification、Flags、Fragment Offset(除非分片)
2.3 IP分片与重组
当IP数据报大于链路层的MTU时,路由器必须将其分片。
2.3.1 分片规则
- 每个分片都是独立的IP数据报,有自己的IP头部
- 分片的数据部分长度必须是8字节的整数倍(除了最后一个分片)
- 分片通过 Identification、Flags、Fragment Offset 三个字段标识
2.3.2 分片示例
原始数据报:Total Length = 4020, IHL = 5, 数据 = 4000字节, MTU = 1500
原始数据报:
+--------+------------------+
|IP头部20B| 数据4000B |
+--------+------------------+
Total Length = 4020
分片1:
+--------+------------------+
|IP头部20B| 数据1480B |
+--------+------------------+
Identification = X, Flags = MF, Offset = 0
Total Length = 1500
分片2:
+--------+------------------+
|IP头部20B| 数据1480B |
+--------+------------------+
Identification = X, Flags = MF, Offset = 185 (1480/8)
Total Length = 1500
分片3:
+--------+------------------+
|IP头部20B| 数据1040B |
+--------+------------------+
Identification = X, Flags = 0(最后), Offset = 370 (2960/8)
Total Length = 10602.3.3 重组
目的主机负责将分片重组为原始数据报。重组通过以下机制实现:
- Identification:同一数据报的所有分片具有相同的标识
- Fragment Offset:标识该分片在原始数据报中的位置
- MF标志:MF=1表示后面还有分片,MF=0表示这是最后一个分片
- 重组定时器:如果在一定时间内没有收到所有分片,则丢弃已收到的分片
2.3.4 分片的问题
IP分片带来了很多问题:
- 性能下降:分片和重组消耗路由器/主机的CPU资源
- 可靠性降低:任何一个分片丢失,整个数据报都需要重传
- 安全隐患:分片重叠攻击(teardrop攻击)
- NAT困难:NAT设备需要跟踪分片,增加复杂性
因此,现代网络倾向于避免分片:
- 使用路径MTU发现(PMTUD)
- TCP在建立连接时协商MSS(最大段大小),确保TCP段加上IP和TCP头部后不超过MTU
- 设置DF标志,让路由器在需要分片时返回ICMP差错报文
2.4 TTL(生存时间)
TTL是一个8位字段,初始值通常为64或128,每经过一个路由器减1。当TTL减到0时,路由器丢弃数据报并发送ICMP超时报文。
TTL的设计目的:防止数据报在网络中无限循环。
如果没有TTL,以下情况会导致数据报永远在网络中循环:
- 路由环路(路由表配置错误导致A→B→A→B...)
- 目的主机不可达且没有默认路由
# 使用ping测试TTL
ping -t 1 www.example.com # TTL=1,第一跳就超时
ping -t 5 www.example.com # TTL=5,最多到达第5跳
# 使用traceroute观察TTL递增
traceroute www.example.com
# 第1跳:TTL=1
# 第2跳:TTL=2
# ...2.5 IP校验和
IP头部校验和用于检测头部在传输过程中是否发生错误。
2.5.1 计算方法
将头部每个16位字相加(校验和字段先置0)
如果有进位,将进位加到结果中
取反码
2.5.2 为什么只校验头部
IP校验和只覆盖头部,不覆盖数据部分。原因:
- 数据部分的校验由上层协议负责(TCP/UDP有自己的校验和)
- 路由器只需要处理头部,不需要解析数据部分
- 减少路由器的处理开销
注意:每跳路由器修改TTL后,必须重新计算校验和。
三、实战案例
3.1 案例一:使用tcpdump分析IP数据报
sudo tcpdump -i eth0 -nn -v 'tcp port 80'输出示例:
12:34:56.789 IP (tos 0x0, ttl 64, id 12345, offset 0, flags [DF],
proto TCP (6), length 52)
192.168.1.100.49152 > 93.184.216.34.80:
Flags [S], seq 0, win 65535, options [mss 1460,sackOK,TS val 123456 ecr 0,nop,wscale 7]分析:
tos 0x0:服务类型为0ttl 64:初始TTL为64id 12345:标识字段flags [DF]:设置了DF标志(不分片)proto TCP (6):上层协议为TCPlength 52:数据报总长度52字节(20字节IP头部 + 32字节TCP头部)
3.2 案例二:观察IP分片
# 发送大数据包(超过MTU)
ping -c 1 -s 3000 -M dont 93.184.216.34
# 设置DF标志,数据3000字节,观察是否分片
# 允许分片
ping -c 1 -s 3000 93.184.216.34
# 抓包观察分片
sudo tcpdump -i eth0 -nn 'ip[6:2] & 0x1fff != 0'3.3 案例三:使用traceroute分析路由
traceroute -n -m 15 www.example.com
# -n: 不做DNS反向查询
# -m 15: 最大15跳四、常见误区与难点
4.1 误区一:"IP数据报的最大长度是65535字节"
理论上是的(Total Length是16位),但实际上受限于链路层MTU。以太网MTU=1500,所以IP数据报通常不超过1500字节。超过的会被分片。
4.2 误区二:"分片可以在任何路由器上重组"
分片只在目的主机上重组,中间路由器不会重组分片。这是因为路由器没有足够的缓冲区和处理能力来重组。
4.3 难点:理解Fragment Offset的单位
Fragment Offset以8字节为单位。这是因为分片数据部分的长度必须是8字节的整数倍,用8字节作为单位可以减小偏移字段的值,用13位就能表示最大65536字节的数据报。
五、本章小结
第6章深入讲解了IP协议:
IP数据报由头部(20-60字节)和数据组成,头部包含版本、IHL、TTL、协议、源/目的地址等关键字段。
IP路由基于目的IP和路由表,使用最长前缀匹配选择下一跳。路由器转发时修改TTL和校验和。
IP分片在数据报大于MTU时发生,通过Identification、Flags、Fragment Offset三个字段标识,在目的主机重组。
TTL防止数据报无限循环,每跳减1,减到0则丢弃并发送ICMP超时报文。
IP校验和只覆盖头部,每跳路由器修改TTL后需要重新计算。
六、思考与练习
思考题
如果IP数据报的Identification字段只有8位(而不是16位),会对分片产生什么影响?
为什么Fragment Offset以8字节为单位而不是1字节?如果以1字节为单位,13位够用吗?
IP协议是"尽力交付"(best-effort)的,它不保证什么?这些保证由谁提供?
如果路径上某个链路的MTU突然变小(如从1500变为576),会发生什么?PMTUD如何处理?
练习题
使用tcpdump捕获IP数据报,记录头部各字段的值,验证Protocol字段与上层协议的对应关系。
使用ping发送不同大小的数据包,观察哪些会导致IP分片,分析分片后的各字段值。
配置静态路由,使用traceroute验证数据包是否按照指定路径传输。