如何在收到SNMP Set报文时触发脚本执行
核心解决方案:直接捕获SNMP Set请求触发脚本
不用转Trap,直接监听SNMP默认UDP 161端口的Set请求,解析后执行指定脚本,这是最直接高效的方案,下面分平台给出实现:
Windows平台(PowerShell实现)
前置准备
- 以管理员身份打开PowerShell,先安装NuGet包管理器:
Install-PackageProvider NuGet -Force
- 安装SNMP解析库
SnmpSharpNet:
Install-Package SnmpSharpNet -Scope CurrentUser
(安装后库文件路径大概在C:\Users\<你的用户名>\AppData\Local\NuGet\Packages\SnmpSharpNet\<版本号>\lib\net45\SnmpSharpNet.dll,替换到后续脚本中)
监听脚本
# 加载SNMP解析库,替换为你的实际路径 Add-Type -Path "C:\Users\John\AppData\Local\NuGet\Packages\SnmpSharpNet\0.9.1\lib\net45\SnmpSharpNet.dll" # 监听UDP 161端口 $udpClient = New-Object System.Net.Sockets.UdpClient(161) $remoteEP = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Any, 0) Write-Host "正在监听SNMP Set请求..." while ($true) { # 接收报文 $receiveBytes = $udpClient.Receive([ref]$remoteEP) $snmpPacket = New-Object SnmpSharpNet.SnmpPacket($receiveBytes) # 判断是否为Set请求 if ($snmpPacket.Pdu.Type -eq [SnmpSharpNet.PduType]::Set) { Write-Host "收到Set请求,来源IP: $($remoteEP.Address)" # 解析请求中的OID和对应值 foreach ($varBind in $snmpPacket.Pdu.VbList) { Write-Host "OID: $($varBind.Oid), 值: $($varBind.Value)" } # 执行你的目标脚本,替换为实际路径 & "C:\scripts\your-action-script.bat" # 可选:给发送端返回成功响应 $response = $snmpPacket.Response() $udpClient.Send($response.encode(), $response.encode().Length, $remoteEP) } }
注意:必须用管理员权限运行,因为161是特权端口,普通用户无法监听。
Linux平台(Go语言实现)
Go的gosnmp库轻量高效,适合快速搭建监听服务:
前置准备
go get github.com/gosnmp/gosnmp
监听代码
package main import ( "fmt" "os/exec" "github.com/gosnmp/gosnmp" ) func main() { // 配置SNMP参数,替换为你的社区字符串 params := &gosnmp.GoSNMP{ Port: 161, Community: "public", Version: gosnmp.Version2c, } // 启动监听,处理Set请求 err := params.Listen("0.0.0.0", func(packet *gosnmp.SnmpPacket) { if packet.PduType == gosnmp.SetRequest { fmt.Printf("收到Set请求,来源: %s\n", packet.RemoteAddr) // 解析OID和值 for _, vb := range packet.Variables { fmt.Printf("OID: %s, 值: %v\n", vb.Name, vb.Value) } // 执行目标脚本,替换为实际路径 cmd := exec.Command("/opt/scripts/your-action.sh") if err := cmd.Run(); err != nil { fmt.Printf("脚本执行失败: %v\n", err) } // 返回成功响应 params.SendResponse(packet, gosnmp.NoError, 0) } }) if err != nil { fmt.Printf("监听启动失败: %v\n", err) return } select {} // 保持进程运行 }
编译运行:
go build -o snmp-set-trigger . sudo ./snmp-set-trigger # 需要sudo监听161端口
零编码快速方案(适合简单场景)
如果不需要解析具体OID,只需要触发脚本,可以用抓包工具配合脚本:
Windows(用WinDump)
- 下载WinDump并配置环境变量
- 打开命令提示符(管理员),运行:
windump -i any udp port 161 and snmp.set -l | findstr /r "SetRequest" > snmp-set.log
- 写个PowerShell脚本实时监控日志文件,发现新内容就执行脚本:
$logFile = "snmp-set.log" $lastSize = (Get-Item $logFile).Length while ($true) { Start-Sleep -Seconds 1 $currentSize = (Get-Item $logFile).Length if ($currentSize -gt $lastSize) { & "C:\scripts\your-action-script.bat" $lastSize = $currentSize } }
Linux(用tcpdump)
直接在终端运行:
tcpdump -i any udp port 161 and snmp.set -l | while read -r line; do /opt/scripts/your-action.sh; done
关于Set转Trap的方案(不推荐)
如果非要转Trap,可通过Linux的snmpd配置自定义扩展,当收到Set请求时调用snmp-trap命令发送Trap,但这种方式多了一层中转,效率低且没必要,不如直接捕获解析。
内容的提问来源于stack exchange,提问作者Joel Upham
相关产品推荐
相关产品推荐

