From 2f24177c361ba4d9deba2d7378f84aa96111db80 Mon Sep 17 00:00:00 2001 From: elie Date: Mon, 14 Sep 2015 05:20:24 +0000 Subject: * synchronous oneliner apps redesigned to offer Python generator-based API along with a more comprehensive set of accepted parameters. * massively documented (in Sphinx, NumPy style) --- .../agent/cmdrsp/v2c-custom-scalar-mib-objects.py | 145 +++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 examples/v1arch/asyncore/agent/cmdrsp/v2c-custom-scalar-mib-objects.py (limited to 'examples/v1arch/asyncore/agent/cmdrsp/v2c-custom-scalar-mib-objects.py') diff --git a/examples/v1arch/asyncore/agent/cmdrsp/v2c-custom-scalar-mib-objects.py b/examples/v1arch/asyncore/agent/cmdrsp/v2c-custom-scalar-mib-objects.py new file mode 100644 index 0000000..5119a15 --- /dev/null +++ b/examples/v1arch/asyncore/agent/cmdrsp/v2c-custom-scalar-mib-objects.py @@ -0,0 +1,145 @@ +""" +Implementing scalar MIB objects ++++++++++++++++++++++++++++++++ + +Listen and respond to SNMP GET/GETNEXT queries with the following options: + +* SNMPv1 or SNMPv2c +* with SNMP community "public" +* over IPv4/UDP, listening at 127.0.0.1:161 +* over IPv6/UDP, listening at [::1]:161 +* serving two Managed Objects Instances (sysDescr.0 and sysUptime.0) + +Either of the following Net-SNMP commands will walk this Agent: + +| $ snmpwalk -v2c -c public 127.0.0.1 .1.3.6 +| $ snmpwalk -v2c -c public udp6:[::1] .1.3.6 + +The Command Receiver below uses two distinct transports for communication +with Command Generators - UDP over IPv4 and UDP over IPv6. + +"""# +from pysnmp.carrier.asyncore.dispatch import AsyncoreDispatcher +from pysnmp.carrier.asyncore.dgram import udp, udp6, unix +from pyasn1.codec.ber import encoder, decoder +from pysnmp.proto import api +import time, bisect + +class SysDescr: + name = (1,3,6,1,2,1,1,1,0) + def __eq__(self, other): return self.name == other + def __ne__(self, other): return self.name != other + def __lt__(self, other): return self.name < other + def __le__(self, other): return self.name <= other + def __gt__(self, other): return self.name > other + def __ge__(self, other): return self.name >= other + def __call__(self, protoVer): + return api.protoModules[protoVer].OctetString( + 'PySNMP example command responder' + ) + +class Uptime: + name = (1,3,6,1,2,1,1,3,0) + birthday = time.time() + def __eq__(self, other): return self.name == other + def __ne__(self, other): return self.name != other + def __lt__(self, other): return self.name < other + def __le__(self, other): return self.name <= other + def __gt__(self, other): return self.name > other + def __ge__(self, other): return self.name >= other + def __call__(self, protoVer): + return api.protoModules[protoVer].TimeTicks( + (time.time()-self.birthday)*100 + ) + +mibInstr = ( + SysDescr(), Uptime() # sorted by object name + ) + +mibInstrIdx = {} +for mibVar in mibInstr: + mibInstrIdx[mibVar.name] = mibVar + +def cbFun(transportDispatcher, transportDomain, transportAddress, wholeMsg): + while wholeMsg: + msgVer = api.decodeMessageVersion(wholeMsg) + if msgVer in api.protoModules: + pMod = api.protoModules[msgVer] + else: + print('Unsupported SNMP version %s' % msgVer) + return + reqMsg, wholeMsg = decoder.decode( + wholeMsg, asn1Spec=pMod.Message(), + ) + rspMsg = pMod.apiMessage.getResponse(reqMsg) + rspPDU = pMod.apiMessage.getPDU(rspMsg) + reqPDU = pMod.apiMessage.getPDU(reqMsg) + varBinds = []; pendingErrors = [] + errorIndex = 0 + # GETNEXT PDU + if reqPDU.isSameTypeWith(pMod.GetNextRequestPDU()): + # Produce response var-binds + for oid, val in pMod.apiPDU.getVarBinds(reqPDU): + errorIndex = errorIndex + 1 + # Search next OID to report + nextIdx = bisect.bisect(mibInstr, oid) + if nextIdx == len(mibInstr): + # Out of MIB + varBinds.append((oid, val)) + pendingErrors.append( + (pMod.apiPDU.setEndOfMibError, errorIndex) + ) + else: + # Report value if OID is found + varBinds.append( + (mibInstr[nextIdx].name, mibInstr[nextIdx](msgVer)) + ) + elif reqPDU.isSameTypeWith(pMod.GetRequestPDU()): + for oid, val in pMod.apiPDU.getVarBinds(reqPDU): + if oid in mibInstrIdx: + varBinds.append((oid, mibInstrIdx[oid](msgVer))) + else: + # No such instance + varBinds.append((oid, val)) + pendingErrors.append( + (pMod.apiPDU.setNoSuchInstanceError, errorIndex) + ) + break + else: + # Report unsupported request type + pMod.apiPDU.setErrorStatus(rspPDU, 'genErr') + pMod.apiPDU.setVarBinds(rspPDU, varBinds) + # Commit possible error indices to response PDU + for f, i in pendingErrors: + f(rspPDU, i) + transportDispatcher.sendMessage( + encoder.encode(rspMsg), transportDomain, transportAddress + ) + return wholeMsg + +transportDispatcher = AsyncoreDispatcher() +transportDispatcher.registerRecvCbFun(cbFun) + +# UDP/IPv4 +transportDispatcher.registerTransport( + udp.domainName, udp.UdpSocketTransport().openServerMode(('localhost', 161)) +) + +# UDP/IPv6 +transportDispatcher.registerTransport( + udp6.domainName, udp6.Udp6SocketTransport().openServerMode(('::1', 161)) +) + +## Local domain socket +#transportDispatcher.registerTransport( +# unix.domainName, unix.UnixSocketTransport().openServerMode('/tmp/snmp-agent') +#) + +transportDispatcher.jobStarted(1) + +try: + # Dispatcher will never finish as job#1 never reaches zero + transportDispatcher.runDispatcher() +except: + transportDispatcher.closeDispatcher() + raise -- cgit v1.2.1