Getting Started¶
Note
This document only covers SNMP version 3, but you can read this other document for help Getting Started with SNMPv1 and SNMPv2c.
The first step in any SNMP application is to create an Engine object. It is
important to declare the Engine in a with statement, in orderly to properly
clean up background threads and network resources.
from snmp import Engine
with Engine() as engine:
# This block will contain the entire SNMP application
...
In order to send SNMP requests, you will need to create a Manager object. Each Manager represents a communication channel between your application and a single remote engine (i.e. an Agent), so you will need more than one Manager to manage multiple nodes.
Before creating a Manager, however, you must provide the Engine with credentials
for the user(s) belonging to the engine that it manages. The
Engine.usm.addUser() method tells the Engine about the algorithm(s) and
password(s) for each user. The snmp.security.usm.auth and
snmp.security.usm.priv modules contain implementations of several common
authentication and privacy (encryption) algorithms.
Note
The snmp.security.usm.priv module is considered optional, because it
requires OpenSSL. If you are unable to import this module, it likely
indicates that something went wrong in the installation. The
Installation page may help in resolving the issue.
As an example, imagine a user "admin" that supports authentication using
HMAC-SHA-256 and privacy using CFB128-AES-128, with "maplesyrup" as
the password for both. Here’s what the call to addUser() would look like:
from snmp import Engine
from snmp.security.usm.auth import HmacSha256
from snmp.security.usm.priv import Aes128Cfb
with Engine() as engine:
engine.usm.addUser(
"admin",
authProtocol=HmacSha256,
privProtocol=Aes128Cfb,
secret=b"maplesyrup",
)
In this example, the user has one password for both authentication and privacy.
However, it is also possible to provide two separate passwords with the
authSecret and privSecret arguments, rather than using the secret
argument. Further, note that the first argument, userName, accepts a
str, while all passwords are expected to be of type bytes. A
justification of this behavior is beyond the scope of this document.
After providing the necessary user configuration via the addUser() method,
you may create a Manager by calling Engine.Manager(). For the purposes of
this tutorial, you should provide a single argument, containing the IPv4 address
of the remote engine. If the remote engine is listening on a non-standard port,
then you may instead use a tuple, containing the address and port number. A
variable containing a Manager object should use a name that clearly identifies
the engine that it manages, such as in the following example:
localhost = engine.Manager("127.0.0.1")
Finally, you may send a request using one of the Manager’s four request methods:
get(), getNext(), getBulk(), and set(). The get*() methods
accept any number of str or snmp.types.OID arguments, while
the set() method accepts arguments of type snmp.pdu.VarBind. In all
cases, the result will be a snmp.pdu.ResponsePDU.
The following example combines all the steps described above to query the
sysContact and sysLocation of an SNMP engine listening on the loopback
address.
Note
This code will run out of the box on an Ubuntu machine with just a few simple
setup steps (as the root user). First, install the snmp daemon with apt
install snmpd. Then edit /etc/snmp/snmpd.conf, and uncomment the line
that says createuser authPrivUser SHA-512 myauthphrase AES myprivphrase
(or add it, if it’s not there). Save and exit that file, and then run
systemctl restart snmpd.
from snmp import Engine
from snmp.security.usm.auth import HmacSha512
from snmp.security.usm.priv import Aes128Cfb
with Engine() as engine:
engine.usm.addUser(
"authPrivUser",
authProtocol=HmacSha512,
authSecret=b"myauthphrase",
privProtocol=Aes128Cfb,
privSecret=b"myprivphrase",
)
localhost = engine.Manager("127.0.0.1")
response = localhost.get("1.3.6.1.2.1.1.4.0", "1.3.6.1.2.1.1.6.0")
print(response)
The output of this example should look something like this:
ResponsePDU:
Request ID: 560757371
Error Status: 0
Error Index: 0
Variable Bindings:
1.3.6.1.2.1.1.4.0: OctetString(b'Me <me@example.org>')
1.3.6.1.2.1.1.6.0: OctetString(b'Sitting on the Dock of the Bay')