SNMP Version 2 Low Level Packet Class

Using the packet class to manipulate SNMP version 2c packet is not too different from manipulating SNMP version 1 packets.

To manipulate a SNMP version 2 packet, you will need to use SnmpV2Packet class.

Layout of the packet is identical to the SNMP version 1 packet format so I will not go into it (again).

Lets focus instead on what information you need encode a valid SNMP version 2 request:

  • Protocol version
  • SNMP community name
  • PDU Type – operation you wish to perform
  • Request ID
  • Variable binding information
    • For requests it can be one or more Oid’ with Null values
    • For SET operation, you will need both Oid and valid values

See, exactly the same as SNMP version 1 !!

Now that you know what information you need to create a valid request lets create a SnmpV2Packet:

SnmpV2Packet packet = new SnmpV2Packet();
// Set the community name
packet.Community.Set("public");
// Set the Pdu type
packet.Pdu.Type = PduType.Get;
// Set request id
packet.Pdu.RequestID = 100;
// Add an Oid for the SNMP-Get operation
packet.Pdu.VbList.Add(".1.3.6.1.2.1.1.1.0");

This example shows how to prepare a SNMP-Get request. By default, when calling Pdu.VbList.Add(string) method, Oid is parsed from the string and value in the VariableBinding is set to Null.

GetNext request is identical except for setting the Pdu type to PduType.GetNext.

SET request is different because you have to set both the Oid and value to set the Oid to on the agent. Here is what you would change for an SNMP-Set request:

// Set the Pdu type
packet.Pdu.Type = PduType.Set;
// Add an Oid and Value for the SNMP-Set operation
packet.Pdu.VbList.Add(new Oid(".1.3.6.1.2.1.1.1.0"), new OctetString("New sysDescr.0 value"));

SNMP version 2 class is now ready to be BER encoded for transmission:

byte[] outBuffer = packet.encode();

That is it! outBuffer byte array now holds the BER encoded SNMP version 2 packet that is ready for transmission to an agent. Just call Socket.Send or Socket.SendTo to send the request.

Now that you have sent a request, what do you do when you receive a reply? Nothing easier, assuming you have received a reply from the agent (you should check IP address and port number of the sender to make sure it’s from the expected device) you need to decode it. In this example, I assume you received the packet into a pre-defined byte array inBuffer and that received data length is stored in inLength variable:

SnmpV2Packet result = new SnmpV2Packet();
result.decode(inBuffer, inLength);

or you can choose to reuse the class you created to send the request:

packet.Reset();
packet.decode(inBuffer, inLength);

From this point, data is available to you in the usable format. You should compare the SNMP community name and request id to confirm they match your request and then process the information returned by the agent.

Trap processing in SNMP version 2 has considerably changed. In SNMP version 1, trap has a different packet format from other SNMP packets and requires special processing. For that reason I had to create a dedicated SnmpV1TrapPacket class to handle processing of traps with the version 1 of the protocol. This has changed in SNMP version 2 and new Trap format, known as V2Trap is adopted. V2Trap has the same format as any other SNMP version 2 packet. There are 2 requirements that need to be met to construct a valid V2Trap packet. First Oid/Value pair in the Variable Bindings collection has to be TrapSysUpTime.0 and second has to be TrapObjectID.0.

When SnmpV2Packet class parses a received V2Trap packet, two required Oid/Value pairs are parsed out of the Variable Bindings collection and removed from it. You can access the values using SnmpV2Packet.Pdu.TrapSysUpTime and SnmpV2Packet.Pdu.TrapObjectID properties.

Other then the two additional properties, V2Trap is the same as any other SNMP v2 packet:

SnmpV2Packet packet = new SnmpV2Packet();
// Decode received packet
packet.decode(inBuffer, inLength);
// Make sure it is a V2Trap
if( packet.Pdu.Type == PduType.V2Trap )
{
	// Process information in the packet
	Console.WriteLine("Received trap {0} at agent upTime {1}", 
	             packet.Pdu.TrapObjectID.ToString(), packet.Pdu.TrapSysUpTime.ToString());
	foreach( Vb v in packet.Pdu.VbList ) {
		Console.WriteLine("\t{0}: {1} {2}", 
		             v.Oid.ToString(), SnmpConstants.GetTypeName(v.Value.Type), v.Value.ToString());
	}
}

There is one new request type, GetBulk and one completely new notification type, Inform that are introduced in the SNMP version 2.

To use SNMP version 2 GetBulk request type you will need to set two new SnmpV2Packet class properties, NonRepeaters and MaxRepetitions.

GetBulk request performs multiple GetNext operations on the requested Oids and returns them in a single response. MaxRepetitions property tells the agent how many GetNext operations to perform on each requested Oid. NonRepeaters tells the agent to perform a single GetNext on the specified number of Oids from the beginning of the Variable Bindings collection.

By default, SnmpV2Packet class sets NonRepeaters value to zero and MaxRepetitions value to 100. You can change these values to any value from 0 to 255. Setting MaxRepetitions property to 1 will make GetBulk request perform like GetNext.

Here are the changes you need to make to the above example to construct a GetBulk request:

Both SnmpV2Packet encode and decode methods will throw Exceptions if an error is encountered. Please check library documentation for details of Exceptions that can be thrown.

// Set the Pdu type
packet.Pdu.Type = PduType.GetBulk;
// Add Oids to the request
packet.Pdu.VbList.Add(".1.3.6.1.2.1.1.3"); // sysUpTime
packet.Pdu.VbList.Add(".1.3.6.1.2.1.2.2.1.2"); // ifDescr
// Get 1 value for the first Oid, that will be sysUpTime (.1.3.6.1.2.1.1.3.0)
packet.Pdu.NonRepeaters = 1;
// Retrieve up to 50 ifDescr interface description values in a single request
packet.Pdu.MaxRepetitions = 50;

When working with the SnmpV2Packet class, make sure you don’t attempt to access MaxRepetitions and NonRepeaters properties on packets that are Type other then GetBulk because you will receive SnmpInvalidPduTypeException if you do. Same is true if you attempt to access ErrorStatus and ErrorIndex properties in GetBulk packet class.

You can think of Inform notifications as acknowledged Traps. When an agent sents an Inform, you are supposed to receive it, process it and send back acknowledgement that you received it.

Since the primary purpose of the library is to help build manager applications, receiving Inform packets and constructing responses/acknowledgement packets is made to be as easy as possible. Here is an example of how to receive an Inform and send back an ack:

In this example we assume that incoming packet was received into a predefined inBuffer byte array and that length of the received data in stored in a variable inLength

// Construct the packet class.
SnmpV2Packet packet = new SnmpV2Packet();
// Decode received information.
packet.decode(inBuffer, inLength);
// Verify we received an Inform packet.
if( packet.Pdu.Type == PduType.Inform )
{
	// Construct appropriate response to the Inform.
	SnmpV2Packet response = packet.BuildInformResponse();
	// BER encode response packet.
	byte[] outBuffer = response.encode();
	// Send response back to the Inform sender.
	mysocket.SendTo(outBuffer,new IPEndPoint(someip, someport));
}