0

我正在编写一个充当 snmp pass_persist 处理程序的小脚本。我希望它读取一个文件(称为“数字”,现在在同一个目录中),它只包含一些整数并将这些作为 oid 树返回。

我已经坚持了几天了,现在我意识到这是由于对 snmpd 工作原理的根本误解。我正在使用 snmpd.conf 手册页,它没有提到处理“get”和“getnext”请求的方式有任何区别,但我假设有一个。我一辈子都无法让 snmpwalk 使用这个脚本。

对 snmp 有更多了解的人可以看一下这段代码吗?我已经看过其他几个版本的 pass 脚本,包括一些在 python 中的版本,但我无法通过查看代码看到它们如何以与我的代码不同的方式处理协议。我看到了一个处理空白命令( '' )的实现,但其他显然没有。

基本上,我在这一点上很困惑!- 调试 snmpd 也非常困难,因为它是调用我的脚本的那个,而不是我。我正在记录我所能记录的内容,并在前台运行 snmpd,但除此之外,这有点“黑匣子”。

任何人都可以解释一下吗?

即:数字文件:

101
102
103
我想返回为:
.1.3.6.1.4.1..[剪辑]..1 = 101
.1.3.6.1.4.1..[剪辑]..2 = 102
.1.3.6.1.4.1..[剪辑]..3 = 103

我的脚本(我不担心返回整数以外的任何内容,而且我知道永远无法关闭文件,但这让我感觉更好):


#!/bin/python -u

import os,sys, syslog

def getLine():
    return sys.stdin.readline().strip()

def getFileLine(sub_oid, lines):
    sub_oid = int(sub_oid)
    if sub_oid >= len(lines):
        return 'NONE'
    else:
        return lines[sub_oid]

def printOutput(oid, var_type, varbind_value):
    if varbind_value == 'NONE':
        print 'NONE'
    else:
        print oid
        print var_type
        print varbind_value

######################################################

sub_oid = 0
FH = open('numbers','r')
lines = FH.readlines()

while True:
    command = getLine()
    syslog.syslog("command: %s" % command)

    if command == 'PING':
        syslog.syslog('got a ping')
        print 'PONG'
    elif command == 'get':
        given_oid = getLine()
        sub_oid = int(given_oid.split('.')[-1])
        varbind_value = getFileLine(sub_oid, lines)
        printOutput(given_oid, 'integer', varbind_value.strip())
    elif command == 'getnext':
        given_oid = getLine()
        syslog.syslog("got a requested oid of: %s" % given_oid)
        sub_oid = int(given_oid.split('.')[-1])
        varbind_value = getFileLine(sub_oid, lines)
        printOutput(given_oid, 'integer', varbind_value.strip())
    else:
        syslog.syslog("Unknown command: %s" % command)

FH.close()
4

1 回答 1

2

首先,有一个专门为此任务编写的snmp-passpersist Python 模块。它的页面有一个指向真实世界使用示例的链接。您的案例的示例代码如下。

关于您的具体问题:

  1. 在规范和维基百科中,描述getnext确实是出了名的不清楚。TUT:snmpgetnext - Net-SNMP Wiki中对此进行了很好的解释。

    简而言之,它检索代理层次结构中指定 OID 之后的第一个有效 OID(及其值)。这里的“层次结构”可以表示为代理知道的所有 OID 的有序列表,这些 OID 目前有效。

    • 有两个主要用例:
      1. 响应包含该“下一个”值的 OID以及值本身。因此,您可以通过在后续请求中使用返回的 OID 来遍历代理的层次结构。当层次结构耗尽时,代理应该返回“未找到”错误(和pass_persist处理程序 - )。"NONE"
      2. 您也可以指定一个不完整的 OID,并且代理应该返回它知道的与提供的匹配的第一个完整的 OID。
    • 在数据包级别,getnext确实不同于get(它的请求类型 ID 是1get的是0)。
    • 您可能想完全忽略这个“魔法”并以与以下相同的方式处理它get:这只意味着“行走”和“猜测”将不起作用(行走可能会无限循环)。这就是我在上一份职业中维护的处理程序的工作方式,这也是您当前代码中正在发生的事情:^)
      • 所以,修复很简单:getFileLine(int(sub_oid)+1, lines)- 因为你的代码已经足够聪明,可以"NONE"在疲惫时返回。“猜测”仍然行不通,但是……你需要吗?
  2. net-snmpd有大量的日志记录选项 - 在其联机帮助页上搜索“日志” (而且,地狱,它是免费软件!当一切都失败时,您总是可以咨询甚至调试源代码)。snmpget但在这种特殊情况下,在使用/和/或使用嗅探器进行查询时记录标准输入和标准输出snmpgetnext就绰绰有余了。

有了前面提到的snmp-passpersist,您的代码归结为:

base_oid=".1.3.6.1.4.1..[snip]"
data_file="<path>"

import snmp_passpersist as snmp
pp=snmp.PassPersist(base_oid)

for l in (l.rstrip() for l in open(data_file)):
    pp.add_int(l,int(l))

pp.start(user_func=lambda:True,refresh=1800)  # If data updates are needed,
                                              # replace lambda with a real fn
                                              # and adjust refresh (sec)

如果您需要监视对文件的更改,您可以轮询它(如上面的评论所建议的那样)或(在 Linux 中)使用类似pyinotify的东西- 在这种情况下,您可能需要pp.main_update()在调用之前替换pp.start()或以其他方式修补模块的机器不知何故。

于 2012-10-27T21:28:23.510 回答