背景
SNMP 协议可以跟远程主机进行通信,实现对目标主机的监控。
路由器的 ARP
路由器的 APR 信息表是通过两个 oid 结果关联形成的,先获取 oid 为 1.3.6.1.2.1.4.22.1.2
标识的主机的 MAC 物理地址信息,再获取 oid 为 1.3.6.1.2.1.4.22.1.3
的 IP 地址信息,二者通过 OID 关联,形成一张 ARP 信息表。snmp4j 的 TableUtil
类可以自动将两个 OID 的结果根据 OID 自动完成关联,形成一张表,这就是解决本文问题的核心要素。
snmpwalk 工具
使用 yum -y install net-snmp*
命令可以在 Linux 操作系统中安装 snmpwalk 工具,用于测试。
常用 OID :
1.3.6.1.2.1.4.22.1.3 主机的IP地址
1.3.6.1.2.1.4.22.1.2 主机的MAC地址
1.3.6.1.2.1.3.1.1.2 直接得到 ARP 地址信息表
snmp4j PDU 发送请求
PUD 是 snmp4j 封装的通信包类,用它可以完成一次 SNMP 请求,但是它有一个缺陷,只能获取到某个 oid 列表数据中的第一个,基本用法为:
try{
//设定CommunityTarget
CommunityTarget myTarget = new CommunityTarget();
//定义远程主机的地址
//Address deviceAdd = GenericAddress.parse("udp:192.168.1.233/161");
//定义本机的地址
Address localAdd = GenericAddress.parse("udp:localhost/161");
//设定远程主机的地址
//myTarget.setAddress(deviceAdd);
//设定本地主机的地址
myTarget.setAddress(localAdd);
//设置snmp共同体
myTarget.setCommunity(new OctetString("public"));
//设置超时重试次数
myTarget.setRetries(2);
//设置超时的时间
myTarget.setTimeout(5*60);
//设置使用的snmp版本
myTarget.setVersion(SnmpConstants.version2c);
//设定采取的协议
TransportMapping transport = new DefaultUdpTransportMapping();//设定传输协议为UDP
//调用TransportMapping中的listen()方法,启动监听进程,接收消息,由于该监听进程是守护进程,最后应调用close()方法来释放该进程
transport.listen();
//创建SNMP对象,用于发送请求PDU
Snmp protocol = new Snmp(transport);
//创建请求pdu,获取mib
PDU request = new PDU();
//调用的add方法绑定要查询的OID
request.add(new VariableBinding(new OID("1.3.6.1.2.1.1.1")));
request.add(new VariableBinding(new OID(new int[] {1,3,6,1,2,1,1,2})));
//调用setType()方法来确定该pdu的类型
request.setType(PDU.GETNEXT);
//调用 send(PDU pdu,Target target)发送pdu,返回一个ResponseEvent对象
ResponseEvent responseEvent = protocol.send(request, myTarget);
//通过ResponseEvent对象来获得SNMP请求的应答pdu,方法:public PDU getResponse()
PDU response=responseEvent.getResponse();
//输出
if(response != null){
System.out.println("request.size()="+request.size());
System.out.println("response.size()="+response.size());
//通过应答pdu获得mib信息(之前绑定的OID的值),方法:VaribleBinding get(int index)
VariableBinding vb1 = response.get(0);
VariableBinding vb2 = response.get(1);
System.out.println(vb1);
System.out.println(vb2);
//调用close()方法释放该进程
transport.close();
}
}catch(IOException e){
e.printStackTrace();
}
}
snmp4j 的 TableUtil 工具类
某个主机的 IP OID 对应的数据不止一条,但是通过 PDU 的 GETNEXT
方法却只能获取到一个,怎么能获取到全部的数据呢?
找到这个包的一个 TableUtil 的工具类,基本用法如下:
public static void main(String[] args) {
try {
// 设定CommunityTarget
CommunityTarget myTarget = new CommunityTarget();
// 定义远程主机的地址
Address localAdd = GenericAddress.parse("udp:127.0.0.1/161");
// 设定本地主机的地址
myTarget.setAddress(localAdd);
// 设置snmp共同体
myTarget.setCommunity(new OctetString("public"));
// 设置超时重试次数
myTarget.setRetries(2);
// 设置超时的时间
myTarget.setTimeout(5 * 60);
// 设置使用的snmp版本
myTarget.setVersion(SnmpConstants.version2c);
// 设定采取的协议
TransportMapping<?> transport = new DefaultUdpTransportMapping();// 设定传输协议为UDP
// 调用TransportMapping中的listen()方法,启动监听进程,接收消息,由于该监听进程是守护进程,最后应调用close()方法来释放该进程
transport.listen();
// 创建SNMP对象,用于发送请求PDU
Snmp protocol = new Snmp(transport);
TableUtils utils = new TableUtils(protocol, new DefaultPDUFactory(PDU.GETBULK));// GETNEXT
utils.setMaxNumRowsPerPDU(5); // only for GETBULK, set
// ARP 信息表 macOid-ipOid 得到的就是 ORP 信息表
String macOid = "1.3.6.1.2.1.4.22.1.2";
String ipOid = "1.3.6.1.2.1.4.22.1.3";
OID[] columnOids = new OID[] { new OID(macOid), new OID(ipOid) };
List<TableEvent> l = utils.getTable(myTarget, columnOids, null, null);
for (TableEvent e : l) {
VariableBinding[] columns = e.getColumns();
System.out.println(columns[0].toValueString() + "," + columns[1].toValueString());
}
transport.close();
} catch (IOException e) {
e.printStackTrace();
}
}
代码参考资源
参考资源一
参考资源二
SNMP4j 的 snmp 使用
其他参考资源:
1)https://www.cnblogs.com/yuanfy008/p/8046189.html
2)https://blog.csdn.net/SignX/article/details/1774023
3)http://www.rfyy.net/archives/638.html
4)https://bbs.csdn.net/topics/392032180