> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/4.3bsd/di-si-bu-fen-jin-cheng-jian-tong-xin/12.8.-wang-ji-kong-zhi-bao-wen-xie-yi-icmp.md).

# 12.8 网际控制报文协议（ICMP）

网际控制报文协议（ICMP）\[Postel, 1981c] 是 IP 的控制与错误报文协议。尽管它在输入输出操作上像 UDP 一样叠在 IP 之上，实际上却是 IP 不可分割的一部分。与 UDP 报文不同，多数 ICMP 报文由内核接收并处理。ICMP 报文也可以用原始 IP 套接字收发（见 11.7 节）。

ICMP 报文分三大类。第一类是各种错误：它们可能发生在网络中的任何地方，也可以向引发错误的分组的始发者报告，包括路由失败（网络或主机不可达）、分组中生存时间字段耗尽，或目的主机报告目标协议或端口号不可用。第二类可视为网关到主机的控制报文：报告输出过量和丢包的源熄灭报文，以及路由重定向——后者告知主机，经由另一个网关到某个主机或网络有更好的路由。最后一类是网络管理、测试和测量分组：网络地址请求与应答、网络掩码请求与应答、回显请求与应答、时间戳请求与应答。

入局 ICMP 报文要求的一切动作和应答都由内核 ICMP 层完成。ICMP 分组经正常的协议输入入口从 IP 收到——ICMP 有自己的 IP 协议号。ICMP 输入例程拟定对任何请求的响应，把应答交给 `ip_output()` 返还给发送者。收到错误指示或源熄灭时，用 `sockaddr` 结构构造一个通用地址，地址和错误码经 `pfctlinput()` 报告给每个网络协议的控制输入入口 `pr_ctlinput()`。

重定向报文指示的路由变化由 `rtredirect()` 例程处理：核实收到报文的网关正是目的地当前使用的下一跳网关，并检查新网关在直接相连的网络上。测试通过则相应修改内核路由表：新路由与旧路由范围相当（如都是到目的地网络的路由）时，路由中的网关改为新网关；新路由范围更小（用了网络路由却收到主机重定向，或旧路由用的是通配路由）时，在内核表中创建新路由。经重定向创建或修改的路由分别标记 RTF\_DYNAMIC 和 RTF\_MODIFIED。路由表一更新，就用 `pfctlinput()` 以重定向代码（而非错误代码）通知协议。收到重定向时，TCP 和 UDP 只是清除协议控制块中缓存的路由；套接字上下一个分组将重新分配路由，若新路由现在是最佳路由则选中它。

入局 ICMP 报文由内核处理完毕后交给 `raw_input()` 供任何 ICMP 原始套接字使用。原始套接字也可用来发送 ICMP 报文。底层网络测试程序 **ping** 的工作方式是在原始套接字上发送 ICMP 回显请求，并监听相应的应答。

其他 Internet 网络协议也使用 ICMP 生成错误报文。UDP 只发 ICMP 端口不可达错误报文，TCP 用别的手段报告这类错误。但 IP 能检测出多种错误，在用作 IP 网关的系统上尤其如此。`icmp_error()` 函数针对一个 IP 分组构造指定类型的错误报文。多数错误报文含引发错误的原分组的一部分，加上错误的类型与代码。原分组的接收接口的身份也传给 `icmp_error()`，以防原分组的目的地是别的主机（转发时就是这样）：错误报文的源地址可以设为离始发主机最近（或与始发主机共享）的网络上的网关地址。此外，IP 通过收到该分组的同一网络接口转发分组时，若始发主机也在该网络上，就可以向它发送重定向报文。`icmp_error()` 例程对重定向报文额外接受一个参数——主机要使用的新网关地址。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://book.bsdcn.org/4.3bsd/di-si-bu-fen-jin-cheng-jian-tong-xin/12.8.-wang-ji-kong-zhi-bao-wen-xie-yi-icmp.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
