> 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/man/man4/ng_patch.4.md).

# ng\_patch.4

`ng_patch` — 简易 mbuf 数据修改 netgraph 节点类型

## 名称

`ng_patch`

## 概要

`#include <netgraph/ng_patch.h>`

## 描述

`patch` 节点对穿过它的数据包执行数据修改。修改操作仅限于对 8、16、32 或 64 位无符号整数执行 C 语言运算的子集，包括：赋新值（=）、加法（+=）、减法（-=）、乘法（\*=）、除法（/=）、取负（=-）、按位与（&=）、按位或（|=）、按位异或（^=）、左移（<<=）、右移（>>=）。取负操作是个例外：整数被视为有符号数，且不使用第二操作数（即 `value`）。如果有多个修改操作，它们会按用户指定的顺序依次应用于数据包。数据包的数据负载被视为字节数组，零偏移对应于数据包头的第一个字节，而从 `offset` 开始、长度为 `length` 字节的字段被视为一个网络字节序的整数。在配置时还可选择性地请求一个附加偏移量，以应对不同的数据包类型。

## 钩子

此节点类型有两个钩子：

**`in`** 在此钩子上接收的数据包将按配置中指定的规则进行修改，然后转发到 `out` 钩子（如果存在）。否则，它们会被反射回 `in` 钩子。

**`out`** 在此钩子上接收的数据包将被原样转发到 `in` 钩子。

## 控制消息

此节点类型支持通用控制消息，此外还支持以下消息：

`#include <net/bpf.h>`

```sh
struct ng_patch_op {
	uint32_t	offset;
	uint16_t	length; /* 1,2,4 或 8 字节 */
	uint16_t	mode;
	uint64_t	value;
};
/* 修改模式 */
#define NG_PATCH_MODE_SET	1
#define NG_PATCH_MODE_ADD	2
#define NG_PATCH_MODE_SUB	3
#define NG_PATCH_MODE_MUL	4
#define NG_PATCH_MODE_DIV	5
#define NG_PATCH_MODE_NEG	6
#define NG_PATCH_MODE_AND	7
#define NG_PATCH_MODE_OR	8
#define NG_PATCH_MODE_XOR	9
#define NG_PATCH_MODE_SHL	10
#define NG_PATCH_MODE_SHR	11
struct ng_patch_config {
	uint32_t	count;
	uint32_t	csum_flags;
	uint32_t	relative_offset;
	struct ng_patch_op ops[];
};
```

**`NGM_PATCH_SETDLT`**（`setdlt`）设置 `in` 钩子上的数据链路类型（用于辅助计算相对偏移）。当前支持的类型包括 `DLT_RAW`（原始 IP 数据报，不应用附加偏移，默认值）和 `DLT_EN10MB`（以太网）。DLT\_ 定义可在以下文件中找到：如果你想在链路层头部上操作，必须通过指定 `DLT_RAW` 来不使用附加偏移。如果指定了 `EN10MB`，则可选的附加偏移会将以太网头部以及存在的 QinQ 头部计算在内。

**`NGM_PATCH_GETDLT`**（`getdlt`）此控制消息返回 `in` 钩子的数据链路类型。

**`NGM_PATCH_SETCONFIG`**（`setconfig`）此命令设置将应用于钩子上传入数据的修改操作序列。必须以下面的 `struct ng_patch_config` 作为参数：`csum_flags` 可以设置为 CSUM\_IP、CSUM\_TCP、CSUM\_SCTP 和 CSUM\_UDP 的任意组合（其他值将被忽略），用于指示 IP 协议栈在输出接口上传输数据包前重新计算相应的校验和。`patch` 节点本身不进行任何校验和修正。默认情况下，`ng_patch_op` 结构中的 `offset` 值从零开始计算（即数据包头的第一个字节）。如果在配置时启用了 `relative_offset`（设置为 1），则操作会基于数据链路类型将一个附加量添加到偏移值上。

**`NGM_PATCH_GETCONFIG`**（`getconfig`）此控制消息以 `struct ng_patch_config` 的形式返回当前的修改操作集合。

**`NGM_PATCH_GET_STATS`**（`getstats`）以 `struct ng_patch_stats` 的形式返回节点统计信息。

**`NGM_PATCH_CLR_STATS`**（`clrstats`）清零节点统计信息。

**`NGM_PATCH_GETCLR_STATS`**（`getclrstats`）此命令与 `NGM_PATCH_GET_STATS` 相同，但同时会原子地清零统计信息。

## 关闭

此节点在收到 `NGM_SHUTDOWN` 控制消息时，或在所有钩子均已断开时关闭。

## 实例

`patch` 节点最初用于修改 IP 数据包中的 TTL 和 TOS/DSCP 字段。举例来说，假设你有两条相邻的简易链路通往远程网络（例如卫星），那么在两者之间过期的数据包将产生不需要的 ICMP 回复，而这些回复必须前进而非返回。因此，你需要将进入链路的每个数据包的 TTL 提升 2，以确保 TTL 在那里不会变为零。为此，你可以设置一条 [ipfw(8)](/man/man8/ipfw.8.md) 规则，使用 `netgraph` 动作将前往简易链路的数据包注入到 patch 节点中，使用如下 ngctl(8) 脚本：

```sh
/usr/sbin/ngctl -f- <<-SEQ
	mkpeer ipfw: patch 200 in
	name ipfw:200 ttl_add
	msg ttl_add: setconfig { count=1 csum_flags=1 ops=[	e
		{ mode=2 value=3 length=1 offset=8 } ] }
SEQ
/sbin/ipfw add 150 netgraph 200 ip from any to simplex.remote.net
```

此处名为“`ttl_add`”的 `patch` 类型节点被配置为对单字节 TTL 字段（即 IP 数据包头的第 9 个字节）加上（模式 `NG_PATCH_MODE_ADD`）`value` 值 3。

另一个示例是对数据包 TOS 字段进行两次连续修改：假设你需要清除 `IPTOS_THROUGHPUT` 位并设置 `IPTOS_MINCOST` 位。可以这样做：

```sh
/usr/sbin/ngctl -f- <<-SEQ
	mkpeer ipfw: patch 300 in
	name ipfw:300 tos_chg
	msg tos_chg: setconfig { count=2 csum_flags=1 ops=[	e
		{ mode=7 value=0xf7 length=1 offset=1 }		e
		{ mode=8 value=0x02 length=1 offset=1 } ] }
SEQ
/sbin/ipfw add 160 netgraph 300 ip from any to any not dst-port 80
```

此处首先执行 `NG_PATCH_MODE_AND` 清除第四位，然后执行 `NG_PATCH_MODE_OR` 设置第三位。

在以上两个示例中，`csum_flags` 字段表示在传输前应重新计算 IP 校验和（但不包括 TCP 或 UDP 校验和）。

注意：应通过设置相应的 [sysctl(8)](/man/man8/sysctl.8.md) 变量，确保数据包在 [netgraph(4)](/man/man4/netgraph.4.md) 内部处理后能够返回到 ipfw：

```sh
sysctl net.inet.ip.fw.one_pass=0
```

## 参见

[netgraph(4)](/man/man4/netgraph.4.md), [ng\_ipfw(4)](/man/man4/ng_ipfw.4.md), ngctl(8)

## 历史

`patch` 节点类型实现于 FreeBSD 8.1。

## 作者

Maxim Ignatenko <gelraen.ua@gmail.com>.

相对偏移代码由 DMitry Vagin 编写

本手册页由 Vadim Goncharov <vadimnuclight@tpu.ru> 编写。

## 缺陷

该节点会盲目地尝试对每个数据包应用每项 patching 操作（偏移大于数据包长度的除外），因此请务必仅向其提供正确的数据包（例如，本应作用于 IP 头部的字节如果被作用于 ARP 数据包，可能会损坏数据包并导致你的机器在网络中不可达）。

*!!! 警告 !!!*

IP 协议栈的输出路径假定数据包中的字段和长度均正确——将其更改为错误的值可能导致不可预测的后果，包括内核崩溃。


---

# 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/man/man4/ng_patch.4.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
