> 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.3-bsd-unix-cao-zuo-xi-tong-she-ji-yu-shi-xian/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 回显请求、聆听相应应答工作。

ICMP 也被其他 Internet 网络协议用来生成错误报文。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.3-bsd-unix-cao-zuo-xi-tong-she-ji-yu-shi-xian/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.
