0

snmp pass_persist ハンドラーとして機能する小さなスクリプトに取り組んでいます。いくつかの整数だけを含むファイル(「numbers」と呼ばれる、今は同じディレクトリにある)を読み取り、これらをoidツリーとして返すようにします。

私はこれに数日間行き詰まっていましたが、snmpd の仕組みに関する根本的な誤解が原因であることに気付きました。私が使用している snmpd.conf の man ページでは、'get' および 'getnext' 要求の処理方法に違いはありませんが、違いがあると思います。私の人生では、snmpwalk をこのスクリプトで動作させることはできません。

snmp についてもう少し知っている人は、このコードを調べてもらえますか? Python のバージョンも含めて、他のバージョンのパス スクリプトをいくつか見たことがありますが、コードを見て、それらが私のコードとは異なる方法でプロトコルを処理する方法を確認できませんでした。空白のコマンド ( '' ) を処理する 1 つの実装を見ましたが、他の実装は明らかにそうではありませんでした。

基本的に、私はこの時点でかなり混乱しています! - snmpd は私ではなく私のスクリプトを呼び出しているため、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 の順序付きリストとして表すことができます。

    • これには、主に次の 2 つの使用例があります。
      1. 応答には、その「次の」値の OIDと値自体が含まれます。したがって、後続のリクエストで返された OID を使用して、エージェントで階層をたどることができます。階層が使い果たされると、エージェントは「見つかりません」エラー (およびpass_persistハンドラー - ) を返すことになっています。"NONE"
      2. 不完全な OID も指定できます。エージェントは、提供されたものと一致することを知っている最初の完全なものを返すことになっています。
    • パケット レベルでgetnextは、 も実際に異なりgetます (そのリクエスト タイプ ID はであり1getのは です0)。
    • この「魔法」を完全に無視して、 と同じように処理することもできますget。これは、「ウォーキング」と「推測」が機能しないことを意味するだけです (ウォーキングは無期限にループする可能性があります)。これは、私が以前の職業で維持していたハンドラーがどのように機能したかであり、これはまさに現在のコードでも起こっていることです :^) .
      • したがって、修正は簡単です: getFileLine(int(sub_oid)+1, lines)- あなたのコードはすでに使い果たされたときに戻るのに十分なほど賢いから"NONE"です。「推測」はまだうまくいきませんが...必要ですか?
  2. net-snmpdマンページで「ログ」を検索してください (そして、これはフリー ソフトウェアです! 他のすべてが失敗した場合は、いつでもソースを参照したり、デバッグしたりすることもできます)。snmpgetしかし、この特定のケースでは、 /および/または sniffer を使用してクエリを実行しながら stdin と stdout をログに記録する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 に答える