带有自定义MIB的Python中的SNMP代理

时间:2019-06-03 12:37:21

标签: python pysnmp mib

我使用pysnmp lib在python中实现了SNMP代理。这是我用来响应自定义OID的代码。


from datetime import datetime
from pysnmp import debug
from pysnmp.carrier.asyncore.dgram import udp
from pysnmp.entity import engine, config
from pysnmp.entity.rfc3413 import cmdrsp, context
from pysnmp.proto.api import v2c
from pysnmp.smi import builder, instrum, exval

# Uncomment this to turn pysnmp debugging on
#debug.setLogger(debug.Debug('all'))

formatting = '[%(asctime)s-%(levelname)s]-(%(module)s) %(message)s'
logging.basicConfig(level=logging.DEBUG, format=formatting, )

logging.info("Starting....")

# Create SNMP engine
snmpEngine = engine.SnmpEngine()

# Transport setup

# UDP over IPv4
config.addTransport(
    snmpEngine,
    udp.domainName,
    udp.UdpTransport().openServerMode(('0.0.0.0', 12345))
)

# SNMPv2c setup

# SecurityName <-> CommunityName mapping.
config.addV1System(snmpEngine, 'my-area', 'public')

# Allow read MIB access for this user / securityModels at VACM
# Limit access to just the custom MIB. Widen if need be
config.addVacmUser(snmpEngine,
                   2,
                   'my-area',
                   'noAuthNoPriv',
                   (1, 3, 6, 4),
                   (1, 3, 6, 4))


# Create an SNMP context and ensure the custom MIB is loaded
# Your system must have this MIB installed otherwise pysnmp
# can't load it!
snmpContext = context.SnmpContext(snmpEngine)
logging.debug('Loading __EXAMPLE-MIB module...'),
mibBuilder = snmpContext.getMibInstrum().getMibBuilder()
(MibTable,
 MibTableRow,
 MibTableColumn,
 MibScalarInstance) = mibBuilder.importSymbols(
    'SNMPv2-SMI',
    'MibTable',
    'MibTableRow',
    'MibTableColumn',
    'MibScalarInstance'
)
logging.debug('done')


RowStatus, = mibBuilder.importSymbols('SNMPv2-TC', 'RowStatus')

mibBuilder.exportSymbols(
    '__EXAMPLE-MIB',
    # table object
    exampleTable=MibTable((1, 3, 6, 4, 1)).setMaxAccess('readcreate'),
    # table row object, also carries references to table indices
    exampleTableEntry=MibTableRow((1, 3, 6, 4, 1, 5)).setMaxAccess('readcreate').setIndexNames((0, '__EXAMPLE-MIB', 'exampleTableColumn1')),
    # table column: string index
    exampleTableColumn1=MibTableColumn((1, 3, 6, 4, 1, 5, 1), v2c.OctetString()).setMaxAccess('readcreate'),
    # table column: string value
    exampleTableColumn2=MibTableColumn((1, 3, 6, 4, 1, 5, 2), v2c.OctetString()).setMaxAccess('readcreate'),
    # table column: integer value with default
    exampleTableColumn3=MibTableColumn((1, 3, 6, 4, 1, 5, 3), v2c.Integer32(123)).setMaxAccess('readcreate'),
    # table column: row status
    exampleTableStatus=MibTableColumn((1, 3, 6, 4, 1, 5, 4), RowStatus('notExists')).setMaxAccess('readcreate')
)
logging.debug('done')

(exampleTableEntry,
 exampleTableColumn2,
 exampleTableColumn3,
 exampleTableStatus) = mibBuilder.importSymbols(
    '__EXAMPLE-MIB',
    'exampleTableEntry',
    'exampleTableColumn2',
    'exampleTableColumn3',
    'exampleTableStatus'
)

rowInstanceId = exampleTableEntry.getInstIdFromIndices('example record one')
mibInstrumentation = snmpContext.getMibInstrum()
mibInstrumentation.writeVars(
    ((exampleTableColumn2.name + rowInstanceId, 'hello'),
     (exampleTableColumn3.name + rowInstanceId, 123456),
     (exampleTableStatus.name + rowInstanceId, 'createAndGo'))
)

logging.debug('done')
logging.debug('Snmp Agent Start')

# Register SNMP Applications at the SNMP engine for particular SNMP context
cmdrsp.GetCommandResponder(snmpEngine, snmpContext)
cmdrsp.SetCommandResponder(snmpEngine, snmpContext)
cmdrsp.NextCommandResponder(snmpEngine, snmpContext)
cmdrsp.BulkCommandResponder(snmpEngine, snmpContext)

# Register an imaginary never-ending job to keep I/O dispatcher running forever
snmpEngine.transportDispatcher.jobStarted(1)

# Run I/O dispatcher which would receive queries and send responses
try:
    snmpEngine.transportDispatcher.runDispatcher()
except:
    snmpEngine.transportDispatcher.closeDispatcher()
    raise

我使用iReasoning MIB浏览器发送snmp请求。
当我发送 .1.3.6.4.1.5.1 oid的 Get 请求时,出现以下错误提示:“ 无访问错误。
最后,我发送 .1.3.6.4.1.5 oid的 Get Subtree 请求,MIB浏览器在下面显示此结果:

enter image description here

如您所见,OID结果为: .1.3.6.4.1.5.1.18.101.120.97.109.112.108.101.32.114.101.99.111.114.100.32.111.110.101

这不短,并且具有一些附加值。

怎么了?

2 个答案:

答案 0 :(得分:1)

您观察到的内容似乎是正确的。

您不能在1.3.6.4.1.5.1受管对象上进行操作,因为它不是值对象,而是一种“类型”,它定义了可以从其派生的“变量”的属性。前者称为SNMP中的托管对象,后者是SNMP中的托管对象实例

要处理特定的托管对象实例,您需要在托管对象OID上附加一个或多个子OID。此结尾部分在SNMP中称为托管对象实例ID

在您的实现中,托管对象实例ID是从“示例记录一个”字符串派生的。它在OID的尾部至少需要与字符串中的字符一样多的元素。这就解释了为什么产生的OID这么长。

答案 1 :(得分:0)

有一个类似的问题,需要使用整数“1”作为索引,因为表是由 IF-MIB ifIndex 索引的。

发现这有效:rowInstanceId = (1,)

下面显示了如下所示脚本的结果:

ubuntu@user:~$ snmpwalk -v 3 -u usr-sha-aes -a SHA -A authkey1 -x aes -X privkey1 -l authPriv -L n -m all localhost 1 
IEEE802dot11-MIB::dot11TransmittedFragmentCount.1 = Counter32: 123
IEEE802dot11-MIB::dot11GroupTransmittedFrameCount.1 = Counter32: 123456
IEEE802dot11-MIB::dot11FailedCount.1 = Counter32: 1350
IEEE802dot11-MIB::dot11RetryCount.1 = Counter32: 1251
IEEE802dot11-MIB::dot11MultipleRetryCount.1 = Counter32: 234
IEEE802dot11-MIB::dot11FrameDuplicateCount.1 = Counter32: 566
IEEE802dot11-MIB::dot11RTSSuccessCount.1 = Counter32: 867
IEEE802dot11-MIB::dot11RTSFailureCount.1 = Counter32: 231
IEEE802dot11-MIB::dot11AckFailureCount.1 = Counter32: 856
IEEE802dot11-MIB::dot11ReceivedFragmentCount.1 = Counter32: 568
IEEE802dot11-MIB::dot11GroupReceivedFrameCount.1 = Counter32: 34568
IEEE802dot11-MIB::dot11FCSErrorCount.1 = Counter32: 345
IEEE802dot11-MIB::dot11TransmittedFrameCount.1 = Counter32: 78567
IEEE802dot11-MIB::dot11WEPUndecryptableCount.1 = Counter32: 4545
RFC1213-MIB::ifDescr.1 = STRING: "wifi0"
RFC1213-MIB::ifDescr.1 = No more variables left in this MIB View (It is past the end of the MIB tree)

脚本如下:

from datetime import datetime
from pysnmp import debug
from pysnmp.carrier.asyncore.dgram import udp
from pysnmp.entity import engine, config
from pysnmp.entity.rfc3413 import cmdrsp, context
from pysnmp.proto.api import v2c
from pysnmp.smi import builder, instrum, exval, error
from pysnmp.proto import rfc1902


# Create SNMP engine
# For the correct  SNMP Engine ID format please see https://www.rfc-editor.org/rfc/rfc3411.html#page-41
# snmpEngine = engine.SnmpEngine()
snmpEngine = engine.SnmpEngine(rfc1902.OctetString(hexValue='8000000004030201'))

# Transport setup
# UDP over IPv4 and allow any IP address at port 161
config.addTransport(
    snmpEngine,
    udp.domainName,
    udp.UdpTransport().openServerMode(('0.0.0.0', 161))
)

# SNMPv2c setup
# SecurityName <-> CommunityName mapping. my-area username maps to the community name of public.
config.addV1System(snmpEngine, 'my-area', 'public')

# Allow readonly MIB access for this v2 user / securityModels at VACM
# Limit access to just the MIBs used here at VACM. Widen if need be
config.addVacmUser(snmpEngine, 2, 'my-area', 'noAuthNoPriv', (1, 2))
config.addVacmUser(snmpEngine, 2, 'my-area', 'noAuthNoPriv', (1, 3, 6, 1, 2, 1, 2, 2))

# SNMPv3/USM setup
# user: usr-sha-des, auth: SHA, priv AES128
config.addV3User(
    snmpEngine, 'usr-sha-aes',
    config.usmHMACSHAAuthProtocol, 'authkey1',
    config.usmAesCfb128Protocol, 'privkey1'
)
# Limit readonly access to just the MIBs used here at VACM for the v3 user.  Widen if need be.
config.addVacmUser(snmpEngine, 3, 'usr-sha-aes', 'authPriv', (1, 2))
config.addVacmUser(snmpEngine, 3, 'usr-sha-aes', 'authPriv', (1, 3, 6, 1, 2, 1, 2, 2))

# Create an SNMP context
snmpContext = context.SnmpContext(snmpEngine)

mibBuilder = snmpContext.getMibInstrum().getMibBuilder()
(MibTable,
 MibTableRow,
 MibTableColumn,
 MibScalarInstance) = mibBuilder.importSymbols(
    'SNMPv2-SMI',
    'MibTable',
    'MibTableRow',
    'MibTableColumn',
    'MibScalarInstance'
)

mibBuilder.exportSymbols(
    'IF-MIB',
    ifTable=MibTable((1, 3, 6, 1, 2, 1, 2, 2), ).setMaxAccess('notaccessible'),
    ifEntry=MibTableRow((1, 3, 6, 1, 2, 1, 2, 2, 1)).setMaxAccess('notaccessible').setIndexNames((0, 'IF-MIB', 'ifIndex')),
    ifIndex=MibTableColumn((1, 3, 6, 1, 2, 1, 2, 2, 1, 1), v2c.Integer32()).setMaxAccess('notaccessible'),
    ifDescr=MibTableColumn((1, 3, 6, 1, 2, 1, 2, 2, 1, 2), v2c.OctetString()).setMaxAccess('readonly')
)


# All WiFi products use the ifIndex of 1 for the WLAN interface.

mibBuilder.exportSymbols(
    'IEEE802dot11-MIB',
    dot11CountersTable=MibTable((1, 2, 840, 10036, 2, 2), ).setMaxAccess('notaccessible'),
    dot11CountersEntry=MibTableRow((1, 2, 840, 10036, 2, 2, 1)).setMaxAccess('notaccessible').setIndexNames((0, 'IF-MIB', 'ifIndex')),
    dot11TransmittedFragmentCount=MibTableColumn((1, 2, 840, 10036, 2, 2, 1, 1), v2c.Counter32()).setMaxAccess('readonly'),
    dot11GroupTransmittedFrameCount=MibTableColumn((1, 2, 840, 10036, 2, 2, 1, 2), v2c.Counter32()).setMaxAccess('readonly'),
    dot11FailedCount=MibTableColumn((1, 2, 840, 10036, 2, 2, 1, 3), v2c.Counter32()).setMaxAccess('readonly'),
    dot11RetryCount=MibTableColumn((1, 2, 840, 10036, 2, 2, 1, 4), v2c.Counter32()).setMaxAccess('readonly'),
    dot11MultipleRetryCount=MibTableColumn((1, 2, 840, 10036, 2, 2, 1, 5), v2c.Counter32()).setMaxAccess('readonly'),
    dot11FrameDuplicateCount=MibTableColumn((1, 2, 840, 10036, 2, 2, 1, 6), v2c.Counter32()).setMaxAccess('readonly'),
    dot11RTSSuccessCount=MibTableColumn((1, 2, 840, 10036, 2, 2, 1, 7), v2c.Counter32()).setMaxAccess('readonly'),
    dot11RTSFailureCount=MibTableColumn((1, 2, 840, 10036, 2, 2, 1, 8), v2c.Counter32()).setMaxAccess('readonly'),
    dot11AckFailureCount=MibTableColumn((1, 2, 840, 10036, 2, 2, 1, 9), v2c.Counter32()).setMaxAccess('readonly'),
    dot11ReceivedFragmentCount=MibTableColumn((1, 2, 840, 10036, 2, 2, 1, 10), v2c.Counter32()).setMaxAccess('readonly'),
    dot11GroupReceivedFrameCount=MibTableColumn((1, 2, 840, 10036, 2, 2, 1, 11), v2c.Counter32()).setMaxAccess('readonly'),
    dot11FCSErrorCount=MibTableColumn((1, 2, 840, 10036, 2, 2, 1, 12), v2c.Counter32()).setMaxAccess('readonly'),
    dot11TransmittedFrameCount=MibTableColumn((1, 2, 840, 10036, 2, 2, 1, 13), v2c.Counter32()).setMaxAccess('readonly'),
    dot11WEPUndecryptableCount=MibTableColumn((1, 2, 840, 10036, 2, 2, 1, 14), v2c.Counter32()).setMaxAccess('readonly')
)

(ifEntry,
 ifIndex,
 ifDescr
 ) = mibBuilder.importSymbols(
    'IF-MIB',
    'ifEntry',
    'ifIndex',
    'ifDescr'
)

(dot11CountersEntry,
 dot11TransmittedFragmentCount,
 dot11GroupTransmittedFrameCount,
 dot11FailedCount,
 dot11RetryCount,
 dot11MultipleRetryCount,
 dot11FrameDuplicateCount,
 dot11RTSSuccessCount,
 dot11RTSFailureCount,
 dot11AckFailureCount,
 dot11ReceivedFragmentCount,
 dot11GroupReceivedFrameCount,
 dot11FCSErrorCount,
 dot11TransmittedFrameCount,
 dot11WEPUndecryptableCount

 ) = mibBuilder.importSymbols(
    'IEEE802dot11-MIB',
    'dot11CountersEntry',
    'dot11TransmittedFragmentCount',
    'dot11GroupTransmittedFrameCount',
    'dot11FailedCount',
    'dot11RetryCount',
    'dot11MultipleRetryCount',
    'dot11FrameDuplicateCount',
    'dot11RTSSuccessCount',
    'dot11RTSFailureCount',
    'dot11AckFailureCount',
    'dot11ReceivedFragmentCount',
    'dot11GroupReceivedFrameCount',
    'dot11FCSErrorCount',
    'dot11TransmittedFrameCount',
    'dot11WEPUndecryptableCount'
)


rowInstanceId = (1,)
mibInstrumentation = snmpContext.getMibInstrum()
mibInstrumentation.writeVars(
    ((ifIndex.name + rowInstanceId, 1),
     (ifDescr.name + rowInstanceId, 'wifi0'))

)

rowInstanceId = (1,)
mibInstrumentation = snmpContext.getMibInstrum()
mibInstrumentation.writeVars(
    ((dot11TransmittedFragmentCount.name + rowInstanceId, 123),
     (dot11GroupTransmittedFrameCount.name + rowInstanceId, 123456),
     (dot11FailedCount.name + rowInstanceId, 1350),
     (dot11RetryCount.name + rowInstanceId, 1251),
     (dot11MultipleRetryCount.name + rowInstanceId, 234),
     (dot11FrameDuplicateCount.name + rowInstanceId, 566),
     (dot11RTSSuccessCount.name + rowInstanceId, 867),
     (dot11RTSFailureCount.name + rowInstanceId, 231),
     (dot11AckFailureCount.name + rowInstanceId, 856),
     (dot11ReceivedFragmentCount.name + rowInstanceId, 568),
     (dot11GroupReceivedFrameCount.name + rowInstanceId, 34568),
     (dot11FCSErrorCount.name + rowInstanceId, 345),
     (dot11TransmittedFrameCount.name + rowInstanceId, 78567),
     (dot11WEPUndecryptableCount.name + rowInstanceId, 4545))
)

# Register SNMP Applications at the SNMP engine for particular SNMP context
cmdrsp.GetCommandResponder(snmpEngine, snmpContext)
cmdrsp.SetCommandResponder(snmpEngine, snmpContext)
cmdrsp.NextCommandResponder(snmpEngine, snmpContext)
cmdrsp.BulkCommandResponder(snmpEngine, snmpContext)

# Register an imaginary never-ending job to keep I/O dispatcher running forever
snmpEngine.transportDispatcher.jobStarted(1)

# Run I/O dispatcher which would receive queries and send responses
try:
    snmpEngine.transportDispatcher.runDispatcher()
except:
    snmpEngine.transportDispatcher.closeDispatcher()
    raise