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
   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.
