Sending SNMP Version 3 traps

When sending SNMPv3 traps, you are in control. Sender of V2TRAP notifications using protocol version 3 is the authoritative SNMP engine, meaning it supplies the engine id, engine boots and engine time values.

Since you are both the originator of the notification and authoritative SNMP engine, there is nothing you need to “discover” making SNMP version 3 Trap notifications the only SNMP operation that doesn’t use the discovery procedure.

Since it is that straight forward, we can dive into the code straight away.

Here is a simplest possible example of how to build a noAuthNoPriv SNMP notification:

SnmpV3Packet packet = new SnmpV3Packet();
// Set the security name
packet.NoAuthNoPriv(ASCIIEncoding.UTF8.GetBytes("mysecurityname"));
// Set your engine id
packet.USM.EngineId.Set(new byte[] { 0x00, 0x08, 0x02, 0x01, 0x10, 0x12, 0x14, 0xa0, 0xb1, 0xc2 });
// Engine id is also stored in the ScopedPdu so just duplicate it
packet.ScopedPdu.ContextEngineId.Set(packet.USM.EngineId);
// Set your engine boots (can be 0)
packet.USM.EngineBoots = 20;
// Set your engine time
packet.USM.EngineTime = 200;
// Set message reportable flag to false. You don't really want to receive errors
packet.MsgFlags.Reportable = false;
// Pdu type is V2TRAP
packet.Pdu.Type = PduType.V2Trap;
// Set the TRAP object ID value
packet.Pdu.TrapObjectID.Set(new int[] { 1, 3, 6, 1, 2, 1, 2, 2, 1, 0 });
// Set your system up time value (this has nothing to do with engineTime)
packet.Pdu.TrapSysUpTime.Value = 23456;
// Add variable bindings to the Pdu to further describe the TRAP
packet.Pdu.VbList.Add(new Oid(new int[] { 1, 3, 6, 1, 2, 1, 1, 1, 0 }), new OctetString("Test noAuthNoPriv"));
// Finally, encode into a byte buffer ready for sending
byte[] outBuffer = packet.encode();
// Send it to the manager
sock.SendTo(outBuffer,new IPEndPoint(IPAddress.Loopback, 162));

In this example I just made up the authoritative SNMP engine values (id, boots and time). While this will work, it is pointless to use SNMPv3 and then have a massive security hole like this in your implementation. What you should do is generate an engine id that is unique, keep track how many times your snmp engine has been started to use as engineBoots value and keep track of how long the engine has been running for the engineTime value.

Sending the above example to a net-snmp snmptrapd application you will get the following debug dump:

dumpx_recv:  02 01 03
dumpv_recv:    Integer: 3 (0x03)
dumph_recv:   SNMPv3 Message
dumph_recv:     SNMP Version Number
dumpx_recv:      02 01 03
dumpv_recv:        Integer:     3 (0x03)
dumph_recv:     msgGlobalData
dumph_recv:       msgID
dumpx_recv:        02 04 7B EA 66 C6
dumpv_recv:          Integer:   2078959302 (0x7BEA66C6)
dumph_recv:       msgMaxSize
dumpx_recv:        02 03 01 00 00
dumpv_recv:          Integer:   65536 (0x10000)
dumph_recv:       msgFlags
dumpx_recv:        04 01 00
dumpv_recv:          String:    .
dumph_recv:       msgSecurityModel
dumpx_recv:        02 01 03
dumpv_recv:          Integer:   3 (0x03)
dumph_recv:     SM msgSecurityParameters
dumph_recv:       msgAuthoritativeEngineID
dumpx_recv:        04 0A 00 08 02 01 10 12 14 A0 B1 C2
dumpv_recv:          String:    ....... ±A
dumph_recv:       msgAuthoritativeEngineBoots
dumpx_recv:        02 01 14
dumpv_recv:          Integer:   20 (0x14)
dumph_recv:       msgAuthoritativeEngineTime
dumpx_recv:        02 02 00 C8
dumpv_recv:          Integer:   200 (0xC8)
dumph_recv:       msgUserName
dumpx_recv:        04 09 6D 69 6C 61 6E 73 68 61 37
dumpv_recv:          String:    milansha7
dumph_recv:       msgAuthenticationParameters
dumpx_recv:        04 00
dumpv_recv:          String:
dumph_recv:       msgPrivacyParameters
dumpx_recv:        04 00
dumpv_recv:          String:
dumph_recv:       ScopedPDU
dumph_recv:         contextEngineID
dumpx_recv:          04 0A 00 08 02 01 10 12 14 A0 B1 C2
dumpv_recv:            String:  ....... ±A
dumph_recv:         contextName
dumpx_recv:          04 00
dumpv_recv:            String:
dumph_recv:         TRAP2
dumpv_recv:     Command TRAP2
dumph_recv:           request_id
dumpx_recv:            02 04 62 EE 96 81
dumpv_recv:              Integer:       1659803265 (0x62EE9681)
dumph_recv:           error status
dumpx_recv:            02 01 00
dumpv_recv:              Integer:       0 (0x00)
dumph_recv:           error index
dumpx_recv:            02 01 00
dumpv_recv:              Integer:       0 (0x00)
dumph_recv:           VarBindList
dumph_recv:             VarBind
dumph_recv:               Name
dumpx_recv:                06 08 2B 06 01 02 01 01 03 00
dumpv_recv:                  ObjID: DISMAN-EVENT-MIB::sysUpTimeInstance
dumph_recv:               Value
dumpx_recv:                43 02 5B A0
dumpv_recv:                  UInteger:  23456 (0x5BA0)
dumph_recv:             VarBind
dumph_recv:               Name
dumpx_recv:                06 0A 2B 06 01 06 03 01 01 04 01 00
dumpv_recv:                  ObjID: SNMPv2-MIB::snmpTrapOID.0
dumph_recv:               Value
dumpx_recv:                06 09 2B 06 01 02 01 02 02 01 00
dumpv_recv:                  ObjID: IF-MIB::ifEntry.0
dumph_recv:             VarBind
dumph_recv:               Name
dumpx_recv:                06 08 2B 06 01 02 01 01 01 00
dumpv_recv:                  ObjID: SNMPv2-MIB::sysDescr.0
dumph_recv:               Value
dumpx_recv:                04 11 54 65 73 74 20 6E 6F 41 75 74 68 4E 6F 50 72 69 76
dumpv_recv:                  String:    Test noAuthNoPriv

To configure a noAuthNoPriv user, add createUser -e 0x00080201101214a0b1c2 mysecurityname to the snmptrapd.conf configuration file.

As you can see from the above debug dump, packet is received and decoded correctly.

Using SNMPv3 without authentication is not very useful, here is now to introduce authentication into your TRAP sending app:

SnmpV3Packet packet = new SnmpV3Packet();
// Set security name and authentication parameters needed for a authNoPriv TRAP
packet.authNoPriv(ASCIIEncoding.UTF8.GetBytes("myauthenticationname"), 
	ASCIIEncoding.UTF8.GetBytes("authpasswd"), AuthenticationDigests.MD5);
// Set your engine id
packet.USM.EngineId.Set(new byte[] { 0x00, 0x08, 0x02, 0x01, 0x10, 0x12, 0x14, 0xa0, 0xb1, 0xc2 });
// Engine id is also stored in the ScopedPdu so just duplicate it
packet.ScopedPdu.ContextEngineId.Set(packet.USM.EngineId);
// Set your engine boots (can be 0)
packet.USM.EngineBoots = 20;
// Set your engine time
packet.USM.EngineTime = 200;
// Set message reportable flag to false. You don't really want to receive errors
packet.MsgFlags.Reportable = false;
// Pdu type is V2TRAP
packet.Pdu.Type = PduType.V2Trap;
// Set the TRAP object ID value
packet.Pdu.TrapObjectID.Set(new int[] { 1, 3, 6, 1, 2, 1, 2, 2, 1, 0 });
// Set your system up time value (this has nothing to do with engineTime)
packet.Pdu.TrapSysUpTime.Value = 23456;
// Add variable bindings to the Pdu to further describe the TRAP
packet.Pdu.VbList.Add(new Oid(new int[] { 1, 3, 6, 1, 2, 1, 1, 1, 0 }), new OctetString("Test noAuthNoPriv"));
// Finally, encode into a byte buffer ready for sending
byte[] outBuffer = packet.encode();
// Send it to the manager
sock.SendTo(outBuffer,new IPEndPoint(IPAddress.Loopback, 162));

Packet dump on the receiving side shows that authentication is correctly encoded and verified:

dumpx_recv:02 01 03
dumpv_recv:  Integer:   3 (0x03)
dumph_recv: SNMPv3 Message
dumph_recv:   SNMP Version Number
dumpx_recv:    02 01 03
dumpv_recv:      Integer:       3 (0x03)
dumph_recv:   msgGlobalData
dumph_recv:     msgID
dumpx_recv:      02 04 7C 5C 95 AF
dumpv_recv:        Integer:     2086442415 (0x7C5C95AF)
dumph_recv:     msgMaxSize
dumpx_recv:      02 03 01 00 00
dumpv_recv:        Integer:     65536 (0x10000)
dumph_recv:     msgFlags
dumpx_recv:      04 01 01
dumpv_recv:        String:      .
dumph_recv:     msgSecurityModel
dumpx_recv:      02 01 03
dumpv_recv:        Integer:     3 (0x03)
dumph_recv:   SM msgSecurityParameters
dumph_recv:     msgAuthoritativeEngineID
dumpx_recv:      04 0A 00 08 02 01 10 12 14 A0 B1 C2
dumpv_recv:        String:      ....... ±A
dumph_recv:     msgAuthoritativeEngineBoots
dumpx_recv:      02 01 14
dumpv_recv:        Integer:     20 (0x14)
dumph_recv:     msgAuthoritativeEngineTime
dumpx_recv:      02 02 00 C8
dumpv_recv:        Integer:     200 (0xC8)
dumph_recv:     msgUserName
dumpx_recv:      04 14 6D 79 61 75 74 68 65 6E 74 69 63 61 74 69 6F 6E 6E 61 6D 65
dumpv_recv:        String:      myauthenticationname
dumph_recv:     msgAuthenticationParameters
dumpx_recv:      04 0C 8F DD 59 BF F8 A1 2A C2 5E 68 FC 71
dumpv_recv:        String:      .YY¿o¡*A^hüq
dumph_recv:     msgPrivacyParameters
dumpx_recv:      04 00
dumpv_recv:        String:
dumph_recv:     ScopedPDU
dumph_recv:       contextEngineID
dumpx_recv:        04 0A 00 08 02 01 10 12 14 A0 B1 C2
dumpv_recv:          String:    ....... ±A
dumph_recv:       contextName
dumpx_recv:        04 00
dumpv_recv:          String:
dumph_recv:       TRAP2
dumpv_recv:     Command TRAP2
dumph_recv:         request_id
dumpx_recv:          02 04 11 4E 18 23
dumpv_recv:            Integer: 290330659 (0x114E1823)
dumph_recv:         error status
dumpx_recv:          02 01 00
dumpv_recv:            Integer: 0 (0x00)
dumph_recv:         error index
dumpx_recv:          02 01 00
dumpv_recv:            Integer: 0 (0x00)
dumph_recv:         VarBindList
dumph_recv:           VarBind
dumph_recv:             Name
dumpx_recv:              06 08 2B 06 01 02 01 01 03 00
dumpv_recv:                ObjID: DISMAN-EVENT-MIB::sysUpTimeInstance
dumph_recv:             Value
dumpx_recv:              43 02 5B A0
dumpv_recv:                UInteger:    23456 (0x5BA0)
dumph_recv:           VarBind
dumph_recv:             Name
dumpx_recv:              06 0A 2B 06 01 06 03 01 01 04 01 00
dumpv_recv:                ObjID: SNMPv2-MIB::snmpTrapOID.0
dumph_recv:             Value
dumpx_recv:              06 09 2B 06 01 02 01 02 02 01 00
dumpv_recv:                ObjID: IF-MIB::ifEntry.0
dumph_recv:           VarBind
dumph_recv:             Name
dumpx_recv:              06 08 2B 06 01 02 01 01 01 00
dumpv_recv:                ObjID: SNMPv2-MIB::sysDescr.0
dumph_recv:             Value
dumpx_recv:              04 0F 54 65 73 74 20 61 75 74 68 4E 6F 50 72 69
76
dumpv_recv:                String:      Test authNoPriv

For the full benefit of SNMPv3, you will use authPriv security model that includes both authentication and privacy encryption of the Pdu. To enable encryption, you need to initialize the SNMP packet with the authPriv() method:

SnmpV3Packet packet = new SnmpV3Packet();
// Set security name and authentication and privacy parameters needed for authPriv TRAP
packet.authPriv(ASCIIEncoding.UTF8.GetBytes("myauthprivname"), 
	ASCIIEncoding.UTF8.GetBytes("authpasswd"), AuthenticationDigests.MD5,
	ASCIIEncoding.UTF8.GetBytes("privpasswd"), PrivacyProtocols.DES);
// Set your engine id
packet.USM.EngineId.Set(new byte[] { 0x00, 0x08, 0x02, 0x01, 0x10, 0x12, 0x14, 0xa0, 0xb1, 0xc2 });
// Engine id is also stored in the ScopedPdu so just duplicate it
packet.ScopedPdu.ContextEngineId.Set(packet.USM.EngineId);
// Set your engine boots (can be 0)
packet.USM.EngineBoots = 20;
// Set your engine time
packet.USM.EngineTime = 200;
// Set message reportable flag to false. You don't really want to receive errors
packet.MsgFlags.Reportable = false;
// Pdu type is V2TRAP
packet.Pdu.Type = PduType.V2Trap;
// Set the TRAP object ID value
packet.Pdu.TrapObjectID.Set(new int[] { 1, 3, 6, 1, 2, 1, 2, 2, 1, 0 });
// Set your system up time value (this has nothing to do with engineTime)
packet.Pdu.TrapSysUpTime.Value = 23456;
// Add variable bindings to the Pdu to further describe the TRAP
packet.Pdu.VbList.Add(new Oid(new int[] { 1, 3, 6, 1, 2, 1, 1, 1, 0 }), new OctetString("Test authNoPriv"));
// Finally, encode into a byte buffer ready for sending
byte[] outBuffer = packet.encode();
// Send it to the manager
sock.SendTo(outBuffer,new IPEndPoint(IPAddress.Loopback, 162));

Receiver debug output will look like this:

dumpx_recv:02 01 03
dumpv_recv:  Integer:   3 (0x03)
dumph_recv: SNMPv3 Message
dumph_recv:   SNMP Version Number
dumpx_recv:    02 01 03
dumpv_recv:      Integer:       3 (0x03)
dumph_recv:   msgGlobalData
dumph_recv:     msgID
dumpx_recv:      02 04 5A E6 5D 23
dumpv_recv:        Integer:     1525046563 (0x5AE65D23)
dumph_recv:     msgMaxSize
dumpx_recv:      02 03 01 00 00
dumpv_recv:        Integer:     65536 (0x10000)
dumph_recv:     msgFlags
dumpx_recv:      04 01 03
dumpv_recv:        String:      .
dumph_recv:     msgSecurityModel
dumpx_recv:      02 01 03
dumpv_recv:        Integer:     3 (0x03)
dumph_recv:   SM msgSecurityParameters
dumph_recv:     msgAuthoritativeEngineID
dumpx_recv:      04 0A 00 08 02 01 10 12 14 A0 B1 C2
dumpv_recv:        String:      ....... ±A
dumph_recv:     msgAuthoritativeEngineBoots
dumpx_recv:      02 01 14
dumpv_recv:        Integer:     20 (0x14)
dumph_recv:     msgAuthoritativeEngineTime
dumpx_recv:      02 02 00 C8
dumpv_recv:        Integer:     200 (0xC8)
dumph_recv:     msgUserName
dumpx_recv:      04 0E 6D 79 61 75 74 68 70 72 69 76 6E 61 6D 65
dumpv_recv:        String:      myauthprivname
dumph_recv:     msgAuthenticationParameters
dumpx_recv:      04 0C 13 7F 7F 26 00 C2 51 F3 16 AB 25 04
dumpv_recv:        String:      ...&.AQó.«%.
dumph_recv:     msgPrivacyParameters
dumpx_recv:      04 08 00 00 00 14 45 F4 DA B1
dumpv_recv:        String:      ....EôU±
dumph_recv:     ScopedPDU
dumph_recv:       contextEngineID
dumpx_recv:        04 0A 00 08 02 01 10 12 14 A0 B1 C2
dumpv_recv:          String:    ....... ±A
dumph_recv:       contextName
dumpx_recv:        04 00
dumpv_recv:          String:
dumph_recv:       TRAP2
dumpv_recv:     Command TRAP2
dumph_recv:         request_id
dumpx_recv:          02 04 7F 0B B7 B2
dumpv_recv:            Integer: 2131474354 (0x7F0BB7B2)
dumph_recv:         error status
dumpx_recv:          02 01 00
dumpv_recv:            Integer: 0 (0x00)
dumph_recv:         error index
dumpx_recv:          02 01 00
dumpv_recv:            Integer: 0 (0x00)
dumph_recv:         VarBindList
dumph_recv:           VarBind
dumph_recv:             Name
dumpx_recv:              06 08 2B 06 01 02 01 01 03 00
dumpv_recv:                ObjID: DISMAN-EVENT-MIB::sysUpTimeInstance
dumph_recv:             Value
dumpx_recv:              43 02 5B A0
dumpv_recv:                UInteger:    23456 (0x5BA0)
dumph_recv:           VarBind
dumph_recv:             Name
dumpx_recv:              06 0A 2B 06 01 06 03 01 01 04 01 00
dumpv_recv:                ObjID: SNMPv2-MIB::snmpTrapOID.0
dumph_recv:             Value
dumpx_recv:              06 09 2B 06 01 02 01 02 02 01 00
dumpv_recv:                ObjID: IF-MIB::ifEntry.0
dumph_recv:           VarBind
dumph_recv:             Name
dumpx_recv:              06 08 2B 06 01 02 01 01 01 00
dumpv_recv:                ObjID: SNMPv2-MIB::sysDescr.0
dumph_recv:             Value
dumpx_recv:              04 0D 54 65 73 74 20 61 75 74 68 50 72 69 76
dumpv_recv:                String:      Test authPriv

As you can see from the dump, both authentication and privacy parameters are present in the packet and data is correctly received, authenticated and unencrypted by the receiving manager.

To generate SNMP receiver dump data I have used net-snmp snmptrapd.exe utility version 5.4.2.1 on Windows with the following snmptrapd.conf configuration:

createUser -e 0x00080201101214a0b1c2 mysecurityname
createUser -e 0x00080201101214a0b1c2 myauthenticationname MD5 authpasswd
createUser -e 0x00080201101214a0b1c2 myauthprivname MD5 authpasswd DES privpasswd

Test output was collected by executing snmptrapd -Le -Ddump.