SNMP 实战与排错 — snmpwalk 抓包、监控落地与故障定位
SNMP 动手实战:Wireshark 过滤式、net-snmp 命令族、v3 用户配置、超时/OID 不存在/Trap 丢失排错、与 NETCONF 对比 / 应用层 / UDP 161
这篇你能学到
- 怎么用 Wireshark / tshark 把 SNMP 报文抓出来看清楚,尤其是"明文 community 到底有多裸奔"。
- net-snmp 全套命令怎么用:读单值、遍历表、批量抓、v3 加密查询、写配置、发 Trap,以及 Linux 与思科/华为设备两侧怎么配。
- 六类高频故障(超时、OID 不存在、写不进去、流量图乱跳、Trap 收不到、被当成 DDoS 放大器)的定位套路,外加选型对比、速查表与面试题。
抓包观察
Wireshark 显示过滤式
下面这些过滤式是排错时的"筛子":你抓到的包往往上千条,先用一条过滤式把无关流量滤掉,再看细节。最值得先记住的是 snmp.error_status != 0(只看出错的)和 snmp.community == "public"(找弱口令)。
| 过滤式 | 用途 |
|---|---|
snmp | 所有 SNMP 报文(Wireshark 自动解 BER) |
udp.port == 161 | 只看轮询请求/响应 |
udp.port == 162 | 只看 Trap / Inform |
snmp.version == 0 | 只看 v1(0=v1, 1=v2c, 3=v3) |
snmp.version == 3 | 只看 v3 |
snmp.community == "public" | 抓默认弱口令,安全审计常用 |
snmp.data == 4 | 只看 v1 Trap(data 即 PDU 类型:0 get, 1 getnext, 2 response, 3 set, 4 trap, 5 getbulk, 6 inform, 7 snmpV2-trap, 8 report) |
snmp.name contains "1.3.6.1.2.1.2.2" | 只看访问接口表的报文 |
snmp.error_status != 0 | 只看出错的响应,排错第一过滤式 |
snmp.msgUserName | v3 用户名(明文可见,即使 authPriv 也不加密) |
snmp && ip.addr == 10.0.0.1 | 只看与某台设备的交互 |
命令行抓包:
没有图形界面时(比如在服务器上),用下面三条命令就能完成"抓下来 → 提取关键字段 → 实时盯"三件事。第二条尤其实用:它能把一个 pcap 里所有明文口令一次性列出来,是安全审计的常用手法。
| |
典型字段说明(Wireshark 解码视图)
一个 v2c GetRequest 在 Wireshark 中展开长这样:
| |
对应的 Response 中 Value 会变成 Value (OctetString): core-sw01。
排错时重点看三处:
- 有没有 Response:只见 GetRequest 无 Response → 网络不通 / ACL 拦截 / Agent 未监听 / community 错(多数 Agent 对错误 community 静默丢弃,不回错误)。
error-status:noSuchName(2)= OID 不存在或无权限;readOnly(4)/notWritable(17)= 用只读 community 做了 SET;authorizationError(16)= v3 权限不足;tooBig(1)= 响应超过 Agent 的 msgMaxSize,减小 getbulk 的 max-repetitions。- v3 的 Report PDU:如果一直收到 Report 而拿不到数据,看它携带的计数器 OID:
1.3.6.1.6.3.15.1.1.5.0usmStatsWrongDigests → 认证口令错1.3.6.1.6.3.15.1.1.3.0usmStatsUnknownUserNames → 用户名不存在1.3.6.1.6.3.15.1.1.2.0usmStatsNotInTimeWindows → 时钟不同步(超出 ±150 秒窗口)1.3.6.1.6.3.15.1.1.6.0usmStatsDecryptionErrors → 加密口令错
常用命令 / 配置
安装 net-snmp 工具族
这一步装的是"客户端工具箱"(snmpget/snmpwalk 等)和"服务端 Agent"(snmpd)。最后两行是 Debian 系特有的坑:默认不加载 MIB 字典,导致输出全是一串数字而不是可读名字。
| |
查询命令(Manager 侧)
这一组是日常用得最多的"读数"命令。简单说:snmpget 读一个值,snmpgetnext 读下一个值,snmpwalk 一路读到底,snmpbulkwalk 是加速版的 walk,snmptable 把表格排整齐给人看,snmptranslate 则纯粹是本地查字典、根本不发包。
| |
SNMPv3 查询
v3 不再用一个 community 字符串走天下,而是"用户名 + 认证口令 + 加密口令"三件套。下面两条命令分别演示"既认证又加密"和"只认证不加密"两档安全级别。
| |
写操作(SET)
这组命令是往设备里"写"值,需要读写权限。第二条会直接把交换机的某个物理口关掉——生产环境执行前务必确认 ifIndex 对不对。命令末尾的单个字母是值的类型标识,写错类型会直接报错。
| |
Agent 侧配置(Linux net-snmp)
这份配置文件决定了"这台 Linux 对外暴露什么、谁能读、往哪发告警"。第一行 agentAddress 最关键——不改它,外部机器永远连不上。
编辑 /etc/snmp/snmpd.conf:
| |
改完配置必须重启生效,然后按下面三步自检:先看服务活没活,再看监听地址是不是还锁在 127.0.0.1,最后本机自己查一次确认能出数。
网络设备侧配置(参考)
交换机路由器上的配置逻辑和 Linux 一样,只是换了套命令:先定义"能看哪些 OID"(view),再定义"哪个组用什么安全级别"(group),然后建用户、指定告警接收方、最后用 ACL 限制谁能来查。
| |
发送与接收 Trap(测试用)
排查"收不到告警"时,不要干等设备出故障——用下面的命令自己造一个假告警发过去,就能立刻验证接收链路通不通。前半段是启动接收端,后半段是手工构造并发送。
| |
常见故障与排错
故障 1:Timeout: No Response from 192.168.1.1
先记住结论:这条报错不代表网络不通。 SNMP 的超时是个"万能报错",网络不可达、防火墙拦截、Agent 只听本地、community 写错、源 IP 不在白名单,这五种完全不同的原因表现出来一模一样。所以只能按下表从下往上逐层排除,不能跳步。
这是 SNMP 最高频的报错,它不区分"网络不通"和"认证失败",需逐层排查:
| 排查层 | 命令 / 检查点 | 说明 |
|---|---|---|
| ① 三层可达 | ping 192.168.1.1 | 不通先解决路由/ARP |
| ② UDP 161 可达 | nmap -sU -p 161 192.168.1.1 | 结果 open|filtered 属正常(UDP 特性);filtered 明确表示被防火墙拦 |
| ③ Agent 监听地址 | 设备侧 ss -ulnp | grep 161 | net-snmp 默认只监听 127.0.0.1,必须改 agentAddress |
| ④ 防火墙 | iptables -L -n | grep 161、云安全组、设备 ACL | 双向都要放行(请求去 161,响应从 161 回) |
| ⑤ community 错 | 换个 community 试 | 绝大多数 Agent 对错误 community 静默丢弃,表现与网络不通完全一样 |
| ⑥ 源 IP 不在白名单 | 检查 rocommunity ... 10.0.0.0/8 或设备 ACL | 从别的机器试一下即可区分 |
| ⑦ 超时太短 | snmpwalk -t 10 -r 3 ... | 老旧设备或大表遍历响应慢 |
故障 2:No Such Object available on this agent at this OID
先记住结论:这句话的意思是"你要的这个门牌号在这台设备上不存在",而九成情况是你自己写错了地址(漏了 .0)或者对方压根没实现这个 MIB,不是设备坏了。
| 原因 | 排查 |
|---|---|
| 该设备根本不实现这个 MIB | snmpwalk 父节点看有没有东西;查厂商 MIB 支持列表 |
OID 写错(少了 .0) | 标量对象必须带 .0:sysName ✗ → sysName.0 ✓ |
| 视图(View)把它排除了 | 检查 view ... excluded 或设备 snmp-server view |
| MIB 文件没装,名字解析失败 | 用纯数字 OID 重试;或 download-mibs 后设 MIBS=ALL |
故障 3:Error in packet. Reason: notWritable / noAccess
先记住结论:这是权限问题,不是网络问题——你拿只读的钥匙去开了写的锁。 而且即使换成读写权限也可能照样写不了,因为很多对象在 MIB 定义里本身就是只读的。
用只读 community 或只读用户执行了 SET。改用 RW community(rwcommunity)或把 v3 用户加入带 write-view 的组。注意:即使有 RW 权限,很多对象在 MIB 中本身就定义为 read-only,永远写不了。
故障 4:流量图出现巨大尖峰或负值
先记住结论:图形异常几乎都不是设备真的跑出了那么大流量,而是"计数器的坑"——32 位计数器绕圈、设备重启清零、或者 ifIndex 变了导致数据错位。
| 现象 | 原因 | 解决 |
|---|---|---|
| 周期性巨大尖峰 | Counter32 回绕。千兆口约 34 秒、万兆口约 3.4 秒就绕一圈 | 改用 ifHCInOctets/ifHCOutOctets(Counter64,需 v2c 及以上);缩短轮询间隔到 60s 以内 |
| 突然归零后暴涨 | 设备重启,计数器清零 | 监控 sysUpTime.0,变小时丢弃该数据点 |
| 数值不动 | 某些虚拟接口/子接口不更新计数器 | 换用物理口的 ifIndex |
| ifIndex 变了导致图断裂 | 设备重启或插拔模块后 ifIndex 重新分配 | 用 ifName/ifAlias(ifXTable)做主键,而不是 ifIndex;设备侧开启 snmp-server ifindex persist |
故障 5:收不到 Trap
先记住结论:先分清"包根本没到"还是"包到了但被丢弃"——这两类原因完全不同,抓一次包就能分开。 下面三条命令就是用来做这个判断的:先确认接收端在监听,再前台跑看有没有解出来,最后抓包看网卡层面到底有没有流量进来。
| 包到了但不显示 | 原因 |
|---|---|
| snmptrapd 授权未配 | /etc/snmp/snmptrapd.conf 缺 authCommunity log,execute,net <community> |
| v3 Trap 用户未配 | v3 Trap 需在接收端配置对应的 createUser + authUser log |
| community 不匹配 | 发送端与接收端的 trap community 要一致 |
| 包根本没到 | 原因 |
|---|---|
| 设备未使能 Trap | Cisco 需 snmp-server enable traps ...,默认多数 Trap 是关的 |
| trap 目标地址配错 / 走了错误的源接口 | 检查 snmp-server source-interface traps |
| 中间防火墙丢 UDP 162 | 抓包对比设备出口与接收端入口 |
| 网络丢包,Trap 无重传 | 改用 Inform(带确认+重传) |
故障 6:安全事件 —— SNMP 反射放大攻击
先记住结论:只要你的 UDP 161 能从公网访问,你的设备就随时可能被别人拿去打人——而且是替别人背锅。 根因是 UDP 不校验源 IP,攻击者伪造受害者地址来查你,你把巨大的响应全砸给受害者。
原理:攻击者伪造受害者源 IP,向大量开放 161 的设备发送 GetBulkRequest(请求包 ~60 字节),设备把巨大的响应(可达数 KB)全发给受害者,放大倍数可超过 600 倍。
自查与加固:
下面第一条命令是"照镜子"——从外网视角扫自己的公网 IP,如果能读到 sysDescr 就说明已经暴露了。后面的清单是按优先级排列的加固动作。
| |
与其他协议对比
| 维度 | SNMP | NETCONF (RFC 6241) | gNMI / Streaming Telemetry | Syslog | NetFlow / IPFIX |
|---|---|---|---|---|---|
| 主要用途 | 指标监控(读)+ 少量配置 | 配置管理(读写) | 高频指标采集 | 日志/事件 | 流量明细分析 |
| 传输 | UDP 161/162 | SSH 830 / TLS | gRPC over HTTP/2 (TLS) | UDP 514 / TCP 6514 | UDP 2055 等 |
| 数据模型 | MIB / SMI(ASN.1) | YANG | YANG | 无结构(纯文本) | 流记录模板 |
| 编码 | BER 二进制 | XML | Protobuf | 文本 | 二进制 |
| 交互模式 | 拉(轮询)为主 | 拉 + 通知 | 推(订阅) | 推 | 推 |
| 采集频率 | 分钟级(轮询开销大) | 分钟级 | 秒级/亚秒级 | 事件驱动 | 流结束时导出 |
| 事务性 | 无 | 有(candidate/commit/rollback) | 有 | — | — |
| 安全 | v1/v2c 明文,v3 authPriv | 默认 SSH/TLS 加密 | 默认 TLS | 默认明文 | 明文 |
| 设备支持度 | 极广,几乎所有设备 | 中高端设备 | 新设备 | 极广 | 中高端设备 |
| 典型工具 | Zabbix / snmp_exporter / Cacti | ncclient / Ansible | Telegraf / OpenConfig | rsyslog / Loki | nfdump / ntopng |
选型结论:
- 存量设备只读监控 → SNMP(无可替代)
- 配置自动化 → NETCONF/YANG 或 Ansible,别用 SNMP SET
- 高频细粒度指标(如微突发检测) → gNMI Streaming Telemetry
- “带宽被谁占满了” → NetFlow / sFlow,SNMP 只能告诉你"占满了"
速查表 / 常见面试题
端口 / 版本速查
| 项 | 值 |
|---|---|
| Agent 监听 | UDP 161 |
| Trap 接收 | UDP 162 |
| DTLS/TLS(RFC 6353) | 10161 / 10162 |
| version 字段编码 | v1 = 0,v2c = 1,v3 = 3(没有 2) |
| 默认只读 community | public |
| 默认读写 community | private |
| v3 时间窗 | ±150 秒 |
| HMAC 摘要长度(MD5/SHA-1) | 12 字节(96 bit 截断) |
PDU 类型速查
| Tag | PDU | 版本 |
|---|---|---|
| 0xA0 | GetRequest | v1+ |
| 0xA1 | GetNextRequest | v1+ |
| 0xA2 | Response(v1 叫 GetResponse) | v1+ |
| 0xA3 | SetRequest | v1+ |
| 0xA4 | Trap(v1 专用结构) | v1 |
| 0xA5 | GetBulkRequest | v2c+ |
| 0xA6 | InformRequest | v2c+ |
| 0xA7 | SNMPv2-Trap | v2c+ |
| 0xA8 | Report | v3 |
一行命令速查
这七条是"到了现场直接抄"的版本,把 HOST 换成设备 IP 即可。
| |
常见面试题
Q1:SNMP 为什么用 UDP 而不是 TCP? A:① 网管流量要在网络已经拥塞/异常时仍能送达,TCP 的重传与拥塞退避反而会延误告警;② Agent 侧资源受限(老交换机 CPU/内存很小),维护上千条 TCP 连接不现实;③ 轮询天然是"一问一答"的短交互,不需要连接状态。代价是不可靠,因此 SNMP 在应用层用 request-id + 超时重传弥补,Trap 则用 Inform 补上确认。
Q2:GetNext 和 GetBulk 的区别?为什么 walk 很慢?
A:GetNext 每次只返回一个变量,遍历 N 个对象需要 N 次往返(RTT),一张 48 口交换机的 ifTable 有 20 多列 × 48 行 ≈ 1000+ 次往返。GetBulk 通过 max-repetitions 一次返回多个后继变量,把往返次数压缩到几十次。snmpbulkwalk 就是基于 GetBulk 的,比 snmpwalk 快一个数量级——但 v1 不支持 GetBulk。
Q3:v2c 相比 v1 改进了什么?它解决安全问题了吗? A:改进了三点——① 新增 GetBulk 大幅提升遍历效率;② 新增 Inform(带确认的 Trap);③ 新增 Counter64 支持高速接口。没有解决安全问题:v2c 的 “c” 就是 community-based,仍然明文传 community。真正的安全版本是 v3。
Q4:SNMPv3 的三种安全级别?为什么需要 Engine Discovery?
A:noAuthNoPriv(不认证不加密)、authNoPriv(HMAC 认证但明文)、authPriv(认证+AES/DES 加密)。需要 Engine Discovery 是因为 USM 采用密钥本地化:实际用于 HMAC/加密的密钥 = Hash(Ku ‖ authoritativeEngineID ‖ Ku),Manager 必须先知道 Agent 的 engineID 才能算出正确密钥。同时 Report 还携带 engineBoots/engineTime 用于建立防重放时间窗。
Q5:Counter32 回绕怎么处理?什么时候必须用 Counter64? A:Counter32 上限 2³²-1 ≈ 42.9 亿字节。1 Gbps 满速约 34 秒回绕一次,10 Gbps 约 3.4 秒。轮询间隔通常 60~300 秒,远大于回绕周期,数据完全失真。因此百兆以上接口一律使用 ifXTable 的 ifHCInOctets/ifHCOutOctets(Counter64),回绕周期长达数千年。注意 Counter64 只在 SNMPv2c 及以上可用。
Q6:Trap 和 Inform 怎么选? A:Trap 无确认、Agent 发完即忘,开销最小,适合高频且可容忍丢失的事件;Inform 有 Response 确认与重传,可靠但 Agent 需缓存报文。关键告警(设备重启、主链路 down、电源故障)用 Inform,常规状态变化用 Trap。另外注意 Inform 会占用 Agent 内存,大量 Inform 可能压垮低端设备。
Q7:sysUpTime 的单位是什么?
A:TimeTicks,单位是百分之一秒(10 毫秒),不是秒。数值 360000 表示 3600 秒 = 1 小时。它也是 32 位的,约 497 天后回绕。
Q8:怎么发现一台陌生设备支持哪些 MIB?
A:① snmpwalk -v2c -c public HOST .1 全树遍历(慢但完整);② snmpget HOST sysObjectID.0 拿到厂商私有 OID,再去厂商网站下对应 MIB;③ snmpwalk HOST 1.3.6.1.4.1 看私有分支下有什么;④ nmap -sU -p161 --script snmp-* HOST 用 NSE 脚本快速枚举。
Q9:为什么说 SNMP 是 DDoS 放大攻击的帮凶?
A:GetBulkRequest 请求包仅约 60 字节,而响应可达数 KB,放大比可超过 600×。攻击者伪造受害者 IP 作源地址,向互联网上大量开放 UDP 161 的设备群发请求,所有响应涌向受害者。这是 UDP 无连接(不校验源 IP)+ 默认 community public + 设备暴露公网三者叠加的结果。防御核心是永不把 161 暴露到公网。
Q10:SNMP 会被什么取代?
A:在配置管理领域已被 NETCONF/YANG、RESTCONF 取代(SNMP SET 无事务性、无回滚);在高频遥测领域正被 gNMI / Streaming Telemetry 取代(推模式、秒级、Protobuf 高效编码)。但在存量设备的只读监控领域,SNMP 因为设备支持度接近 100%,短期内仍不可替代——Prometheus 的 snmp_exporter 就是把 SNMP 数据桥接到现代监控栈的典型方案。