1

我正在尝试使用 SNMP4J 在 Java 中创建一个 SNMP TRAP/Notify 代理。陷阱/通知旨在发送到远程侦听器。

我想通过身份验证添加对 V2 和 V3 陷阱的支持。

我目前的设置:

  • 运行通知程序的开发机器。(192.168.1.61)

  • 运行 snmptrapd 的 debian 9(Stretch) (192.168.1.92) 上的 VM

我的问题简短地描述了:

  • V2 消息有效。
  • 从 Java 发送时,V3 消息被接收但不被处理。

我已经使用以下命令尝试了我的设置,确认它有效:

虚拟机:

sudo snmptrapd -f -Lo -c /usr/share/snmpdtrapd.conf

开发:

sudo snmptrap -e 0x80001370017f000101 -v 3 -a SHA -A 02m-auth -x DES -X o2m-priv -l authPriv o2m-user 192.168.1.92:162 1 .1.3.6.1.2.1.1.8

在 VM 上,它会生成以下日志消息:

2018-10-29 14:42:21 <UNKNOWN> [UDP: [192.168.1.61]:44309-> 
[192.168.1.92]:162]:
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (1) 0:00:00.01  
SNMPv2-MIB::snmpTrapOID.0 = OID: SNMPv2-MIB::sysORLastChange

现在我运行了以下代码,并确认它到达了 VM(运行 snmptrapd 命令并启用 -d 以查看 snmp 数据包实际到达)

        TransportMapping transportMapping = new DefaultUdpTransportMapping();
        Snmp snmp = new Snmp(transportMapping);
        OctetString localEngineId = new OctetString(MPv3.createLocalEngineID());

        USM usm = new USM(SecurityProtocols.getInstance(), localEngineId, 0);

        SecurityModels.getInstance().addSecurityModel(usm);


        OctetString securityName = new OctetString("o2m-user");

        OID authProtocol = AuthSHA.ID;
        OID privProtocol = PrivDES.ID;

        OctetString authPassphrase = new OctetString("o2m-auth");
        OctetString privPassphrase = new OctetString("o2m-priv");

        snmp.getUSM().addUser(securityName, new UsmUser(securityName, authProtocol, authPassphrase, privProtocol, privPassphrase));

        UserTarget target = new UserTarget();
        target.setSecurityLevel(SecurityLevel.AUTH_PRIV);
        target.setSecurityName(securityName);

        target.setAddress(new UdpAddress("192.168.1.92" + "/" + 162));
        target.setVersion(SnmpConstants.version3);

        snmp.listen();

        ScopedPDU pdu = new ScopedPDU();
        pdu.setType(PDU.TRAP);
        pdu.setContextEngineID(localEngineId);
        pdu.add(new VariableBinding(SnmpConstants.sysUpTime, new TimeTicks(1)));
        pdu.add(new VariableBinding(SnmpConstants.snmpTrapOID, new OID(".1.3.6.1.2.1.1.8")));


        System.out.println("Sending V3 trap");
        snmp.send(pdu, target);
        snmp.close();

上面的代码不会在 snmptrapd 服务器上生成任何日志消息。

我也尝试用MPv3.createLocalEngineId()实际的引擎 ID 替换,但这似乎也没有帮助。

我已经 Wireshark 了这两个请求(来自 JAVA 和来自 snmp-trap),我注意到的唯一区别是它们都有不同的 AuthorativeEngineID。

Java 有一个生成的,因为它在每个请求上都不同,snmp-trap 有一个静态的。

我究竟做错了什么?

4

2 回答 2

1

您能否附上有关到达的 snmp 数据包的详细日志?

我认为用户“o2m-user”是在 192.168.1.92 上使用 AuthorativeEngineID 0x80001370017f000101 创建的,所以我尝试用它发送陷阱消息。

所以,我更新了

snmp.getUSM().addUser(securityName, new UsmUser(securityName, authProtocol, authPassphrase, privProtocol, privPassphrase));

OctetString  authorativeEngineID = createOctetString("0x80001370017f000101");  +
snmp.getUSM().addUser(securityName, authorativeEngineID, new UsmUser(securityName, authProtocol, authPassphrase, privProtocol, privPassphrase));  -+

private OctetString createOctetString(String s) {
    if (s == null) {
        return null;
    }
    OctetString octetString = null;
    if (s.startsWith("0x")) {
        octetString = createStr16(s.substring(2));
    }
    else {
        octetString = new OctetString(s);
    }
    return octetString;
}

private OctetString createStr16(String str10) {
    String[] strs  = str10.split("");
    byte[] value = new byte[strs.length];
    for (int n = 0; n < strs.length; n++) {
        value[n] = (byte)Integer.parseInt(strs[n], 16);
    }
    return new OctetString(value);
}

之后,当我尝试发送 v3 陷阱时,收到错误SNMPv3_USM_UNKNOWN_SECURITY_NAME。然后我阅读了 SNMP4J 的 snmp.send(pdu, target) 的源代码,发现本地引擎 ID 应该与请求的 AuthorativeEngineID 相同,所以我继续设置本地引擎 ID,如下所示,

snmp.setLocalEngine(authorativeEngineID.getValue(), 0, 0);  +
snmp.listen();

然后可以发送陷阱消息而没有任何错误,但是 192.168.1.92 仍然无法匹配 engineID,详细日志如下(使用命令snmptrapd -f -d -Dusm -Lo查看日志):
注意:我的测试 authorativeEngineID是0x8000000001020305,我的测试用户名是mytrapuser2

Received 559 byte packet from UDP: [xxxxxx]:xxxxx->[xxxxxx]:162
0000: 30 82 01 B0  02 01 03 30  11 02 04 6B  E7 AD 69 02    0......0...k..i.
0016: 03 00 FF FF  04 01 00 02  01 03 04 2B  30 29 04 10    ...........+0)..
0032: 08 00 00 00  00 00 00 00  00 01 00 02  00 03 00 05    ................
0048: 02 01 00 02  01 00 04 0B  6D 79 74 72  61 70 75 73    ........mytrapus
0064: 65 72 32 04  00 04 00 30  82 01 69 04  10 08 00 00    er2....0..i.....
...

usm: USM processing begun...
usm: match on user mytrapuser2
usm: no match on engineID (08 00 00 00 00 00 00 00 00 01 00 02 00 03 00 05 )
usm: Unknown User(mytrapuser2)
...

“08 00 00 00 00 00 00 00 00 01 00 02 00 03 00 05”不等于“0x8000000001020305”,所以引擎ID不匹配错误发生了吗?我现在不确定,我会继续研究。

我的问题:
我不确定是否应该将本地引擎 ID 设置为 0x80001370017f000101,如果没有,如何避免 SNMPv3_USM_UNKNOWN_SECURITY_NAME 问题?

于 2018-10-30T07:21:57.910 回答
0

在Vicky的问题的帮助下,我实际上已经确定了问题所在。

我没有设置正确的 ID,忘记在两个地方设置 ID。

我在服务器端的引擎 ID 实际上是创建的程序 localEngineID 的前 9 个字节Mpv3.createLocaleEngineId()

所以我实际上只是对 ID 进行了子串化,如下所示:

OctetString localEngineId = new OctetString(MPv3.createLocalEngineID()).substring(0, 9);

并在 addUser 部分添加了 localEngineId,如下所示:

snmp.getUSM().addUser(securityName, localEngineId, new UsmUser(securityName, authProtocol, authPassphrase, privProtocol, privPassphrase));

对于 snmp 引擎 ID:

snmp.setLocalEngine(localEngineId.getValue(), 0, 0);

这解决了我的问题,并且消息记录在snmptrapd守护进程中。

于 2018-10-30T09:59:51.353 回答