飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • IP协议

    • 认识 IP 协议与网络层定位
    • IPv4 编址体系与分类地址
    • CIDR 与子网划分实战
    • IPv6 编址体系
    • ARP 协议详解
    • NDP 协议详解
    • IGMP 与 MLD 组播侦听发现
    • VRRP 与网关冗余
    • IPv4 数据报首部解析
    • IPv6 数据报与扩展首部
    • IPsec 安全扩展
    • 分片、MTU 与路径发现
    • ICMP 与 Traceroute 原理
    • 路由基础与转发流水线
    • 动态路由协议
    • NAT 网络地址转换
    • DHCP 与自动配置
    • Wireshark 与命令行工具
    • IPv6 过渡技术
    • IP 协议栈排障与攻击防御
  • TCP协议

    • 认识 TCP 协议与传输层定位
    • TCP 报文段首部解析
    • 三次握手与连接建立
    • 四次挥手与连接释放
    • TCP 有限状态机
    • 序列号与确认机制
    • 超时重传与 RTO 计算
    • 滑动窗口与流量控制
    • 拥塞控制基础
    • 现代拥塞控制算法
    • TCP 选项与扩展
    • TCP 性能调优与内核参数
    • Nagle 算法与糊涂窗口综合征
    • TCP 定时器与 Keep-Alive 机制
    • TCP 安全与攻击防御
    • TCP 与上层/下层交互
    • TCP 综合实践与排障

IPv4 数据报首部解析

IP 数据报的结构

IP 数据报就像一封标准格式的快递单 + 货物:

  • 首部(Header):20~60 字节的"快递单信息",包含收发地址、包裹大小、优先级等
  • 数据(Payload):上层协议(TCP/UDP/ICMP)的内容,即"货物本身"
+------------------+------------------+
|   IP 首部        |   数据(TCP段)   |
|   20~60 字节     |   可变长度       |
+------------------+------------------+

## 固定首部 20 字节逐字段解析

把 20 字节展开成 5 行 × 32 位(每行 4 字节),这是 RFC 791 的标准画法:

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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


### 1. Version(版本,4 位)

固定为 `0100`(即 4),表示 IPv4。IPv6 这里是 `0110`(6)。

### 2. IHL(首部长度,4 位)

表示首部有多少个 **32 位字(4 字节)**。最小值 5(5×4=20 字节),最大值 15(15×4=60 字节)。

如果首部有选项,IHL > 5。例如 IHL=6 表示首部 24 字节(20 字节固定 + 4 字节选项)。

### 3. TOS / DSCP / ECN(8 位)

这 8 位经历了三代演变:

**第一代:TOS(Type of Service,RFC 791)**
- 前 3 位:优先级(0~7,7 最高)
- 后 5 位:延迟/吞吐量/可靠性/开销请求

**第二代:DSCP + ECN(RFC 2474 / 3168)**
- 前 6 位:DSCP(区分服务代码点),决定 QoS 队列
- 后 2 位:ECN(显式拥塞通知)

**DSCP 常用值**:

| DSCP 值 | 名称 | 用途 |
|---------|------|------|
| 0 | BE(Best Effort)| 尽力而为,默认 |
| 46 | EF(Expedited Forwarding)| 语音/视频,最高优先级 |
| 10 | AF11 | 高优先级数据 |
| 18 | AF21 | 中优先级数据 |

**ECN 值**:
- 00:不支持 ECN
- 01/10:ECT(ECN-Capable Transport)
- 11:CE(Congestion Experienced),路由器标记拥塞

```mermaid
flowchart LR
    subgraph TOSField["TOS / Traffic Class 字段 (8位)"]
        direction LR
        DSCP["DSCP (6位)<br/>区分服务代码点"]
        ECN["ECN (2位)<br/>显式拥塞通知"]
    end
    
    DSCP --> Class0["000000<br/>BE 尽力而为"]
    DSCP --> Class46["101110<br/>EF 语音优先"]
    DSCP --> Class10["001010<br/>AF11 高优先级数据"]
    
    ECN --> E00["00<br/>不支持"]
    ECN --> E01["01/10<br/>ECT 支持"]
    ECN --> E11["11<br/>CE 经历拥塞"]
    
    style DSCP fill:#99ccff,stroke:#333
    style ECN fill:#ffcc99,stroke:#333
    style Class46 fill:#99ff99,stroke:#333,stroke-width:2px
    style E11 fill:#ff9999,stroke:#333

这 8 位经历了三代演变:最初是 TOS(RFC 791),后来演进为 DSCP+ECN(RFC 2474/3168)。DSCP 决定包进入哪个 QoS 队列,ECN 让路由器在不丢包的情况下标记拥塞,配合 TCP 降速。

4. Total Length(总长度,16 位)

首部 + 数据的总字节数,最大 65535 字节(2^16 - 1)。但以太网 MTU 只有 1500,所以实际很少超过 1500。

计算示例:

首部 20 字节 + TCP 数据 1460 字节 = Total Length = 1480

5. Identification(标识,16 位)

同一个数据报分片后的所有片段拥有相同的 Identification 值,就像快递单号。目的主机靠这个字段识别"这些碎片属于同一个包裹"。

6. Flags(标志,3 位)

位名称含义
第 1 位保留必须为 0
第 2 位DF(Don't Fragment)1=禁止分片
第 3 位MF(More Fragments)1=后面还有分片

DF=1 的典型场景:

  • Path MTU Discovery:发送方故意设 DF=1,如果中间路由器需要分片但 DF=1,就丢弃并返回 ICMP "需要分片但 DF 置位",发送方据此探测路径 MTU。

7. Fragment Offset(片偏移,13 位)

表示该分片在原始数据报中的位置,单位是 8 字节。例如 Offset=185 表示该分片从原始数据的第 185×8=1480 字节开始。

第一个分片的 Offset=0,MF=1(后面还有)最后一个分片的 MF=0,Offset>0不分片的包 MF=0,Offset=0

8. TTL(生存时间,8 位)

每经过一个路由器减 1,到 0 时丢弃并返回 ICMP Time Exceeded。初始值由操作系统决定:

  • Windows:128
  • Linux:64
  • 某些 Unix:255

Traceroute 就是利用 TTL 递增来探测路径的。

9. Protocol(协议,8 位)

标识上层协议类型,常见值:

值协议
1ICMP
2IGMP
6TCP
17UDP
41IPv6(6in4 隧道)
47GRE
50ESP(IPsec)
51AH(IPsec)

10. Header Checksum(首部校验和,16 位)

只校验首部,不校验数据。每经过一个路由器,TTL 减 1,校验和必须重新计算(因为 TTL 变了)。

IPv6 取消了首部校验和,因为链路层(以太网 CRC)和传输层(TCP/UDP 校验和)已经有足够校验,路由器重新计算校验和浪费 CPU 周期。

11. Source / Destination Address(各 32 位)

收发双方的 IPv4 地址。

选项字段(0~40 字节)

IHL 最大 15(60 字节),固定首部 20 字节,所以选项最多 40 字节。常见选项:

选项类型用途现状
记录路由让每个路由器写入自己的 IP已废弃,安全/性能问题
时间戳记录经过每个路由器的时间已废弃
严格源路由必须按指定路径逐跳转发已废弃,被用于攻击
松散源路由必须经过指定路由器,其余自由已废弃
路由器警告提示路由器需要检查该包RSVP / IGMP 仍在使用

现代互联网中,选项字段几乎不用,很多路由器遇到带选项的包会直接丢弃或慢路径处理。

Wireshark 实战:解读一个真实包

Internet Protocol Version 4, Src: 192.168.1.10, Dst: 8.8.8.8
    0100 .... = Version: 4
    .... 0101 = Header Length: 20 bytes (5)
    Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
    Total Length: 60
    Identification: 0x1a2b (6699)
    Flags: 0x4000, Don't fragment
        0... .... .... .... = Reserved bit: Not set
        .1.. .... .... .... = Don't fragment: Set
        ..0. .... .... .... = More fragments: Not set
    Fragment offset: 0
    Time to live: 128
    Protocol: ICMP (1)
    Header checksum: 0x1234 [validation disabled]
    Source: 192.168.1.10
    Destination: 8.8.8.8

解读:

  • 版本 4,首部 20 字节
  • 总长度 60 字节,数据部分 40 字节(ICMP Echo Request)
  • DF=1,不允许分片(Windows 默认 ping 设 DF)
  • TTL=128,Windows 主机发出
  • Protocol=1,上层是 ICMP

本篇小结

  • IPv4 首部固定 20 字节 + 选项最多 40 字节
  • IHL 以 4 字节为单位;Total Length 以字节为单位
  • Identification + Flags + Fragment Offset 管理分片
  • TTL 防环,每跳减 1;Protocol 标识上层协议
  • 首部校验和只覆盖首部,路由器需重新计算
  • DSCP/ECN 在 TOS 字段中实现 QoS 和拥塞通知
  • 选项字段现代已很少使用

动手实践

  1. Wireshark 抓一个 ping 包,逐字段对照 RFC 791 的首部图

  2. 计算:如果 IHL=5,Total Length=1500,数据部分多少字节?

  3. 观察不同操作系统的 TTL 初始值:

    • ping 8.8.8.8 看返回的 TTL(Linux 约 64,Windows 约 128)
    • 用 64 - 返回TTL 或 128 - 返回TTL 估算经过了几跳
  4. Wireshark 过滤 ip.dsfield.dscp == 46,观察是否有 EF 标记的包(企业网络中可能有语音流量)

上一页
VRRP 与网关冗余
下一页
IPv6 数据报与扩展首部