习吾学

徐武的技术博客

今天学习了什么?第n+2天

56 0

学习SNMP

了解MIB

昨天提到,MIB就是所谓的‌管理信息库。就是所有‌代理包含的,并且能够被‌管理站查询和设置的信息的集合。它定义了‌被管理对象的一系列属性:对象的名称、对象的访问权限和对象的数据类型等。这样一来,双方就可以识别对方的数据,从而能够实现通信。‌管理站代理申请MIB中定义的数据,‌代理识别后,将‌被管理设备提供的相关状态或参数转换为MIB定义的格式,响应给‌管理站,完成一次管理操作。

既然已经提到了MIB,那就不得不提SMI了,因为MIB就是用SMI来定义的。

我们来看看百度百科中MIB词条的相关定义,如下:

TCP/IP网络管理协议标准框架可分为三部分:

  1. 简单网络管理协议(SNMP: Simple Network Management Protocol),定义了‌管理站软件如何与‌代理通信,包括两者之间交换的消息分组的格式、含义及名字与值的表示等。此外也定义了‌被管理设备间的管理关系,即提供了管理系统的授权管理。
  2. 管理信息结构(SMI: Structure of Management Information),是描述管理信息的标准符号,说明了定义和构造MIB的总体框架,以及数据类型的表示和命名方法。
  3. 管理信息库(MIB:Management Information Base)MIB定义了‌被管理设备必须保存的数据项,允许对每个数据项进行的操作和含义,即‌管理站可访问的‌被管理设备的控制和状态信息等数据变量都保存在MIB中。MIB定义的通用化格式支持对每一个被管理设备定义其特定的MIB组,因此厂家可以采用标准的方法定义其专用的管理对象,从而可以管理许多新协议和设备,可扩展性很好。

上述三部分相互独立,每部分都定义了单独标准(RFC)。SNMP定义通信的方式和格式,但不指明具体设备上的具体数据。每种设备的数据细节在MIB中定义,这就达到了‌控制与数据相分离的目的,能提供很好的兼容性和可扩展性,而SMI又为保持MIB的简单性和可扩展性提供了很好的支持。

基于SNMP网络管理的示意图

它们之间的通信关系如下:

  • NMS通过SNMP协议与设备的Agent通信,完成对MIB的读取和修改操作,从而实现对网络设备的监控与管理。
  • SNMP是NMS与Agent之间通信的载体,通过其协议数据单元PDU(Protocol Data Unit)完成信息交换。SNMP并不负责数据的实际传输,数据交换的任务是通过UDP等传输层协议来完成的。
  • Agent是设备上的代理进程,主要工作包括与NMS通信,对设备中的MIB库进行维护,以管理和监控设备中的各个模块。
  • MIB保存设备中各个模块的信息。通过对MIB信息的读写操作来完成对设备的监控和维护。

MIB主要用途是通过SNMP查询、修改代理MIB中相应对象的值,实现对系统资源的监视和控制。

另外,MIB又可分为公有MIB与私有MIB。前者由RFC(Request For Comments)定义,主要用来对各种公有协议进行结构化设计和接口标准化处理。大多数的设备商都是按照RFC的定义来提供SNMP接口的。后者是对公有MIB的补充,当公司自行开发私有协议或者特有功能时,可以利用私有MIB来完善SNMP接口的管理功能,同时对第三方网管软件管理存在私有协议或特有功能的设备提供支持。

下面我们来深入学习了MIB的概念。MIB以树状结构进行存储,树的叶子节点表示管理对象,它可以通过从根节点开始的一条唯一路径来识别,也就是‌对象标识符OID(Object Identifier)。这些变量名取自ISO和ITU管理的对象标识符名字空间。如下图所示,我们看到第一级有三个节点:ccitt、iso、iso-ccitt。低级的对象ID分别由相关组织分配。一般网络设备取iso节点下的对象内容。

MIB树状结构示意图

OID是由一系列非负整数组成,用于标识管理对象在MIB树中的位置,由SMI来保证OID不会冲突。能够唯一标识一个MIB对象。

MIB文件一旦发布,OID就和被定义的对象绑定,不能修改。MIB节点不能被删除,只能将它的状态置为"obsolete",表示该节点已经被废除。上图中,mgmt对象可以标识为:{iso(1) org(3) dod(6) internet(1) mgmt(2)},简单标记为:1.3.6.1.2,这种标识就叫做OID‌管理站(NMS)通过‌OID引用‌代理中的对象。

再举一例,名字空间ip节点下一个名字为ipInReceivers的MIB变量被指派数字值3,因而该变量的名字为:

iso.org.dod.internet.mgmt.mib.ip.ipInReceives,相应的OID1.3.6.1.2.1.4.3。当网络管理协议在报文中使用MIB变量时,我们个变量名后还要加一个后缀,以作为该变量的一个实例。如ipInReceives的实例数字表示为:1.3.6.1.2.1.4.3.0。另外,MIB中的管理对象的OID有些需要动态确认,如IP路由表,为了指明地址202.110.45.37的下一站路由,我们可以引用这样的实例:

iso.org.dod.internet.mgmt.mib.ip. ipRouteTable.ipRouteEntry.ipRouteNextHop.202.110.45.37,其OID为1.3.6.1.2.1.4.21.1.7.202.110.45.37

下面我们以IF—MIB为例,了解下MIB对象。MIB树中有表对象、行对象和列对象。表对象由行对象构成,行对象由一系列列对象构成。

MIB节点及对象

在具体的MIB参考中,经常将行对象“Entry”描述为前缀。例如,在ifTable中描述为“该表的OID前缀为1.3.6.1.2.1.2.2”对应ifEntry

MIB文件

那么什么是MIB文件呢?

上文提到过,MIB是由SMI定义的,而SMI又是ASN.1(Abstract Syntax Notation One,抽象语法标记)的子集。它主要约定了使用到的语法、类型、宏、数据格式等。所谓的MIB文件便是指使用抽象语法标记(Abstract Syntax Notation One)ASN.1来描述MIB中各管理对象的文本文件,它通过ASN.1语法的有关文档如RFC1155、RFC1212等精确定义MIB中各管理对象。

网管侧使用网管软件导入MIB文件和设备进行标准对接,通过对MIB节点的操作以实现网络管理。

那么如何编写MIB文件呢?

通常会有相关的软件辅助,如MIB Builder、MG-SOFT MIB Browser等。我们只需要看懂即可。

所有的MIB文件均以DEFINITIONS ::= BEGIN关键字开始,以END结束。我们所有添加的节点均应在此之间。

XXX-TEST-MIB DEFINITIONS ::= BEGIN
                            ""
END

在MIB文件开始关键字后,即是‌模块引用区域。利用IMPORTS来标识,所有的模块引用及群组引用均使用FROM关键字来说明其出处,引用使用分号来结束。在一个MIB文件中,所有引用到的数据类型均应有引用。

IMPORTS
                enterprises
                        FROM RFC1155-SMI
                Integer32
                        FROM SNMPv2-SMI
                DisplayString
                        FROM SNMPv2-TC;

相关语法内容实在是太多了,暂时就整理到这吧。

参考文章:

http://m.elecfans.com/article/615941.html

http://support.huawei.com/enterprise/docinforeader!loadDocument1.action?contentId=DOC1000097258&partNo=10042

https://wenku.baidu.com/view/46184f6ef5335a8102d2203a.html

https://wenku.baidu.com/view/3b725c391711cc7931b716a1.html

学习PySNMP

PySNMP一款跨平台,纯Python编写的SNMP引擎实现。它支持SNMP引擎在‌代理‌管理站的所有功能。

‌下载PySNMP

pip install pysnmp

‌获取SNMP变量

from pysnmp.hlapi import *

errorIndication, errorStatus, errorIndex, varBinds = next(
    getCmd(SnmpEngine(),
           CommunityData('public', mpModel=0),
           UdpTransportTarget(('demo.snmplabs.com', 161)),
           ContextData(),
           ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)))
)

if errorIndication:
    print(errorIndication)
elif errorStatus:
    print('%s at %s' % (errorStatus.prettyPrint(),
                        errorIndex and varBinds[int(errorIndex) - 1][0] or '?'))
else:
    for varBind in varBinds:
        print(' = '.join([x.prettyPrint() for x in varBind]))

这是官方提供的一个例子,执行该脚本将会执行SNMP的GET操作,获取sysDescr.0对象,这是一个公开可用的SNMP Command Responder(demo.snmplabs.com)。

执行成功后,结果为

SNMPv2-MIB::sysDescr.0 = Linux zeus 4.8.6.5-smp #2 SMP Sun Nov 13 14:58:11 CDT 2016 i686

‌发送SNMP Trap

想给demo.snmplabs.com中列出的宿主‌Notification Receiver发送Trap消息,可用如下代码

from pysnmp.hlapi import *

errorIndication, errorStatus, errorIndex, varBinds = next(
    sendNotification(
        SnmpEngine(),
        CommunityData('public', mpModel=0),
        UdpTransportTarget(('demo.snmplabs.com', 162)),
        ContextData(),
        'trap',
        NotificationType(
            ObjectIdentity('1.3.6.1.6.3.1.1.5.2')
        ).addVarBinds(
            ('1.3.6.1.6.3.1.1.4.3.0', '1.3.6.1.4.1.20408.4.1.1.2'),
            ('1.3.6.1.2.1.1.1.0', OctetString('my system'))
        )
    )
)

if errorIndication:
    print(errorIndication)

许多ASN.1 MIB文件可以通过mibs.snmplabs.com进行下载,也可以配置PySNMP自动下载他们

‌数据类型

我们知道MIB是由SMI定义的,SMI提出了十一种基本数据类型,用来描述被管理对象状态,他们要不是纯ASN.1类型,要不就是他们的特例。

  • ASN.1类型

    • INTEGER(整型)
    • OCTET STRING(八位字符串)
    • OBJECT IDENTIFIER(对象标识符)
  • 基本ASN.1类型的SNMP特定子类型有:
    • Integer32/Unsigned32 - 32-bit integer
    • Counter32/Counter64 - ever increasing number
    • Gauge32 - positive, non-wrapping 31-bit integer
    • TimeTicks - time since some event
    • IPaddress - IPv4 address
    • Opaque - uninterpreted ASN.1 string

对于标量类型(scalar types),SNMP定义了一种方式:把他们收集在一个有序数组中。从这些数组可以建立一个二维表。

PySNMP依赖于PyASN1包来模型化所有的SNMP类型,通过PyASN1,ASN.1类型实例可以表述为看起来像一个字符串或者整数的python对象。

我们可以相互转换PyASN1对象与Python类型,PyASN1对象可以进行基本的算术运算(数字)或字符串操作(串接等)。所有的SNMP基本类型和相对应的Python对象一样,都是不可变的。

In[2]: from pyasn1.type.univ import *

In[3]: Integer(21) * 2
Out[3]: <Integer value object at 0x106498250 tagSet <TagSet object at 0x105a96b50 tags 0:0:2> payload [42]>

In[4]: Integer(-1) + Integer(1)
Out[4]: <Integer value object at 0x106316f50 tagSet <TagSet object at 0x105a96b50 tags 0:0:2> payload [0]>

In[5]: int(Integer(42))
Out[5]: 42

In[6]: OctetString('Hello') + '. ' + OctetString(hexValue='5079534e4d5021')
Out[6]: <OctetString value object at 0x1063e9290 tagSet <TagSet object at 0x105a9f290 tags 0:0:4> encoding iso-8859-1 payload [Hello. PySNMP!]>

通过PySNMP传输和接收数据时,PySNMP库用户可能会遇到PyASN1类和对象。

我们会深入讨论的一个数据类型是OBJECT IDENTIFIER,它被用来命名一个对象。在该系统中,对象用层次式方式标识。

Object Identifier

相关概念前面已经介绍过,只需要知道它是由点和数字构成,能够唯一定义一个MIB对象即可。

In PyASN1 model, OID looks like an immutable sequence of numbers. Like it is with Python tuples, PyASN1 OID objects can be concatinated or split apart. Subscription operation returns a numeric sub-OID

在PyASN1模块中,OID像不可变数字序列,类似于Python元组。PyASN1中的OID对象能够被拼接或切割。Subscription操作返回一个数字的子OID。

In[7]: from pyasn1.type.univ import *

In[8]: internetId = ObjectIdentifier((1, 3, 6, 1))

In[9]: internetId
Out[9]: <ObjectIdentifier value object at 0x106768090 tagSet <TagSet object at 0x105a9f790 tags 0:0:6> payload [1.3.6.1]>

In[10]: print internetId
1.3.6.1

In[11]: internetId[2]
Out[11]: 6

In[12]: [ x for x in internetId ]
Out[12]: [1, 3, 6, 1]

In[13]: internetId + (2,)
Out[13]: <ObjectIdentifier value object at 0x10676c810 tagSet <TagSet object at 0x105a9f790 tags 0:0:6> payload [1.3.6.1.2]>

In[14]: type(internetId)
Out[14]: pyasn1.type.univ.ObjectIdentifier

In[15]: internetId[1:3]
Out[15]: <ObjectIdentifier value object at 0x106697210 tagSet <TagSet object at 0x105a9f790 tags 0:0:6> payload [3.6]>

In[16]: internetId[1] = 2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-16-3f0fb126c277> in <module>()
----> 1 internetId[1] = 2

TypeError: 'ObjectIdentifier' object does not support item assignment

‌对象集合

MIB的概念前面也已经说过,这里不再详谈。每一个被管理设备上均维护一个数据库,储存写入MIB的各个定义值。所以,数据实际上并不依赖于这个数据库,而依赖于其实现。MIB文件从来没有包含数据,认识这一点很重要,他们的功能与数据库模式相似而不是与数据库存储相似。

为了恰当地组织MIB模块与对象,所有产品(来自各个厂商)的所有可管理特性排列在MIB树结构中。每一个MIB模块和对象均被一个OID唯一标识。

SNMP管理实体和被管理实体均可以消费MIB消息。

  • 管理实体
    • 通过MIB对象名查询OID
    • 转换值为合适的MIB对象类型
    • 阅读其他人留下的注释
  • 被管理实体
    • 在代码中实现MIB对象

从人的角度看,MIB是一个文本文件,使用ASN.1语言的子集(即SMI)编写。我们维护了一个超过9000个模块的MIB集合,你可以在你的项目中使用它。

PySNMP转换ASN.1 MIB文件为Python模块,然后SNMP引擎在运行时按需加载模块。PySNMP MIB模块是通用的:同一个模块可以同时被管理实体和被管理实体使用。

MIB转换是由PySNMP自动执行的,但是技术上,它也能被PySNMP姊妹项目PySMI处理。当然,你也可以使用PySMI的mibdump.py工具手动完成这种转换。

PySNMP架构

PySNMP内部组件

‌PySNMP常见操作

‌创建SNMP引擎

SNMP引擎是核心,保护伞。所有的PySNMP操作都涉及到SnmpEngine对象实例。PySNMP APP可以运行多个独立SNMP引擎,每个都被它自己的SnmpEngine对象操纵

In[1]: from pysnmp.hlapi import *

In[2]: SnmpEngine()
Out[2]: SnmpEngine(snmpEngineID=<SnmpEngineID value object at 0x108319490 subtypeSpec <ConstraintsIntersection object at 0x108319150 consts <ValueSizeConstraint object at 0x107a416d0 consts 0, 65535>, <ValueSizeConstraint object at 0x108319110 consts 5, 32>> tagSet <TagSet object at 0x107a0c790 tags 0:0:4> encoding iso-8859-1 payload [0x80004fb8054d61...6c6f6361c4004638]>)

SNMP引擎有一个独立的标识符,它可以被自动赋值,也可以管理方式赋值。这个标识符在SNMP协议操作中会被使用

‌执行SNMP查询

我们将会发送SNMP GET命令从SNMP代理中读取MIB对象。为此我们将会调用同步高级API getCmd()函数。也可以使用类似的方式调用相应的函数来执行SNMP命令

In[1]: from pysnmp.hlapi import *

In[2]: [ x for x in dir() if 'Cmd' in x]
Out[2]: ['bulkCmd', 'getCmd', 'nextCmd', 'setCmd']

In[3]: getCmd
Out[3]: <function pysnmp.hlapi.asyncore.sync.cmdgen.getCmd>

‌选择SNMP协议和证书

我们有三个SNMP协议版本可供选择。想使用SNMPv1/v2c,我们可以传递合适的CommunityData类初始化实例;想使用v3可以传递UsmUserData类实例。

SNMP社区名字,在你选择v1/v2c时,就通过CommunityData对象传给SNMP LCD

In[4]: CommunityData('public', mpModel=0) # SNMPv1
Out[4]: CommunityData(communityIndex='s-4760772078027520392', communityName=<COMMUNITY>, mpModel=0, contextEngineId=None, contextName='', tag='', securityName='s-4760772078027520392')

In[5]: CommunityData('public', mpModel=1) # SNMPv2c
Out[5]: CommunityData(communityIndex='s5738328248839393531', communityName=<COMMUNITY>, mpModel=1, contextEngineId=None, contextName='', tag='', securityName='s5738328248839393531')

使用UsmUserData对象进行LCD配置暗示使用SNMPv3。除了需要设置USM用户名字,UsmUserData对象也可以携带加密秘钥和加密协议给SNMP引擎LCD。

In[6]: UsmUserData('testuser', authKey='myauthkey')
Out[6]: UsmUserData(userName='testuser', authKey=<AUTHKEY>, privKey=<PRIVKEY>, authProtocol=(1, 3, 6, 1, 6, 3, 10, 1, 1, 2), privProtocol=(1, 3, 6, 1, 6, 3, 10, 1, 2, 1), securityEngineId='<DEFAULT>', securityName='testuser')

In[7]: UsmUserData('testuser', authKey='myauthkey', privKey='myenckey')
Out[7]: UsmUserData(userName='testuser', authKey=<AUTHKEY>, privKey=<PRIVKEY>, authProtocol=(1, 3, 6, 1, 6, 3, 10, 1, 1, 2), privProtocol=(1, 3, 6, 1, 6, 3, 10, 1, 2, 2), securityEngineId='<DEFAULT>', securityName='testuser')

PySNMP支持md5和sha消息认证算法,des,aes128/192/356和3des加密算法。

为了简便,我们将使用SNMPv2。虽然不完全安全,但它仍然是使用最广泛的SNMP版本。

‌设置传输和目标

PySNMP支持UDP-over-IPv4和UDP-over-IPv6网络传输。 在这个例子里,我们将会查询demo.snmplabs.com网站上可通过IPv4访问的public SNMP simulator。传输配置以相应的合适的UdpTransportTarget和Udp6TransportTarget对象传递给SNMP LCD。

In[10]: from pysnmp.hlapi import *

In[11]: g = getCmd(SnmpEngine(),
    ...:             CommunityData('public'),
    ...:             UdpTransportTarget(('demo.snmplabs.com', 161)),

‌指定MIB对象

我们想要指定我们想要读取的MIB对象。在协议层,MIb对象由OID标识,但是人们想要用名字来处理他们。

 ~ ⮀ snmpget -v2c -c public demo.snmplabs.com SNMPv2-MIB::sysDescr.0
SNMPv2-MIB::sysDescr.0 = STRING: Linux zeus 4.8.6.5-smp #2 SMP Sun Nov 13 14:58:11 CDT 2016 i686
 ~ ⮀ snmpget -v2c -c public demo.snmplabs.com 1.3.6.1.2.1.1.1.0
SNMPv2-MIB::sysDescr.0 = STRING: Linux zeus 4.8.6.5-smp #2 SMP Sun Nov 13 14:58:11 CDT 2016 i686

对象名字和OID都来自于MIB。名字和OID的关联由称作OBJECT-TYPE的高级SMI结构完成。这里有MIB对象定义的例子:sysUpTime,它的OID是…mgmt.mib-2.system.3,它的值类型是TimeTicks

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才一个完全可解析的状态。ObjectIdentity可以由MIB对象名字初始化,之后他的行为就类似OID了。

未完待续...

参考文档:

http://snmplabs.com/pysnmp/docs/tutorial.html

https://gtcsq.readthedocs.io/en/latest/py_doc/pysnmp_doc.html

常用mib信息

今天学习了什么?第n+3天
Comments
Write a Comment