Advanced topics

Observe SNMP engine internal operations

Receive SNMP TRAP/INFORM messages with the following options:

  • SNMPv1/SNMPv2c
  • with SNMP community “public”
  • over IPv4/UDP, listening at 127.0.0.1:162 over IPv6/UDP, listening at [::1]:162
  • registers its own execution observer to snmpEngine
  • print received data on stdout

Either of the following Net-SNMP commands will send notifications to this receiver:

$ snmptrap -v1 -c public 127.0.0.1 1.3.6.1.4.1.20408.4.1.1.2 127.0.0.1 1 1 123 1.3.6.1.2.1.1.1.0 s test
$ snmptrap -v2c -c public udp6:[::1]:162 123 1.3.6.1.6.3.1.1.5.1 1.3.6.1.2.1.1.5.0 s test
$ snmpinform -v2c -c public 127.0.0.1 123 1.3.6.1.6.3.1.1.5.1
from pysnmp.entity import engine, config
from pysnmp.carrier.asyncore.dgram import udp, udp6
from pysnmp.entity.rfc3413 import ntfrcv

# Create SNMP engine with autogenernated engineID and pre-bound
# to socket transport dispatcher
snmpEngine = engine.SnmpEngine()


# Execution point observer setup

# Register a callback to be invoked at specified execution point of 
# SNMP Engine and passed local variables at code point's local scope
# noinspection PyUnusedLocal,PyUnusedLocal
def requestObserver(snmpEngine, execpoint, variables, cbCtx):
    print('Execution point: %s' % execpoint)
    print('* transportDomain: %s' % '.'.join([str(x) for x in variables['transportDomain']]))
    print('* transportAddress: %s' % '@'.join([str(x) for x in variables['transportAddress']]))
    print('* securityModel: %s' % variables['securityModel'])
    print('* securityName: %s' % variables['securityName'])
    print('* securityLevel: %s' % variables['securityLevel'])
    print('* contextEngineId: %s' % variables['contextEngineId'].prettyPrint())
    print('* contextName: %s' % variables['contextName'].prettyPrint())
    print('* PDU: %s' % variables['pdu'].prettyPrint())


snmpEngine.observer.registerObserver(
    requestObserver,
    'rfc3412.receiveMessage:request',
    'rfc3412.returnResponsePdu'
)

# Transport setup

# UDP over IPv4
config.addTransport(
    snmpEngine,
    udp.domainName,
    udp.UdpTransport().openServerMode(('127.0.0.1', 162))
)

# UDP over IPv6
config.addTransport(
    snmpEngine,
    udp6.domainName,
    udp6.Udp6Transport().openServerMode(('::1', 162))
)

# SNMPv1/2c setup

# SecurityName <-> CommunityName mapping
config.addV1System(snmpEngine, 'my-area', 'public')


# Callback function for receiving notifications
# noinspection PyUnusedLocal,PyUnusedLocal,PyUnusedLocal
def cbFun(snmpEngine, stateReference, contextEngineId, contextName,
          varBinds, cbCtx):
    print('Notification from ContextEngineId "%s", ContextName "%s"' % (contextEngineId.prettyPrint(),
                                                                        contextName.prettyPrint()))
    for name, val in varBinds:
        print('%s = %s' % (name.prettyPrint(), val.prettyPrint()))


# Register SNMP Application at the SNMP engine
ntfrcv.NotificationReceiver(snmpEngine, cbFun)

snmpEngine.transportDispatcher.jobStarted(1)  # this job would never finish

# Run I/O dispatcher which would receive queries and send confirmations
try:
    snmpEngine.transportDispatcher.runDispatcher()
except:
    snmpEngine.observer.unregisterObserver()
    snmpEngine.transportDispatcher.closeDispatcher()
    raise

Download script.

Serve SNMP Community names defined by regexp

Receive SNMP TRAP/INFORM messages with the following options:

  • SNMPv1/SNMPv2c
  • with any SNMP community matching regexp ‘.*love.*’
  • over IPv4/UDP, listening at 127.0.0.1:162
  • print received data on stdout

Either of the following Net-SNMP commands will send notifications to this receiver:

$ snmptrap -v1 -c rollover 127.0.0.1 1.3.6.1.4.1.20408.4.1.1.2 127.0.0.1 1 1 123 1.3.6.1.2.1.1.1.0 s test
$ snmpinform -v2c -c glove 127.0.0.1 123 1.3.6.1.6.3.1.1.5.1

The Notification Receiver below taps on v1/v2c SNMP security module to deliver certains values, normally internal to SNMP Engine, up to the context of user application.

This script examines the value of CommunityName, as it came from peer SNMP Engine, and may modify it to match the only locally configured CommunityName ‘public’. This effectively makes NotificationReceiver accepting messages with CommunityName’s, not explicitly configured to local SNMP Engine.

from pysnmp.entity import engine, config
from pysnmp.carrier.asyncore.dgram import udp
from pysnmp.entity.rfc3413 import ntfrcv
from pysnmp.proto.api import v2c
import re

# Create SNMP engine with autogenernated engineID and pre-bound
# to socket transport dispatcher
snmpEngine = engine.SnmpEngine()


# Register a callback to be invoked at specified execution point of
# SNMP Engine and passed local variables at execution point's local scope.
# If at this execution point passed variables are modified, their new
# values will be propagated back and used by SNMP Engine for securityName
# selection.
# noinspection PyUnusedLocal,PyUnusedLocal,PyUnusedLocal
def requestObserver(snmpEngine, execpoint, variables, cbCtx):
    if re.match('.*love.*', str(variables['communityName'])):
        print('Rewriting communityName \'%s\' from %s into \'public\'' % (variables['communityName'], ':'.join([str(x) for x in variables['transportInformation'][1]])))
        variables['communityName'] = variables['communityName'].clone('public')


snmpEngine.observer.registerObserver(
    requestObserver,
    'rfc2576.processIncomingMsg:writable'
)

# Transport setup

# UDP over IPv4
config.addTransport(
    snmpEngine,
    udp.domainName,
    udp.UdpTransport().openServerMode(('127.0.0.1', 162))
)

# SNMPv1/2c setup

# SecurityName <-> CommunityName mapping
config.addV1System(snmpEngine, 'my-area', 'public')


# Callback function for receiving notifications
# noinspection PyUnusedLocal,PyUnusedLocal,PyUnusedLocal
def cbFun(snmpEngine, stateReference, contextEngineId, contextName,
          varBinds, cbCtx):
    print('Notification from ContextEngineId "%s", ContextName "%s"' % (contextEngineId.prettyPrint(),
                                                                        contextName.prettyPrint()))
    for name, val in varBinds:
        print('%s = %s' % (name.prettyPrint(), val.prettyPrint()))


# Register SNMP Application at the SNMP engine
ntfrcv.NotificationReceiver(snmpEngine, cbFun)

snmpEngine.transportDispatcher.jobStarted(1)  # this job would never finish

# Run I/O dispatcher which would receive queries and send confirmations
try:
    snmpEngine.transportDispatcher.runDispatcher()
except:
    snmpEngine.transportDispatcher.closeDispatcher()
    raise

Download script.

See also: library reference.