%% # 纲要 > 主干纲要、Hint/线索/路标 # Q&A #### 已明确 #### 待明确 > 当下仍存有的疑惑 **❓<font color="#c0504d"> 有什么问题?</font>** %% # ICMP 协议 > **ICMP** (Internet Control Message Protocol,**互联网控制报文协议**),也称 "**网际控制报文协议**"。 ICMP 是**网络层的协议**,工作在 **==网络层==**,用于向主机或路由器 **发送 IP 层的 "==错误报告=="、"==诊断信息==" 和其他==控制消息==**。 ICMP 是 IP 协议栈中的重要组成部分,但其**不用于传输数据**,而是用于**传递与 IP 网络通信有关的控制消息**。 <br> # ICMP 协议的作用 ICMP 的主要作用是**通过发送和接收特殊的消息**来**传递网络状态信息**,具体包括: - (1)**错误报告**:当路由器或主机在处理 IP 数据包时发现问题时,会使用 ICMP 通知源主机。 - 例如**当一个 IP 地址不可达时**(如无法找到目的地或没有路由可用),就会发送 ICMP 错误消息。 - (2)**网络诊断**:ICMP 协议提供了用于**诊断和调试网络通信的工具**,如 `ping` 和 `traceroute` ,其都依赖 ICMP 消息来工作。 基于 ICMP 协议的应用: - **Ping(网络连通性测试)** - `ping` 工具通过**发送 ICMP ==Echo Request== 消息并接收 ==Echo Reply== 消息** 来测试两台主机之间的连通性、网络延迟和丢包率。 - **Traceroute(路由跟踪)**: - `traceroute` 利用 ICMP 的 **==Time Exceeded== 消息**,通过**逐步增加数据包的 TTL,来探测数据包从源到目标的每一跳路由器**。<br>每当 TTL 变为 0 时,路由器会发送 Time Exceeded 消息,从而让源主机知道中途经过的路由器 IP 地址。 > [!example] 示例:ICMP 报告 IP 地址不可达 > ![[_attachment/02-开发笔记/07-计算机网络/网络层/ICMP 协议.assets/IMG-ICMP 协议-0E942657B3E959AAE4460B097D6C75F2.png|422]] <br><br><br> # ICMP 报文格式 ICMP 报文位于 "**==IP 数据报==**" 中的**有效载荷部分**,其格式如下: - (1)前 4 字节为 "**ICMP 头部**",共三个字段: - **类型**(8 位):ICMP 报文类型。 例如回显请求 8、回显应答 0、目标不可达 3; - **代码**(8 位):进一步区分**某类型下的不同报文**。例如类型为 3 时,代码为 0 代表**网络不可达**,1 代表**主机不可达**,2 代表**协议不可达**。 - **校验和**(16 位) - (2)中间 4 字节为 "**消息特定数据**",取决于具体的**ICMP 消息类型** - (3)后续为**数据部分**。 ![[_attachment/02-开发笔记/07-计算机网络/网络层/ICMP 协议.assets/IMG-ICMP 协议-783458E4D0C6F522150EBEA2C1AECDE6.png|566]] > [!example] ICMP 报文封装在 "**==IP 数据报==**" 中 > ![[_attachment/02-开发笔记/07-计算机网络/网络层/ICMP 协议.assets/IMG-ICMP 协议-2B7BA48B7E1724F0D45521A815D7A74C.png|676]] <br><br><br> # ICMP 报文类型 ICMP 报文可分为两大类: - **==差错报文==**:用以**通知出错原因**的错误消息 - **==请求报文==**:用于诊断的**查询消息**,包括:**回显请求及应答**、**时间戳请求及应答** 具体类型如下表,由 "**类型**" 字段的值指示: | ICMP 报文类型 | 类型字段的值 | | | ------------------------------------------------ | -------------------- | ----------------------------------------------------------------------------------------------------------------- | | - **回显请求** Echo Request<br>- **回显应答** Echo Reply | - 8(请求) <br>- 0(应答) | **==`ping` 命令==使用的 ICMP 消息**。<br>发送 `Echo Request` 消息到目标主机,目标主机收到后会返回一个 `Echo Reply`,以此检测**目标主机是否可达**,以及计算网络延迟 | | | | | | **目标不可达** Destination Unreachable | 3 | 当**路由器或主机无法将 IP 数据包送达目标**时,发送该消息给数据包的源主机。<br>例如,目标主机不可达、网络不可达或端口不可达等。 | | **超时** Time Exceeded | 11 | 当 IP 数据包中的 TTL 字段变为 0 时,**路由器会丢弃该数据包并发送 `Time Exceeded` 消息给源主机**。<br>**==`traceroute` 命令==** 就利用这一机制来探测数据包到目标的路径。 | | **参数问题** Parameter Problem | 12 | 当路由器或主机**发现接收到的 IP 数据包中存在非法的或不可识别的字段**时,会发送此消息告知源主机 | | **重定向** Redirect | 5 | 当**路由路径**需要改变时(例如路由器发现发送端主机使用了 "非最优" 的路由路径时),**路由器将该报文发送给主机,告知主机下次应==将数据报发送给另外的路由器==** | <br><br><br> # "终点不可达" 消息 当 IP 路由器**无法将 IP 数据包发送给目标地址**时,将发送**类型为 3** 的 "**目标不可达**" ICMP 差错报文给**发送端主机**。 同时,在 ICMP 头部的 "**==代码==**" 字段,进一步指出**不可达的具体原因**: ![[_attachment/02-开发笔记/07-计算机网络/网络层/ICMP 协议.assets/IMG-ICMP 协议-B0AF949E7AC9A84AEA20A306C1262E71.png|439]] 不可达原因说明: | | 代码 | 说明 | | --------- | --- | -------------------------------------------------------------------------- | | **网络不可达** | 0 | 路由器中**路由表匹配不到目的 IP 所在网络**时 | | **主机不可达** | 1 | 路由表中**无该主机信息**时 | | **协议不可达** | 2 | 例如,使用 TCP 协议访问对端时,对端主机防火墙**禁止 TCP 协议访问** | | **端口不可达** | 3 | 就 "IP 数据报中的**目的端口**",对端主机**未开启监听**时; | | 需分片但设置不分片 | 4 | IP 头部的 "**分片禁止**" 标志位为 1,故路由器**遇见超过 MTU 的数据包时直接丢弃**, <br>同时返回该 ICMP 不可达消息 | <br><br><br> # ping 命令的工作原理 源主机上执行 `ping` 命令后: - **源主机**向目标主机发送一个 **ICMP ==Echo Request== 消息**(类型 **8**) - **目标主机**收到消息后,自动回复一个 **ICMP ==Echo Reply== 消息**(类型 **0**) - 源主机会记录 **"发送消息" 的时间**以及 **"收到应答" 的时间**,由此计算出 **==RTT==**(Round Trip Time,往返时间) ping 执行后,会显示每个数据包的**包大小、往返时间、TTL** 等信息,以及**总的丢包率**。 > [!example] > > `-c 4` 选项表示发送的 **ICMP 请求数量**为 4。 > > ![[_attachment/02-开发笔记/07-计算机网络/网络层/ICMP 协议.assets/IMG-ICMP 协议-A5CD81C3613B84FFDCC7A3212A62D84D.png|511]] > > ![[_attachment/02-开发笔记/07-计算机网络/总结/网络上两台主机之间的通信过程.assets/IMG-网络上两台主机之间的通信过程-17963EA68F7E47A2CB4979B6C65FDEF4.png|514]] > > <br><br> ### ping 过程的 ICMP 报文 > [!info] ping 发送的 ICMP 报文说明 > > ![[_attachment/02-开发笔记/07-计算机网络/网络层/ICMP 协议.assets/IMG-ICMP 协议-B8508F74BB8C464C50FC693F36E3628F.png|736]] > > 两个字段: > > - **标识符**:设置为**进程 PID 号**,用以区分发送 ICMP 报文的进程; > - **序号**:从 0 起,每发送一次新的回显请求就+1,用以确认报文是否丢失。 > - **选项**:存放发送请求的时间值,用于计算 RTT。 > [!example] ping 过程 ICMP 数据报的封装 > > 下图以 "局域网" 内两主机互 ping 为例: > > ![[_attachment/02-开发笔记/07-计算机网络/网络层/ICMP 协议.assets/IMG-ICMP 协议-425474DD8BD6DD5E3FD6BAD0AD3DED1C.png|1014]] > ^2shgdo <br><br> ### ❓ping 本机地址与环回地址 ping **环回地址 `127.0.0.1`** 、**本机地址**(本机网卡的 IP 地址)时,**均不会通过==物理网卡==发出数据包**。 因此,**断网的情况下也能 ping 通**。 当 IP 数据报的 **目的 IP 地址** 为环回地址、本机地址时,数据到达网络层时,协议栈会选择一个 "**==虚拟网卡==**", 而虚拟网卡会将数据推送到 "**本机接收消息**" 的 `input_pkt_queue` 数据结构上,而后**触发软中断**,由中断处理程序介入,提取消息。 因此,实际上**消息发往协议栈后,最后又传回到了本机**。 > [!NOTE] 向 "环回地址"、"本机地址" 发送数据的过程 > ![[_attachment/02-开发笔记/07-计算机网络/网络层/ICMP 协议.assets/IMG-ICMP 协议-441D944CD1A33CD0581B3BCFBCE4F589.png|665]] <br><br><br> # traceroute 工作原理 traceroute 工具有两个作用: 1. **探测/追踪**从源端到**目的 IP 地址**处 **沿途经过的每一跳路由器**; 2. **路径 MTU 发现**; > [!info] Linux 下工具命令为 `traceroute` ,Windows 中为 `tracert` > > 使用示例:`traceroute 192.168.1.100` #### 功能一:探测每一跳路由器 实现原理:利用 **IP 头部的 ==TTL 字段==** & ICMP **==Time Exceeded== 消息**。 - 通过设置 **IP 数据包的 TTL 从 1 起逐步 +1**,traceroute 依次发送 TTL=1、2、3、....的 **==UDP 数据包==**。 - 每当 TTL 减为 0 时,**路由器会向源端回发 Time Exceeded 消息**,从而让源主机知道中途经过的路由器 IP 地址。 > [!FAQ] ❓如何判断是否到达了目的主机? > > traceroute 发送的 UDP 包会设置一个 **"通常认为不被使用" 的目的端口**(例如 33434) > 故当返回的 ICMP 差错报文类型是 "**==端口不可达==**" 时,说明发出的 UDP 包到达了目的主机。 #### 功能二:路径 MTU 发现 实现原理:利用 **IP 头部的 "==分片禁止==" 标志位** & ICMP "**==目标不可达==**" 消息 - 发送端主机发送 IP 数据报,设置 "**分片禁止**" 标志位为 1; - 当中转路由器发现 **IP 数据报大小 > MTU** 时,**丢弃该数据报**,回传 ICMP "**目标不可达**" 消息(代码为 4,表示**需进行分片但设置了 "禁止分片" 标志位**) - 发送端主机收到 ICMP 差错报文后,**确定 MTU 值**,减少包大小。 > [!example] 过程示意 > ![[_attachment/02-开发笔记/07-计算机网络/网络层/ICMP 协议.assets/IMG-ICMP 协议-043AC2C5FA45A72D2A538B52F111A2D6.png|492]] <br><br> # Buffer ## 闪念 > sudden idea ## 候选资料 > Read it later # ♾️参考资料 # Footnotes