Click here to Skip to main content
15,913,115 members
Articles / Programming Languages / C#
Tip/Trick

SNMP - Very Small UDP SNMP Tool for Getting SNMP Data Using C#

Rate me:
Please Sign up or sign in to vote.
4.38/5 (5 votes)
16 Mar 2020CPOL3 min read 9.9K   5  
Small SNMP UDP client for C#
This is a quick and easy way to avoid using complicated SNMP libraries. I wrote this code so I could write a Bandwidth control that uses SNMP. Most routers and security appliances have Counters for the data passing in and out. My solution was to use everybody else's tools to formulate the Request Bytes (just a Byte[] array), then fire the Request at the device using UDPClient or a raw Socket. Now all you have to do is dig through the Response Byte[] array and fetch your data.

Introduction

This C# UDP SNMP solution allows you to avoid using bloated and bug ridden SNMP libraries for getting small amounts of data using SNMP to access a device's SNMP data. I have looked at several C# SNMP libraries that offer source code, most of these libraries are reasonably well developed but in my opinion, I want nothing to do with them. They are over-engineered and complicated. Many use excessive abstraction and try to use every Language feature of C# possible to produce a library. This is fine for libraries developed by large companies who have unlimited funds and fifty seven good developers who will never quit the company. This is why I want nothing to do with one-man-libraries, even if it comes with source code.

When looking at the source code for some of these SNMP libraries, some people use XML comments for every single C# object. This makes it impossible to read the source code. If there was one feature I would ask for in Visual Studio, it would be: HideAllComments = true.

Background

SNMP is a simple Client Server technology. Fire a Request Byte[] array at the device using UDP, and you will get a Response Byte[] back. Simple enough. I have always wanted a C# BandWidth monitoring control, that doesn't use a SNMP library with 785,567 lines of buggy code. In order to write this BandWidth monitoring control, you need only two counters from your Internet Connection device (Router / Security Appliance). I was using a Cisco ASA 5505 and so it has two counters on the outside interface that track the number of octets passing through the device. Once you have the Request Byte[] created, it never needs to change.

All you have to do is create that Request Byte[] array manually by hand, looking at the RFC for an SNMP Request format. Or, use one of the commonly available SNMP libraries that came with source code and print out the Request Bytes to a C# Byte[] Array once you have found the OIDs and data you are looking for.

The example Request Byte[] should work against any device that uses the "public" String. You may need to configure the device by enabling SNMP.

Caveats:
To start with, you can just retrieve your data from the Response bytes using a fixed Address offset.

C#
UInt32 value = BitConverter.ToUInt32( responseBytes, 0x54 );

I discovered 32 bit Octet counters will eventually roll over, and the Response Byte[] data can be at different offsets.

To make this solution BulletProof, you should write an access method or class that retrieves the data from the Response bytes using its OID. For example, let's say you want the SysUpTime value from the Response Bytes:

C#
String oid = "1.3.6.1.2.1.1.3.0";

UInt32 sysUpTime = GetSysUpTime(Byte[] bytes, String oid);

And so in closing, if you wanted to use this extremely simple and bulletproof access solution, you only have to learn how the Request / Response Bytes are formatted. SNMP is reasonably well documented.

So I am enjoying my newly created BandWidth Control, that fires a UDP SNMP packet every 10 seconds and updates my custom bandwidth control.

Using the Code

Simply paste this code into your C# project and play with it.

C#
/*
       Buried in the byte array below are SNMP OIDs (Object Identifiers)
       Most if not all SNMP devices will support these OIDs. 
       I used "public" for access String.
       
        1.3.6.1.2.1.1.1.0 //sysDescr
        1.3.6.1.2.1.1.2.0 //sysObjectID
        1.3.6.1.2.1.1.3.0 //sysUpTime
        1.3.6.1.2.1.1.4.0 //sysContact
        1.3.6.1.2.1.1.5.0 //sysName
        1.3.6.1.2.1.1.6.0 //sysLocation */

      Byte[ ] requestBytes = 
      {
        0x30,0x6F,0x02,0x01,0x00,0x04,0x06,0x70,0x75,0x62,
        0x6C,0x69,0x63,0xA0,0x62,0x02,0x04,0x79,0xEE,0xE3,
        0xBA,0x02,0x01,0x00,0x02,0x01,0x00,0x30,0x54,0x30,
        0x0C,0x06,0x08,0x2B,0x06,0x01,0x02,0x01,0x01,0x01,
        0x00,0x05,0x00,0x30,0x0C,0x06,0x08,0x2B,0x06,0x01,
        0x02,0x01,0x01,0x02,0x00,0x05,0x00,0x30,0x0C,0x06,
        0x08,0x2B,0x06,0x01,0x02,0x01,0x01,0x03,0x00,0x05,
        0x00,0x30,0x0C,0x06,0x08,0x2B,0x06,0x01,0x02,0x01,
        0x01,0x04,0x00,0x05,0x00,0x30,0x0C,0x06,0x08,0x2B,
        0x06,0x01,0x02,0x01,0x01,0x05,0x00,0x05,0x00,0x30,
        0x0C,0x06,0x08,0x2B,0x06,0x01,0x02,0x01,0x01,0x06,
        0x00,0x05,0x00};
       
      // Fire the Request Bytes at the Device and receive the Response Bytes.
      // Simple as that. Now you can dig through the Response bytes and find your data.
      Byte[] responseBytes = SnmpClient.GetResponseBytes( m_IpAddress, requestBytes );      
       
      Console.WriteLine( "{0} Bytes received", responseBytes.Length );       

      // Now all you have to do is dig the data out of the response Byte[] Array.

 public static class SnmpClient
  {
    public static Byte[ ] GetResponseBytes( String ip, Byte[ ] requestBytes )
    {
      Byte[ ] responseBytes = new Byte[ 0 ]; // If Exception occurs, 
                                             // return an empty Byte[] array.

      Int32 receiveTimeOutMs = 2000;
      Int32 sendTimeOutMs = 500;
      Int32 port = 161;

      try
      {
        using ( UdpClient c = new UdpClient( ) )
        {
          c.Client.ReceiveTimeout = receiveTimeOutMs;
          c.Client.SendTimeout = sendTimeOutMs;

          IPEndPoint ipEndPoint = new IPEndPoint( IPAddress.Any, 0 );

          c.Send( requestBytes, requestBytes.Length, 
                  new IPEndPoint( IPAddress.Parse( ip ), port ) );

          responseBytes = c.Receive( ref ipEndPoint );

          return responseBytes;
        }
      }
      catch ( SocketException exc )
      {
        Console.WriteLine( exc.Message );
      }

      return responseBytes;
    }
  }

History

  • 15th March, 2020: First published

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer
United States United States
I'm a cranky old C# developer.

Comments and Discussions

 
-- There are no messages in this forum --