[comment]: # ({f40368a0-622befb9})
# 4 SNMP trap

[comment]: # ({/f40368a0-622befb9})

[comment]: # ({811a26b0-ff07904b})
#### 概述

接收 SNMP trap 与查询启用 SNMP 的设备正好相反。

在这种情况下，信息从启用 SNMP 的设备发送到 snmptrapd，并由 Zabbix 服务器或 Zabbix proxy 从文件中收集或“捕获”。

通常，trap 会在某些条件发生变化时发送，agent 连接到服务器的 162 端口（与用于查询的 agent 侧 161 端口相对）。使用 trap 可能会检测到在查询间隔期间发生的一些短暂问题，而这些问题可能会被查询数据遗漏。

Zabbix 中接收 SNMP trap 的设计是与 **snmptrapd** 以及将 trap 传递给 Zabbix 的一种机制配合使用的 - 该机制可以是 Bash 或 Perl 脚本，也可以是 SNMPTT。

::: noteclassic
在配置 Zabbix 之后，设置 trap 监控的最简单方法是使用 Bash 脚本方案，因为 Perl 和 SNMPTT 在现代发行版中通常缺失，并且需要更复杂的配置。不过，此方案使用的是配置为 `traphandle` 的脚本。为了在生产系统上获得更好的性能，请使用内置 Perl 方案（即带有 `do perl` 选项的脚本，或 SNMPTT）。
:::

接收 trap 的工作流程：

1.  `snmptrapd` 接收一个 trap。
2.  `snmptrapd` 将 trap 传递给接收脚本（Bash、Perl）或 SNMPTT。
3.  接收端解析、格式化并将 trap 写入文件。
4.  Zabbix SNMP trapper 读取并解析 trap 文件。
5.  对于每个 trap，Zabbix 会查找所有 SNMP trapper 监控项，这些监控项的主机接口与接收到的 trap 地址匹配。
    请注意，在匹配过程中只使用主机接口中选定的 *IP* 或 *DNS*。
6.  对于找到的每个监控项，将 trap 与 `snmptrap[regexp]` 中的正则表达式进行比较。
    trap 会被设置为**所有**匹配监控项的值。
    如果未找到匹配的监控项，并且存在 `snmptrap.fallback` 监控项，则会将 trap 设置为该监控项的值。
7.  如果 trap 未被设置为任何监控项的值，Zabbix 默认会记录未匹配的 trap。
    （可通过 *Administration* > *General* > *Other* 中的 *Log unmatched SNMP traps* 进行配置。）

[comment]: # ({/811a26b0-ff07904b})

[comment]: # ({3b1ff1a9-657fb528})
#####HA 故障转移注意事项

在高可用性（HA）节点切换期间，Zabbix 将在最后一个 ISO 8601 时间戳内的最后一条记录之后继续处理；如果未找到相同的记录，则仅使用时间戳来识别最后位置。

[comment]: # ({/3b1ff1a9-657fb528})

[comment]: # ({e5746000-a8df124c})
#### 配置 SNMP trap

此监控项类型需要以下前端配置：

##### 步骤 1：为主机创建 SNMP 接口

1. 在 *数据采集 > 主机* 中，[创建主机](/manual/config/hosts/host) 或编辑现有主机。
2. 在 *接口* 字段中，选择 *SNMP* 接口类型。
3. 输入 IP 地址/DNS 名称和端口号。
4. 从下拉菜单中选择 *SNMP 版本*：([*SNMPv1*、*SNMPv2*](#snmpv-snmpv)，或 [*SNMPv3*](#snmpv))，并根据所选 SNMP 版本添加接口凭据。

每个接收到的 trap 中的地址都会与所有 SNMP 接口的 IP 和 DNS 地址进行比较，以找到对应的主机。

##### 步骤 2：配置监控项

1. 对于该主机，[创建监控项](/manual/config/items/item) 或编辑现有监控项。
2. 在 *Key* 字段中，使用以下 SNMP trap 键之一：

    -   `snmptrap[regexp]` - 捕获所有与 `regexp` 参数中指定的 [正则表达式](/manual/regular_expressions) 匹配的 SNMP trap；如果未指定 `regexp`，则捕获任意 trap。<br>
        该参数支持用户宏和全局正则表达式。<br>
        返回值：SNMP trap。<br>
        此监控项只能为 SNMP 接口设置。
    -   `snmptrap.fallback` - 捕获所有未被该接口的任何 `snmptrap[]` 监控项捕获的 SNMP trap。<br>
        返回值：SNMP trap。<br>
        此监控项只能为 SNMP 接口设置。

::: noteclassic
目前不支持多行正则表达式匹配。
:::

3. 将 *信息类型* 设置为 *日志*，以便解析时间戳。其他格式（如 *数值*）也可以接受，但可能需要自定义 trap 处理程序。

[comment]: # ({/e5746000-a8df124c})

[comment]: # ({56d22f70-a08bce2a})
#### 设置SNMP trap监控

[comment]: # ({/56d22f70-a08bce2a})

[comment]: # ({0ce4b7cf-581aa946})
##### 配置 Zabbix 服务器/proxy

要读取 trap，必须配置 Zabbix 服务器或 proxy，以启动 SNMP trapper 进程，并指向由 SNMPTT 或 Bash/Perl trap 接收器写入的 trap 文件。
为此，请编辑配置文件（[`zabbix\_server.conf`](/manual/appendix/config/zabbix_server) 或 [`zabbix\_proxy.conf`](/manual/appendix/config/zabbix_proxy)）：

```ini
StartSNMPTrapper=1
SNMPTrapperFile=[TRAP FILE]
```

::: notewarning
如果使用了 systemd 参数 [`PrivateTmp`](http://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateTmp=)，则该文件很可能无法在 `/tmp` 中正常工作。
:::

##### 配置 Bash trap 接收器

要求：仅需 snmptrapd。

可以使用 Bash trap 接收器 [脚本](https://raw.githubusercontent.com/zabbix/zabbix-docker/7.4/templates/scripts/snmptraps/zabbix_trap_handler.sh)，通过 trapper 文件将 trap 从 snmptrapd 传递到 Zabbix 服务器。
要进行配置，请在 snmptrapd 配置文件（`snmptrapd.conf`）中添加 `traphandle` 选项，参见[示例](https://raw.githubusercontent.com/zabbix/zabbix-docker/7.4/templates/config/snmptraps/snmp/snmptrapd.conf)。

:::notetip
可能需要重启 snmptrapd 才能使其读取配置更改。
:::

[comment]: # ({/0ce4b7cf-581aa946})

[comment]: # ({2bf8b8af-0aa82990})
##### 配置 Perl trap 接收器

要求：Perl、使用 `--enable-embedded-perl` 编译的 Net-SNMP（自 Net-SNMP 5.4 起默认启用）

Perl trap 接收器（请查找 `misc/snmptrap/zabbix\_trap\_receiver.pl`）可用于将 trap 直接从 snmptrapd 传递到 Zabbix 服务器。
配置方法如下：

-   将 Perl 脚本添加到 snmptrapd 配置文件（`snmptrapd.conf`）中，例如：

```perl
perl do "[FULL PATH TO PERL RECEIVER SCRIPT]";
```

-   配置接收器，例如：

```ini
$SNMPTrapperFile = '[TRAP FILE]';
$DateTimeFormat = '[DATE TIME FORMAT]';
```

:::notetip
可能需要重启 snmptrapd 才能使其加载配置更改。
:::

::: notetip
如果脚本名称没有加引号，snmptrapd 将拒绝启动，并显示类似以下的消息：<br><br>

```yaml
Regexp modifiers "/l" and "/a" are mutually exclusive at (eval 2) line 1, at end of line
Regexp modifier "/l" may not appear twice at (eval 2) line 1, at end of line
```

:::

[comment]: # ({/2bf8b8af-0aa82990})

[comment]: # ({b937712d-af1e38f9})
##### 配置 SNMPTT

首先，应将 snmptrapd 配置为使用 SNMPTT。

::: notetip
为了获得最佳性能，应将 SNMPTT 配置为守护进程，并使用 `snmptthandler-embedded` 将 trap 传递给它。
请参阅 [配置 SNMPTT](http://snmptt.sourceforge.net/docs/snmptt.shtml) 的说明。
:::

当 SNMPTT 配置为接收 trap 后，请配置 `snmptt.ini`：

1. 启用 `NET-SNMP` 包中的 Perl 模块：

```ini
net_snmp_perl_enable = 1
```

2. 将 trap 记录到 Zabbix 将读取的 trap 文件中：

```ini
log_enable = 1
log_file = [TRAP FILE]
```
    
3. 设置日期时间格式：

```ini
date_time_format = %Y-%m-%dT%H:%M:%S%z
```

::: notewarning
`net-snmp-perl` 包已在 RHEL 8.0-8.2 中移除；在 RHEL 8.3 中重新添加。
有关更多信息，请参阅 [已知问题](/manual/installation/known_issues#snmp-traps)。
:::

现在，请将 trap 格式化为 Zabbix 可识别的格式（编辑 `snmptt.conf`）：

1. 每个 `FORMAT` 语句都应以 `ZBXTRAP [address]` 开头，其中 `[address]` 将与 Zabbix 上 SNMP 接口的 IP 和 DNS 地址进行比较。
例如：

```ini
EVENT coldStart .1.3.6.1.6.3.1.1.5.1 "Status Events" Normal
FORMAT ZBXTRAP $aA Device reinitialized (coldStart)
```

2. 有关 SNMP trap 格式的更多信息，请参见下文。

::: noteimportant
不要使用未知 trap - Zabbix 将无法识别它们。 
可以通过在 `snmptt.conf` 中定义一个通用事件来处理未知 trap：<br><br>

```ini
EVENT general .* "General event" Normal
```

:::

[comment]: # ({/b937712d-af1e38f9})

[comment]: # ({b354a28f-cd001892})
##### SNMP trap 格式

所有自定义的 Perl trap 接收器和 SNMPTT trap 配置都必须按以下方式格式化 trap：

```yaml
[timestamp] [the trap, part 1] ZBXTRAP [address] [the trap, part 2]
```

其中

-   `[timestamp]` - 采用 `%Y-%m-%dT%H:%M:%S%z` 格式的时间戳。
-   `ZBXTRAP` - 表示此行中开始了一个新 trap 的头部。
-   `[address]` - 用于查找此 trap 所属主机的 IP 地址。

请注意，在处理过程中，`ZBXTRAP` 和 `[address]` 会从消息中被截取掉。
如果 trap 的格式不同，Zabbix 可能会以意外的方式解析这些 trap。

示例 trap：

```bash
2024-01-11T15:28:47+0200 .1.3.6.1.6.3.1.1.5.3 Normal "Status Events" localhost - ZBXTRAP 192.168.1.1 Link down on interface 2. Admin state: 1. Operational state: 2
```

这将为 IP=`192.168.1.1` 的 SNMP 接口生成如下 trap：

```bash
2024-01-11T15:28:47+0200 .1.3.6.1.6.3.1.1.5.3 Normal "Status Events"
localhost - Link down on interface 2. Admin state: 1. Operational state: 2
```

[comment]: # ({/b354a28f-cd001892})

[comment]: # ({40179940-357f1824})
#### 系统要求

::: noteclassic
建议[安装 MIB 文件](/manual/config/items/itemtypes/snmp/mibs)，
以确保监控项值以正确的格式显示。
如果没有 MIB 文件，可能会出现格式问题，例如以 HEX 而不是 UTF-8 显示值，或反之亦然。
:::

[comment]: # ({/40179940-357f1824})

[comment]: # ({3866234a-6245c6ae})
##### 大文件支持

Zabbix为SNMP trap文件提供了“大文件支持”。Zabbix可以读取的最大文件大小为2^63（8 EiB）。请注意，文件系统可能会对文件大小添加下限。

[comment]: # ({/3866234a-6245c6ae})

[comment]: # ({754aa7b8-0f27a9bb})
##### 日志轮转

Zabbix 不提供任何日志轮转系统 - 这应由用户自行处理。日志轮转应先重命名旧文件，之后再删除，以确保不会丢失任何 trap：

1.  Zabbix 在上次已知位置打开 trap 文件，并转到步骤 3。
2.  Zabbix 通过将 inode 编号与已定义 trap 文件的 inode 编号进行比较，检查当前打开的文件是否已轮转。
    如果没有打开的文件，Zabbix 会重置上次位置并转到步骤 1。
3.  Zabbix 读取当前打开文件中的数据，并设置新位置。
4.  解析新数据。如果这是已轮转的文件，则关闭该文件并返回步骤 2。
5.  如果没有新数据，Zabbix 休眠 1 秒，然后返回步骤 2。

[comment]: # ({/754aa7b8-0f27a9bb})

[comment]: # ({6da22db2-608a14bd})
##### 文件系统

由于 trap 文件的实现方式，Zabbix 需要文件系统支持 inode，以便区分文件（这些信息通过 `stat()` 调用获取）。

[comment]: # ({/6da22db2-608a14bd})

[comment]: # ({51071ded-ee69482d})
#### 使用不同 SNMP 协议版本的设置示例

此示例使用 snmptrapd 和一个 Bash 接收脚本将 trap 转发到 Zabbix 服务器。

设置：

1.  配置 Zabbix 以启动 SNMP trapper 并设置 trap 文件。将以下内容添加到 `zabbix_server.conf`：

```ini
StartSNMPTrapper=1
SNMPTrapperFile=/var/lib/zabbix/snmptraps/snmptraps.log
```

2.  将 Bash 脚本下载到 `/usr/sbin/zabbix_trap_handler.sh`：

```bash
curl -o /usr/sbin/zabbix_trap_handler.sh https://raw.githubusercontent.com/zabbix/zabbix-docker/7.4/templates/scripts/snmptraps/zabbix_trap_handler.sh
```

如有必要，请调整脚本中的 `ZABBIX_TRAPS_FILE` 变量。
如需使用默认值，请先创建父目录：

```bash
mkdir -p /var/lib/zabbix/snmptraps
```

3. 将以下内容添加到 `snmtrapd.conf`（请参考可工作的 [示例](https://raw.githubusercontent.com/zabbix/zabbix-docker/7.4/templates/config/snmptraps/snmp/snmptrapd.conf)）

```ini
traphandle default /bin/bash /usr/sbin/zabbix_trap_handler.sh
```

:::notetip
可能需要重启 snmptrapd 才能使其读取配置更改。
:::

4.  [创建](/manual/config/items/item) 一个 SNMP 监控项 TEST（请注意初始 [配置要求](/manual/config/items/itemtypes/snmptrap#configuring-snmp-traps)）：

    类型: *SNMP trap*<br>
    信息类型: *日志*<br>
    主机接口: *SNMP 127.0.0.1*<br>
    键值: `snmptrap["linkUp"]`<br>
    日志时间格式: `yyyyMMdd.hhmmss`

请注意，这里使用的是 ISO 8601 日期和时间格式。

5.  接下来，我们将为所选的 SNMP 协议版本配置 `snmptrapd`，并使用 `snmptrap` 工具发送测试 trap。

##### SNMPv1, SNMPv2

SNMPv1 和 SNMPv2 协议依赖于“community string”认证。在下面的示例中，
我们将使用“secret”作为 community string。它必须与 SNMP trap 发送端上设置的值相同。

请注意，尽管 SNMPv2 仍在生产环境中广泛使用，但它不提供
加密和真正的发送方认证。数据以明文形式发送，因此
这些协议版本只能用于安全环境，例如私有网络，
绝不能用于任何公共网络或第三方网络。

SNMP 版本 1 现在实际上已经很少使用，因为它不支持 64 位计数器，
并且被视为遗留协议。

要启用接收 SNMPv1 或 SNMPv2 trap，请在 `snmptrapd.conf` 中添加以下行。
请将 `secret` 替换为在 SNMP trap 发送端上配置的 SNMP community string：

```ini
authCommunity log,execute,net secret
```

接下来，我们可以使用 `snmptrap` 发送测试 trap。在此示例中，我们将使用常见的“link up” OID：

```bash
snmptrap -v 2c -c secret localhost '' linkUp.0
```

##### SNMPv3

SNMPv3 解决了 SNMPv1/v2 的安全问题，并提供认证和加密。
您可以使用 MD5 或多种 SHA 认证方法，以及 DES/多种 AES 作为加密算法。

要启用接收 SNMPv3，请向 `snmptrapd.conf` 添加以下行：

```ini
createUser -e 0x8000000001020304 traptest SHA mypassword AES
authuser log,execute traptest
```

:::noteimportant
请注意 `execute` 关键字，它允许为该用户安全模型执行脚本。
:::

```bash
snmptrap -v 3 -n "" -a SHA -A mypassword -x AES -X mypassword -l authPriv -u traptest -e 0x8000000001020304 localhost 0 linkUp.0
```

::: notewarning
如果您希望使用 AES192 或 AES256 等强加密方法，请使用
5.8 及以上版本的 net-snmp。您可能需要使用
`configure` 选项 `--enable-blumenthal-aes` 重新编译它。
较旧版本的 net-snmp 不支持 AES192/AES256。
另请参见：[强认证或加密](http://www.net-snmp.org/wiki/index.php/Strong_Authentication_or_Encryption)。
:::

##### 验证

在这两个示例中，您都会在 `/var/lib/zabbix/snmptraps/snmptraps.log` 中看到类似的行：

```bash
2024-01-30T10:04:23+0200 ZBXTRAP 127.0.0.1
UDP: [127.0.0.1]:56585->[127.0.0.1]:162
DISMAN-EVENT-MIB::sysUpTimeInstance = 2538834
SNMPv2-MIB::snmpTrapOID.0 = IF-MIB::linkUp.0

```

Zabbix 中的监控项值将是：

```bash
2024-01-30 10:04:23 2024-01-30 10:04:21	

2024-01-30T10:04:21+0200 UDP: [127.0.0.1]:56585->[127.0.0.1]:162
DISMAN-EVENT-MIB::sysUpTimeInstance = 2538834
SNMPv2-MIB::snmpTrapOID.0 = IF-MIB::linkUp.0
```

Perl 示例：

```perl
2024-01-30T11:42:54+0200 ZBXTRAP 127.0.0.1
PDU INFO:
  receivedfrom                   UDP: [127.0.0.1]:58649->[127.0.0.1]:162
  notificationtype               TRAP
  version                        1
  community                      public
  errorstatus                    0
  transactionid                  1
  requestid                      2101882550
  messageid                      0
  errorindex                     0
VARBINDS:
  DISMAN-EVENT-MIB::sysUpTimeInstance type=67 value=Timeticks: (457671) 1:16:16.71
  SNMPv2-MIB::snmpTrapOID.0      type=6  value=OID: IF-MIB::linkUp.0
```

[comment]: # ({/51071ded-ee69482d})

[comment]: # ({91956d23-75026475})
#### 请参阅

- · [关于SNMP traps的Zabbix博客文章](https://blog.zabbix.com/snmp-traps-in-zabbix)
- · [配置snmptrapd（net-snmp官方文档）](https://net-snmp.sourceforge.io/wiki/index.php/TUT:Configuring_snmptrapd)
- · [配置snmptrapd接收SNMPv3通知（net-snmp官方文档）](https://net-snmp.sourceforge.io/wiki/index.php/TUT:Configuring_snmptrapd_to_receive_SNMPv3_notifications)

[comment]: # ({/91956d23-75026475})
