1

I'm trying to create a SNMP TRAP/Notify agent in Java using SNMP4J. The traps/notify's are meant to be sent to a remote listener.

I'd like to add support for V2 and V3 traps with authentication.

My setup currently:

  • Dev machine running the notifier. (192.168.1.61)

  • VM on debian 9(Stretch) (192.168.1.92) running snmptrapd

My problem described shortly:

  • V2 messages work.
  • V3 messages are received but are not processed when send from Java.

I've tried my settings with the following command, confirming it worked:

VM:

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

Dev:

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

On the VM it generates this log message:

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

Now I've ran the following code, and have confirmed it arrives at the VM(ran the snmptrapd command with -d enabled to see the snmp packet actually arrived)

        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();

The code above doesn't generate any log messages on the snmptrapd server.

I've also tried replacing the MPv3.createLocalEngineId() with the actual engine id, but that didn't seem to help either.

I've Wiresharked both requests(From JAVA and from snmp-trap) and the only difference that I noticed is that they both have a different AuthorativeEngineID.

Java had a generated one as it differs on each request, snmp-trap has a static one.

What am I doing wrong?

2 Answers2

1

Can you attach the detail logs about the arrived snmp packet?

I think that the user "o2m-user" has been create with AuthorativeEngineID 0x80001370017f000101 on 192.168.1.92, so I tried to send the trap message with it.

So, I updated

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

to

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);
}

After that, when I tried to send v3 trap, I got an error SNMPv3_USM_UNKNOWN_SECURITY_NAME. Then I read the source code of SNMP4J's snmp.send(pdu, target) and found that the local engine ID should be same with the requested AuthorativeEngineID, so I cotinue to set the local engine ID like below,

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

Then the trap message could be sent without any error, but 192.168.1.92 still could not match on engineID, detail logs are as below (use command snmptrapd -f -d -Dusm -Lo to see the log):
NOTE: My test authorativeEngineID is 0x8000000001020305, my test user name is 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)
...

Does the "08 00 00 00 00 00 00 00 00 01 00 02 00 03 00 05" not equal to "0x8000000001020305", so the no match on engineID error occurred? I am not sure now, I will continue to look into that.

My questions:
I'm not sure if I should set the local engine ID as 0x80001370017f000101, if not, how to avoid the issue SNMPv3_USM_UNKNOWN_SECURITY_NAME?

Vicky
  • 11
  • 3
  • Hi! I managed to solve the problem thanks to your comment. I figured out the engineId I used is the first 9 bytes of my local engine ID, and setting the engineID of the SNMP model worked out for me. I'll explain in an answer what I did. – Stefan Candan Oct 30 '18 at 09:55
  • For your string you could use `OctetString octetString = OctetString.fromHexString("80:00:00:00:01:02:03:05");` – Stefan Candan Oct 30 '18 at 10:03
  • Yes, I have updated my answer. Even I converted 0x80001370017f000101 to hex, I still have the issue no match on engineID. The user is created like below in file /var/lib/net-snmp/snmptrapd.conf. usmUser 1 3 0x8000000001020305 "mytrapuser2" "mytrapuser2" .... I'm waiting for your explanation :) – Vicky Oct 30 '18 at 11:06
  • `0x8000000001020305` should equal `80:00:00:00:01:02:03:05` not `08:00:00:00:00:00:00:00:00:01:00:02:00:03:00:05`. There are a few too many `00:`'s in there – Stefan Candan Oct 30 '18 at 11:18
  • Thanks, my issue is fixed with your solution, but i am not very clear about the whole work flow. Currently i am considering about what is the correct logic of the engine Id creation and with what approach can we provide the generated engine id to end user so that end user can know what engine id he/she should use for creating the snmp user on NMS server? – Vicky Oct 30 '18 at 11:56
  • It depends on what you want the workflow to be. For my requirements it is actually completely going into a configuration file to be setup by the end-user You could store the engine ID in a database and retrieve it from there. Show it to the user with some information on how to set up the user on the NMS. – Stefan Candan Oct 30 '18 at 13:17
  • Thanks :). I want to know how can I get snmp engine ID? From above code, we can get the snmp engine ID through **MPv3.createLocalEngineID()**, do we have any other ways to get the engine ID? Then I can store it in a database for NMS to get it. – Vicky Oct 31 '18 at 02:11
  • I created a question for my confusion https://stackoverflow.com/questions/53077818/how-to-set-a-specified-engine-id-for-snmp4j-to-send-v3-trap Welcome to leave a message. – Vicky Oct 31 '18 at 06:54
0

With the help of Vicky's question I've actually identified the problem.

I was not setting the correct ID, and forgot to set the ID on two places.

My engine ID on the server side is actually the first 9 bytes of the programs localEngineID created by Mpv3.createLocaleEngineId().

So I've actually just substring'd the ID as following:

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

And added the localEngineId in the addUser part as following:

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

And for the snmp engine id:

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

This fixxed my problem and the message is logged on the snmptrapd daemon.