SNMP协议中OID的编码规则

前言

SNMP协议基于UDP,代理软件(服务器)监听161端口,管理端(客户端)监听162端口。

正常请求:管理端发送请求到161端口,代理软件收到请求后将数据返回给管理端源端口。 主动上报:代理软件主动把数据发送管理端的162端口。

SNMP协议中请求数据主要是读和写操作。 每个操作会有一个目标对象,这个对象用OID来表示。 OID是用一串数字表示:比如.1.3.6.1.2.1.1.5表示设备名称。 并且父子节点之间用小数点(.)分隔,形成类似于文件夹的树形结构。


本文主要介绍OID的编码和解码规则。

编码:.1.3.6.1.2.1.1.5在UDP报文中是怎么表达的?

解码:我收到一串UDP报文,如何解析出它的OID值是多少?

设备名称 = .1.3.6.1.2.1.1.5 = 0x2B, 0x06, 0x01, 0x02, 0x01, 0x01, 0x05


编码规则:

最开始的2个数字.1.3是特殊规则,编码固定值:0x2B 其后面的每个OID节点数值都用一个或多个字节来表示。 如果这个值小于128,最简单的情况就用1个字节。 如果大于128则需要用多个字节: 对OID进行128整除,如果商大于128则继续整除,直到商小于128,则记为第1字节。 对余数重复上面的操作,将产生第2,3,4…字节,直到余数小于128,此时的余数记为最后1字节。 最后除了最后1字节外,前面的所有字节都要把最高位置1。

文字表达可能并不容易理解,下面多举几个例子就很容易理解了:

OID:.1.3.6.1.2.1.1.5

HEX:0x2B, 0x06, 0x01, 0x02, 0x01, 0x01, 0x05
所有数字都小于128,每个数字直接用1字节表示。

OID:.1.3.6.1.2.1.255.5

HEX: 0x2B, 0x06, 0x01, 0x02, 0x01, 0x81, 0x7F, 0x05 
由于255大于128,需要分解为多个字节:
255 = 128 * 1 + 127(商为1,余数为127,所以用2个字节表示:0x81(高位置1), 0x7F)

OID: .1.3.6.1.2.1.255.99999

HEX: 0x2B, 0x06, 0x01, 0x02, 0x01, 0x81, 0x7F, 0x86, 0x8D, 0x1F 
255 = 128 * 1 + 127(0x81, 0x7F)
99999 = 128 * 128 * 6 + 128 * 13 + 31(0x86,0x8D, 0x1F)

OID:.1.3.6.1.2.1.255.99999.4294967295

HEX:0x2B, 0x06, 0x01, 0x02, 0x01, 0x81, 0x7F, 0x86, 0x8D, 0x1F, 0x8F,0xFF,0xFF,0xFF,0x7F 
4294967295是32位无符号整数的最大值了,现实中真实的OID最大还没有超过65535。

解码规则:

解码就是编码的反过程。 第1字节0x2B是固定解码为.1.3。 后续每个字节都按下面的规则: 如果当前字节最高位为0,则OID节点就是1字节本身; 如果当前字节最高位为1,则OID节点=低7位乘以128,再加上下一字节的低7位; 如果下一字节最高位还是1,则OID节点再乘128,再加上下一字节的低7位; 直到下一字节最高位为0,结束计算。

还是把上面的例子算一算: 收到的OID原始数据是:0x2B, 0x06, 0x01, 0x02, 0x01, 0x81, 0x7F, 0x86, 0x8D, 0x1F, 0x8F,0xFF,0xFF,0xFF,0x7F

0x2B, 0x06, 0x01, 0x02, 0x01 这部分直接解码为:.1.3.6.1.2.1 0x81, 0x7F : 0x01 * 128 + 0x7F = 255 0x86, 0x8D, 0x1F : (0x06 * 128 + 0x0D) * 128 + 0x1F = 99999 0x8F,0xFF,0xFF,0xFF,0x7F :(((0x0F * 128 + 0x7F) * 128 + 0x7F) * 128 + 0x7F) * 128 + 0x7F = 4294967295


以上就是OID的编码和解码计算方法。