Introductions to different concepts related to Simple Network Management Protocol and how they are implemented in SNMP#Net library.
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:
. 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.
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 authentication 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 successful 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 abandon 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()); } }
SNMP version 3 gives you three major new security improvements when compared with previous versions of the protocol. These are:
Before getting into what these things are, there is one term that needs to be understood. Authoritative SNMP engine is the engine that controls the information used for timeliness, authentication and privacy operations. In most cases authoritative SNMP engine is the agent containing the information that managers query. The only exception is when agent is sending an Inform notification in which case manager is the authoritative engine and "controls" the SNMP information used to perform above listed security operations.
Timeliness is a feature that allows the authoritative SNMP engine to check if information is arriving in timely way and is not being intercepted, stored and then retransmitted outside the acceptable time window from the time it was sent.
While this might sound like a complex feature, it really isn't. How this is done is using 2 values in the SNMP version 3 packet called engine boots and engine time.
Engine boots value is the number of times authoritative SNMP engine has been started, booted, executed, initialized, or assumed any other state that can be called "booted". Engine time is the number of seconds since the last time authoritative SNMP engine has been " booted". These two values, together, are used for timeliness check.
Timeliness check is performed by verifying that engine boots value is identical between the arriving packet and the stored value on the authoritative SNMP engine and that engine time is within 150 seconds of the value on the authoritative SNMP engine. In other words, if engine boots in the incoming packet is not equal to the local value and time is outside the 150 second window when compared with the local value, authoritative SNMP engine will discard the packet.
Authentication is a verification method that allows a receiver that confirm that packet was not modified in transit. This is done by performing a hashing operation on the entire packet and, through use of a secret password shared by the agent and manager involved in the exchange, ensures that only authorized SNMP entities can modify the packet.
Privacy is encryption of the data portion of the SNMP packet. Data portion is the Protocol Data Unit in the SNMP packet. Encryption is performed using a secret (password) that is shared between the agent and manager.
Because authoritative SNMP engine originates information used for timeliness, authentication and privacy operations, there has to be a way for the non-authoritative engine to retrieve required values. This process is called Discovery process.
Prior to making any SNMP request from an authoritative SNMP engine, you will need to send it a discovery packet, basically an empty SNMP version 3 packet and wait for the REPORT message agent will send you. REPORT that you will receive includes authoritative SNMP engine ID, SNMP engine boots and SNMP engine time values that you need to use in subsequent requests.
Once you have retrieved authoritative SNMP engine information, you can start making requests using authentication and privacy settings specific for the agent you are querying.
Now a little more detail about the SnmpSharpNet implementation of SNMP version 3. All functionality is grouped in the SnmpV3Packet class. This class lets you select what level of security you wish to use, authentication digest and secret value, privacy protocol and secret value, security name (user name), etc. To see which authentication digests are supported in the library version you are using, check out SecurityDigests enumeration which enumerates supported digests. To find supported privacy protocols, see PrivacyProtocols enumeration.
For examples of how to use SNMPv3, check out project web site