Search Forum
(53671 Postings)
Search Site/Articles

Archived Articles
712 Articles

C# Books
C# Consultants
What Is C#?
Download Compiler
Code Archive
Archived Articles
Advertise
Contribute
C# Jobs
Beginners Tutorial
C# Contractors
C# Consulting
Links
C# Manual
Contact Us
Legal

GoDiagram for .NET from Northwoods Software www.nwoods.com


 
Printable Version

An SNMP Library for .NET Framework Version 0.2
By Malcolm Crowe

This document forms part of the documentation set for the accompanying software and describes the usable interfaces exposed by snmp.dll and mib.dll.

Snmp.dll is a C# class library for the .NET framework. It has been developed on the Windows platform and may be useful on others also. In contains two namespaces, X690 and Snmp.

The X690 namespace contains an implementation of the Basic Encoding Rules (BER) of Abstract Syntax Notation 1 (ASN.1) as specified by international standards (ISO's code for this standard in X.690) and used within Snmp. Snmp is specified in an Internet Standard, and uses a logical Management Information Base (MIB). Implementation of at least the mib-2 (RFC1213) is mandatory for all computer systems connected to the Internet. For recent developments see RFC2570. It is notable that more recent SNMP-related protocols (such as RFC2741) do not use BER.

Mib.dll is a C# class library that handles the translation of MIB object identifiers (OID) such as 1.3.6.1.2.1.1.4.0 to readable names such as "system.sysContact.0". It also collects the help strings from the system mib files (on windows systems these are in the system folder, usually c:\windows\system32.) It contains one namespace, RFC1157. Later versions of this toolkit will extend these aspects to allow for some validation of MIB values.

The distribution includes some simple applications that show these libraries in use.

Getting Started with Snmp.dll and Mib.dll

The simplest possible call on the Snmp protocol is to GET a single MIB entry such as "system.sysContact.0" from an agent (host) such as "localhost" with community "public". The traditional snmputil.exe would do this using the command

snmputil get ict-main-s.msroot.student.paisley.ac.uk public system.sysContact.0

To do this programmatically, proceed as follows:

    RFC1157.Mgmt mib = new RFC1157.Mgmt();
    ManagerSession sess=new ManagerSession("localhost","public");
    ManagerItem mi=new ManagerItem(sess,mib.OID("mgmt.mib-2.system.sysContact.0"));
    Console.WriteLine(mi.Value.ToString());
This code is explained as follows.

1. You will need a an instance of Mgmt() to encode and decode IODs:

new RFC1157.Mgmt()

Store the returned value in a RFC1157.Mgmt variable, mib, say. This constructor takes some time at present, as it reads all the mib definitions it finds in the system folder.

2. Create a ManagerSession to the chosen agent and community by

new ManagerSession("localhost","public")

Store the returned value in a ManagerSession variable, sess, say.

3. Translate the given OID into a uint[]:

uint[] oid = mib.OID("mgmt.mib-2.system.sysContact.0");

The prefix mgmt.mib-2 is added to provide a uniform starting point for the numerous mibs you will find on your system. A typical Windows-2000 system has 20 mibs defined. All of the mibs begin "iso.dod.internet." followed by such things as "mgmt.mib-2".

4. Create a ManagerItem to obtain the result:

new ManagerItem(sess,oid)

Store the returned value in a ManagerItem variable, mi, say.

5. Now mi.Oid contains the actual OID returned (which can be converted to a string using mib.OID() again), and mi.Value the actual value object. You can call ToString on this value to obtain a readable version.

You can also retrieve a SubTree by using the GET/.GETNEXT combination.

More advanced use of the classes

Snmp

As a first step, it is a good idea to Close a ManagerSession that is no longer in use. This will happen automatically if the object becomes inaccessible (goes out of scope).

It is possible to request a number of managed objects in a single PDU, by using the VarBind and Get methods of ManagerSession: sess.Get(VarBind(oid1),VarBind(oid2)…). The returned value is a sequence of Variable Bindings, according to the SNMP standard. That is, if we set

Universal[] results = sess.Get(…);

Then each of results[0], results[1]etc is a variable binding. If we set

Universal varbind = results[k];

Then varbind[0] contains the OID which can be extracted as (uint[])(varbind[0].Value) , and varbind[1] contains the value. This is again a Universal, whose Value property can be cast into whatever form the OID's value uses.

If you want to construct a SetRequest, you can write code very similar to the Get method: just place the value(s) in the vbinds, and use the SetRequestPDU instead of GetRequestPDU.

ASN.1

ASN.1 provides a way of defining objects in a platform-independent way. It is less commonly used today for new protocols, but many existing protocols are defined using ASN.1. If you want to extend the BER libraries here to cover another protocol, the machinery is as follows. You should provide constructors to create BER data for each of the objects in the protocol. Then you extend the decoding machinery for BER to build structures containing BER data from the encoded data stream.

Universal can be used as a base class for building other BER encodings (e.g. Application, Context-Specific, or Private) for ASN.1 applications. For example, suppose we were to build Application types for the Foo protocol.

First we need to sort out the types that the Foo protocol uses: something like

public enum FooType { something=0xA1, … // application specific, construct, .. }
public enum FooTag : BERTag
{
	public FooTag(FooType t): base((byte)t) {}
	public FooTag() {}
	public FooTag(byte t): base(t) {}
	public FooTag(Stream s): base(s) {}
	public override string ToString() { return ((FooType)ToByte()).ToString(); }
}
We would declare
public class FooBER : Universal
{	// make creators for your types, placing the coding in byte array b.
	public FooBER(something x) // for creating byte array b from your data
	{	type = new FooTag(FooType.something); // set the right type coding
		e = true;
		b = .. // set the byte[] b to contain the encoded version
	}			 
	...
	// now support the machinery to decode your objects from streams
	protected override BERtag CreateTag(Stream s) { return new FooTag(s); }
	protected override Universal Creator(Stream s) { return new FooBER(s); }
	protected override Universal[] Creators(int n) { return new FooBER[n]; }
	public FooBER(Stream s) : base(s) {}	
protected virtual bool ValueOf(uint n)
	{	// use Universal's type property to work out what to do
		switch((FooType)(type.ToByte()))
{	// set up a suitable value in val from the binary data in b.
			case FooType.something: 
val = MakeASomethingFrom(b,n); break;
...
default: // maybe some Universal type
	return base.ValueOf(n);
}
return true;
}
// finally provide a protected default constructor
	protected FooBER() {}	
}
[Continued]