pass_persist处理程序中的正确getnext逻辑

时间:2012-10-23 19:53:23

标签: python snmp net-snmp

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

我已经被困在这几天了,现在我意识到这是由于对于snmpd如何工作的基本误解。我正在使用snmpd.conf手册页,它没有提到如何处理'get'和'getnext'请求的任何区别,但我认为有一个。我无法为我的生活轻松地使用这个剧本。

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

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

任何人都能解释一下吗?

即: 数字文件:

101
102
103
I want returned as:
.1.3.6.1.4.1..[snip]..1 = 101
.1.3.6.1.4.1..[snip]..2 = 102
.1.3.6.1.4.1..[snip]..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()

1 个答案:

答案 0 :(得分:2)

首先,已经有一个专门用于此任务的snmp-passpersist Python module。其页面包含指向实际使用示例的链接。您的案例的示例代码如下。

关于您的具体问题:

  1. getnext的描述确实在规范和维基百科中都不为人所知。在TUT:snmpgetnext - Net-SNMP Wiki中很好地解释了这一点 简而言之,它检索第一个有效的OID (及其值),它位于代理程序层次结构中的指定值之后。这里的“层次结构”可以表示为代理知道的当前有效的所有OID的有序列表。

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

  3. 使用前面提到的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()或者以某种方式修补模块的机制。