Appendix E. The Twenty-Minute SNMP Tutorial
The Simple Network Management Protocol (SNMP) is the ubiquitous
protocol used to manage devices on a network. Unfortunately, as we
metioned at the beginning of Chapter 10, SNMP is
not a particularly simple protocol (despite its name). This longish
tutorial will give you the information you need to get started with
Version 1 of SNMP.
SNMP is predicated on the
notion that you have a management station that polls an SNMP agent
running on a remote device for information. The agent can also be
instructed to signal the management station if an important condition
arises (like a counter exceeding a threshold). When we programmed in
Perl in Chapter 10, we essentially acted as a
management station, polling the SNMP agents on other network
devices.
We're going to concentrate on Version 1 of SNMP. There have
been seven versions of the protocol (SNMPv1, SNMPsec, SNMPv2p,
SNMPv2c, SNMPv2u, SNMPv2* and SNMPv3) proposed. v1 is the only one
that has been widely implemented and deployed, though v3 is expected
to eventually ascend thanks to its superior security architecture.
Perl
and SNMP both have simple data types. Perl uses a scalar as its base
type. Lists and hashes are just collections of scalars in Perl. In
SNMP, you also work with scalar variables. SNMP
variables can hold one of four primitive types: integers, strings,
object identifiers (more on this in a moment), or null values. And
just like Perl, in SNMP a set of related variables can be grouped
together to form larger structures (most often
tables). This is where their similarity ends.
Perl and SNMP diverge radically when we come to the subject of
variable names. In Perl, you can, given a few restrictions, name your
variables anything you'd like. SNMP variable names are considerably more
restrictive. All SNMP variables exist within a virtual hierarchical
storage structure known as the Management Information Base (MIB). All
valid variable names are defined within this framework. The MIB, now
at version MIB-II, defines a tree structure for all of the objects
(and their names) that can be managed via SNMP.
In some ways the MIB is similar to a filesystem. Instead of
organizing files, the MIB logically organizes management information
in a hierarchical tree-like structure. Each node in this tree has a
short text string, called a label, and an
accompanying number that represents its position at that level in the
tree. To give you a sense of how this works, let's go find the
SNMP variable in the MIB used to hold a system's description of
itself. Bear with me; we have a bit of a tree walking (eight
levels' worth) to get there.
Figure 5.1 shows a picture of the top of the MIB
tree.
The top of the tree consists of standards organizations:
iso(1), ccitt(2),
joint-iso-ccitt(3). Under the
iso(1) node, there is a node called
org(3) for other organizations. Under this node is
dod(6), for the Department of Defense. Under that
node is internet(1), a subtree for the Internet
community.
Here's where things start to get interesting. The Internet
Activities Board has assigned the subtrees listed in Table 5.1 under internet(1).
Table E.1. Subtrees of the internet(1) Node
Subtree |
Description |
---|
directory(1) |
OSI directory |
mgmt(2) |
RFC standard objects |
experimental(3) |
Internet experiments |
private(4) |
Vendor-specific |
security(5) |
Security |
snmpV2(6) |
SNMP internals |
Because we're interested in using SNMP for device management,
we will want to take the mgmt(2) branch, The first
node under mgmt(2) is the MIB itself (this is
almost recursive). Since there is only one MIB, the only node under
mgmt(2) is mib-2(1).
The real meat (or tofu) of the MIB begins at this level in the tree.
We find the first set of branches, called object groups, that hold
the variables we'll want to query:
system(1)
interfaces(2)
at(3)
ip(4)
icmp(5)
tcp(6)
udp(7)
egp(8)
cmot(9)
transmission(10)
snmp(11)
Remember, we're hunting for the "system
description" SNMP variable, so the system(1)
group is the logical place to look. The first node in that tree is
sysDescr(1). We've located the object we
need.
Why
bother with all of this tree-walking stuff? This trip provides us
with sysDescr(1)'s Object Identifier. The
Object Identifier, or OID, is just the dotted set of the numbers from
each label of the tree we encountered on our way to this object.
Figure 5.2 shows this graphically.
So the OID for the Internet tree is 1.3.6.1, the
OID for the system object group is 1.3.6.1.2.1.1,
and the OID for the sysDescr object is
1.3.6.1.2.1.1.1.
When we want to actually use this OID in practice, we'll need
to tack on another number to get the value of this variable. We will
need to append a .0, representing the first (and
only, since a device cannot have more than one description)
instance of this object.
In fact, let's do that; let's use this OID in a sneak
preview of SNMP in action. In this appendix we'll be using the
command-line tools from the UCD-SNMP package for demonstration
purposes. The UCD-SNMP package that can be found at http://ucd-snmp.ucdavis.edu/ is an excellent
free SNMPv1 and v3 implementation. We're using this particular
SNMP implementation because one of the Perl modules links to its
library, but any other client that can send an SNMP request will do
just as nicely. Once you're familiar with command-line SNMP
utilities, making the jump to the Perl equivalents is easy.
The UCD-SNMP command-line tools require us to prepend a dot if we
wish to specify an OID/variable name starting at the root of the
tree. Otherwise the OID/variable name is assumed to begin at the top
of the mib-2 tree. Here are two ways we might
query the machine solarisbox
for its systems description:
$ snmpget solarisbox public .1.3.6.1.2.1.1.1.0
$ snmpget solarisbox public .iso.org.dod.internet.mgmt.mib-2.system.sysDescr.0
These lines both yield:
system.sysDescr.0 = Sun SNMP Agent, Ultra-1
Back to the theory. It is important
to remember that the P in SNMP stands for
Protocol. SNMP itself is just the protocol for
the communication between entities in a management infrastructure.
The operations, or "protocol data units" (PDUs), are
meant to be simple. Here are the PDUs
you'll see most often, especially when programming in
Perl:
get-request
get-request is the workhorse of the PDU family.
get-request is used to poll an SNMP entity for
the value of some SNMP variable. Many people live their whole SNMP
lives using nothing but this operation.
get-next-request
get-next-request is just like
get-request, except it returns the item in the
MIB just after the specified item (the
"first lexicographic successor" in RFC terms). This
operation comes into play most often when you are attempting to find
all of the items in a logical table object. For instance, you might
send a set of repeated get-next-requests to
query for each line of a workstation's ARP table. We'll
see an example of this in practice in a moment.
set-request
set-request does just what you would anticipate;
it attempts to change the value of an SNMP variable. This is the
operation used to change the configuration of an SNMP-capable device.
trap/snmpV2-trap
trap is the SNMPv1 name, and
snmpV2-trap is the SNMPv2/3 name. Traps are
beyond the scope of this book, but in essence they allow you to ask
an SNMP-capable box to signal its management entity about an event
(like a reboot, or a counter threshold being reached) without being
explicitly polled.
response
response is the PDU used to carry the response
back from any of the other PDUs. It can be used to reply to a
get-request, signal if a
set-request succeeded, and so on. You rarely
reference this PDU explicitly when programming, since most SNMP
libraries, programs, and Perl modules automatically handle SNMP
response receipt. Still, it is important to understand not just how
requests are made, but also how they are answered.
If you've never dealt with SNMP before, a natural reaction to
the above list might be "That's it? Get, set, tell me
when something happens, that's all it can do?" But
simple, as SNMP's creators realized early
on, is not the opposite of powerful. If the
manufacturer of an SNMP device chooses her or his variables well,
there's little that cannot be done with the protocol. The
classic example from the RFCs is the rebooting of an SNMP-capable
device. There may be no "reboot-request" PDU, but a
manufacturer could easily implement this operation by using an SNMP
trigger variable to hold the number of seconds before a reboot. When
this variable is changed via set-request, a
reboot of the device could be initiated in the specified amount of
time.
Given this power, what sort of security
is in place to keep anyone with an SNMP client from rebooting your
machine? In earlier versions of the protocol, the protection
mechanism was pretty puny. In fact, some people have taken to
expanding the acronym as "Security Not My Problem"
because of SNMPv1's poor authentication mechanism. To explain
the who, what, and
how of this protection mechanism, we have to
drag out some nomenclature, so bear with me.
SNMPv1
and SNMPv2C allow you to define administrative relationships between
SNMP entities called communities. Communities
are a way of grouping SNMP agents that have similar access
restrictions with the management entities that meet those
restrictions. All entities that are in a community share the same
community name. To prove you are part of a
community, you just have to know the name of that community. That is
the who can access? part of the scheme.
For the "what can they access?" part, RFC1157 calls the
parts of a MIB applicable to a particular network entity an
SNMP MIB view. For instance, an SNMP-capable
toaster would not provide all of the
same SNMP configuration variables as that of an SNMP-capable router.
Each object in a MIB is defined as being accessible
read-only, read-write, or
none. This is known as that object's
SNMP access mode. If we put an SNMP MIB view and
an SNMP access mode together, we get an SNMP community
profile that describes the type of access available to the
applicable variables in the MIB by a particular community.
Now we bring the
who and the what parts
together and we have an SNMP access policy that
describes what kind of access members of a particular community offer
each other.
How does this all work in real life? You configure your router or
your workstation to be in at least two communities, one controlling
read, the other controlling read-write access. People often refer to
these communities as the public and the
private communities, named after popular default
names for these communities. For instance, on a Cisco router you
might include this as part of the configuration:
! set the read-only community name to MyPublicCommunityName
snmp-server community MyPublicCommunityName RO
! set the read-write community name to MyPrivateCommunityName
snmp-server community MyPrivateCommunityName RW
On a Solaris machine, you might include this in the
/etc/snmp/conf/snmpd.conf file:
read-community MyPublicCommunityName
write-community MyPrivateCommunityName
SNMP queries to either of these devices would have to use the
MyPublicCommunityName community name to gain
access to read-only variables or the
MyPrivateCommunityName community names to change
read-write variables on those devices. The community name is then
functioning as a pseudo-password to gain SNMP access to a device.
This is a poor security scheme. Not only is the community name passed
in clear text in every SNMP packet, but it is trying to protect
access using "security by obscurity."
Later versions of SNMP, Version 3 in particular, added significantly
better security to the protocol. RFC2274 and RFC2275 define a User
Security Model (USM) and a View-Based Access Control (VACM) Model.
USM provides crypto-based protection for authentication and
encryption of messages. VACM offers a comprehensive access control
mechanism for MIB objects. These mechanisms are still relatively new
and unimplemented (for instance, only one of the available Perl
modules supports it, and this support is very new). We won't be
discussing these mechanisms here, but it is probably worth your while
to peruse the RFCs since v3 is increasing in
popularity.
E.1. SNMP in Practice
Now
that you've received a healthy dose of SNMP theory, let's
do something practical with this knowledge. You've already seen
how to query a machine's system description (remember the sneak
preview earlier). Now let's look at two more examples: querying
the system uptime and the IP routing table.
Until now, you just had to take my word for the location and name of
an SNMP variable in the MIB. We need to change that, since the first
step in querying information via SNMP is a process I call "MIB
groveling:"