SNMP version 3 requests

SNMP version 3 requests can be made using 3 different security configurations. noAuthNoPriv is a request that doesn’t use authentication or privacy, authNoPriv is an authenticated but not privacy protected (encrypted) request and authPriv an authenticated and privacy protected request and reply exchange.

This example will focus on how to make SNMP version 3 requests and process replies.

There are 2 steps required to make SNMP version 3 requests. First you need to “know” the authoritative engine id, boots and time values (this is the agent you are sending requests to) and second is making the actual request.

Getting the authoritative engine values is known as “discovery” process. To perform agent discovery, send an SNMP request with security name and engine id set to 0 length OctetString values and engine boots and time values set to 0.

Here is how you do this in SnmpSharpNet:

UdpTarget target = new UdpTarget((IPAddress)SomeHostIP);
SecureAgentParameters param = new SecureAgentParameters();
if (!target.Discovery(param))
{
  Console.WriteLine("Discovery failed. Unable to continue...");
  target.Close();
  return;
}

That’s it. To summarize:

  1. construct a UdpTarget object for the agent
  2. create a new SecureAgentParameters class which, by default, initializes all the values required for discovery request
  3. call UdpTarget.Discovery

. What happens is that a request is sent to the agent, agent receives it and recognizes that values for a valid request are not present (engine id, boots and time values) and sends you back a REPORT (SNMPv3 error “message”) with values you need in the packet. The call to UdpTarget.Discovery will receive the values in the REPORT returned by the agent, fill them into your SecureAgentParameters class and you are now ready to make requests.

Before you can make any requests, you need to set the Security Name (or user name) for the request. This is done through SecureAgentParameters.SecurityName property:

param.SecurityName.Set("mySecureName");

Security name can be a byte array or string value. Only ASCII values are correctly encoded.

To make a simplest, noAuthNoPriv request to an SNMP version 3 agent after discovery process has been completed, you can do the following:

// Construct a Protocol Data Unit (PDU)
Pdu pdu = new Pdu();
// Set the request type (default is GET)
pdu.Type = PduType.Get;
// Add variables you wish to query
pdu.VbList.Add("1.3.6.1.2.1.1.1.0");
// optional: make sure no authentication or privacy is configured in the 
// SecureAgentParameters class (see discovery section above)
param.Authentication = AuthenticationDigests.None;
param.Privacy = PrivacyProtocols.None;
// optional: make sure you request REPORT packet return on errors
param.Reportable = false;
// Make a request. Request can throw a number of errors so wrap it in try/catch
SnmpV3Packet result;
try {
  SnmpV3Packet result = (SnmpV3Packet)target.Request(pdu, param);
} catch( Exception ex ) {
  // deal with errors
  result = null;
}
if( result != null ) {
  // You have results to process here....
}

To make authenticated (authNoPriv) requests is not much harder. Follow the same logic as noAuthNoPriv except don’t set the autentication digest value to AuthenticationDigests.None but set it to the digest you need to communicate with the agent and set the authentication secret (password).

// Set the authentication digest
param.Authentication = AuthenticationDigests.MD5;
// Set the authentication password
param.AuthenticationSecret.Set("password");

You can use SHA-1 for authentication if that is what is configured on the agent:

// Set the authentication digest
param.Authentication = AuthenticationDigests.SHA1;
// Set the authentication password
param.AuthenticationSecret.Set("password");

Make sure you set the authentication values (or privacy values in the authPriv requests) after discovery process has completed. If you set the authentication and privacy values in the SecureAgentParameters class and then make a call to UdpTarget.Discovery, you’ll have to set those values again because Discovery call resets the SecureAgentParameters class to default values erasing all authentication and privacy settings.

Now to complete the circle, to make a authPriv call, you need to follow the above steps for discovery, request preparation and authentication configuration, plus configure privacy parameters. Here is what you need to do:

// Set the privacy protocol
param.Privacy = PrivacyProtocols.DES;
// Set the privacy password
param.PrivacySecret.Set("CryptoPassword");

To use SHA-128 instead of DES:

// Set the privacy protocol
param.Privacy = PrivacyProtocols.AES128;
// Set the privacy password
param.PrivacySecret.Set("CryptoPassword");

Done and done. Sending the request is done by calling UdpTarget.Request(param, pdu) and authentication and privacy protection of the outgoing request and received reply will be done for you.

Once you have made a successfull request, what do you do with the response?

Library has been designed to return SnmpPacket class instead of just data class like Pdu to allow you to examine all information returned by the agent response. SnmpV3Packet class inherits from SnmpPacket class so you can cast the return value to the version specific class you need.

First step is make sure you got the reply. If UdpTarget.Request returned a null, you’ve got yourself a strange and unexpected situation. Request was made but no valid reply received. At this point, you’ll either have to make another request or abendon attempts to get data from that particular agent.

Assuming that values returned by UdpTarget.Request is not null, you should check if the contained Pdu type is not SnmpConstants.REPORT. If returned pdu type is Report, then agent detected an error and is sending you notification of it. Reports carry Oid/Value Vb pairs in the SnmpV3Packet.Pdu.VbList collection that you can examine to find our what the error is.

Once you check Pdu type is not Report, make sure there are no errors reported in the Pdu. If SnmpV3Packet.Pdu.ErrorCode != 0 you have an error in the request you made. Value SnmpV3Packet.Pdu.ErrorIndex will indicate the index of the value that caused the error in the VbList collection.

Moving on, if the Pdu type is not a Report and there are not errors, check that it is a SnmpConstants.RESPONE. If it is, you’ve got the return values to your request. You can retrieve them, enumerate them, print them or whatever else you’d like to do with them using SnmpV3Packet.Pdu.VbList class.

Here is an example:

try {
  SnmpV3Packet result = (SnmpV3Packet)target.Request(pdu, param);
} catch( Exception ex ) {
  // deal with errors
  result = null;
}
if( result != null ) {
  if (result.Pdu.Type == PduType.Report)
  {
    // we've got an error
    Console.WriteLine("Report packet received.");
    string errstr = SNMPV3ReportError.TranslateError(pkt);
    Console.WriteLine("Error: {0}", errstr);
    target.Close();
    return;
  }
  if (result.Pdu.ErrorStatus != 0)
  {
    Console.WriteLine("SNMP target has returned error code {0} on index {1}.",
                      SnmpError.ErrorMessage(result.Pdu.ErrorStatus), 
                      result.Pdu.ErrorIndex);
    return;
  }
  // Process returned Oid/Variable pairs
  foreach( Vb v in result.Pdu.VbList ) {
    Console.WriteLine("{0}: {1} {2}", v.Key.ToString(), 
        SnmpConstants.GetTypeName(v.Value.Type), v.Value.ToString());
  }
}