跳到主要内容

ARP 与 ICMP 协议详解

在网络层中,除了核心的 IP 协议外,还有两个至关重要的辅助协议:ARP(地址解析协议)和 ICMP(互联网控制消息协议)。ARP 解决了 IP 地址到 MAC 地址的映射问题,ICMP 则提供了网络诊断和错误报告机制。理解这两个协议对于网络故障排查和安全防护至关重要。

ARP 协议

为什么需要 ARP

在以太网等局域网中,数据帧的实际传输依赖于 MAC 地址(物理地址),而不是 IP 地址。当主机需要向同一局域网内的另一台主机发送数据时,它必须知道对方的 MAC 地址才能构建以太网帧。

问题在于:网络层使用的是 IP 地址,而数据链路层使用的是 MAC 地址。这两种地址之间没有直接的关联——IP 地址是逻辑地址,由网络管理员分配或 DHCP 自动分配;MAC 地址是物理地址,由网卡厂商烧录。ARP(Address Resolution Protocol,地址解析协议)的作用就是在这两种地址之间建立映射关系。

ARP 报文格式

ARP 报文直接封装在以太网帧中,以太网帧的类型字段为 0x0806。ARP 报文格式如下:

 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 硬件类型 | 协议类型 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 硬件地址长度 | 协议地址长度 | 操作码 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 发送方硬件地址 (前 4 字节) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 发送方硬件地址 (后 2 字节) | 发送方协议地址 (前 2 字节) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 发送方协议地址 (后 2 字节) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 目标硬件地址 (前 4 字节) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 目标硬件地址 (后 2 字节) | 目标协议地址 (前 2 字节) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 目标协议地址 (后 2 字节) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

字段详解

字段长度说明
硬件类型2 字节硬件地址类型,以太网为 1
协议类型2 字节协议地址类型,IP 为 0x0800
硬件地址长度1 字节MAC 地址长度,以太网为 6
协议地址长度1 字节IP 地址长度,IPv4 为 4
操作码2 字节1=ARP 请求,2=ARP 响应,3=RARP 请求,4=RARP 响应
发送方硬件地址6 字节发送者的 MAC 地址
发送方协议地址4 字节发送者的 IP 地址
目标硬件地址6 字节目标的 MAC 地址(请求时为 0)
目标协议地址4 字节目标的 IP 地址

ARP 请求与响应报文示例

ARP 请求报文(主机 192.168.1.10 查询 192.168.1.20 的 MAC 地址):

硬件类型: 0x0001 (以太网)
协议类型: 0x0800 (IPv4)
硬件地址长度: 6
协议地址长度: 4
操作码: 1 (请求)
发送方硬件地址: 00:11:22:33:44:55
发送方协议地址: 192.168.1.10
目标硬件地址: 00:00:00:00:00:00 (未知,填充 0)
目标协议地址: 192.168.1.20

ARP 请求报文会被封装在以太网广播帧中发送,目的 MAC 地址为 ff:ff:ff:ff:ff:ff,这样局域网内的所有主机都会收到这个请求。

ARP 响应报文(192.168.1.20 响应自己的 MAC 地址):

硬件类型: 0x0001 (以太网)
协议类型: 0x0800 (IPv4)
硬件地址长度: 6
协议地址长度: 4
操作码: 2 (响应)
发送方硬件地址: 66:77:88:99:aa:bb
发送方协议地址: 192.168.1.20
目标硬件地址: 00:11:22:33:44:55
目标协议地址: 192.168.1.10

ARP 响应报文会被封装在以太网单播帧中发送,目的 MAC 地址为请求方的 MAC 地址。

ARP 工作流程

详细步骤

步骤 1:查找 ARP 缓存

当主机 A 需要发送数据给主机 B 时,首先检查自己的 ARP 缓存表,看是否已经有 B 的 MAC 地址映射。如果找到,直接使用缓存中的 MAC 地址发送数据帧。

步骤 2:发送 ARP 请求

如果缓存中没有找到,主机 A 构造一个 ARP 请求报文,包含:

  • 自己的 IP 地址和 MAC 地址
  • 目标的 IP 地址
  • 目标 MAC 地址字段填 0

这个 ARP 请求被封装在以太网广播帧中发送到局域网内的所有主机。

步骤 3:处理 ARP 请求

局域网内的所有主机都会收到这个广播帧,并解析其中的 ARP 请求。每台主机检查"目标协议地址"字段:

  • 如果目标 IP 是自己的 IP,则处理这个请求
  • 如果目标 IP 不是自己的 IP,则忽略这个请求

步骤 4:发送 ARP 响应

目标主机 B 发现请求的是自己的 IP 地址,于是构造 ARP 响应报文:

  • 把请求报文中的"发送方硬件地址"和"发送方协议地址"复制到"目标硬件地址"和"目标协议地址"
  • 把自己的 MAC 地址和 IP 地址填入"发送方硬件地址"和"发送方协议地址"
  • 把操作码改为 2(响应)

ARP 响应被封装在以太网单播帧中,直接发送给请求方。

步骤 5:更新 ARP 缓存

请求方 A 收到 ARP 响应后,提取其中的 MAC 地址和 IP 地址映射,存入自己的 ARP 缓存表。之后发送给 B 的数据帧就可以直接使用缓存中的 MAC 地址了。

ARP 缓存机制

ARP 缓存(ARP Cache)存储了 IP 地址到 MAC 地址的映射关系,避免每次通信都发送 ARP 请求。

缓存表结构

每台主机的 ARP 缓存表包含以下信息:

IP 地址MAC 地址接口状态超时时间
192.168.1.100:11:22:33:44:55eth0Reachable剩余时间
192.168.1.2066:77:88:99:aa:bbeth0Stale已过期

缓存老化机制

ARP 缓存条目有生命周期,超过一定时间未被使用就会被删除。不同操作系统的默认超时时间:

操作系统默认超时时间
Linux60 秒(可配置)
Windows15-45 秒(动态调整)
macOS20 分钟
Cisco 路由器4 小时

缓存老化机制的目的是适应网络拓扑的变化。当设备的网卡被更换时,其 MAC 地址会改变,老化的缓存可以自动更新。

缓存更新策略

ARP 缓存会在以下情况更新:

  1. 收到 ARP 响应:更新或添加对应的映射条目
  2. 收到 ARP 请求:如果请求方的 IP-MAC 映射不在缓存中,则添加;如果已存在但 MAC 地址不同,则更新
  3. 主动探测:缓存即将过期时,发送单播 ARP 请求验证 MAC 地址是否仍然有效
  4. 超时删除:超过生命周期未被使用的条目被删除

ARP 相关命令

查看 ARP 缓存

# Linux 查看 ARP 缓存
arp -n
# 或使用 ip 命令
ip neigh show

# 输出示例
# 192.168.1.1 dev eth0 lladdr 00:11:22:33:44:55 REACHABLE
# 192.168.1.20 dev eth0 lladdr 66:77:88:99:aa:bb STALE

# Windows 查看 ARP 缓存
arp -a

# 输出示例
# Interface: 192.168.1.10 --- 0x2
# Internet Address Physical Address Type
# 192.168.1.1 00-11-22-33-44-55 dynamic
# 192.168.1.20 66-77-88-99-aa-bb dynamic

添加静态 ARP 条目

静态 ARP 条目不会过期,常用于防止 ARP 欺骗攻击或确保关键设备的通信。

# Linux 添加静态 ARP 条目
arp -s 192.168.1.1 00:11:22:33:44:55

# 使用 ip 命令
ip neigh add 192.168.1.1 lladdr 00:11:22:33:44:55 dev eth0 nud permanent

# Windows 添加静态 ARP 条目(需要管理员权限)
arp -s 192.168.1.1 00-11-22-33-44-55

删除 ARP 条目

# Linux 删除 ARP 条目
arp -d 192.168.1.1

# 使用 ip 命令
ip neigh del 192.168.1.1 dev eth0

# Windows 删除 ARP 条目
arp -d 192.168.1.1

# 清空所有 ARP 缓存
arp -d *

发送 ARP 请求(手动解析)

# Linux 使用 arping 工具发送 ARP 请求
arping -c 3 192.168.1.1

# 输出示例
# ARPING 192.168.1.1 from 192.168.1.10 eth0
# Unicast reply from 192.168.1.1 [00:11:22:33:44:55] 0.542ms
# Unicast reply from 192.168.1.1 [00:11:22:33:44:55] 0.523ms
# Sent 3 probes (1 broadcast(s))
# Received 3 response(s)

特殊 ARP 机制

免费 ARP(Gratuitous ARP)

免费 ARP 是一种特殊的 ARP 请求,发送方请求的是自己的 IP 地址。它的作用是:

检测 IP 地址冲突:当主机配置了一个 IP 地址后,发送免费 ARP 请求。如果收到响应,说明局域网内已有其他主机使用了相同的 IP 地址,触发地址冲突警告。

更新其他主机的 ARP 缓存:当主机的 MAC 地址改变(如更换网卡)后,发送免费 ARP 请求,通知局域网内的其他主机更新 ARP 缓存。

# 手动发送免费 ARP
arping -A -c 1 -I eth0 192.168.1.10

免费 ARP 报文的特点:

  • 发送方协议地址 = 目标协议地址 = 自己的 IP 地址
  • 发送方硬件地址 = 自己的 MAC 地址
  • 目标硬件地址 = 0 或广播地址

代理 ARP(Proxy ARP)

代理 ARP 允许路由器代替目标主机响应 ARP 请求。这在以下场景中有用:

跨网段通信:当主机配置了错误的子网掩码时,可能认为目标主机在同一网段,从而发送 ARP 请求。路由器可以通过代理 ARP 响应这个请求,使通信正常进行。

透明代理:防火墙或代理服务器使用代理 ARP 拦截流量,实现透明代理。

代理 ARP 的工作原理:

ARP 安全问题

ARP 欺骗(ARP Spoofing)

ARP 欺骗是最常见的局域网攻击方式之一。攻击者发送伪造的 ARP 响应,将网关或其他主机的 IP 地址映射到攻击者的 MAC 地址,从而截获或篡改流量。

攻击后果:

  • 中间人攻击:攻击者可以窃听、篡改通信内容
  • 拒绝服务:攻击者丢弃流量,导致受害者无法上网
  • 会话劫持:攻击者可以劫持已建立的会话

防护措施

静态 ARP 绑定:在关键设备上配置静态 ARP 条目,防止被伪造的 ARP 响应覆盖。

# 在服务器上绑定网关的静态 ARP
arp -s 192.168.1.1 00:11:22:33:44:55

ARP 防护软件:使用专门的 ARP 防护软件,如 ARPWatch、XArp 等,监控异常的 ARP 活动。

交换机安全特性

  • DAI(Dynamic ARP Inspection):交换机验证 ARP 报文的合法性,丢弃伪造的 ARP 报文
  • 端口安全:限制每个端口可以学习的 MAC 地址数量
  • IP Source Guard:绑定 IP 地址和 MAC 地址,防止 IP 欺骗

网络分段:使用 VLAN 将网络分段,缩小 ARP 欺骗的影响范围。

ICMP 协议

为什么需要 ICMP

IP 协议是无连接、不可靠的,它只是尽力将数据包传送到目的地,但不保证数据包一定到达。当网络中出现问题时,如目的地不可达、路由失败、数据包超时等,IP 协议本身没有机制来报告这些错误。

ICMP(Internet Control Message Protocol,互联网控制消息协议)的作用就是提供一种机制,让路由器和主机能够报告错误情况和网络状况。ICMP 是 IP 协议不可或缺的一部分,每个 IP 实现都必须支持 ICMP。

ICMP 报文格式

ICMP 报文封装在 IP 数据包中,IP 首部的协议字段值为 1。ICMP 报文的基本格式:

 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 类型 | 代码 | 校验和 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| 报文内容(可变) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

字段说明

字段长度说明
类型1 字节ICMP 消息类型,决定报文的含义
代码1 字节对消息类型的进一步细分
校验和2 字节整个 ICMP 报文的校验和
报文内容可变根据类型和代码不同而不同

ICMP 消息类型

根据 IANA 的官方定义,ICMP 消息类型如下:

类型名称用途
0Echo ReplyPing 响应
3Destination Unreachable目标不可达
4Source Quench源点抑制(已废弃)
5Redirect路由重定向
8EchoPing 请求
9Router Advertisement路由器通告
10Router Solicitation路由器请求
11Time Exceeded超时
12Parameter Problem参数问题
13Timestamp时间戳请求
14Timestamp Reply时间戳响应
42Extended Echo Request扩展 Echo 请求
43Extended Echo Reply扩展 Echo 响应

Destination Unreachable(类型 3)

目标不可达消息由路由器或目标主机发送,表示数据包无法到达目的地。代码字段进一步说明原因:

代码说明
0网络不可达
1主机不可达
2协议不可达
3端口不可达
4需要分片但设置了 DF 标志
5源路由失败
6目标网络未知
7目标主机未知
8源主机被隔离
9目标网络被管理禁止
10目标主机被管理禁止
11网络不可达(TOS)
12主机不可达(TOS)
13通信被管理禁止
14主机优先级违规
15优先级截断

常见的目标不可达场景:

  • 网络不可达(代码 0):路由器没有到达目标网络的路由
  • 主机不可达(代码 1):数据包到达目标网络,但目标主机不存在或已关闭
  • 端口不可达(代码 3):数据包到达目标主机,但目标端口没有服务监听
  • 需要分片但 DF=1(代码 4):用于 Path MTU Discovery

Time Exceeded(类型 11)

超时消息在以下情况发送:

代码说明
0TTL 超时(传输过程中)
1分片重组超时

TTL 超时是 Traceroute 的工作基础。当路由器收到 TTL=1 的数据包时,将 TTL 减为 0,丢弃数据包并发送 ICMP Time Exceeded 消息给源主机。

Redirect(类型 5)

路由器发现主机使用了非最优路由时,发送重定向消息通知主机使用更好的路由。

代码说明
0重定向网络
1重定向主机
2重定向网络和服务类型
3重定向主机和服务类型

重定向消息通常在以下场景出现:主机将发往其他网络的数据包发送给默认网关,但网关发现目标网络实际上可以通过同一局域网内的另一台路由器到达。

Ping 命令详解

Ping 是最常用的网络诊断工具,使用 ICMP Echo 请求和响应来测试主机的可达性。

工作原理

Ping 发送 ICMP Echo 请求(类型 8),目标主机收到后返回 ICMP Echo 响应(类型 0)。通过计算请求发送时间和响应接收时间的差值,可以得到往返时间(RTT)。

Echo 请求/响应报文格式

 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 类型 | 代码 | 校验和 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 标识符 | 序列号 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| 数据(可选) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • 标识符:用于匹配请求和响应,通常是进程 ID
  • 序列号:用于标识同一会话中的不同请求,从 0 开始递增
  • 数据:可选的数据部分,用于测试不同大小数据包的传输

Ping 命令参数

# 基本用法
ping 8.8.8.8

# 指定发送次数
ping -c 4 8.8.8.8 # Linux/macOS: 发送 4 次
ping -n 4 8.8.8.8 # Windows: 发送 4 次

# 指定数据包大小
ping -s 1000 8.8.8.8 # Linux/macOS: 发送 1000 字节数据
ping -l 1000 8.8.8.8 # Windows: 发送 1000 字节数据

# 指定发送间隔
ping -i 0.5 8.8.8.8 # 每 0.5 秒发送一次

# 设置 TTL
ping -t 64 8.8.8.8 # Linux/macOS: 设置 TTL 为 64
ping -i 64 8.8.8.8 # Windows: 设置 TTL 为 64

# 持续 ping
ping -t 8.8.8.8 # Windows: 持续 ping,Ctrl+C 停止

Ping 输出解读

$ ping -c 4 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: icmp_seq=0 ttl=117 time=15.123 ms
64 bytes from 8.8.8.8: icmp_seq=1 ttl=117 time=14.987 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=117 time=15.234 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=117 time=15.001 ms

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 14.987/15.086/15.234/0.102 ms

关键指标:

  • icmp_seq:序列号,连续的请求应该有连续的序列号
  • ttl:响应包的 TTL 值,可以用来估算目标系统的类型
  • time:往返时间(RTT),单位是毫秒
  • packet loss:丢包率,反映网络质量
  • min/avg/max/stddev:RTT 的最小值、平均值、最大值和标准差

常见 Ping 结果分析

正常响应:收到所有响应,RTT 稳定。

请求超时

  • 目标主机不可达
  • 防火墙阻止 ICMP
  • 目标主机禁用了 ICMP 响应

响应延迟大

  • 网络拥塞
  • 路径中有高延迟链路
  • 目标主机负载过高

丢包

  • 网络拥塞导致队列溢出
  • 无线网络信号不稳定
  • 链路故障

Traceroute 命令详解

Traceroute 用于追踪数据包从源到目的所经过的路由路径,是网络故障排查的重要工具。

工作原理

Traceroute 利用 IP 数据包的 TTL 字段和 ICMP Time Exceeded 消息来探测路径上的路由器。

Traceroute 实现

Traceroute 的探测过程:

  1. 发送 TTL=1 的数据包,第一个路由器收到后 TTL-1=0,丢弃并返回 ICMP Time Exceeded
  2. 发送 TTL=2 的数据包,第二个路由器返回 ICMP Time Exceeded
  3. 依此类推,直到数据包到达目标主机
  4. 目标主机返回 ICMP Echo Reply(如果使用 ICMP)或 Port Unreachable(如果使用 UDP)

不同实现方式:

  • Linux traceroute:默认使用 UDP,目标端口从 33434 开始递增
  • Windows tracert:使用 ICMP Echo 请求
  • Linux traceroute -I:使用 ICMP Echo 请求

Traceroute 命令参数

# 基本用法
traceroute www.google.com # Linux
tracert www.google.com # Windows

# 使用 ICMP
traceroute -I www.google.com

# 指定探测次数
traceroute -q 3 www.google.com

# 指定起始 TTL(跳过前几跳)
traceroute -f 5 www.google.com

# 指定最大跳数
traceroute -m 30 www.google.com

# 指定等待超时时间
traceroute -w 5 www.google.com

# 禁用 DNS 解析(只显示 IP)
traceroute -n www.google.com

Traceroute 输出解读

$ traceroute -n 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
1 192.168.1.1 0.543 ms 0.421 ms 0.512 ms
2 10.0.0.1 5.123 ms 4.987 ms 5.234 ms
3 172.16.0.1 10.456 ms 10.234 ms 10.567 ms
4 * * *
5 8.8.8.8 15.123 ms 14.987 ms 15.234 ms

每行显示一跳的信息:

  • 第一列:跳数
  • 第二列:路由器的 IP 地址
  • 后续列:三次探测的 RTT

特殊标记:

  • *:探测超时,可能是路由器禁用了 ICMP 响应
  • !N:收到 ICMP Destination Unreachable(网络不可达)
  • !H:收到 ICMP Destination Unreachable(主机不可达)
  • !P:收到 ICMP Destination Unreachable(协议不可达)

Traceroute 与 MTU 发现

Traceroute 还可以用来探测路径 MTU(Path MTU Discovery),避免 IP 分片:

# 发送不分片的大包,观察是否收到 "需要分片" 的 ICMP 消息
traceroute --mtu 1500 www.google.com

ICMP 安全问题

ICMP 攻击类型

Smurf 攻击:攻击者向广播地址发送 ICMP Echo 请求,源地址伪造为受害者的 IP。网络中的所有主机都会向受害者发送响应,造成 DDoS 攻击。

Ping of Death:发送超大 ICMP 数据包,导致目标系统缓冲区溢出。现代系统已经修复了这个漏洞。

ICMP 重定向攻击:攻击者发送伪造的 ICMP Redirect 消息,修改受害者的路由表,将流量导向攻击者控制的路径。

ICMP 隧道:通过 ICMP 数据包隐蔽传输数据,绕过防火墙限制。

防护措施

限制 ICMP 类型:防火墙只允许必要的 ICMP 类型,如 Echo 请求/响应、Destination Unreachable、Time Exceeded。

# Linux iptables 示例
# 允许 Echo 请求
iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT
# 允许 Echo 响应
iptables -A INPUT -p icmp --icmp-type 0 -j ACCEPT
# 允许 Destination Unreachable
iptables -A INPUT -p icmp --icmp-type 3 -j ACCEPT
# 允许 Time Exceeded
iptables -A INPUT -p icmp --icmp-type 11 -j ACCEPT
# 拒绝其他 ICMP
iptables -A INPUT -p icmp -j DROP

限制 ICMP 速率:防止 ICMP 泛洪攻击。

# Linux 限制 ICMP 速率
iptables -A INPUT -p icmp -m limit --limit 1/s --limit-burst 4 -j ACCEPT

禁用 ICMP 重定向:防止路由欺骗。

# Linux 禁用接受 ICMP 重定向
sysctl -w net.ipv4.conf.all.accept_redirects=0
sysctl -w net.ipv4.conf.default.accept_redirects=0

禁用源路由:防止攻击者指定数据包路径。

# Linux 禁用源路由
sysctl -w net.ipv4.conf.all.accept_source_route=0

ICMP 编程示例

发送 ICMP Echo 请求

import socket
import struct
import time
import select

def checksum(data):
"""计算 ICMP 校验和"""
if len(data) % 2:
data += b'\x00'

s = sum(struct.unpack('!%dH' % (len(data) // 2), data))
s = (s >> 16) + (s & 0xffff)
s += s >> 16
return ~s & 0xffff

def ping(host, timeout=2, count=4):
"""发送 ICMP Echo 请求"""
# 创建原始套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
sock.settimeout(timeout)

# 获取目标 IP
dest_addr = socket.gethostbyname(host)

print(f"PING {host} ({dest_addr})")

for seq in range(count):
# 构建 ICMP Echo 请求
# 类型(1B) + 代码(1B) + 校验和(2B) + 标识符(2B) + 序列号(2B) + 数据
icmp_type = 8 # Echo 请求
icmp_code = 0
icmp_checksum = 0
icmp_id = 0x1234 # 标识符
icmp_seq = seq

# 构建数据部分
data = b'abcdefghijklmnopqrstuvwxyz'

# 构建报文(校验和先填 0)
header = struct.pack('!BBHHH', icmp_type, icmp_code, icmp_checksum, icmp_id, icmp_seq)
packet = header + data

# 计算校验和
icmp_checksum = checksum(packet)

# 重新打包(包含正确的校验和)
header = struct.pack('!BBHHH', icmp_type, icmp_code, icmp_checksum, icmp_id, icmp_seq)
packet = header + data

# 记录发送时间
send_time = time.time()

try:
# 发送数据包
sock.sendto(packet, (dest_addr, 0))

# 接收响应
while True:
ready = select.select([sock], [], [], timeout)
if not ready[0]:
print(f"Request timeout for icmp_seq {seq}")
break

recv_packet, addr = sock.recvfrom(1024)
recv_time = time.time()

# 解析 IP 头部(通常 20 字节)
ip_header = recv_packet[:20]
ip_proto = ip_header[9]

if ip_proto != 1: # 不是 ICMP
continue

# 解析 ICMP 报文
icmp_header = recv_packet[20:28]
recv_type, recv_code, recv_checksum, recv_id, recv_seq = struct.unpack('!BBHHH', icmp_header)

# 检查是否是我们的响应
if recv_type == 0 and recv_id == icmp_id and recv_seq == seq:
rtt = (recv_time - send_time) * 1000
print(f"64 bytes from {dest_addr}: icmp_seq={seq} ttl={ip_header[8]} time={rtt:.3f} ms")
break

except socket.timeout:
print(f"Request timeout for icmp_seq {seq}")

sock.close()

# 使用示例
if __name__ == "__main__":
ping("8.8.8.8")

故障排查实战

场景 1:无法 Ping 通目标主机

可能原因

  1. 网络不通:物理链路故障、IP 地址配置错误
  2. 防火墙阻止:目标主机或中间设备阻止了 ICMP
  3. 目标主机关闭:目标主机未开机或已关机
  4. 路由问题:没有到达目标的正确路由

排查步骤

# 1. 检查本地网络配置
ip addr show
ip route show

# 2. Ping 本地回环地址
ping 127.0.0.1

# 3. Ping 本机 IP
ping <本机IP>

# 4. Ping 网关
ping <网关IP>

# 5. Ping 目标主机
ping <目标IP>

# 6. 追踪路由
traceroute <目标IP>

# 7. 检查 ARP 缓存
arp -n

# 8. 检查防火墙规则
iptables -L -n # Linux

场景 2:ARP 缓存异常

可能原因:ARP 欺骗攻击或网络设备故障

排查步骤

# 1. 查看 ARP 缓存
arp -n

# 2. 检查网关 MAC 地址是否正确
# (对比路由器上显示的 MAC 地址)

# 3. 清空 ARP 缓存
ip neigh flush all

# 4. 重新获取 ARP 映射
ping -c 1 <网关IP>
arp -n

# 5. 添加静态 ARP 条目(临时解决)
arp -s <网关IP> <正确的MAC地址>

场景 3:网络延迟高或丢包

可能原因:网络拥塞、链路故障、路由问题

排查步骤

# 1. 持续 Ping 测试
ping -i 0.2 <目标IP>

# 2. 检查网络接口统计
ip -s link show eth0

# 3. 追踪路由并查看延迟分布
traceroute -n <目标IP>

# 4. 使用 MTR 综合诊断
mtr <目标IP>

# 5. 检查带宽使用情况
iftop -i eth0

总结

ARP 和 ICMP 是网络层的重要辅助协议:

ARP 协议

  • 解决 IP 地址到 MAC 地址的映射问题
  • 通过请求-响应机制获取目标 MAC 地址
  • ARP 缓存提高效率,但有老化机制
  • 面临 ARP 欺骗攻击风险,需要防护措施

ICMP 协议

  • 提供错误报告和网络诊断功能
  • Ping 使用 Echo 请求/响应测试可达性
  • Traceroute 使用 TTL 超时探测路由路径
  • 面临 ICMP 攻击风险,需要限制和防护

掌握 ARP 和 ICMP 的工作原理,对于网络故障排查、安全防护至关重要。

[!TIP] 想了解网络层核心协议?请看 IP 协议详解。想了解传输层协议?请看 TCP 协议详解UDP 协议详解