# Usage of Westhawk's SNMP stack

# Introduction

This document describes the delivery of this stack and how the stack can be used for SNMPv1, SNMPv2c and SNMPv3. The stack supports traps, authentication and privacy. As authentication protocols the stack offers MD5 and SHA1.

This document does not explain SNMP (Simple Network Management Protocol) itself. The reader is assumed to have basic knowledge of the protocol. If you want to learn more, see the Reading section.

The target applications are small applets, for that reason the stack has remained tiny. We wanted something lighter that we could just pop in a (Netscape) frame and leave there all day. It has no MIB (Management Information Base) browsing capabilities, you have to know the OID (Object Identifier) of what you want to monitor. There are many other packages that do MIB browsing and general network management.

The Westhawk Java SNMP stack comes with generated (javadoc) documentation. Check that documentation for the description of all methods that are not mentioned in this document or for the description of the method parameters.

# The delivery

The file `snmp<version>.zip` contains the SNMP stack. The distribution can be downloaded from the Westhawk's SNMP page. The contents of the zip file is:

snmp<version>.jar
  The jar file with the core of the SNMP stack classes. It contains the precompiled `uk.westhawk.snmp.X` packages. This jar file does not contain any examples or beans.
javadoc/
  The directory with the javadoc files.
stubs/
  The directory with experimental software to auto generate a Java source file of a PDU or bean out off a MIB file, using smidump (libsmi)
uk/co/westhawk/
  The source of the SNMP stack
uk/co/westhawk/examplev1/
  The directory with the source of examples how to use the stack for SNMPv1.
uk/co/westhawk/examplev2c/
  The directory with the source of examples how to use the stack for SNMPv2c.
uk/co/westhawk/examplev3/
  The directory with the source of examples how to use the stack for SNMPv3.
uk/co/westhawk/nothread/
  The directory with the source of example how to use the stack in environments where thread creation is unwanted, e.g. database JVMs such as Oracle ™ JServer.
uk/co/westhawk/snmp/beans/
  The directory with the source of the different beans that come with the stack.
uk/co/westhawk/snmp/pdu/
  The directory with the source of the different PDUs (among other things the BlockPdu) that come with the stack.
uk/co/westhawk/snmp/stack/
  The directory with the source of the context and ASN functionality of the stack.

# The usage

The stack can be used in a number of ways:

- Using the beans
- Using the PDUs
- Using the blocking calls

## Using the beans

The package `uk.co.westhawk.snmp.beans` contains all the beans in the stack. Except for the `UsmDiscoveryBean` they all (still) relate to SNMPv1.

The beans form a bridge between the `uk.co.westhawk.snmp.pdu` (and `uk.co.westhawk.snmp.stack`) package(s) and any applet or application you may want to write.

The beans work via the (asynchronous) `java.beans.PropertyChange` mechanism. If you are using Swing, don't forget to use `javax.swing.SwingUtilities.invokeLater(java.lang.Runnable)` if you want to do any screen updates from the `propertyChange` method.

Our beans gather specific MIB information, i.e. the OID (Object Identifier) is hard coded. The beans should be easy enough to understand, and with little effort you can write a bean for your own purpose. The beans `SNMPBean` and `SNMPRunBean` contain some general information about the beans as well. The coding examples will show you how to use the beans as well.

## Using the PDUs

The package `uk.co.westhawk.snmp.pdu` contains all the public accessible PDUs. All the Pdus (well, except for the BlockPdu) extend abstract `uk.co.westhawk.snmp.stack.Pdu`. The PDUs are non blocking and work via the `java.util.Observer/java.util.Observable` mechanism.

The idea is that for each class of problem you should subclass the abstract `uk.co.westhawk.snmp.stack.Pdu` class. You will have to implement the `protected void new_value(int n, varbind res)` and the `protected void tell_them()` methods. As example look at the `uk.co.westhawk.snmp.pdu.OneIntPdu` class or any other class in that package.

In order to use a PDU do the following:

1. Create a context, giving it the host name and port number of your SNMP agent. If this is run in an applet then you can only connect back to that server!
2. Create a PDU, passing it the context; `OneGetPdu pdu = new OneGetPdu(context)`.
3. Add the OIDs you are interested in with `pdu.add_oid(oid)`.
4. Add an observer with `pdu.addObserver(observer)`. The argument is the object that wishes to be notified when the new value arrives. It must implement `java.util.Observer`, that is it must have a `public void update(java.util.Observable obs, java.lang.Object obj)` method. This method will get called when the value arrives. If you are using Swing, don't forget to use `javax.swing.SwingUtilities.invokeLater(java.lang.Runnable)` if you want to do any screen updates.
5. Call `pdu.send()`.
6. Sleep, or do something else. Your `update` method will get called automatically when the data has arrived. Both the context and PDU objects spawn their own threads, so there is nothing further to do.

Since traps do not get a reply, you can omit adding an `observer` (step 4) and implementing `update` (the last step) when sending one. When sending traps with SNMPv3, please read the section about the authoritative engine.

The coding examples will show you how to use the PDUs as well.

## Using the blocking calls

The class `uk.co.westhawk.snmp.pdu.BlockPdu` is a wrapper class around the traditional (non blocking) Pdu. It allows the user to send either a Set request, a Get request, a GetNext request or a GetBulk request by specifying the type of request, see the `setPduType` method. The caller has to add the necessary OIDs with the method `addOid`.

As the title suggests, the BlockPdu sends the request and waits for the response. We suggest that you only use this class if you have to; Because the pdu blocks, you can not do anything else on that thread while it is waiting for a reply. If that thread is driving a UI, then the user may see a sluggish interface. If you can, use the beans or the PDUs.

There are four methods that send the request, wait for the response and return the variables or variable bindings. They throw the `uk.co.westhawk.snmp.stack.PduException` exception:

- AsnObject getResponseVariable()
- AsnObject [ ] getResponseVariables()
- varbind getResponseVariableBinding()
- varbind [ ] getResponseVariableBindings()

The OIDs that are added via `addOid` method for the request will not be replaced by the OIDs from the response. This means that every request will result in the same answer and that the GetNext does not walk the MIB

# The context

Every Pdu that is created needs a context. The same context can be used for a number of Pdus.

### the context for SNMPv1

For SNMPv1 the context is built out of the following parameters:

- The name of the host to which the Pdu is sent
- The port number on that host
- The community name that is used, by default public
- The type of socket that is used, by default Standard

The next section explains the use of the type of socket.

This SNMP stack provides three contexts for SNMPv1:

- uk.co.westhawk.snmp.stack.SnmpContext
- uk.co.westhawk.snmp.stack.SnmpContextPool
- uk.co.westhawk.snmp.stack.PassiveSnmpContext

The `SnmpContextPool` contains a pool of `SnmpContext` and will share any context that it can share. This results in a reduced number of threads and other resources.

The `PassiveSnmpContextPool` contains the SNMP v1 context that is needed by a Pdu to send a SNMP v1 request in environments where thread creation is unwanted, see the nothread notes.

### the context for SNMPv2c

The context for SNMPv2c is very similar to the SNMPv1 context. It is built out of the following parameters:

- The name of the host to which the Pdu is sent
- The port number on that host
- The community name that is used, by default public
- The type of socket that is used, by default Standard

The next section explains the use of the type of socket.

This SNMP stack provides three contexts for SNMPv2c:

- uk.co.westhawk.snmp.stack.SnmpContextv2c
- uk.co.westhawk.snmp.stack.SnmpContextv2cPool
- uk.co.westhawk.snmp.stack.PassiveSnmpContextv2c

The `SnmpContextv2cPool` contains a pool of `SnmpContextv2c` and will share any context that it can share. This results in a reduced number of threads and other resources.

The `PassiveSnmpContextv2c` contains the SNMP v2c context that is needed by a Pdu to send a SNMP v2c request in environments where thread creation is unwanted, see the nothread notes.

### the context for SNMPv3

For SNMPv3 the context is built out of the following parameters.

- The name of the host to which the Pdu is sent
- The port number on that host
- The type of socket that is used, by default Standard
- The user name of the SNMP principle, by default initial
- Whether the user wants to use authentication or not, by default false
- The user authentication password
- The authentication protocol the user wants to use, by default MD5
- Whether the user wants to use privacy or not, by default false
- The user privacy password
- The context engine id of the host
- The context name of the host, by default the empty string

This SNMP stack provides two contexts for SNMPv3:

- uk.co.westhawk.snmp.stack.SnmpContextv3
- uk.co.westhawk.snmp.stack.SnmpContextv3Pool

The `SnmpContextv3Pool` contains a pool of `SnmpContextv3` and will share any context that it can share. This results in a reduced number of threads and other resources.

# The socket type

At the moment two types of sockets can be used:

- The standard socket, defined by `SnmpContextFace.STANDARD_SOCKET`
- The Netscape socket, defined by `SnmpContextFace.NETSCAPE_SOCKET`

By default the standard socket will be used. The Netscape socket provides extra functionality for the Netscape capabilities classes.

The caller needs to use the NETSCAPE_SOCKET socket type when this stack is used in an applet that is running in Netscape 4.X and when the jar files needs to be signed. For more documentation on this subject see Introduction to the capabilities classes.

# The authoritative engine

When sending traps the stack becomes an agent, or an authoritative engine as it is called in SNMPv3, rather than a manager, or a non-authoritative engine as it is called in SNMPv3.

In SNMPv3 the User-Based Security Model (USM) timeliness mechanism is different for authoritative and non-authoritative SNMP engines:

- a non-authoritative engine must remain loosely synchronised with an authoritative engine
- an authoritative engine must maintain it snmpEngineBoots and snmpEngineTime

This distinction does not apply to SNMPv1 or SNMPv2c.

Since the stack is not a real agent, it cannot provide all the USM synchronisation parameters. For that reason the user has to provide an implementation of the interface `uk.co.westhawk.snmp.stack.UsmAgent`. This interface provides the stack with the following information of its authoritative engine:

- `Engine ID` - The authoritative SNMP Engine ID, which (at least within an administrative domain) uniquely and unambiguously identifies the SNMP engine
- `Engine Boots` - The authoritative SNMP Engine Boots, which is a count of the number of times the SNMP engine has re-booted/re-initialized since snmpEngineID was last configured
- `Engine Time` - The authoritative SNMP Engine Time, which is the number of seconds since the snmpEngineBoots counter was last incremented

# Receiving traps

There are different ways to receive traps. Any combination of these ways can be used at the same time:

- Receive traps for all hosts
- Receive traps from a specific host
- Receive unhandled traps

The conventional and default port to listen for traps is 162. Since on UNIX and Linux systems only the `root` user is allowed to open that port, you will have to run as `root` in order to listen for traps on that port.

### Receiving traps from all hosts

The class `uk.co.westhawk.snmp.stack.DefaultTrapContext` forms the base to receiving traps:

- Get the instance of the class with `DefaultTrapContext trapContext = DefaultTrapContext.getInstance(port, typeSocket)`
- Add a trap listener with `trapContext.addTrapListener(listener)`. The argument is the object that wishes to be notified when the traps arrives. It must implement `uk.co.westhawk.snmp.event.TrapListener`, that is it must have a `public void trapReceived(uk.co.westhawk.snmp.event.TrapEvent evt)` method. This method will get called when the trap is received.

The `DefaultTrapContext` fires undecoded trap events.

### Receiving traps from a specific host

To receive traps from a specific host do the following:

- Create or reuse a context with the host name and parameters of your SNMP agent. The port number will be ignored in this case.
- Add a trap listener with `context.addTrapListener(listener)`. The argument is the object that wishes to be notified when the traps arrives. It must implement `uk.co.westhawk.snmp.event.TrapListener`, that is it must have a `public void trapReceived(uk.co.westhawk.snmp.event.TrapEvent evt)` method. This method will get called when the trap is received.

The `SnmpContext` classes fires decoded trap events.

### Receiving unhandled traps

Unhandled traps are traps that are received (see traps for all hosts) but do not match any of the contexts (see traps from a specific host):

- Get the instance of the class with `DefaultTrapContext trapContext = DefaultTrapContext.getInstance(port, typeSocket)`
- Add a trap listener with `trapContext.addUnhandledTrapListener(listener)`. The argument is the object that wishes to be notified when unhandled traps are received. It must implement `uk.co.westhawk.snmp.event.TrapListener`, that is it must have a `public void trapReceived(uk.co.westhawk.snmp.event.TrapEvent evt)` method. This method will get called when the trap is received and remains unhandled.

The `DefaultTrapContext` fires undecoded trap events.

# The trap event

There are two types of trap events:

- The decoded trap event where a trap pdu is passed
- The undecoded trap event where the raw bytes of the message are passed

### The decoded trap event

Decoded trap events are fired by the `SnmpContext` classes when receiving traps from a specific host. In this case the `uk.co.westhawk.snmp.event.TrapEvent` will contain one of the two trap PDUs:

- `uk.co.westhawk.snmp.stack.TrapPduv1` - The Trap PDU for SNMPv1
- `uk.co.westhawk.snmp.stack.TrapPduv2` - The Trap PDU for SNMPv2c and SNMPv3

### The undecoded trap event

Undecoded trap events are fired by the `DefaultTrapContext` class when receiving traps for all hosts and/or receiving unhandled traps. In this case the `uk.co.westhawk.snmp.event.TrapEvent` will contain the following:

- `version` - The SNMP version number of the trap
- `host address` - The IP host address of the host where the trap came from
- `message` - The trap in bytes

To decode an undecoded trap event, you create a context on the fly and call `Pdu trapPdu = context.processIncomingTrap(byte[ ] message)`. The context should contain all the parameters needed to decode the message. For SNMPv3 this is not so obvious.

# Coding example

The stack contains a lot of examples in the form of applications in the package `uk.co.westhawk.examplev1`. The package `uk.co.westhawk.examplev2c` contains a few examples for SNMPv2c. The package `uk.co.westhawk.examplev3` contains a few examples for SNMPv3. These packages show you how to use the PDUs and beans. Note that because we implemented SNMPv3 before SNMPv2c, there are more examples for the first one.

The scripts to run these examples are explained in the next section. If this example is not sufficient, check if the other examples do what you are looking for.

This example requests sysContact with the BlockPdu. The complete example can be found in `uk.co.westhawk.examplev1.OneBlockOperation`

    private void createContext(String host, int port, String comm,
          String socketType)
    {
        if (context != null)
        {
            context.destroy();
        }
        try
        {
            context = new SnmpContextPool(host, port, socketType);
            context.setCommunity(comm);
        }
        catch (java.io.IOException exc)
        {
            // give the user feedback
            exc.printStackTrace();
        }
    }

    private void sendGetRequest(String oid)
    {
        pdu = new BlockPdu(context);
        pdu.setPduType(BlockPdu.GET);
        pdu.addOid(oid);
        sendRequest(pdu);
    }

    private void sendRequest(BlockPdu pdu)
    {
        try
        {
            varbind var = pdu.getResponseVariableBinding();
            AsnObjectId oid = var.getOid();
            AsnObject res = var.getValue();
            if (res != null)
            {
                // print or display the answer
            }
            else
            {
                // Received no answer
            }
        }
        catch (PduException exc)
        {
            // give the user feedback
            exc.printStackTrace();
        }
        catch (java.io.IOException exc)
        {
            // give the user feedback
            exc.printStackTrace();
        }
    }

# Running the examples

The `uk.co.westhawk.examplev1`, `uk.co.westhawk.examplev2c` and `uk.co.westhawk.examplev3` directories contain scripts that, after some configuration, will run the applications in this directory on the commandline:

- `runapplication.bat` - MSDOS batch script to run an application
- `runapplication.sh` - Bourne shell script to run an application

To run the scripts on the commandline, the applications have to use the STANDARD socket type. The SNMP jar file only contains the actual SNMP stack, i.e. examples are not included and need to be compiled.

There are two scripts that contain the general environment settings:

- `setenv.bat` - MSDOS batch script with settings
- `setenv.sh` - Bourne shell script with settings

They contain the following parameters:

- `TABLE` - The tablelayout zip or jar file, this file comes with the stack
- `SOURCE` - The root dir where the application source live
- `SNMPJAR` - The snmp jar file. Leave empty (or comment out) when you use the source under SOURCE. SNMPJAR has priority over SOURCE

You only need to customise the following parameter in the runapplication.* scripts:

- `JAVA_HOME` - The root dir where Java lives

You have to pass the name of the class file as argument to the application script. You have to omit the package name, like `'uk.co.westhawk.examplev1.'`, since that is already filled in in the script:

    C:\> cd <to where the applications live>
    C:\> runapplication OneBlockOperation

    % cd <to where the applications live>
    % ./runapplication.sh OneBlockOperation

Most of the applications will accept a properties file as first argument. A properties file has the extension `.properties` and contains the initialisation parameters such as the hostname and the port number. When the argument is missing, the application will look for the file `<classname>.properties` in the current directory.

The commands

    % cd <to where the applications live>
    % ./runapplication.sh OneBlockOperation

and

    % cd <to where the applications live>
    % ./runapplication.sh OneBlockOperation OneBlockOperation.properties

will both use `OneBlockOperation.properties` if that file exists.

# Reading

Our article on Simple Times (issue Dec 2001) explains the history and design decisions of the stack.

The SimpleWeb provides links and information on network management, including software, RFCs and tutorials. The focus is on SNMP and Internet management.

For more background on SNMP we recommend the following books:

- The Simple Book by Marshall T. Rose (Prentice Hall, 1994)
- SNMP, SNMPv2, SNMPv3 and RMON 1 and 2 by William Stallings (Addison-Wesley, 1999), ISBN 0-201-48534-6

# Third party packages

All the jar files that are needed for the core stack are delivered with the stack. A few jar files are used in other packages that do not come with the stack:

- XML parser for Java from IBM
- Xalan XSLT from Apache
- Java Servlets from Sun Microsystems

libsmi is used in the stubs directory. It is available for Linux, Win, Mac.

# Copyright & License

The stack is freeware. The license (see the header of each file) means that you can do whatever you like with it without cost, except

1. blame us when it does/doesn't work
2. remove our copyright

Strictly the license requires that you acknowledge our code, by mentioning its origin in the documentation of any product that uses it (in some cases there may be no documentation).

There are no commercial license fees, nor do we have any GPL-style open-source requirements on our stack.

If you want software written that uses the stack or modifications to it to better suit your project, we would be happy to quote you for the work.

We also offer commercial support for organisations who want it.

11 Nov 2002

Contact the snmp group at Westhawk Ltd