美文网首页
pysnmp 常用操作

pysnmp 常用操作

作者: Joncc | 来源:发表于2019-08-23 15:45 被阅读0次

常用操作
在本教程中,我们将逐步构建并运行一些不同的SNMP命令请求和通知。我们将使用 最简单的PySNMP同步高级API。

创建SNMP引擎

SNMP引擎是PySNMP中的一个核心伞形对象。所有PySNMP操作都涉及SnmpEngine类实例。PySNMP应用程序可以运行多个独立的SNMP引擎,每个引擎都由自己的SnmpEngine对象引导。

>>> from pysnmp.hlapi import *
>>>
>>> SnmpEngine()
SnmpEngine(snmpEngineID=OctetString(hexValue='80004fb80567'))
SNMP引擎具有可以自动或管理分配的唯一标识符。此标识符用于SNMP协议操作。

进行SNMP查询

我们将发送SNMP GET命令以从SNMP代理读取MIB对象。为此,我们将调用同步,高级 getCmd()功能。通过调用相应的函数,可以以不同的方式使用其他SNMP命令。

>>> from pysnmp.hlapi import *
>>> [ x for x in dir() if 'Cmd' in x]
['bulkCmd', 'getCmd', 'nextCmd', 'setCmd']
>>> getCmd
<function getCmd at 0x222b330>

选择SNMP协议和凭证

我们可以选择三种SNMP协议版本。要使用SNMP版本1或2c,我们传递正确初始化的CommunityData类实例 。对于第三个SNMP版本,我们传递UsmUserData类实例。

SNMP社区名称以及SNMP v1和v2c之间的选择通过CommunityData 对象传送到SNMP LCD 。

>>> from pysnmp.hlapi import *
>>>
>>> CommunityData('public', mpModel=0)  # SNMPv1
CommunityData('public')
>>> CommunityData('public', mpModel=1)  # SNMPv2c
CommunityData('public')

使用UsmUserData对象进行LCD配置意味着使用SNMPv3。除了设置USM用户名外, UsmUserData对象还可以携带加密密钥和加密协议到SNMP引擎LCD。

>>> from pysnmp.hlapi import *
>>>
>>> UsmUserData('testuser', authKey='myauthkey')
UsmUserData(userName='testuser', authKey=<AUTHKEY>)
>>> UsmUserData('testuser', authKey='myauthkey', privKey='myenckey')
UsmUserData(userName='testuser', authKey=<AUTHKEY>, privKey=<PRIVKEY>)

PySNMP支持MD5和SHA消息认证算法,DES,AES128 / 192/256和3DES加密算法。

为简单起见,我们使用SNMPv2。虽然完全不安全,但它仍然是最受欢迎的SNMP版本。

>>> from pysnmp.hlapi import *
>>>
>>> g = getCmd(SnmpEngine(), CommunityData('public'),
...

设置传输和目标

PySNMP支持UDP-over-IPv4和UDP-over-IPv6网络传输。在此示例中,我们将 在因特网上通过demo.snmplabs.com查询 IPv4上可用的公共SNMP模拟器。传输配置分别以正确初始化或 对象的形式传递给SNMP LCD 。UdpTransportTargetUdp6TransportTarget

>>> from pysnmp.hlapi import *
>>>
>>> g = getCmd(SnmpEngine(),
...            CommunityData('public'),
...            UdpTransportTarget(('demo.snmplabs.com', 161)),
...

寻址SNMP上下文

SNMP上下文是SNMP(v3)消息头中的参数,用于处理由受管实体上的SNMP引擎提供的特定MIB集合。SNMP引擎可以提供许多相同的MIB对象,这些对象代表完全不同的硬件或软件实例。这是可以使用SNMP上下文的地方。

要在高级API上指示SNMP上下文,ContextData应使用正确初始化的 对象。在本例中,我们将使用'empty'上下文(默认)。

>>> from pysnmp.hlapi import *
>>>
>>> g = getCmd(SnmpEngine(),
...            CommunityData('public'),
...            UdpTransportTarget(('demo.snmplabs.com', 161)),
...            ContextData(),
...

指定MIB对象
最后,我们必须指定我们想要读取的MIB对象。在协议级别,MIB对象由OID标识,但人们倾向于通过名称来解决它们:

$ snmpget -v2c -c public demo.snmplabs.com SNMPv2-MIB::sysDescr.0
SNMPv2-MIB::sysDescr.0 = STRING: SunOS zeus.snmplabs.com
$
$ snmpget -v2c -c public demo.snmplabs.com 1.3.6.1.2.1.1.1.0
SNMPv2-MIB::sysDescr.0 = STRING: SunOS zeus.snmplabs.com

对象名称和OID都来自MIB。名称和OID链接由名为OBJECT-TYPE的高级SMI构造完成。以下是带有OID ... mgmt.mib-2.system.3和值类型TimeTicks的sysUpTime的示例MIB对象定义。

sysUpTime OBJECT-TYPE
    SYNTAX      TimeTicks
    MAX-ACCESS  read-only
    STATUS      current
    DESCRIPTION
            "The time (in hundredths of a second) since
            the network management portion of the system
            was last re-initialized."
    ::= { system 3 }

在PySNMP中,我们使用ObjectIdentity负责MIB对象识别的类。ObjectIdentity 表示从人的角度处理MIB对象的方法。它需要咨询MIB才能进入完全“已解决”的状态。可以使用MIB对象名称初始化ObjectIdentity,在MIB查找后,它开始表现得像OID。

>>> from pysnmp.hlapi import *
>>>
>>> x = ObjectIdentity('SNMPv2-MIB', 'system')
>>> # ... calling MIB lookup ...
>>> tuple(x)
(1, 3, 6, 1, 2, 1, 1, 1)
>>> x = ObjectIdentity('iso.org.dod.internet.mgmt.mib-2.system.sysDescr')
>>> # ... calling MIB lookup ...
>>> str(x)
'1.3.6.1.2.1.1.1'

MIB解析意味着将MIB对象名称服务到OID转换中,反之亦然。

在ObjectType类实例表示对象类型中PySNMP SMI constuct。ObjectType是一个引用ObjectIdentity和SNMP类型实例的容器对象。作为Python对象,它看起来像(OID,value)的元组。

>>> from pysnmp.hlapi import *
>>> x = ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0), 'Linux i386 box'))
>>> # ... calling MIB lookup ...
>>> x[0].prettyPrint()
'SNMPv2-MIB::sysDescr.0'
>>> x[1].prettyPrint()
'Linux i386 box'

尾随零表示MIB对象实例。MIB中描述的对象只是声明,它们从不包含任何数据。数据存储在MIB对象实例中,通过向MIB对象标识符附加额外信息(称为索引)来解决。

对于标量MIB对象,索引按惯例为“0”。该 ObjectIdentity进行类采用指数作为其初始化。

>>> x = ObjectIdentity('SNMPv2-MIB', 'system', 0)
>>> # ... calling MIB lookup ...
>>> tuple(x)
(1, 3, 6, 1, 2, 1, 1, 1, 0)

我们将读取SNMPv2-MIB模块中定义的sysDescr标量MIB对象实例。

>>> from pysnmp.hlapi import *
>>> g = getCmd(SnmpEngine(),
...            CommunityData('public'),
...            UdpTransportTarget(('demo.snmplabs.com', 161)),
...            ContextData(),
...            ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)))

默认情况下,PySNMP将在您的本地文件系统中搜索您引用的ASN.1 MIB文件。它还可以配置为从远程主机自动下载它们,如 示例 中所示。我们维护了一 组可在SNMP项目中使用的ASN.1 MIB模块。

注意
“ASN.1 MIB”是标识符和类型的纯文本描述。它是制造商分发用于描述其SNMP服务的通用格式,与Perl的Net :: SNMP和几乎所有SNMP工具使用的格式相同。

读取标量值
我们终于可以发送SNMP查询,并希望收到一些有意义的回复。

同步API的显着特点是它是围绕Python生成器的思想构建的。任何函数调用都以生成器对象结束。对生成器对象的迭代执行实际的SNMP通信。在每次迭代中,构建并发送SNMP消息,等待,接收和解析响应。

>>> from pysnmp.hlapi import *
>>>
>>> g = getCmd(SnmpEngine(),
...            CommunityData('public'),
...            UdpTransportTarget(('demo.snmplabs.com', 161)),
...            ContextData(),
...            ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysUpTime', 0)))
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.3.0'), TimeTicks(44430646))])

使用SNMP表

SNMP定义了表的概念。当单个给定的MIB对象可以应用于属性的许多实例时,使用表。例如,网络接口的属性被放入SNMP表中。属性的每个实例都通过附加到基本MIB对象的后缀来寻址。

表在MIB中指定,它们的索引(或索引)通过INDEX子句声明。表索引是非零整数,或字符串或任何基本SNMP类型。

在协议级别,所有索引都形成OID部分。对于人类舒适地处理索引,SNMP管理应用程序依赖于DISPLAY-HINT子句在其OID和SNMP类型特定的,人性化的表示之间进行自动索引转换。

ifEntry OBJECT-TYPE
    SYNTAX      IfEntry
    INDEX   { ifIndex }
::= { ifTable 1 }

ifIndex OBJECT-TYPE
    SYNTAX      InterfaceIndex
::= { ifEntry 1 }

ifDescr OBJECT-TYPE
    SYNTAX      DisplayString (SIZE (0..255))
::= { ifEntry 2 }

InterfaceIndex ::= TEXTUAL-CONVENTION
    DISPLAY-HINT "d"
    SYNTAX       Integer32 (1..2147483647)

用PySNMP的说法:

>>> x = ObjectIdentity('IF-MIB', 'ifDescr', 123)
>>> # ... calling MIB lookup ...
>>> str(x)
'1.3.6.1.2.1.2.2.1.2.123'

某些SNMP表由许多索引编制索引。这些索引中的每一个都成为彼此相连的OID的一部分,并最终成为MIB对象OID。

从语义角度来看,每个索引都反映了MIB对象的重要且不同的属性。

tcpConnectionEntry OBJECT-TYPE
    SYNTAX  TcpConnectionEntry
    INDEX   { tcpConnectionLocalAddressType,
              tcpConnectionLocalAddress,
              tcpConnectionLocalPort,
              tcpConnectionRemAddressType,
              tcpConnectionRemAddress,
              tcpConnectionRemPort }
::= { tcpConnectionTable 1 }

tcpConnectionLocalPort OBJECT-TYPE
    SYNTAX     InetPortNumber
::= { tcpConnectionEntry 3 }
PySNMP的ObjectIdentity类在人类友好的表示中获取任意数量的索引并将它们转换为完整的OID:

>>> x = ObjectIdentity('TCP-MIB', 'tcpConnectionState',
...                    'ipv4', '195.218.254.105', 41511,
...                    'ipv4', '194.67.1.250', 993)
>>> # ... calling MIB lookup ...
>>> str(x)
'1.3.6.1.2.1.6.19.1.7.1.4.195.218.254.105.41511.1.4.194.67.1.250.993'

让我们为TCP连接读取TCP-MIB :: tcpConnectionState对象:

>>> from pysnmp.hlapi import *
>>>
>>> g = getCmd(SnmpEngine(),
...            CommunityData('public'),
...            UdpTransportTarget(('demo.snmplabs.com', 161)),
...            ContextData(),
...            ObjectType(ObjectIdentity('TCP-MIB', 'tcpConnectionState',
...                                      'ipv4', '195.218.254.105', 41511,
...                                      'ipv4', '194.67.1.250', 993)
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.6.19.1.7.1.4.195.218.254.105.41511.1.4.194.67.1.250.993')), Integer(5))])

SNMP命令操作

SNMP允许您请求与给定的MIB对象“下一步”的MIB对象。这样您就可以提前读取您不知道的MIB对象。MIB对象在概念上按其OID排序。此功能由该nextCmd() 功能实现。

>>> from pysnmp.hlapi import *
>>> g = nextCmd(SnmpEngine(),
...             CommunityData('public'),
...             UdpTransportTarget(('demo.snmplabs.com', 161)),
...             ContextData(),
...             ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr')))
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0'), DisplayString('SunOS zeus.snmplabs.com'))])
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.2.0'), ObjectIdentity(ObjectIdentifier('1.3.6.1.4.1.8072.3.2.10')))])

通过SNMP代理的MIB对象迭代生成器对象“walk”。

SNMPv2c引入了对GETNEXT命令的重要优化- 修订版本称为GETBULK,能够同时收集和响应一堆“下一个”MIB对象。可以使用附加的非中继器和最大重复参数来影响MIB对象的批处理。

PySNMP 在协议级别隐藏了这个GETBULK优化,为方便起见,该 bulkCmd()函数公开了与getNext()相同的生成器API 。

>>> from pysnmp.hlapi import *
>>>
>>> N, R = 0, 25
>>> g = bulkCmd(SnmpEngine(),
...             CommunityData('public'),
...             UdpTransportTarget(('demo.snmplabs.com', 161)),
...             ContextData(),
...             N, R,
...             ObjectType(ObjectIdentity('1.3.6')))
>>>
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0'), DisplayString('SunOS zeus.snmplabs.com'))])
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.2.0'), ObjectIdentifier('1.3.6.1.4.1.20408'))])

Python生成器不仅可以生成数据,还可以将数据发送到正在运行的生成器对象。高级API使用该功能为一组新的MIB对象重复相同的SNMP操作。

>>> from pysnmp.hlapi import *
>>>
>>> g = nextCmd(SnmpEngine(),
...             CommunityData('public'),
...             UdpTransportTarget(('demo.snmplabs.com', 161)),
...             ContextData(),
...             ObjectType(ObjectIdentity('IF-MIB', 'ifTable')))
>>>
>>> g.send([ObjectType(ObjectIdentity('IF-MIB', 'ifInOctets'))])
(None, 0, 0, [(ObjectType(ObjectIdentity('1.3.6.1.2.1.2.2.1.10.1'), Counter32(284817787))])

您可以通过将它们列在单个PDU中来操作许多不相关的MIB对象。响应PDU将携带MIB对象及其值的列表,其顺序与请求消息中的顺序完全相同。

>>> from pysnmp.hlapi import *
>>>
>>> g = getCmd(SnmpEngine(),
...            CommunityData('public'),
...            UdpTransportTarget(('demo.snmplabs.com', 161)),
...            ContextData(),
...            ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)),
...            ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysUpTime', 0))
... )
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0'), DisplayString('SunOS zeus.snmplabs.com')), ObjectType(ObjectIdentity('1.3.6.1.2.1.1.3.0'), TimeTicks(44430646))])

SNMP的配置管理部分依赖于SNMP SET命令。尽管在管理实体方面的实施证明有些苛刻(由于锁定和交易行为要求)。因此供应商倾向于将其排除在外,从而使管理实体成为只读。

PySNMP 通过 函数统一支持SETsetCmd()。

>>> from pysnmp.hlapi import *
>>>
>>> g = setCmd(SnmpEngine(),
...            CommunityData('public'),
...            UdpTransportTarget(('demo.snmplabs.com', 161)),
...            ContextData(),
...            ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0), 'Linux i386')
... )
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0'), DisplayString('Linux i386'))])

发送SNMP通知

受管实体可以向管理实体发送未经请求的消息。这在SNMP中称为通知。通知有助于减少轮询,这可能会成为大型网络的问题。

枚举SNMP通知,每个通知都有明确的语义。这是通过名为NOTIFICATION-TYPE的特殊高级SMI结构完成的 。与定义MIB对象的OBJECT-TYPE一样, NOTIFICATION-TYPE具有唯一的OID,但是SNMP值不是引用一系列其他MIB对象。使用OBJECTS子句指定这些MIB对象,并且在发送通知时,它们的当前值包含在通知消息中。

linkUp NOTIFICATION-TYPE
    OBJECTS { ifIndex, ifAdminStatus, ifOperStatus }
    STATUS  current
    DESCRIPTION
        "..."
::= { snmpTraps 4 }

为了在PySNMP中建模NOTIFICATION-TYPE构造,我们有NotificationType一个容器对象的 类。它由ObjectIdentity类标识 并引用一系列ObjectType类实例。

从行为的角度来看,NotificationType看起来像一系列 ObjectType类实例。

>>> from pysnmp.hlapi import *
>>>
>>> x = NotificationType(ObjectIdentity('IF-MIB', 'linkUp'))
>>> # ... calling MIB lookup ...
>>> >>> [ str(y) for x in n ]
['SNMPv2-MIB::snmpTrapOID.0 = 1.3.6.1.6.3.1.1.5.3', 'IF-MIB::ifIndex = ', 'IF-MIB::ifAdminStatus = ', 'IF-MIB::ifOperStatus = ']

使用PySNMP发送通知与发送SNMP命令没有太大区别。不同之处在于如何构建PDU变量。SNMP中有两种不同的通知:trap和 通知。

使用trap,代理与管理器之间的通信是单向的 - 不发送响应或确认。

>>> from pysnmp.hlapi import *
>>>
>>> g = sendNotification(SnmpEngine(),
...                      CommunityData('public'),
...                      UdpTransportTarget(('demo.snmplabs.com', 162)),
...                      ContextData(),
...                      'trap',
...                      NotificationType(ObjectIdentity('IF-MIB', 'linkUp'), instanceIndex=(123,))
... )
>>> next(g)
(None, 0, 0, [])

该通知通知是很像的命令。不同之处在于PDU格式。通知用于管理器到管理器的通信以及代理到管理器。

>>> from pysnmp.hlapi import *
>>>
>>> g = sendNotification(SnmpEngine(),
...                      CommunityData('public'),
...                      UdpTransportTarget(('demo.snmplabs.com', 162)),
...                      ContextData(),
...                      'inform',
...                      NotificationType(ObjectIdentity('IF-MIB', 'linkUp'), instanceIndex=(123,))
... )
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.3.0'), TimeTicks(0)), ObjectType(ObjectIdentity('1.3.6.1.6.3.1.1.4.1.0'), ObjectIdentity('1.3.6.1.6.3.1.1.5.4')), ObjectType(ObjectName('1.3.6.1.2.1.2.2.1.1.123'), Null('')), ObjectType(ObjectIdentity('1.3.6.1.2.1.2.2.1.7.123'), Null('')), ObjectType(ObjectIdentity('1.3.6.1.2.1.2.2.1.8.123'), Null(''))])

在后一个示例中,您可以看到从IF-MIB :: linkUp通知自动扩展的MIB对象(ifIndex,ifAdminStatus,ifOperStatus)。要通过索引处理特定的SNMP表对象行,可以通过 instanceIndex参数将MIB对象的索引部分传递给NotificationType。

如您所见,扩展MIB对象的实际值为NULL。那是因为在这些示例中,我们的简单脚本无法访问这些MIB对象。我们可以通过将NotificationType传递给类似字典的对象来提供缺少的信息,该对象将MIB对象OID映射到当前值。

>>> from pysnmp.hlapi import *
>>>
>>> mib = {ObjectIdentifier('1.3.6.1.2.1.2.2.1.1.123'): 123,
...        ObjectIdentifier('1.3.6.1.2.1.2.2.1.7.123'): 'testing',
...        ObjectIdentifier('1.3.6.1.2.1.2.2.1.8.123'): 'up'}
>>>
>>> g = sendNotification(SnmpEngine(),
...                      CommunityData('public'),
...                      UdpTransportTarget(('demo.snmplabs.com', 162)),
...                      ContextData(),
...                      'inform',
...                      NotificationType(ObjectIdentity('IF-MIB', 'linkUp'), instanceIndex=(123,), objects=mib)
... )
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.3.0'), TimeTicks(0)), ObjectType(ObjectIdentity('1.3.6.1.6.3.1.1.4.1.0'), ObjectIdentity('1.3.6.1.6.3.1.1.5.4')), ObjectType(ObjectName('1.3.6.1.2.1.2.2.1.1.123'), InterfaceIndex(123)), ObjectType(ObjectIdentity('1.3.6.1.2.1.2.2.1.7.123'), Integer(3)), ObjectType(ObjectIdentity('1.3.6.1.2.1.2.2.1.8.123'), Integer(1))])

大量消息传递
在管理大型网络时,按顺序读取MIB对象会引入延迟。在某种程度上,延迟变得无法忍受。并行化查询的解决方案是众所周知的 - 您可以通过将单个操作卸载到多个进程或多个执行线程或围绕异步I / O模型构建应用程序来实现。

与其他解决方案相比,异步模型最轻量级且可扩展。这个想法很简单:永远不要等待I / O - 尽可能做其他事情。这背面是执行流程变得非线性,这会伤害人类读者的程序分析。

PySNMP高级API适用于与三种流行的异步I / O框架的工作- asyncore,twisted和 asyncio。有关异步API的更多信息,请参阅PySNMP 库参考 和示例。

相关文章

网友评论

      本文标题:pysnmp 常用操作

      本文链接:https://www.haomeiwen.com/subject/dbltectx.html