SNMP 学习中篇——v3 版本使用

背景

SNMP v3 版本是一种安全的协议,支持认证和加密过程,前面实现了 v1、v2 版本获取路由器 ARP 表的过程,这里继续完善一下 v3 版本的支持。v3 版本的特点是,增加了帐号密码认证和加密传输,所以需要安全方面的配置信息,详情如下。

v3 协议配置选项

根据 snmpwalk 命令的帮助文档可知,v3 版本的协议参数选项有:

  a) –l LEVEL 指定安全级别:noAuthNoPriv|authNoPriv|authPriv
  b) –u USER-NAME 安全名字
  c) –A PROTOCOL 验证协议:MD5|SHA。如果 -l 指定为 authNoPriv 或 authPriv 时才需要。
  d) –a PASSPHRASE 验证字符串。如果-l指定为 authNoPriv 或 authPriv 时才需要。
  e) –X PROTOCOL 加密协议:DES|AES。如果 -l 指定为 authPriv 时才需要。
  f) -x PASSPHRASE 加密字符串:如果-l指定为 authPriv 时才需要。

第一个选项,安全级别类型,其区别为:

  1. noAuthNoPriv:不认证、不加密,等价于 v1、v2 版本;所以不建议开启
  2. authNoPriv:认证不加密,只对帐号密码进行校验,数据传输不加密
  3. authPriv:既认证又加密,校验帐号密码,同时加密传输

认证和加密基础

曾研究过浏览器实现 https 协议的过程,所以很容易理解 v3 版本中的安全配置选项。在需要管理的设备上配置 SNMP v3 服务时,需设置这些安全配置信息,包括帐号、密码、认证方式、加密算法、加密密钥,然后将这些信息告知 SNMP 服务角色,双方基于此前提进行 snmp 通信。

先看看 -A 选项,它是指验证协议,算法有 MD5 和 SHA 。
MD5 是指 Message Digest ,SHA 是 Security Hash ,它们都属于摘要算法,即:不限制输入的明文长度,而生成固定长度的摘要,且不可逆。摘要算法常用来做数字签名的,在 v3 协议中,用来做密码认证。

原理为,SNMP 服务端和代理端都知道一个帐号和密码,然后通信时,服务端发送 v3 请求并用 MD5 或 SHA 摘要算法生成密码摘要发送,SNMP 代理端用同样的摘要算法生成密码的摘要信息,与接收到的摘要比对,一致,则通过认证。

-X 选项,加密算法有两种,AES(Advanced Encrypt Stnadard) 和 DES ( Data Encryption Standard ),它们都是对称加密算法,通信双方约定相同的密钥后,就能进行加密和解密了。

snmp4j 实现 v3 版本

snmp4j 工具包的官方文档中给出了 Snmp 类实现 v3 版本的示意代码,与 v2 版本不同的是,它使用的 ATarget 的实现是 UserTarget 类,并设置安全等级。

第一步,先创建 Target

UserTarget target = new UserTarget();
target.setVersion(SnmpConstants.version3);
target.setAddress(new UdpAddress(snmpInfo.getIp()+"/"+snmpInfo.getPort()));
switch (snmpInfo.getLevel()){
	case Level_noAuthNoPriv://不认证、不加密
	    target.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV);
	    break;
	case Level_authNoPriv://只认证不加密
	    target.setSecurityLevel(SecurityLevel.AUTH_NOPRIV);
	    break;
	case Level_authPriv://既认证、又 加密
	    //设置安全等级
	    target.setSecurityLevel(SecurityLevel.AUTH_PRIV);
	    
	    //设置签名方式和加密方式
	    target.setSecurityName(new OctetString(snmpInfo.getAuthProtocol()+snmpInfo.getEncryptType()));
	    break;
	}

target.setTimeout(3000);    //3s
target.setRetries(2);

第二步,创建 Snmp 对象:

TransportMapping<?> transport = new DefaultUdpTransportMapping();// 设定传输协议为UDP       
transport.listen();
Snmp manager = new Snmp(transport);

经过测试,只支持 UDP 协议,TCP 协议貌似不支持。

第三步,添加认证用户信息:

//获取摘要算法对应的 OID 对象
OID authProtocol = null;
String signatureType = snmpInfo.getAuthProtocol();
if(signatureType.equals(Signature_MD5)) {//MD5 签名方式
    authProtocol = AuthMD5.ID;
}else if(signatureType.equals(Signature_SHA)){//SHA 签名方式
    authProtocol = AuthSHA.ID;
}

//获取加密算法对应的 OID 对象
OID encryptProtocol = null;
String encryptType = snmpInfo.getEncryptType();
if(encryptType.equals(Encrypt_DES)) {
    encryptProtocol = PrivDES.ID;
}else {//加密方式有三种
    switch(encryptType) {
    case Encrypt_AES128:
	encryptProtocol = PrivAES128.ID;
	break;
    case Encrypt_AES192:
	encryptProtocol = PrivAES192.ID;
	break;
    case Encrypt_AES256:
	encryptProtocol = PrivAES256.ID;
	break;
    }
}

//创建用户安全模型对象
USM usm = new USM(SecurityProtocols.getInstance(),
                new OctetString(MPv3.createLocalEngineID()), 0);
SecurityModels.getInstance().addSecurityModel(usm);

//添加用户配置信息
usm.addUser(new OctetString(snmpInfo.getAccount()),
	new UsmUser(new OctetString(snmpInfo.getAccount()), authProtocol,
		new OctetString(snmpInfo.getPassword()), encryptProtocol,
		new OctetString(snmpInfo.getPrivateKey())));

snmpInfo 是一个存储了 v3 配置信息的实体,类的属性有:

ip:SNMP 管理设备 IP
port:通信端口,默认 161
level:安全等级
account:帐号
password:口令
authProtocol:摘要算法
encryptType:加密算法
privateKey:加密密钥

启示录

前面三部分合起来,就是一个完整的基于 snmp4j 工具包提供的 v3 版本的例子了。开始对官方给出的例子不是很明白,因为只是代码片段,也没有完整的参数说明,官网文档开着三天,因为没搞明白,没敢关。

转机发生在分析过 v3 协议的配置信息后,再对比 demo ,突然就知道了 v3 版本的配置信息对应什么参数了,这可能就是传说中的顿悟吧,就这样解决了 snmp 版本的支持!

谨以此文,记录此过程。

发布了234 篇原创文章 · 获赞 494 · 访问量 37万+

猜你喜欢

转载自blog.csdn.net/wojiushiwo945you/article/details/103206124