Atri Website

Back

1. SNMP 协议简介#

不同于 HTTP 协议在 Web 客户端和服务器之间传输超文本数据,SNMP(也称简单网络管理协议)主要用于网络设备的监控和管理。它允许网络管理员在中央控制台上,远程收集和查看各种网络设备(如路由器、交换机、服务器、打印机)的运行状态,例如 CPU 占用率、接口流量、温度,甚至可以远程修改设备的配置。

2. SNMP 工作原理与架构设计#

SNMP 采用”管理者-代理”模型,核心思想是将网络管理功能分离为两个角色:管理者负责决策与监控,代理负责数据采集与响应。该架构主要由三个核心组件构成:

  1. NMS:即网络管理系统,是安装在管理员电脑或监控服务器上的管理软件,负责向设备发起查询指令或下发配置修改命令。
  2. Agent:即代理进程,运行在被管理的网络设备上,持续监听来自 NMS 的请求,负责收集设备的本地硬件和运行数据,并将结果返回给 NMS。
  3. MIB:即管理信息库,类似于数据库的表结构定义(Schema),是一个树状的虚拟数据库,定义了设备上所有可被管理的参数。树上的每一个叶子节点都有一个全球唯一的编号,称为 OID(对象标识符)。例如 1.3.6.1.2.1.1.1 代表设备的系统描述信息。

基于该架构,SNMP 支持两种交互模式:

  • 拉取模式(Polling):NMS 主动向 Agent 发送 Get 请求,获取特定 OID 对应的数据。
  • 推送模式(Trap):当设备发生紧急故障时(例如某个网口突然断开),Agent 会主动向 NMS 发送告警报文,无需等待 NMS 的轮询。

3. SNMP 报文格式#

3.1. 与 HTTP 的编码差异#

在底层通信上,HTTP 通常基于面向连接的 TCP,而 SNMP 基于无连接的轻量级 UDP,端口 161 用于常规轮询,162 用于 Trap 接收。

在数据描述与编码上,SNMP 使用 ASN.1(抽象语法标记)来定义复杂的数据结构,并通过 BER(基本编码规则)将这些结构转换为紧凑的二进制比特流进行网络传输。

在编码上,HTTP/1.1 报文是人类可读的 ASCII 纯文本,通过回车换行符分割。而 SNMP 为了追求极致的网络传输效率,采用了面向机器的二进制编码。

BER 编码的 TLV 结构

BER 编码的基本单位是 TLV 三元组(Type-Length-Value),每个字段都由三部分组成:

  • Type:1 字节,标识数据类型。高 2 位表示类别(Universal=00、Application=01、Context=10、Private=11),低 5 位表示具体标签编号。
  • Length:指示 Value 部分的字节数。当长度 ≤ 127 时用 1 字节表示;当长度 > 127 时,最高位置 1,其余位表示后续字节数(如 0x81 表示后 1 字节是长度,0x82 表示后 2 字节是长度)。
  • Value:实际的数据内容,可以嵌套新的 TLV 结构。

例如共同体名 public 的 BER 编码为 04 06 70 75 62 6C 69 63

字段十六进制含义
Type04OCTET STRING(字符串类型)
Length066 字节
Value70 75 62 6C 69 63ASCII 编码的 “public”

BER 常用数据类型标识

类型十六进制标识说明
INTEGER02整数,用于版本号、Request ID、Error Status 等
OCTET STRING04字节串,用于共同体名、系统描述等文本数据
NULL05空值,用于请求报文中的变量值占位
OBJECT IDENTIFIER06OID 标识符,用于表示 MIB 树中的节点
SEQUENCE30序列容器,用于封装嵌套的 TLV 结构

PDU 类型的 BER 标识

SNMP 的 PDU 类型使用 Context 类别的标签编码,具体标识如下:

PDU 类型十六进制标识说明
GetRequest-PDUA0查询请求
GetNextRequest-PDUA1查询下一个节点请求
Response-PDUA2响应报文(SNMPv2 中替代 GetResponse)
SetRequest-PDUA3设置请求
Trap-PDUA4陷阱报文(SNMPv2 中已废弃)
GetBulkRequest-PDUA5批量查询请求(SNMPv2 新增)
InformRequest-PDUA6通知请求(SNMPv2 新增)
SNMPv2-Trap-PDUA7SNMPv2 陷阱报文(SNMPv2 新增)

3.2. 报文整体结构#

由于上述编码差异,SNMP 的报文格式与 HTTP 有较大不同。一个标准的 SNMPv2c 报文主要由三大部分组成:

1. 版本号

标识 SNMP 的版本,版本字段按序号从 0 开始递增:v1 编码为 0,v2c 编码为 1,v3 编码为 2。

2. 共同体

共同体(Community)字段是 SNMPv1/v2c 中管理进程与代理进程之间的共享口令,用于标识管理方对代理方的操作权限。共同体名以明文形式在网络中传输,接收方通过比对该字段判断请求是否合法。常见的默认值为 public(只读)和 private(读写),但在生产环境中应替换为自定义字符串,以降低未授权访问的风险。

共同体名权限对应场景
public只读(Read-Only)监控查询:NMS 获取设备的 CPU 使用率、接口流量、系统描述等信息,不允许修改设备配置
private读写(Read-Write)配置管理:NMS 不仅能查询信息,还能通过 SetRequest 修改设备参数(如关闭接口、修改 sysContact)
自定义名称按配置决定生产环境中应将默认的 public/private 改为自定义字符串,防止未授权访问

该机制的安全缺陷在于:共同体名以明文在网络中传输,任何抓包工具均可直接读取,攻击者一旦截获即可伪造请求。这是 SNMPv1/v2c 的核心安全缺陷,SNMPv3 通过 USM(基于用户的安全模型)引入了加密和认证机制来解决此问题。

3. PDU(协议数据单元)

PDU 是 SNMP 报文的核心载荷,承载了具体的管理操作指令和数据。SNMP 规定了 5 种 PDU 类型,按用途可分为三类:

  • 请求类:由管理进程发起
    • get-request:从代理进程处提取一个或多个参数值
    • get-next-request:从代理进程处提取紧跟当前参数值的下一个参数值
    • set-request:设置代理进程的一个或多个参数值
  • 响应类:由代理进程返回
    • get-response:对上述请求的应答,返回一个或多个参数值
  • 通知类:由代理进程主动发起
    • trap:当设备发生紧急事件时,代理进程主动向管理进程发送的告警报文

3.3. 核心概念#

管理进程:请求发起方,类似 Web 浏览器,一般运行在网管中心的监控服务器(NMS)上,负责主动向各地的网络设备发出查询指令、下发配置修改命令,或者被动地接收设备发来的紧急报警。

代理进程:请求响应方,类似 Web 服务器,运行在被监控的网络设备上的后台程序,负责收集自己所在设备的硬件和运行状态,并把这些数据整理好存入数据库(MIB),当管理进程发出查询请求时,读取 MIB 里的数据告诉管理进程。

3.4. PDU 内部字段#

请求标识符(Request ID)(请求/响应类 PDU)

由于 UDP 是无连接协议,报文可能乱序到达,因此该 ID 用于让管理进程识别返回的响应报文对应哪一个请求报文。

差错状态(Error Status)(请求/响应类 PDU)

用于响应报文中,提示查询是否成功。具体数字含义如下:

名称含义
0noError操作成功
1tooBig响应报文过大,超出限制
2noSuchName请求的 OID 不存在
3badValueSet 操作的值或语法无效
4readOnly试图修改只读变量
5genErr其他一般性错误

差错索引(Error Index)(请求/响应类 PDU)

当出现 noSuchNamebadValuereadOnly 的差错时,由代理进程在响应中设置的一个整数,指明有差错的变量在变量列表中的索引位置。

Trap 类型(generic-trap)(仅 Trap PDU)

此字段正式的名称是 generic-trap,共分为以下 7 种:

类型含义
0coldStart代理进程冷启动
1warmStart代理进程热启动
2linkDown网络接口故障
3linkUp网络接口恢复
4authenticationFailure认证失败
5egpNeighborLossEGP 邻居丢失
6enterpriseSpecific企业自定义事件

当 trap 类型为 linkDownlinkUpegpNeighborLoss 时,变量绑定中的第一个变量应标识对应的接口。

特定代码(Specific Trap)(仅 Trap PDU)

若 trap 类型为 enterpriseSpecific,则指明代理自定义的事件代码,否则为 0。

时间戳(Time Stamp)(仅 Trap PDU)

指明自代理进程初始化到 trap 所报告的事件发生所经历的时间,单位为 ms。例如时间戳为 1908 表明在代理初始化后 1908ms 发生了该事件。

变量绑定(Variable Bindings)(所有 PDU)

指明一个或多个变量的名和对应的值。在 get-request 或 get-next-request 报文中,变量的值应忽略。管理变量表示管理对象类型在某一时刻的值(称该类型的实例),SNMP 以管理变量作为操作对象。

管理变量的表示方法:形如 x.y,其中 x 是管理对象的 OID(对象标识符),y 是能唯一确定对象类型值的一组数字——在标量变量中为 0,在表型变量中是该表的索引(如接口号或路由表中的目的网络地址)。

例如:MIB 中定义了管理对象 ipAdEntNetMask,其 OID 为 1.3.6.1.1.5.6.1.3,它是路由表中的一项。若某行的索引和目的网络地址为 129.102.1.0,则该变量的完整名称为 1.3.6.1.1.5.6.1.3.129.102.1.0。其中 x.y 的 y 称为实例,用于唯一标识具体的管理变量。

在请求报文中,变量绑定包含待查询的 OID,Value 为空;在响应报文中,代理进程会在 Value 字段填入具体的系统数据。

3.5. OID 的 BER 编码规则#

OID 在 BER 编码中有特殊的压缩规则。前两个子标识符(通常为 1.3)会被合并为一个字节,计算公式为 40 × x + y。例如 1.3 编码为 0x2B(即 40 × 1 + 3 = 43)。后续每个子标识符按以下规则编码:

  • 值 < 128:直接用 1 字节表示。
  • 值 ≥ 128:使用多字节编码,每个字节的最高位作为延续标志(1 表示后续还有字节,0 表示结束),低 7 位存储数据。

以 OID 1.3.6.1.2.1.1.2.0 为例:

子标识符原始值编码字节说明
1.31, 32B40×1+3=43=0x2B
6606< 128,直接编码
1101< 128,直接编码
2202< 128,直接编码
1101< 128,直接编码
1101< 128,直接编码
2202< 128,直接编码
0000< 128,直接编码

因此完整的 BER 编码为 06 08 2B 06 01 02 01 01 02 00,其中 06 是 OBJECT IDENTIFIER 的类型标签,08 是长度(8 字节)。

再以 OID 1.3.6.1.4.1.674 为例,其中子标识符 674 > 127,需要多字节编码:

674 = 0x2A2
二进制:0000 0101 0010 0010
分组(7位一组):0000101 0100010
设置延续标志:10000101 01000010
十六进制:0x85 0x22
plaintext

因此 674 编码为 85 22,完整的 OID BER 编码为 06 07 2B 06 01 04 01 85 22

SNMP 协议解析
Author Juyao Huang
Published at May 18, 2026
Comment seems to stuck. Try to refresh?✨