From 3f2f132a9fdf7a48ec6131d5498145dded3cfcad Mon Sep 17 00:00:00 2001 From: Ilya Etingof Date: Tue, 26 Feb 2019 08:56:24 +0100 Subject: PEP-8 long lines and dunders (#245) This patch massively reformats the whole codebase mainly wrapping long lines and eliminating dundered private attributes. --- pysnmp/cache.py | 51 +- pysnmp/carrier/asyncio/base.py | 2 +- pysnmp/carrier/asyncio/dgram/base.py | 46 +- pysnmp/carrier/asyncio/dispatch.py | 26 +- pysnmp/carrier/asyncore/base.py | 38 +- pysnmp/carrier/asyncore/dgram/base.py | 93 +++- pysnmp/carrier/asyncore/dgram/udp6.py | 13 +- pysnmp/carrier/asyncore/dgram/unix.py | 11 +- pysnmp/carrier/asyncore/dispatch.py | 21 +- pysnmp/carrier/base.py | 54 +- pysnmp/carrier/sockmsg.py | 10 +- pysnmp/carrier/twisted/dgram/base.py | 20 +- pysnmp/carrier/twisted/dgram/udp.py | 12 +- pysnmp/carrier/twisted/dgram/unix.py | 10 +- pysnmp/carrier/twisted/dispatch.py | 22 +- pysnmp/debug.py | 43 +- pysnmp/entity/config.py | 203 +++++--- pysnmp/entity/engine.py | 76 +-- pysnmp/entity/observer.py | 6 + pysnmp/entity/rfc3413/cmdgen.py | 99 +++- pysnmp/entity/rfc3413/cmdrsp.py | 42 +- pysnmp/entity/rfc3413/config.py | 48 +- pysnmp/entity/rfc3413/context.py | 27 +- pysnmp/entity/rfc3413/ntforg.py | 107 ++-- pysnmp/entity/rfc3413/ntfrcv.py | 13 +- pysnmp/hlapi/transport.py | 11 +- pysnmp/hlapi/v1arch/asyncio/cmdgen.py | 12 +- pysnmp/hlapi/v1arch/asyncore/cmdgen.py | 1 - pysnmp/hlapi/v1arch/asyncore/sync/cmdgen.py | 3 +- pysnmp/hlapi/v3arch/asyncio/cmdgen.py | 65 ++- pysnmp/hlapi/v3arch/asyncio/transport.py | 20 +- pysnmp/hlapi/v3arch/asyncore/cmdgen.py | 76 +-- pysnmp/hlapi/v3arch/asyncore/ntforg.py | 19 +- pysnmp/hlapi/v3arch/asyncore/sync/cmdgen.py | 15 + pysnmp/hlapi/v3arch/asyncore/sync/ntforg.py | 1 + pysnmp/hlapi/v3arch/asyncore/transport.py | 18 +- pysnmp/hlapi/v3arch/auth.py | 68 ++- pysnmp/hlapi/v3arch/lcd.py | 110 +++- pysnmp/hlapi/v3arch/twisted/cmdgen.py | 99 ++-- pysnmp/hlapi/v3arch/twisted/ntforg.py | 22 +- pysnmp/hlapi/v3arch/twisted/transport.py | 16 +- pysnmp/hlapi/varbinds.py | 15 +- pysnmp/nextid.py | 41 +- pysnmp/proto/acmod/rfc3415.py | 55 +- pysnmp/proto/acmod/void.py | 14 +- pysnmp/proto/api/v1.py | 104 +++- pysnmp/proto/api/v2c.py | 43 +- pysnmp/proto/api/verdec.py | 6 +- pysnmp/proto/cache.py | 20 +- pysnmp/proto/errind.py | 134 +++-- pysnmp/proto/error.py | 5 +- pysnmp/proto/mpmod/base.py | 4 + pysnmp/proto/mpmod/cache.py | 36 +- pysnmp/proto/mpmod/rfc2576.py | 152 +++--- pysnmp/proto/mpmod/rfc3412.py | 442 +++++++++------- pysnmp/proto/proxy/rfc2576.py | 46 +- pysnmp/proto/rfc1155.py | 18 +- pysnmp/proto/rfc1157.py | 11 +- pysnmp/proto/rfc1902.py | 37 +- pysnmp/proto/rfc1905.py | 21 +- pysnmp/proto/rfc3412.py | 304 ++++++----- pysnmp/proto/secmod/cache.py | 12 +- pysnmp/proto/secmod/eso/priv/aes192.py | 6 +- pysnmp/proto/secmod/eso/priv/aes256.py | 6 +- pysnmp/proto/secmod/eso/priv/aesbase.py | 22 +- pysnmp/proto/secmod/eso/priv/des3.py | 51 +- pysnmp/proto/secmod/rfc2576.py | 349 +++++++------ pysnmp/proto/secmod/rfc3414/auth/hmacmd5.py | 38 +- pysnmp/proto/secmod/rfc3414/auth/hmacsha.py | 37 +- pysnmp/proto/secmod/rfc3414/localkey.py | 15 +- pysnmp/proto/secmod/rfc3414/priv/des.py | 53 +- pysnmp/proto/secmod/rfc3414/service.py | 732 +++++++++++++++++---------- pysnmp/proto/secmod/rfc3826/priv/aes.py | 102 ++-- pysnmp/proto/secmod/rfc7860/auth/hmacsha2.py | 64 ++- pysnmp/smi/builder.py | 321 +++++++----- pysnmp/smi/compiler.py | 33 +- pysnmp/smi/error.py | 14 +- pysnmp/smi/indices.py | 86 ++-- pysnmp/smi/instrum.py | 84 +-- pysnmp/smi/rfc1902.py | 695 +++++++++++++++---------- pysnmp/smi/view.py | 255 ++++++---- 81 files changed, 3832 insertions(+), 2300 deletions(-) (limited to 'pysnmp') diff --git a/pysnmp/cache.py b/pysnmp/cache.py index f4b8796e..55521f96 100644 --- a/pysnmp/cache.py +++ b/pysnmp/cache.py @@ -10,36 +10,41 @@ class Cache(object): def __init__(self, maxSize=256): - self.__maxSize = maxSize - self.__size = 0 - self.__chopSize = maxSize // 10 - self.__chopSize = self.__chopSize and self.__chopSize or 1 - self.__cache = {} - self.__usage = {} + self._maxSize = maxSize + self._size = 0 + self._chopSize = maxSize // 10 + self._chopSize = self._chopSize or 1 + self._cache = {} + self._usage = {} def __contains__(self, k): - return k in self.__cache + return k in self._cache def __getitem__(self, k): - self.__usage[k] += 1 - return self.__cache[k] + self._usage[k] += 1 + return self._cache[k] def __len__(self): - return self.__size + return self._size def __setitem__(self, k, v): - if self.__size >= self.__maxSize: - usageKeys = sorted(self.__usage, key=lambda x, d=self.__usage: d[x]) - for _k in usageKeys[:self.__chopSize]: - del self.__cache[_k] - del self.__usage[_k] - self.__size -= self.__chopSize - if k not in self.__cache: - self.__size += 1 - self.__usage[k] = 0 - self.__cache[k] = v + if self._size >= self._maxSize: + usageKeys = sorted( + self._usage, key=lambda x, d=self._usage: d[x]) + + for _k in usageKeys[:self._chopSize]: + del self._cache[_k] + del self._usage[_k] + + self._size -= self._chopSize + + if k not in self._cache: + self._size += 1 + self._usage[k] = 0 + + self._cache[k] = v def __delitem__(self, k): - del self.__cache[k] - del self.__usage[k] - self.__size -= 1 + del self._cache[k] + del self._usage[k] + self._size -= 1 diff --git a/pysnmp/carrier/asyncio/base.py b/pysnmp/carrier/asyncio/base.py index 4ee21ead..65be62ed 100644 --- a/pysnmp/carrier/asyncio/base.py +++ b/pysnmp/carrier/asyncio/base.py @@ -35,5 +35,5 @@ from pysnmp.carrier.base import AbstractTransport class AbstractAsyncioTransport(AbstractTransport): - PROTO_TRANSPORT_DISPATCHER = AsyncioDispatcher """Base Asyncio Transport, to be used with AsyncioDispatcher""" + PROTO_TRANSPORT_DISPATCHER = AsyncioDispatcher diff --git a/pysnmp/carrier/asyncio/dgram/base.py b/pysnmp/carrier/asyncio/dgram/base.py index ae5ab3a7..be91a983 100644 --- a/pysnmp/carrier/asyncio/dgram/base.py +++ b/pysnmp/carrier/asyncio/dgram/base.py @@ -57,27 +57,38 @@ class DgramAsyncioProtocol(asyncio.DatagramProtocol, AbstractAsyncioTransport): def __init__(self, sock=None, sockMap=None, loop=None): self._writeQ = [] self._lport = None + if loop is None: loop = asyncio.get_event_loop() + self.loop = loop def datagram_received(self, datagram, transportAddress): if self._cbFun is None: raise error.CarrierError('Unable to call cbFun') + else: self.loop.call_soon(self._cbFun, self, transportAddress, datagram) def connection_made(self, transport): self.transport = transport + debug.logger & debug.FLAG_IO and debug.logger('connection_made: invoked') + while self._writeQ: outgoingMessage, transportAddress = self._writeQ.pop(0) - debug.logger & debug.FLAG_IO and debug.logger('connection_made: transportAddress %r outgoingMessage %s' % - (transportAddress, debug.hexdump(outgoingMessage))) + + debug.logger & debug.FLAG_IO and debug.logger( + 'connection_made: transportAddress %r outgoingMessage %s' % ( + transportAddress, debug.hexdump(outgoingMessage))) + try: - self.transport.sendto(outgoingMessage, self.normalizeAddress(transportAddress)) + self.transport.sendto( + outgoingMessage, self.normalizeAddress(transportAddress)) + except Exception: - raise error.CarrierError(';'.join(traceback.format_exception(*sys.exc_info()))) + raise error.CarrierError( + ';'.join(traceback.format_exception(*sys.exc_info()))) def connection_lost(self, exc): debug.logger & debug.FLAG_IO and debug.logger('connection_lost: invoked') @@ -89,14 +100,17 @@ class DgramAsyncioProtocol(asyncio.DatagramProtocol, AbstractAsyncioTransport): c = self.loop.create_datagram_endpoint( lambda: self, local_addr=iface, family=self.SOCK_FAMILY ) + # Avoid deprecation warning for asyncio.async() if IS_PYTHON_344_PLUS: self._lport = asyncio.ensure_future(c) + else: # pragma: no cover self._lport = getattr(asyncio, 'async')(c) except Exception: raise error.CarrierError(';'.join(traceback.format_exception(*sys.exc_info()))) + return self def openServerMode(self, iface): @@ -104,36 +118,48 @@ class DgramAsyncioProtocol(asyncio.DatagramProtocol, AbstractAsyncioTransport): c = self.loop.create_datagram_endpoint( lambda: self, local_addr=iface, family=self.SOCK_FAMILY ) + # Avoid deprecation warning for asyncio.async() if IS_PYTHON_344_PLUS: self._lport = asyncio.ensure_future(c) + else: # pragma: no cover self._lport = getattr(asyncio, 'async')(c) + except Exception: raise error.CarrierError(';'.join(traceback.format_exception(*sys.exc_info()))) + return self def closeTransport(self): if self._lport is not None: self._lport.cancel() + if self.transport is not None: self.transport.close() + AbstractAsyncioTransport.closeTransport(self) def sendMessage(self, outgoingMessage, transportAddress): - debug.logger & debug.FLAG_IO and debug.logger('sendMessage: %s transportAddress %r outgoingMessage %s' % ( - (self.transport is None and "queuing" or "sending"), - transportAddress, debug.hexdump(outgoingMessage) - )) + debug.logger & debug.FLAG_IO and debug.logger( + 'sendMessage: %s transportAddress %r outgoingMessage ' + '%s' % (self.transport is None and "queuing" or "sending", + transportAddress, debug.hexdump(outgoingMessage))) + if self.transport is None: self._writeQ.append((outgoingMessage, transportAddress)) + else: try: - self.transport.sendto(outgoingMessage, self.normalizeAddress(transportAddress)) + self.transport.sendto( + outgoingMessage, self.normalizeAddress(transportAddress)) + except Exception: - raise error.CarrierError(';'.join(traceback.format_exception(*sys.exc_info()))) + raise error.CarrierError( + ';'.join(traceback.format_exception(*sys.exc_info()))) def normalizeAddress(self, transportAddress): if not isinstance(transportAddress, self.ADDRESS_TYPE): transportAddress = self.ADDRESS_TYPE(transportAddress) + return transportAddress diff --git a/pysnmp/carrier/asyncio/dispatch.py b/pysnmp/carrier/asyncio/dispatch.py index cb9f2020..2fd7d86e 100644 --- a/pysnmp/carrier/asyncio/dispatch.py +++ b/pysnmp/carrier/asyncio/dispatch.py @@ -34,24 +34,29 @@ import platform import sys import traceback -from pysnmp.carrier.base import AbstractTransportDispatcher -from pysnmp.error import PySnmpError - try: import asyncio + except ImportError: import trollius as asyncio +from pysnmp.carrier.base import AbstractTransportDispatcher +from pysnmp.error import PySnmpError + IS_PYTHON_344_PLUS = platform.python_version_tuple() >= ('3', '4', '4') + class AsyncioDispatcher(AbstractTransportDispatcher): """AsyncioDispatcher based on asyncio event loop""" def __init__(self, *args, **kwargs): AbstractTransportDispatcher.__init__(self) + self.__transportCount = 0 + if 'timeout' in kwargs: self.setTimerResolution(kwargs['timeout']) + self.loopingcall = None self.loop = kwargs.pop('loop', asyncio.get_event_loop()) @@ -65,25 +70,32 @@ class AsyncioDispatcher(AbstractTransportDispatcher): if not self.loop.is_running(): try: self.loop.run_forever() + except KeyboardInterrupt: raise + except Exception: - raise PySnmpError(';'.join(traceback.format_exception(*sys.exc_info()))) + raise PySnmpError( + ';'.join(traceback.format_exception(*sys.exc_info()))) def registerTransport(self, tDomain, transport): if self.loopingcall is None and self.getTimerResolution() > 0: # Avoid deprecation warning for asyncio.async() if IS_PYTHON_344_PLUS: - self.loopingcall = asyncio.ensure_future(self.handle_timeout()) - else: # pragma: no cover - self.loopingcall = getattr(asyncio, 'async')(self.handle_timeout()) + self.loopingcall = asyncio.ensure_future(self.handle_timeout()) + + else: + self.loopingcall = getattr(asyncio, 'async')(self.handle_timeout()) + AbstractTransportDispatcher.registerTransport( self, tDomain, transport ) + self.__transportCount += 1 def unregisterTransport(self, tDomain): t = AbstractTransportDispatcher.getTransport(self, tDomain) + if t is not None: AbstractTransportDispatcher.unregisterTransport(self, tDomain) self.__transportCount -= 1 diff --git a/pysnmp/carrier/asyncore/base.py b/pysnmp/carrier/asyncore/base.py index f7b1af9e..3fa13290 100644 --- a/pysnmp/carrier/asyncore/base.py +++ b/pysnmp/carrier/asyncore/base.py @@ -24,17 +24,21 @@ class AbstractSocketTransport(asyncore.dispatcher, AbstractTransport): # noinspection PyUnusedLocal def __init__(self, sock=None, sockMap=None): asyncore.dispatcher.__init__(self) + if sock is None: if self.SOCK_FAMILY is None: raise error.CarrierError( 'Address family %s not supported' % self.__class__.__name__ ) + if self.SOCK_TYPE is None: raise error.CarrierError( 'Socket type %s not supported' % self.__class__.__name__ ) + try: sock = socket.socket(self.SOCK_FAMILY, self.SOCK_TYPE) + except socket.error as exc: raise error.CarrierError('socket() failed: %s' % exc) @@ -43,9 +47,16 @@ class AbstractSocketTransport(asyncore.dispatcher, AbstractTransport): bsize = sock.getsockopt(socket.SOL_SOCKET, b) if bsize < self.BUFFER_SIZE: sock.setsockopt(socket.SOL_SOCKET, b, self.BUFFER_SIZE) - debug.logger & debug.FLAG_IO and debug.logger('%s: socket %d buffer size increased from %d to %d for buffer %d' % (self.__class__.__name__, sock.fileno(), bsize, self.BUFFER_SIZE, b)) + debug.logger & debug.FLAG_IO and debug.logger( + '%s: socket %d buffer size increased from %d to %d ' + 'for buffer %d' % ( + self.__class__.__name__, sock.fileno(), + bsize, self.BUFFER_SIZE, b)) + except Exception as exc: - debug.logger & debug.FLAG_IO and debug.logger('%s: socket buffer size option mangling failure for buffer: %s' % (self.__class__.__name__, exc)) + debug.logger & debug.FLAG_IO and debug.logger( + '%s: socket buffer size option mangling failure for buffer: ' + '%s' % (self.__class__.__name__, exc)) # The socket map is managed by the AsyncoreDispatcher on # which this transport is registered. Here we just prepare @@ -54,6 +65,7 @@ class AbstractSocketTransport(asyncore.dispatcher, AbstractTransport): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.setblocking(0) + self.set_socket(sock) def __hash__(self): @@ -61,16 +73,6 @@ class AbstractSocketTransport(asyncore.dispatcher, AbstractTransport): # The following two methods are part of base class so here we overwrite # them to separate socket management from dispatcher registration tasks. - # These two are just for dispatcher registration. - def add_channel(self, map=None): - if map is not None: - map[self._fileno] = self - self.connected = True - - def del_channel(self, map=None): - if map is not None and self._fileno in map: - del map[self._fileno] - self.connected = False def registerSocket(self, sockMap=None): self.add_channel(sockMap) @@ -84,6 +86,18 @@ class AbstractSocketTransport(asyncore.dispatcher, AbstractTransport): # asyncore API + # The first two methods are just for dispatcher registration + + def add_channel(self, map=None): + if map is not None: + map[self._fileno] = self + self.connected = True + + def del_channel(self, map=None): + if map is not None and self._fileno in map: + del map[self._fileno] + self.connected = False + def handle_close(self): raise error.CarrierError('Transport unexpectedly closed') diff --git a/pysnmp/carrier/asyncore/dgram/base.py b/pysnmp/carrier/asyncore/dgram/base.py index e456da20..06453096 100644 --- a/pysnmp/carrier/asyncore/dgram/base.py +++ b/pysnmp/carrier/asyncore/dgram/base.py @@ -47,16 +47,20 @@ class DgramSocketTransport(AbstractSocketTransport): if iface is not None: try: self.socket.bind(iface) + except socket.error as exc: - raise error.CarrierError( - 'bind() for %s failed: %s' % (iface is None and "" or iface, exc)) + raise error.CarrierError('bind() for %s failed: %s' % ( + iface is None and "" or iface, exc)) + return self def openServerMode(self, iface): try: self.socket.bind(iface) + except socket.error as exc: raise error.CarrierError('bind() for %s failed: %s' % (iface, exc)) + return self def enableBroadcast(self, flag=1): @@ -64,30 +68,47 @@ class DgramSocketTransport(AbstractSocketTransport): self.socket.setsockopt( socket.SOL_SOCKET, socket.SO_BROADCAST, flag ) + except socket.error as exc: - raise error.CarrierError('setsockopt() for SO_BROADCAST failed: %s' % exc) - debug.logger & debug.FLAG_IO and debug.logger('enableBroadcast: %s option SO_BROADCAST on socket %s' % (flag and "enabled" or "disabled", self.socket.fileno())) + raise error.CarrierError('setsockopt() for SO_BROADCAST ' + 'failed: %s' % exc) + + debug.logger & debug.FLAG_IO and debug.logger( + 'enableBroadcast: %s option SO_BROADCAST on ' + 'socket %s' % (flag and "enabled" or "disabled", self.socket.fileno())) + return self def enablePktInfo(self, flag=1): if (not hasattr(self.socket, 'sendmsg') or not hasattr(self.socket, 'recvmsg')): - raise error.CarrierError('sendmsg()/recvmsg() interface is not supported by this OS and/or Python version') + raise error.CarrierError( + 'sendmsg()/recvmsg() interface is not supported by this OS ' + 'and/or Python version') try: if self.socket.family == socket.AF_INET: self.socket.setsockopt(socket.SOL_IP, socket.IP_PKTINFO, flag) if self.socket.family == socket.AF_INET6: - self.socket.setsockopt(socket.SOL_IPV6, socket.IPV6_RECVPKTINFO, flag) + self.socket.setsockopt( + socket.SOL_IPV6, socket.IPV6_RECVPKTINFO, flag) except socket.error as exc: - raise error.CarrierError('setsockopt() for %s failed: %s' % (self.socket.family == socket.AF_INET6 and "IPV6_RECVPKTINFO" or "IP_PKTINFO", exc)) + raise error.CarrierError( + 'setsockopt() for %s failed: ' + '%s' % (self.socket.family == socket.AF_INET6 and + "IPV6_RECVPKTINFO" or "IP_PKTINFO", exc)) self._sendto = sockmsg.getSendTo(self.ADDRESS_TYPE) self._recvfrom = sockmsg.getRecvFrom(self.ADDRESS_TYPE) - debug.logger & debug.FLAG_IO and debug.logger('enablePktInfo: %s option %s on socket %s' % (self.socket.family == socket.AF_INET6 and "IPV6_RECVPKTINFO" or "IP_PKTINFO", flag and "enabled" or "disabled", self.socket.fileno())) + debug.logger & debug.FLAG_IO and debug.logger( + 'enablePktInfo: %s option %s on socket ' + '%s' % (self.socket.family == socket.AF_INET6 and "IPV6_RECVPKTINFO" + or "IP_PKTINFO", flag and "enabled" or "disabled", + self.socket.fileno())) + return self def enableTransparent(self, flag=1): @@ -96,25 +117,34 @@ class DgramSocketTransport(AbstractSocketTransport): self.socket.setsockopt( socket.SOL_IP, socket.IP_TRANSPARENT, flag ) + if self.socket.family == socket.AF_INET6: self.socket.setsockopt( socket.SOL_IPV6, socket.IPV6_TRANSPARENT, flag ) except socket.error as exc: - raise error.CarrierError('setsockopt() for IP_TRANSPARENT failed: %s' % exc) + raise error.CarrierError('setsockopt() for IP_TRANSPARENT ' + 'failed: %s' % exc) except OSError: - raise error.CarrierError('IP_TRANSPARENT socket option requires superuser priveleges') + raise error.CarrierError('IP_TRANSPARENT socket option requires ' + 'superuser privileges') + + debug.logger & debug.FLAG_IO and debug.logger( + 'enableTransparent: %s option IP_TRANSPARENT on socket ' + '%s' % (flag and "enabled" or "disabled", self.socket.fileno())) - debug.logger & debug.FLAG_IO and debug.logger('enableTransparent: %s option IP_TRANSPARENT on socket %s' % (flag and "enabled" or "disabled", self.socket.fileno())) return self def sendMessage(self, outgoingMessage, transportAddress): self.__outQueue.append( (outgoingMessage, self.normalizeAddress(transportAddress)) ) - debug.logger & debug.FLAG_IO and debug.logger('sendMessage: outgoingMessage queued (%d octets) %s' % (len(outgoingMessage), debug.hexdump(outgoingMessage))) + + debug.logger & debug.FLAG_IO and debug.logger( + 'sendMessage: outgoingMessage queued (%d octets) %s' % ( + len(outgoingMessage), debug.hexdump(outgoingMessage))) def normalizeAddress(self, transportAddress): if not isinstance(transportAddress, self.ADDRESS_TYPE): @@ -134,6 +164,7 @@ class DgramSocketTransport(AbstractSocketTransport): return '0.0.0.0', 0 # asyncore API + def handle_connect(self): pass @@ -142,40 +173,58 @@ class DgramSocketTransport(AbstractSocketTransport): def handle_write(self): outgoingMessage, transportAddress = self.__outQueue.pop(0) - debug.logger & debug.FLAG_IO and debug.logger('handle_write: transportAddress %r -> %r outgoingMessage (%d octets) %s' % (transportAddress.getLocalAddress(), transportAddress, len(outgoingMessage), debug.hexdump(outgoingMessage))) + + debug.logger & debug.FLAG_IO and debug.logger( + 'handle_write: transportAddress %r -> %r outgoingMessage (%d ' + 'octets) %s' % (transportAddress.getLocalAddress(), transportAddress, + len(outgoingMessage), debug.hexdump(outgoingMessage))) + if not transportAddress: - debug.logger & debug.FLAG_IO and debug.logger('handle_write: missing dst address, loosing outgoing msg') + debug.logger & debug.FLAG_IO and debug.logger( + 'handle_write: missing dst address, loosing outgoing msg') return + try: - self._sendto( - self.socket, outgoingMessage, transportAddress - ) + self._sendto(self.socket, outgoingMessage, transportAddress) + except socket.error as exc: if exc.args[0] in SOCK_ERRORS: - debug.logger & debug.FLAG_IO and debug.logger('handle_write: ignoring socket error %s' % exc) + debug.logger & debug.FLAG_IO and debug.logger( + 'handle_write: ignoring socket error %s' % exc) + else: - raise error.CarrierError('sendto() failed for %s: %s' % (transportAddress, exc)) + raise error.CarrierError( + 'sendto() failed for %s: %s' % (transportAddress, exc)) def readable(self): - return 1 + return True def handle_read(self): try: incomingMessage, transportAddress = self._recvfrom(self.socket, 65535) + transportAddress = self.normalizeAddress(transportAddress) + debug.logger & debug.FLAG_IO and debug.logger( - 'handle_read: transportAddress %r -> %r incomingMessage (%d octets) %s' % (transportAddress, transportAddress.getLocalAddress(), len(incomingMessage), debug.hexdump(incomingMessage))) + 'handle_read: transportAddress %r -> %r incomingMessage (%d ' + 'octets) %s' % (transportAddress, transportAddress.getLocalAddress(), + len(incomingMessage), debug.hexdump(incomingMessage))) + if not incomingMessage: self.handle_close() return + else: self._cbFun(self, transportAddress, incomingMessage) return + except socket.error as exc: if exc.args[0] in SOCK_ERRORS: - debug.logger & debug.FLAG_IO and debug.logger('handle_read: known socket error %s' % exc) + debug.logger & debug.FLAG_IO and debug.logger( + 'handle_read: known socket error %s' % exc) SOCK_ERRORS[exc.args[0]] and self.handle_close() return + else: raise error.CarrierError('recvfrom() failed: %s' % exc) diff --git a/pysnmp/carrier/asyncore/dgram/udp6.py b/pysnmp/carrier/asyncore/dgram/udp6.py index 75d348d6..3207c6ff 100644 --- a/pysnmp/carrier/asyncore/dgram/udp6.py +++ b/pysnmp/carrier/asyncore/dgram/udp6.py @@ -22,17 +22,18 @@ class Udp6SocketTransport(DgramSocketTransport): def normalizeAddress(self, transportAddress): if '%' in transportAddress[0]: # strip zone ID - ta = self.ADDRESS_TYPE((transportAddress[0].split('%')[0], - transportAddress[1], - 0, # flowinfo - 0)) # scopeid + ta = self.ADDRESS_TYPE( + (transportAddress[0].split('%')[0], transportAddress[1], 0, 0)) + else: - ta = self.ADDRESS_TYPE((transportAddress[0], - transportAddress[1], 0, 0)) + ta = self.ADDRESS_TYPE( + (transportAddress[0], transportAddress[1], 0, 0)) if (isinstance(transportAddress, self.ADDRESS_TYPE) and transportAddress.getLocalAddress()): + return ta.setLocalAddress(transportAddress.getLocalAddress()) + else: return ta.setLocalAddress(self.getLocalAddress()) diff --git a/pysnmp/carrier/asyncore/dgram/unix.py b/pysnmp/carrier/asyncore/dgram/unix.py index 0f68f962..b5233844 100644 --- a/pysnmp/carrier/asyncore/dgram/unix.py +++ b/pysnmp/carrier/asyncore/dgram/unix.py @@ -9,6 +9,7 @@ import random try: from socket import AF_UNIX + except ImportError: AF_UNIX = None @@ -33,14 +34,20 @@ class UnixSocketTransport(DgramSocketTransport): if iface is None: # UNIX domain sockets must be explicitly bound iface = '' + while len(iface) < 8: iface += chr(random.randrange(65, 91)) iface += chr(random.randrange(97, 123)) - iface = os.path.sep + 'tmp' + os.path.sep + 'pysnmp' + iface + + iface = os.path.join(os.path.sep, 'tmp', 'pysnmp', iface) + if os.path.exists(iface): os.remove(iface) + DgramSocketTransport.openClientMode(self, iface) + self._iface = iface + return self def openServerMode(self, iface): @@ -50,8 +57,10 @@ class UnixSocketTransport(DgramSocketTransport): def closeTransport(self): DgramSocketTransport.closeTransport(self) + try: os.remove(self._iface) + except OSError: pass diff --git a/pysnmp/carrier/asyncore/dispatch.py b/pysnmp/carrier/asyncore/dispatch.py index 897fdd0c..3f448471 100644 --- a/pysnmp/carrier/asyncore/dispatch.py +++ b/pysnmp/carrier/asyncore/dispatch.py @@ -16,7 +16,8 @@ from pysnmp.error import PySnmpError class AsyncoreDispatcher(AbstractTransportDispatcher): def __init__(self): - self.__sockMap = {} # use own map for MT safety + # use own map for MT safety + self.__sockMap = {} AbstractTransportDispatcher.__init__(self) def getSocketMap(self): @@ -25,13 +26,14 @@ class AsyncoreDispatcher(AbstractTransportDispatcher): def setSocketMap(self, sockMap=socket_map): self.__sockMap = sockMap - def registerTransport(self, tDomain, t): - AbstractTransportDispatcher.registerTransport(self, tDomain, t) - t.registerSocket(self.__sockMap) + def registerTransport(self, transportDomain, transport): + AbstractTransportDispatcher.registerTransport( + self, transportDomain, transport) + transport.registerSocket(self.__sockMap) - def unregisterTransport(self, tDomain): - self.getTransport(tDomain).unregisterSocket(self.__sockMap) - AbstractTransportDispatcher.unregisterTransport(self, tDomain) + def unregisterTransport(self, transportDomain): + self.getTransport(transportDomain).unregisterSocket(self.__sockMap) + AbstractTransportDispatcher.unregisterTransport(self, transportDomain) def transportsAreWorking(self): for transport in self.__sockMap.values(): @@ -43,9 +45,12 @@ class AsyncoreDispatcher(AbstractTransportDispatcher): try: loop(timeout or self.getTimerResolution(), use_poll=True, map=self.__sockMap, count=1) + except KeyboardInterrupt: raise except Exception: - raise PySnmpError('poll error: %s' % ';'.join(format_exception(*exc_info()))) + raise PySnmpError( + 'poll error: %s' % ';'.join(format_exception(*exc_info()))) + self.handleTimerTick(time()) diff --git a/pysnmp/carrier/base.py b/pysnmp/carrier/base.py index 12dfc86b..518f304b 100644 --- a/pysnmp/carrier/base.py +++ b/pysnmp/carrier/base.py @@ -53,6 +53,7 @@ class AbstractTransportDispatcher(object): def _cbFun(self, incomingTransport, transportAddress, incomingMessage): if incomingTransport in self.__transportDomainMap: transportDomain = self.__transportDomainMap[incomingTransport] + else: raise error.CarrierError( 'Unregistered transport %s' % (incomingTransport,) @@ -62,6 +63,7 @@ class AbstractTransportDispatcher(object): recvId = self.__routingCbFun( transportDomain, transportAddress, incomingMessage ) + else: recvId = None @@ -69,6 +71,7 @@ class AbstractTransportDispatcher(object): self.__recvCallables[recvId]( self, transportDomain, transportAddress, incomingMessage ) + else: raise error.CarrierError( 'No callback for "%r" found - loosing incoming event' % (recvId,) @@ -81,6 +84,7 @@ class AbstractTransportDispatcher(object): raise error.CarrierError( 'Data routing callback already registered' ) + self.__routingCbFun = routingCbFun def unregisterRoutingCbFun(self): @@ -92,6 +96,7 @@ class AbstractTransportDispatcher(object): raise error.CarrierError( 'Receive callback %r already registered' % (recvId is None and '' or recvId,) ) + self.__recvCallables[recvId] = recvCb def unregisterRecvCbFun(self, recvId=None): @@ -101,38 +106,44 @@ class AbstractTransportDispatcher(object): def registerTimerCbFun(self, timerCbFun, tickInterval=None): if not tickInterval: tickInterval = self.__timerResolution + self.__timerCallables.append(TimerCallable(timerCbFun, tickInterval)) def unregisterTimerCbFun(self, timerCbFun=None): if timerCbFun: self.__timerCallables.remove(timerCbFun) + else: self.__timerCallables = [] - def registerTransport(self, tDomain, transport): - if tDomain in self.__transports: + def registerTransport(self, transportDomain, transport): + if transportDomain in self.__transports: raise error.CarrierError( - 'Transport %s already registered' % (tDomain,) + 'Transport %s already registered' % (transportDomain,) ) + transport.registerCbFun(self._cbFun) - self.__transports[tDomain] = transport - self.__transportDomainMap[transport] = tDomain - def unregisterTransport(self, tDomain): - if tDomain not in self.__transports: + self.__transports[transportDomain] = transport + self.__transportDomainMap[transport] = transportDomain + + def unregisterTransport(self, transportDomain): + if transportDomain not in self.__transports: raise error.CarrierError( - 'Transport %s not registered' % (tDomain,) + 'Transport %s not registered' % (transportDomain,) ) - self.__transports[tDomain].unregisterCbFun() - del self.__transportDomainMap[self.__transports[tDomain]] - del self.__transports[tDomain] + + self.__transports[transportDomain].unregisterCbFun() + + del self.__transportDomainMap[self.__transports[transportDomain]] + del self.__transports[transportDomain] def getTransport(self, transportDomain): if transportDomain in self.__transports: return self.__transports[transportDomain] + raise error.CarrierError( - 'Transport %s not registered' % (transportDomain,) - ) + 'Transport %s not registered' % (transportDomain,)) def sendMessage(self, outgoingMessage, transportDomain, transportAddress): @@ -140,10 +151,10 @@ class AbstractTransportDispatcher(object): self.__transports[transportDomain].sendMessage( outgoingMessage, transportAddress ) + else: - raise error.CarrierError( - 'No suitable transport domain for %s' % (transportDomain,) - ) + raise error.CarrierError('No suitable transport domain for ' + '%s' % (transportDomain,)) def getTimerResolution(self): return self.__timerResolution @@ -151,6 +162,7 @@ class AbstractTransportDispatcher(object): def setTimerResolution(self, timerResolution): if timerResolution < 0.01 or timerResolution > 10: raise error.CarrierError('Impossible timer resolution') + self.__timerResolution = timerResolution self.__timerDelta = timerResolution * 0.05 @@ -173,6 +185,7 @@ class AbstractTransportDispatcher(object): def jobStarted(self, jobId, count=1): if jobId in self.__jobs: self.__jobs[jobId] += count + else: self.__jobs[jobId] = count @@ -191,6 +204,7 @@ class AbstractTransportDispatcher(object): for tDomain in list(self.__transports): self.__transports[tDomain].closeTransport() self.unregisterTransport(tDomain) + self.__transports.clear() self.unregisterRecvCbFun() self.unregisterTimerCbFun() @@ -207,7 +221,8 @@ class AbstractTransportAddress(object): return self._localAddress def clone(self, localAddress=None): - return self.__class__(self).setLocalAddress(localAddress is None and self.getLocalAddress() or localAddress) + return self.__class__(self).setLocalAddress( + localAddress is None and self.getLocalAddress() or localAddress) class AbstractTransport(object): @@ -221,9 +236,8 @@ class AbstractTransport(object): def registerCbFun(self, cbFun): if self._cbFun: - raise error.CarrierError( - 'Callback function %s already registered at %s' % (self._cbFun, self) - ) + raise error.CarrierError('Callback function %s already registered ' + 'at %s' % (self._cbFun, self)) self._cbFun = cbFun def unregisterCbFun(self): diff --git a/pysnmp/carrier/sockmsg.py b/pysnmp/carrier/sockmsg.py index e36bc85a..6249b79d 100644 --- a/pysnmp/carrier/sockmsg.py +++ b/pysnmp/carrier/sockmsg.py @@ -21,11 +21,13 @@ from pysnmp import debug if sys.version_info[:2] < (3, 3): def getRecvFrom(addressType): - raise error.CarrierError('sendmsg()/recvmsg() interface is not supported by this OS and/or Python version') + raise error.CarrierError('sendmsg()/recvmsg() interface is not ' + 'supported by this OS and/or Python version') def getSendTo(addressType): - raise error.CarrierError('sendmsg()/recvmsg() interface is not supported by this OS and/or Python version') + raise error.CarrierError('sendmsg()/recvmsg() interface is not ' + 'supported by this OS and/or Python version') else: import ctypes @@ -82,13 +84,13 @@ else: if anc[0] == socket.SOL_IP and anc[1] == socket.IP_PKTINFO: addr = in_pktinfo.from_buffer_copy(anc[2]) addr = ipaddress.IPv4Address(memoryview(addr.ipi_addr).tobytes()) - _to = (str(addr), s.getsockname()[1]) + _to = str(addr), s.getsockname()[1] break elif anc[0] == socket.SOL_IPV6 and anc[1] == socket.IPV6_PKTINFO: addr = in6_pktinfo.from_buffer_copy(anc[2]) addr = ipaddress.ip_address(memoryview(addr.ipi6_addr).tobytes()) - _to = (str(addr), s.getsockname()[1]) + _to = str(addr), s.getsockname()[1] break debug.logger & debug.FLAG_IO and debug.logger( diff --git a/pysnmp/carrier/twisted/dgram/base.py b/pysnmp/carrier/twisted/dgram/base.py index c752e580..eddd5a76 100644 --- a/pysnmp/carrier/twisted/dgram/base.py +++ b/pysnmp/carrier/twisted/dgram/base.py @@ -18,8 +18,9 @@ class DgramTwistedTransport(DatagramProtocol, AbstractTwistedTransport): # Twisted Datagram API def datagramReceived(self, datagram, transportAddress): - if self._cbFun is None: + if not self._cbFun: raise error.CarrierError('Unable to call cbFun') + else: # Callback fun is called through callLater() in attempt # to make Twisted timed calls work under high load. @@ -27,11 +28,16 @@ class DgramTwistedTransport(DatagramProtocol, AbstractTwistedTransport): def startProtocol(self): debug.logger & debug.FLAG_IO and debug.logger('startProtocol: invoked') + while self._writeQ: outgoingMessage, transportAddress = self._writeQ.pop(0) - debug.logger & debug.FLAG_IO and debug.logger('startProtocol: transportAddress %r outgoingMessage %s' % (transportAddress, debug.hexdump(outgoingMessage))) + debug.logger & debug.FLAG_IO and debug.logger( + 'startProtocol: transportAddress %r outgoingMessage ' + '%s' % (transportAddress, debug.hexdump(outgoingMessage))) + try: self.transport.write(outgoingMessage, transportAddress) + except Exception as exc: raise error.CarrierError('Twisted exception: %s' % exc) @@ -39,11 +45,17 @@ class DgramTwistedTransport(DatagramProtocol, AbstractTwistedTransport): debug.logger & debug.FLAG_IO and debug.logger('stopProtocol: invoked') def sendMessage(self, outgoingMessage, transportAddress): - debug.logger & debug.FLAG_IO and debug.logger('startProtocol: %s transportAddress %r outgoingMessage %s' % ((self.transport is None and "queuing" or "sending"), transportAddress, debug.hexdump(outgoingMessage))) - if self.transport is None: + debug.logger & debug.FLAG_IO and debug.logger( + 'startProtocol: %s transportAddress %r outgoingMessage ' + '%s' % ((self.transport is None and "queuing" or "sending"), + transportAddress, debug.hexdump(outgoingMessage))) + + if not self.transport: self._writeQ.append((outgoingMessage, transportAddress)) + else: try: self.transport.write(outgoingMessage, transportAddress) + except Exception as exc: raise error.CarrierError('Twisted exception: %s' % exc) diff --git a/pysnmp/carrier/twisted/dgram/udp.py b/pysnmp/carrier/twisted/dgram/udp.py index 10cf946f..2057c97d 100644 --- a/pysnmp/carrier/twisted/dgram/udp.py +++ b/pysnmp/carrier/twisted/dgram/udp.py @@ -26,24 +26,30 @@ class UdpTwistedTransport(DgramTwistedTransport): def openClientMode(self, iface=None): if iface is None: iface = ('', 0) + try: self._lport = reactor.listenUDP(iface[1], self, iface[0]) + except Exception as exc: raise error.CarrierError(exc) + return self def openServerMode(self, iface): try: self._lport = reactor.listenUDP(iface[1], self, iface[0]) + except Exception as exc: raise error.CarrierError(exc) + return self def closeTransport(self): if self._lport is not None: - d = self._lport.stopListening() - if d: - d.addCallback(lambda x: None) + deferred = self._lport.stopListening() + if deferred: + deferred.addCallback(lambda x: None) + DgramTwistedTransport.closeTransport(self) diff --git a/pysnmp/carrier/twisted/dgram/unix.py b/pysnmp/carrier/twisted/dgram/unix.py index 6ce3cde2..2d5aa195 100644 --- a/pysnmp/carrier/twisted/dgram/unix.py +++ b/pysnmp/carrier/twisted/dgram/unix.py @@ -26,13 +26,16 @@ class UnixTwistedTransport(DgramTwistedTransport): def openClientMode(self, iface=''): try: self._lport = reactor.connectUNIXDatagram(iface, self) + except Exception as exc: raise error.CarrierError(exc) + return self def openServerMode(self, iface): try: self._lport = reactor.listenUNIXDatagram(iface, self) + except Exception as exc: raise error.CarrierError(exc) @@ -40,9 +43,10 @@ class UnixTwistedTransport(DgramTwistedTransport): def closeTransport(self): if self._lport is not None: - d = self._lport.stopListening() - if d: - d.addCallback(lambda x: None) + deferred = self._lport.stopListening() + if deferred: + deferred.addCallback(lambda x: None) + DgramTwistedTransport.closeTransport(self) diff --git a/pysnmp/carrier/twisted/dispatch.py b/pysnmp/carrier/twisted/dispatch.py index 77f5c168..ace0f6a4 100644 --- a/pysnmp/carrier/twisted/dispatch.py +++ b/pysnmp/carrier/twisted/dispatch.py @@ -28,9 +28,12 @@ class TwistedDispatcher(AbstractTransportDispatcher): def __init__(self, *args, **kwargs): AbstractTransportDispatcher.__init__(self) + self.__transportCount = 0 + if 'timeout' in kwargs: self.setTimerResolution(kwargs['timeout']) + self.loopingcall = task.LoopingCall( lambda self=self: self.handleTimerTick(time.time()) ) @@ -44,22 +47,27 @@ class TwistedDispatcher(AbstractTransportDispatcher): raise except Exception: - raise PySnmpError('reactor error: %s' % ';'.join(traceback.format_exception(*sys.exc_info()))) + raise PySnmpError('reactor error: %s' % ';'.join( + traceback.format_exception(*sys.exc_info()))) # jobstarted/jobfinished might be okay as-is - def registerTransport(self, tDomain, transport): + def registerTransport(self, transportDomain, transport): if not self.loopingcall.running and self.getTimerResolution() > 0: self.loopingcall.start(self.getTimerResolution(), now=False) + AbstractTransportDispatcher.registerTransport( - self, tDomain, transport + self, transportDomain, transport ) + self.__transportCount += 1 - def unregisterTransport(self, tDomain): - t = AbstractTransportDispatcher.getTransport(self, tDomain) - if t is not None: - AbstractTransportDispatcher.unregisterTransport(self, tDomain) + def unregisterTransport(self, transportDomain): + transport = AbstractTransportDispatcher.getTransport( + self, transportDomain) + if transport: + AbstractTransportDispatcher.unregisterTransport( + self, transportDomain) self.__transportCount -= 1 # The last transport has been removed, stop the timeout diff --git a/pysnmp/debug.py b/pysnmp/debug.py index f6e69c79..e0e53607 100644 --- a/pysnmp/debug.py +++ b/pysnmp/debug.py @@ -43,14 +43,20 @@ class Printer(object): def __init__(self, logger=None, handler=None, formatter=None): if logger is None: logger = logging.getLogger('pysnmp') + logger.setLevel(logging.DEBUG) + if handler is None: handler = logging.StreamHandler() + if formatter is None: formatter = logging.Formatter('%(asctime)s %(name)s: %(message)s') + handler.setFormatter(formatter) handler.setLevel(logging.DEBUG) + logger.addHandler(handler) + self.__logger = logger def __call__(self, msg): @@ -64,7 +70,7 @@ if hasattr(logging, 'NullHandler'): NullHandler = logging.NullHandler else: - # Python 2.6 and older + # Python 2.6 class NullHandler(logging.Handler): def emit(self, record): pass @@ -75,33 +81,42 @@ class Debug(object): def __init__(self, *flags, **options): self._flags = FLAG_NONE + if options.get('printer') is not None: self._printer = options.get('printer') + elif self.DEFAULT_PRINTER is not None: self._printer = self.DEFAULT_PRINTER + else: if 'loggerName' in options: # route our logs to parent logger self._printer = Printer( logger=logging.getLogger(options['loggerName']), - handler=NullHandler() - ) + handler=NullHandler()) + else: self._printer = Printer() + self('running pysnmp version %s' % __version__) - for f in flags: - inverse = f and f[0] in ('!', '~') - if inverse: - f = f[1:] + + for flag in flags: + negate = flag and flag[0] in ('!', '~') + if negate: + flag = flag[1:] + try: - if inverse: - self._flags &= ~FLAG_MAP[f] + if negate: + self._flags &= ~FLAG_MAP[flag] + else: - self._flags |= FLAG_MAP[f] + self._flags |= FLAG_MAP[flag] + except KeyError: - raise error.PySnmpError('bad debug flag %s' % f) + raise error.PySnmpError('bad debug flag %s' % flag) - self('debug category \'%s\' %s' % (f, inverse and 'disabled' or 'enabled')) + self('debug category "%s" ' + '%s' % (flag, negate and 'disabled' or 'enabled')) def __str__(self): return 'logger %s, flags %x' % (self._printer, self._flags) @@ -128,5 +143,5 @@ def setLogger(l): def hexdump(octets): return ' '.join( - ['%s%.2X' % (n % 16 == 0 and ('\n%.5d: ' % n) or '', x) - for n, x in zip(range(len(octets)), octs2ints(octets))]) + '%s%.2X' % (n % 16 == 0 and ('\n%.5d: ' % n) or '', x) + for n, x in zip(range(len(octets)), octs2ints(octets))) diff --git a/pysnmp/entity/config.py b/pysnmp/entity/config.py index 0ae87c0b..57e8704f 100644 --- a/pysnmp/entity/config.py +++ b/pysnmp/entity/config.py @@ -77,9 +77,13 @@ PRIV_SERVICES = { def __cookV1SystemInfo(snmpEngine, communityIndex): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder - snmpEngineID, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') - snmpCommunityEntry, = mibBuilder.importSymbols('SNMP-COMMUNITY-MIB', 'snmpCommunityEntry') + snmpEngineID, = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') + snmpCommunityEntry, = mibBuilder.importSymbols( + 'SNMP-COMMUNITY-MIB', 'snmpCommunityEntry') + tblIdx = snmpCommunityEntry.getInstIdFromIndices(communityIndex) + return snmpCommunityEntry, tblIdx, snmpEngineID @@ -91,6 +95,7 @@ def addV1System(snmpEngine, communityIndex, communityName, if contextEngineId is None: contextEngineId = snmpEngineID.syntax + else: contextEngineId = snmpEngineID.syntax.clone(contextEngineId) @@ -101,10 +106,13 @@ def addV1System(snmpEngine, communityIndex, communityName, (snmpCommunityEntry.name + (8,) + tblIdx, 'destroy'), snmpEngine=snmpEngine ) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (snmpCommunityEntry.name + (1,) + tblIdx, communityIndex), (snmpCommunityEntry.name + (2,) + tblIdx, communityName), - (snmpCommunityEntry.name + (3,) + tblIdx, securityName is not None and securityName or communityIndex), + (snmpCommunityEntry.name + (3,) + tblIdx, ( + securityName is not None and securityName or + communityIndex)), (snmpCommunityEntry.name + (4,) + tblIdx, contextEngineId), (snmpCommunityEntry.name + (5,) + tblIdx, contextName), (snmpCommunityEntry.name + (6,) + tblIdx, transportTag), @@ -117,6 +125,7 @@ def addV1System(snmpEngine, communityIndex, communityName, def delV1System(snmpEngine, communityIndex): (snmpCommunityEntry, tblIdx, snmpEngineID) = __cookV1SystemInfo(snmpEngine, communityIndex) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (snmpCommunityEntry.name + (8,) + tblIdx, 'destroy'), snmpEngine=snmpEngine @@ -126,17 +135,23 @@ def delV1System(snmpEngine, communityIndex): def __cookV3UserInfo(snmpEngine, securityName, securityEngineId): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder - snmpEngineID, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') + snmpEngineID, = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') if securityEngineId is None: snmpEngineID = snmpEngineID.syntax + else: snmpEngineID = snmpEngineID.syntax.clone(securityEngineId) - usmUserEntry, = mibBuilder.importSymbols('SNMP-USER-BASED-SM-MIB', 'usmUserEntry') + usmUserEntry, = mibBuilder.importSymbols( + 'SNMP-USER-BASED-SM-MIB', 'usmUserEntry') + tblIdx1 = usmUserEntry.getInstIdFromIndices(snmpEngineID, securityName) - pysnmpUsmSecretEntry, = mibBuilder.importSymbols('PYSNMP-USM-MIB', 'pysnmpUsmSecretEntry') + pysnmpUsmSecretEntry, = mibBuilder.importSymbols( + 'PYSNMP-USM-MIB', 'pysnmpUsmSecretEntry') + tblIdx2 = pysnmpUsmSecretEntry.getInstIdFromIndices(securityName) return snmpEngineID, usmUserEntry, tblIdx1, pysnmpUsmSecretEntry, tblIdx2 @@ -147,24 +162,29 @@ def addV3User(snmpEngine, userName, privProtocol=USM_PRIV_NONE, privKey=None, securityEngineId=None, securityName=None): + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder if securityName is None: securityName = userName (snmpEngineID, usmUserEntry, tblIdx1, - pysnmpUsmSecretEntry, tblIdx2) = __cookV3UserInfo(snmpEngine, userName, securityEngineId) + pysnmpUsmSecretEntry, tblIdx2) = __cookV3UserInfo( + snmpEngine, userName, securityEngineId) # Load augmenting table before creating new row in base one - pysnmpUsmKeyEntry, = mibBuilder.importSymbols('PYSNMP-USM-MIB', 'pysnmpUsmKeyEntry') + pysnmpUsmKeyEntry, = mibBuilder.importSymbols( + 'PYSNMP-USM-MIB', 'pysnmpUsmKeyEntry') # Load clone-from (may not be needed) - zeroDotZero, = mibBuilder.importSymbols('SNMPv2-SMI', 'zeroDotZero') + zeroDotZero, = mibBuilder.importSymbols( + 'SNMPv2-SMI', 'zeroDotZero') snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (usmUserEntry.name + (13,) + tblIdx1, 'destroy'), snmpEngine=snmpEngine ) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (usmUserEntry.name + (2,) + tblIdx1, userName), (usmUserEntry.name + (3,) + tblIdx1, securityName), @@ -180,9 +200,11 @@ def addV3User(snmpEngine, userName, hashedAuthPassphrase = AUTH_SERVICES[authProtocol].hashPassphrase( authKey and authKey or null ) + localAuthKey = AUTH_SERVICES[authProtocol].localizeKey( hashedAuthPassphrase, snmpEngineID ) + else: raise error.PySnmpError('Unknown auth protocol %s' % (authProtocol,)) @@ -190,9 +212,11 @@ def addV3User(snmpEngine, userName, hashedPrivPassphrase = PRIV_SERVICES[privProtocol].hashPassphrase( authProtocol, privKey and privKey or null ) + localPrivKey = PRIV_SERVICES[privProtocol].localizeKey( authProtocol, hashedPrivPassphrase, snmpEngineID ) + else: raise error.PySnmpError('Unknown priv protocol %s' % (privProtocol,)) @@ -211,6 +235,7 @@ def addV3User(snmpEngine, userName, (pysnmpUsmSecretEntry.name + (4,) + tblIdx2, 'destroy'), snmpEngine=snmpEngine ) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (pysnmpUsmSecretEntry.name + (1,) + tblIdx2, userName), (pysnmpUsmSecretEntry.name + (2,) + tblIdx2, authKey), @@ -225,10 +250,12 @@ def delV3User(snmpEngine, securityEngineId=None): (snmpEngineID, usmUserEntry, tblIdx1, pysnmpUsmSecretEntry, tblIdx2) = __cookV3UserInfo(snmpEngine, userName, securityEngineId) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (usmUserEntry.name + (13,) + tblIdx1, 'destroy'), snmpEngine=snmpEngine ) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (pysnmpUsmSecretEntry.name + (4,) + tblIdx2, 'destroy'), snmpEngine=snmpEngine @@ -272,6 +299,7 @@ def __cookTargetParamsInfo(snmpEngine, name): snmpTargetParamsEntry, = mibBuilder.importSymbols('SNMP-TARGET-MIB', 'snmpTargetParamsEntry') tblIdx = snmpTargetParamsEntry.getInstIdFromIndices(name) + return snmpTargetParamsEntry, tblIdx @@ -279,10 +307,13 @@ def __cookTargetParamsInfo(snmpEngine, name): def addTargetParams(snmpEngine, name, securityName, securityLevel, mpModel=3): if mpModel == 0: securityModel = 1 + elif mpModel in (1, 2): securityModel = 2 + elif mpModel == 3: securityModel = 3 + else: raise error.PySnmpError('Unknown MP model %s' % mpModel) @@ -292,6 +323,7 @@ def addTargetParams(snmpEngine, name, securityName, securityLevel, mpModel=3): (snmpTargetParamsEntry.name + (7,) + tblIdx, 'destroy'), snmpEngine=snmpEngine ) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (snmpTargetParamsEntry.name + (1,) + tblIdx, name), (snmpTargetParamsEntry.name + (2,) + tblIdx, mpModel), @@ -323,28 +355,36 @@ def __cookTargetAddrInfo(snmpEngine, addrName): def addTargetAddr(snmpEngine, addrName, transportDomain, transportAddress, params, timeout=None, retryCount=None, tagList=null, sourceAddress=None): + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder - (snmpTargetAddrEntry, snmpSourceAddrEntry, + (snmpTargetAddrEntry, + snmpSourceAddrEntry, tblIdx) = __cookTargetAddrInfo(snmpEngine, addrName) if transportDomain[:len(SNMP_UDP_DOMAIN)] == SNMP_UDP_DOMAIN: SnmpUDPAddress, = mibBuilder.importSymbols('SNMPv2-TM', 'SnmpUDPAddress') transportAddress = SnmpUDPAddress(transportAddress) + if sourceAddress is None: sourceAddress = ('0.0.0.0', 0) + sourceAddress = SnmpUDPAddress(sourceAddress) + elif transportDomain[:len(SNMP_UDP6_DOMAIN)] == SNMP_UDP6_DOMAIN: TransportAddressIPv6, = mibBuilder.importSymbols('TRANSPORT-ADDRESS-MIB', 'TransportAddressIPv6') transportAddress = TransportAddressIPv6(transportAddress) + if sourceAddress is None: sourceAddress = ('::', 0) + sourceAddress = TransportAddressIPv6(sourceAddress) snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (snmpTargetAddrEntry.name + (9,) + tblIdx, 'destroy'), snmpEngine=snmpEngine ) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (snmpTargetAddrEntry.name + (1,) + tblIdx, addrName), (snmpTargetAddrEntry.name + (2,) + tblIdx, transportDomain), @@ -362,6 +402,7 @@ def addTargetAddr(snmpEngine, addrName, transportDomain, transportAddress, def delTargetAddr(snmpEngine, addrName): (snmpTargetAddrEntry, snmpSourceAddrEntry, tblIdx) = __cookTargetAddrInfo(snmpEngine, addrName) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (snmpTargetAddrEntry.name + (9,) + tblIdx, 'destroy'), snmpEngine=snmpEngine @@ -372,18 +413,23 @@ def addTransport(snmpEngine, transportDomain, transport): if snmpEngine.transportDispatcher: if not transport.isCompatibleWithDispatcher(snmpEngine.transportDispatcher): raise error.PySnmpError( - 'Transport %r is not compatible with dispatcher %r' % (transport, snmpEngine.transportDispatcher)) + 'Transport %r is not compatible with dispatcher %r' % ( + transport, snmpEngine.transportDispatcher)) + else: snmpEngine.registerTransportDispatcher( transport.PROTO_TRANSPORT_DISPATCHER() ) + # here we note that we have created transportDispatcher automatically snmpEngine.setUserContext(automaticTransportDispatcher=0) snmpEngine.transportDispatcher.registerTransport(transportDomain, transport) + automaticTransportDispatcher = snmpEngine.getUserContext( 'automaticTransportDispatcher' ) + if automaticTransportDispatcher is not None: snmpEngine.setUserContext( automaticTransportDispatcher=automaticTransportDispatcher + 1 @@ -393,8 +439,10 @@ def addTransport(snmpEngine, transportDomain, transport): def getTransport(snmpEngine, transportDomain): if not snmpEngine.transportDispatcher: return + try: return snmpEngine.transportDispatcher.getTransport(transportDomain) + except error.PySnmpError: return @@ -402,21 +450,26 @@ def getTransport(snmpEngine, transportDomain): def delTransport(snmpEngine, transportDomain): if not snmpEngine.transportDispatcher: return + transport = getTransport(snmpEngine, transportDomain) + snmpEngine.transportDispatcher.unregisterTransport(transportDomain) + # automatically shutdown automatically created transportDispatcher automaticTransportDispatcher = snmpEngine.getUserContext( 'automaticTransportDispatcher' ) + if automaticTransportDispatcher is not None: automaticTransportDispatcher -= 1 snmpEngine.setUserContext( - automaticTransportDispatcher=automaticTransportDispatcher - ) + automaticTransportDispatcher=automaticTransportDispatcher) + if not automaticTransportDispatcher: snmpEngine.transportDispatcher.closeDispatcher() snmpEngine.unregisterTransportDispatcher() snmpEngine.delUserContext(automaticTransportDispatcher) + return transport @@ -428,8 +481,12 @@ delSocketTransport = delTransport def __cookVacmContextInfo(snmpEngine, contextName): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder - vacmContextEntry, = mibBuilder.importSymbols('SNMP-VIEW-BASED-ACM-MIB', 'vacmContextEntry') + + vacmContextEntry, = mibBuilder.importSymbols( + 'SNMP-VIEW-BASED-ACM-MIB', 'vacmContextEntry') + tblIdx = vacmContextEntry.getInstIdFromIndices(contextName) + return vacmContextEntry, tblIdx @@ -440,6 +497,7 @@ def addContext(snmpEngine, contextName): (vacmContextEntry.name + (2,) + tblIdx, 'destroy'), snmpEngine=snmpEngine ) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (vacmContextEntry.name + (1,) + tblIdx, contextName), (vacmContextEntry.name + (2,) + tblIdx, 'createAndGo'), @@ -459,20 +517,24 @@ def delContext(snmpEngine, contextName): def __cookVacmGroupInfo(snmpEngine, securityModel, securityName): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder - vacmSecurityToGroupEntry, = mibBuilder.importSymbols('SNMP-VIEW-BASED-ACM-MIB', - 'vacmSecurityToGroupEntry') - tblIdx = vacmSecurityToGroupEntry.getInstIdFromIndices(securityModel, - securityName) + vacmSecurityToGroupEntry, = mibBuilder.importSymbols( + 'SNMP-VIEW-BASED-ACM-MIB', 'vacmSecurityToGroupEntry') + + tblIdx = vacmSecurityToGroupEntry.getInstIdFromIndices( + securityModel, securityName) + return vacmSecurityToGroupEntry, tblIdx def addVacmGroup(snmpEngine, groupName, securityModel, securityName): (vacmSecurityToGroupEntry, tblIdx) = __cookVacmGroupInfo(snmpEngine, securityModel, securityName) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (vacmSecurityToGroupEntry.name + (5,) + tblIdx, 'destroy'), snmpEngine=snmpEngine ) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (vacmSecurityToGroupEntry.name + (1,) + tblIdx, securityModel), (vacmSecurityToGroupEntry.name + (2,) + tblIdx, securityName), @@ -486,6 +548,7 @@ def delVacmGroup(snmpEngine, securityModel, securityName): vacmSecurityToGroupEntry, tblIdx = __cookVacmGroupInfo( snmpEngine, securityModel, securityName ) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (vacmSecurityToGroupEntry.name + (5,) + tblIdx, 'destroy'), snmpEngine=snmpEngine @@ -496,17 +559,19 @@ def __cookVacmAccessInfo(snmpEngine, groupName, contextName, securityModel, securityLevel): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder - vacmAccessEntry, = mibBuilder.importSymbols('SNMP-VIEW-BASED-ACM-MIB', 'vacmAccessEntry') - tblIdx = vacmAccessEntry.getInstIdFromIndices(groupName, contextName, - securityModel, securityLevel) + vacmAccessEntry, = mibBuilder.importSymbols( + 'SNMP-VIEW-BASED-ACM-MIB', 'vacmAccessEntry') + + tblIdx = vacmAccessEntry.getInstIdFromIndices( + groupName, contextName, securityModel, securityLevel) + return vacmAccessEntry, tblIdx def addVacmAccess(snmpEngine, groupName, contextName, securityModel, securityLevel, prefix, readView, writeView, notifyView): - vacmAccessEntry, tblIdx = __cookVacmAccessInfo(snmpEngine, groupName, - contextName, securityModel, - securityLevel) + vacmAccessEntry, tblIdx = __cookVacmAccessInfo( + snmpEngine, groupName, contextName, securityModel, securityLevel) addContext(snmpEngine, contextName) @@ -514,6 +579,7 @@ def addVacmAccess(snmpEngine, groupName, contextName, securityModel, (vacmAccessEntry.name + (9,) + tblIdx, 'destroy'), snmpEngine=snmpEngine ) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (vacmAccessEntry.name + (1,) + tblIdx, contextName), (vacmAccessEntry.name + (2,) + tblIdx, securityModel), @@ -529,9 +595,9 @@ def addVacmAccess(snmpEngine, groupName, contextName, securityModel, def delVacmAccess(snmpEngine, groupName, contextName, securityModel, securityLevel): - vacmAccessEntry, tblIdx = __cookVacmAccessInfo(snmpEngine, groupName, - contextName, securityModel, - securityLevel) + + vacmAccessEntry, tblIdx = __cookVacmAccessInfo( + snmpEngine, groupName, contextName, securityModel, securityLevel) delContext(snmpEngine, contextName) @@ -545,19 +611,23 @@ def __cookVacmViewInfo(snmpEngine, viewName, subTree): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder vacmViewTreeFamilyEntry, = mibBuilder.importSymbols( - 'SNMP-VIEW-BASED-ACM-MIB', 'vacmViewTreeFamilyEntry' - ) + 'SNMP-VIEW-BASED-ACM-MIB', 'vacmViewTreeFamilyEntry') + tblIdx = vacmViewTreeFamilyEntry.getInstIdFromIndices(viewName, subTree) + return vacmViewTreeFamilyEntry, tblIdx def addVacmView(snmpEngine, viewName, viewType, subTree, mask): - vacmViewTreeFamilyEntry, tblIdx = __cookVacmViewInfo(snmpEngine, viewName, - subTree) + + vacmViewTreeFamilyEntry, tblIdx = __cookVacmViewInfo( + snmpEngine, viewName, subTree) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (vacmViewTreeFamilyEntry.name + (6,) + tblIdx, 'destroy'), snmpEngine=snmpEngine ) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (vacmViewTreeFamilyEntry.name + (1,) + tblIdx, viewName), (vacmViewTreeFamilyEntry.name + (2,) + tblIdx, subTree), @@ -569,8 +639,9 @@ def addVacmView(snmpEngine, viewName, viewType, subTree, mask): def delVacmView(snmpEngine, viewName, subTree): - vacmViewTreeFamilyEntry, tblIdx = __cookVacmViewInfo(snmpEngine, viewName, - subTree) + vacmViewTreeFamilyEntry, tblIdx = __cookVacmViewInfo( + snmpEngine, viewName, subTree) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (vacmViewTreeFamilyEntry.name + (6,) + tblIdx, 'destroy'), snmpEngine=snmpEngine @@ -583,8 +654,11 @@ def __cookVacmUserInfo(snmpEngine, securityModel, securityName, securityLevel): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder groupName = 'v-%s-%d' % (hash(securityName), securityModel) + SnmpSecurityLevel, = mibBuilder.importSymbols('SNMP-FRAMEWORK-MIB', 'SnmpSecurityLevel') + securityLevel = SnmpSecurityLevel(securityLevel) + return (groupName, securityLevel, 'r' + groupName, 'w' + groupName, 'n' + groupName) @@ -592,16 +666,22 @@ def __cookVacmUserInfo(snmpEngine, securityModel, securityName, securityLevel): def addVacmUser(snmpEngine, securityModel, securityName, securityLevel, readSubTree=(), writeSubTree=(), notifySubTree=(), contextName=null): + (groupName, securityLevel, readView, writeView, - notifyView) = __cookVacmUserInfo(snmpEngine, securityModel, securityName, - securityLevel) + notifyView) = __cookVacmUserInfo( + snmpEngine, securityModel, securityName, securityLevel) + addVacmGroup(snmpEngine, groupName, securityModel, securityName) + addVacmAccess(snmpEngine, groupName, contextName, securityModel, securityLevel, 1, readView, writeView, notifyView) + if readSubTree: addVacmView(snmpEngine, readView, "included", readSubTree, null) + if writeSubTree: addVacmView(snmpEngine, writeView, "included", writeSubTree, null) + if notifySubTree: addVacmView(snmpEngine, notifyView, "included", notifySubTree, null) @@ -610,43 +690,48 @@ def delVacmUser(snmpEngine, securityModel, securityName, securityLevel, readSubTree=(), writeSubTree=(), notifySubTree=(), contextName=null): (groupName, securityLevel, readView, writeView, - notifyView) = __cookVacmUserInfo(snmpEngine, securityModel, - securityName, securityLevel) + notifyView) = __cookVacmUserInfo( + snmpEngine, securityModel, securityName, securityLevel) + delVacmGroup(snmpEngine, securityModel, securityName) + delVacmAccess(snmpEngine, groupName, contextName, securityModel, securityLevel) + if readSubTree: - delVacmView( - snmpEngine, readView, readSubTree - ) + delVacmView(snmpEngine, readView, readSubTree) + if writeSubTree: - delVacmView( - snmpEngine, writeView, writeSubTree - ) + delVacmView(snmpEngine, writeView, writeSubTree) + if notifySubTree: - delVacmView( - snmpEngine, notifyView, notifySubTree - ) + delVacmView(snmpEngine, notifyView, notifySubTree) # Notification target setup def __cookNotificationTargetInfo(snmpEngine, notificationName, paramsName, filterSubtree=None): + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder - snmpNotifyEntry, = mibBuilder.importSymbols('SNMP-NOTIFICATION-MIB', 'snmpNotifyEntry') + snmpNotifyEntry, = mibBuilder.importSymbols( + 'SNMP-NOTIFICATION-MIB', 'snmpNotifyEntry') + tblIdx1 = snmpNotifyEntry.getInstIdFromIndices(notificationName) - snmpNotifyFilterProfileEntry, = mibBuilder.importSymbols('SNMP-NOTIFICATION-MIB', - 'snmpNotifyFilterProfileEntry') + snmpNotifyFilterProfileEntry, = mibBuilder.importSymbols( + 'SNMP-NOTIFICATION-MIB', 'snmpNotifyFilterProfileEntry') + tblIdx2 = snmpNotifyFilterProfileEntry.getInstIdFromIndices(paramsName) profileName = '%s-filter' % hash(notificationName) if filterSubtree: - snmpNotifyFilterEntry, = mibBuilder.importSymbols('SNMP-NOTIFICATION-MIB', - 'snmpNotifyFilterEntry') - tblIdx3 = snmpNotifyFilterEntry.getInstIdFromIndices(profileName, - filterSubtree) + snmpNotifyFilterEntry, = mibBuilder.importSymbols( + 'SNMP-NOTIFICATION-MIB', 'snmpNotifyFilterEntry') + + tblIdx3 = snmpNotifyFilterEntry.getInstIdFromIndices( + profileName, filterSubtree) + else: snmpNotifyFilterEntry = tblIdx3 = None @@ -658,15 +743,17 @@ def __cookNotificationTargetInfo(snmpEngine, notificationName, paramsName, def addNotificationTarget(snmpEngine, notificationName, paramsName, transportTag, notifyType=None, filterSubtree=None, filterMask=None, filterType=None): + (snmpNotifyEntry, tblIdx1, snmpNotifyFilterProfileEntry, tblIdx2, profileName, snmpNotifyFilterEntry, - tblIdx3) = __cookNotificationTargetInfo(snmpEngine, notificationName, - paramsName, filterSubtree) + tblIdx3) = __cookNotificationTargetInfo( + snmpEngine, notificationName, paramsName, filterSubtree) snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (snmpNotifyEntry.name + (5,) + tblIdx1, 'destroy'), snmpEngine=snmpEngine ) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (snmpNotifyEntry.name + (2,) + tblIdx1, transportTag), (snmpNotifyEntry.name + (3,) + tblIdx1, notifyType), @@ -678,6 +765,7 @@ def addNotificationTarget(snmpEngine, notificationName, paramsName, (snmpNotifyFilterProfileEntry.name + (3,) + tblIdx2, 'destroy'), snmpEngine=snmpEngine ) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (snmpNotifyFilterProfileEntry.name + (1,) + tblIdx2, profileName), (snmpNotifyFilterProfileEntry.name + (3,) + tblIdx2, 'createAndGo'), @@ -691,6 +779,7 @@ def addNotificationTarget(snmpEngine, notificationName, paramsName, (snmpNotifyFilterEntry.name + (5,) + tblIdx3, 'destroy'), snmpEngine=snmpEngine ) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (snmpNotifyFilterEntry.name + (1,) + tblIdx3, filterSubtree), (snmpNotifyFilterEntry.name + (2,) + tblIdx3, filterMask), @@ -704,8 +793,8 @@ def delNotificationTarget(snmpEngine, notificationName, paramsName, filterSubtree=None): (snmpNotifyEntry, tblIdx1, snmpNotifyFilterProfileEntry, tblIdx2, profileName, snmpNotifyFilterEntry, - tblIdx3) = __cookNotificationTargetInfo(snmpEngine, notificationName, - paramsName, filterSubtree) + tblIdx3) = __cookNotificationTargetInfo( + snmpEngine, notificationName, paramsName, filterSubtree) snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (snmpNotifyEntry.name + (5,) + tblIdx1, 'destroy'), diff --git a/pysnmp/entity/engine.py b/pysnmp/entity/engine.py index 60b45b0c..d7f16ff8 100644 --- a/pysnmp/entity/engine.py +++ b/pysnmp/entity/engine.py @@ -65,8 +65,12 @@ class SnmpEngine(object): if msgAndPduDsp is None: self.msgAndPduDsp = MsgAndPduDispatcher() + else: self.msgAndPduDsp = msgAndPduDsp + + mibBuilder = self.msgAndPduDsp.mibInstrumController.mibBuilder + self.messageProcessingSubsystems = { SnmpV1MessageProcessingModel.MESSAGE_PROCESSING_MODEL_ID: SnmpV1MessageProcessingModel(), @@ -75,11 +79,13 @@ class SnmpEngine(object): SnmpV3MessageProcessingModel.MESSAGE_PROCESSING_MODEL_ID: SnmpV3MessageProcessingModel() } + self.securityModels = { SnmpV1SecurityModel.SECURITY_MODEL_ID: SnmpV1SecurityModel(), SnmpV2cSecurityModel.SECURITY_MODEL_ID: SnmpV2cSecurityModel(), SnmpUSMSecurityModel.SECURITY_MODEL_ID: SnmpUSMSecurityModel() } + self.accessControlModel = { void.Vacm.ACCESS_MODEL_ID: void.Vacm(), rfc3415.Vacm.ACCESS_MODEL_ID: rfc3415.Vacm() @@ -88,48 +94,59 @@ class SnmpEngine(object): self.transportDispatcher = None if self.msgAndPduDsp.mibInstrumController is None: - raise error.PySnmpError( - 'MIB instrumentation does not yet exist' - ) - snmpEngineMaxMessageSize, = self.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( + raise error.PySnmpError('MIB instrumentation does not yet exist') + + snmpEngineMaxMessageSize, = mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') + snmpEngineMaxMessageSize.syntax = snmpEngineMaxMessageSize.syntax.clone(maxMessageSize) - snmpEngineBoots, = self.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', - 'snmpEngineBoots') + + snmpEngineBoots, = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineBoots') + snmpEngineBoots.syntax += 1 - origSnmpEngineID, = self.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', - 'snmpEngineID') + + origSnmpEngineID, = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') if snmpEngineID is None: self.snmpEngineID = origSnmpEngineID.syntax + else: origSnmpEngineID.syntax = origSnmpEngineID.syntax.clone(snmpEngineID) self.snmpEngineID = origSnmpEngineID.syntax debug.logger & debug.FLAG_APP and debug.logger( - 'SnmpEngine: using custom SNMP Engine ID: %s' % self.snmpEngineID.prettyPrint()) + 'SnmpEngine: using custom SNMP Engine ' + 'ID: %s' % self.snmpEngineID.prettyPrint()) # Attempt to make some of snmp Engine settings persistent. # This should probably be generalized as a non-volatile MIB store. - persistentPath = os.path.join(tempfile.gettempdir(), '__pysnmp', self.snmpEngineID.prettyPrint()) + persistentPath = os.path.join(tempfile.gettempdir(), '__pysnmp', + self.snmpEngineID.prettyPrint()) - debug.logger & debug.FLAG_APP and debug.logger('SnmpEngine: using persistent directory: %s' % persistentPath) + debug.logger & debug.FLAG_APP and debug.logger( + 'SnmpEngine: using persistent directory: %s' % persistentPath) if not os.path.exists(persistentPath): try: os.makedirs(persistentPath) + except OSError: return f = os.path.join(persistentPath, 'boots') + try: snmpEngineBoots.syntax = snmpEngineBoots.syntax.clone(open(f).read()) + except Exception: pass try: snmpEngineBoots.syntax += 1 + except Exception: snmpEngineBoots.syntax = snmpEngineBoots.syntax.clone(1) @@ -138,12 +155,15 @@ class SnmpEngine(object): os.write(fd, str2octs(snmpEngineBoots.syntax.prettyPrint())) os.close(fd) shutil.move(fn, f) + except Exception as exc: debug.logger & debug.FLAG_APP and debug.logger( 'SnmpEngine: could not stored SNMP Engine Boots: %s' % exc) + else: debug.logger & debug.FLAG_APP and debug.logger( - 'SnmpEngine: stored SNMP Engine Boots: %s' % snmpEngineBoots.syntax.prettyPrint()) + 'SnmpEngine: stored SNMP Engine Boots: ' + '%s' % snmpEngineBoots.syntax.prettyPrint()) def __repr__(self): return '%s(snmpEngineID=%r)' % (self.__class__.__name__, self.snmpEngineID) @@ -158,31 +178,28 @@ class SnmpEngine(object): def __receiveTimerTickCbFun(self, timeNow): self.msgAndPduDsp.receiveTimerTick(self, timeNow) + for mpHandler in self.messageProcessingSubsystems.values(): mpHandler.receiveTimerTick(self, timeNow) + for smHandler in self.securityModels.values(): smHandler.receiveTimerTick(self, timeNow) def registerTransportDispatcher(self, transportDispatcher, recvId=None): - if self.transportDispatcher is not None and \ - self.transportDispatcher is not transportDispatcher: - raise error.PySnmpError( - 'Transport dispatcher already registered' - ) - transportDispatcher.registerRecvCbFun( - self.__receiveMessageCbFun, recvId - ) - if self.transportDispatcher is None: - transportDispatcher.registerTimerCbFun( - self.__receiveTimerTickCbFun - ) + if (self.transportDispatcher and + self.transportDispatcher is not transportDispatcher): + raise error.PySnmpError('Transport dispatcher already registered') + + transportDispatcher.registerRecvCbFun(self.__receiveMessageCbFun, recvId) + + if not self.transportDispatcher: + transportDispatcher.registerTimerCbFun(self.__receiveTimerTickCbFun) self.transportDispatcher = transportDispatcher def unregisterTransportDispatcher(self, recvId=None): if self.transportDispatcher is None: - raise error.PySnmpError( - 'Transport dispatcher not registered' - ) + raise error.PySnmpError('Transport dispatcher not registered') + self.transportDispatcher.unregisterRecvCbFun(recvId) self.transportDispatcher.unregisterTimerCbFun() self.transportDispatcher = None @@ -192,9 +209,7 @@ class SnmpEngine(object): # User app may attach opaque objects to SNMP Engine def setUserContext(self, **kwargs): - self.cache.update( - dict([('__%s' % k, kwargs[k]) for k in kwargs]) - ) + self.cache.update(dict([('__%s' % k, kwargs[k]) for k in kwargs])) def getUserContext(self, arg): return self.cache.get('__%s' % arg) @@ -202,5 +217,6 @@ class SnmpEngine(object): def delUserContext(self, arg): try: del self.cache['__%s' % arg] + except KeyError: pass diff --git a/pysnmp/entity/observer.py b/pysnmp/entity/observer.py index 3f7bd845..ddc959c3 100644 --- a/pysnmp/entity/observer.py +++ b/pysnmp/entity/observer.py @@ -31,21 +31,26 @@ class MetaObserver(object): def registerObserver(self, cbFun, *execpoints, **kwargs): if cbFun in self.__contexts: raise error.PySnmpError('duplicate observer %s' % cbFun) + else: self.__contexts[cbFun] = kwargs.get('cbCtx') + for execpoint in execpoints: if execpoint not in self.__observers: self.__observers[execpoint] = [] + self.__observers[execpoint].append(cbFun) def unregisterObserver(self, cbFun=None): if cbFun is None: self.__observers.clear() self.__contexts.clear() + else: for execpoint in dict(self.__observers): if cbFun in self.__observers[execpoint]: self.__observers[execpoint].remove(cbFun) + if not self.__observers[execpoint]: del self.__observers[execpoint] @@ -59,6 +64,7 @@ class MetaObserver(object): if execpoints: for execpoint in execpoints: del self.__execpoints[execpoint] + else: self.__execpoints.clear() diff --git a/pysnmp/entity/rfc3413/cmdgen.py b/pysnmp/entity/rfc3413/cmdgen.py index 6f13c265..17db6f33 100644 --- a/pysnmp/entity/rfc3413/cmdgen.py +++ b/pysnmp/entity/rfc3413/cmdgen.py @@ -49,7 +49,8 @@ class CommandGenerator(object): # 3.1.3 if statusInformation: debug.logger & debug.FLAG_APP and debug.logger( - 'processResponsePdu: sendPduHandle %s, statusInformation %s' % (sendPduHandle, statusInformation)) + 'processResponsePdu: sendPduHandle %s, statusInformation ' + '%s' % (sendPduHandle, statusInformation)) errorIndication = statusInformation['errorIndication'] @@ -60,16 +61,22 @@ class CommandGenerator(object): origDiscoveryRetries = 0 origRetries += 1 - if origRetries > origRetryCount or origDiscoveryRetries > self.__options.get('discoveryRetries', 4): + if (origRetries > origRetryCount or + origDiscoveryRetries > self.__options.get('discoveryRetries', 4)): + debug.logger & debug.FLAG_APP and debug.logger( - 'processResponsePdu: sendPduHandle %s, retry count %d exceeded' % (sendPduHandle, origRetries)) - cbFun(snmpEngine, origSendRequestHandle, errorIndication, None, cbCtx) + 'processResponsePdu: sendPduHandle %s, retry count %d ' + 'exceeded' % (sendPduHandle, origRetries)) + + cbFun(snmpEngine, origSendRequestHandle, + errorIndication, None, cbCtx) return # User-side API assumes SMIv2 if origMessageProcessingModel == 0: reqPDU = rfc2576.v2ToV1(origPdu) pduVersion = 0 + else: reqPDU = origPdu pduVersion = 1 @@ -92,16 +99,20 @@ class CommandGenerator(object): origContextName, origPduVersion, origPdu, origTimeout, origRetryCount, origRetries, origDiscoveryRetries ) + return except StatusInformation as exc: statusInformation = exc + debug.logger & debug.FLAG_APP and debug.logger( - 'processResponsePdu: origSendRequestHandle %s, _sendPdu() failed with %r' % ( - sendPduHandle, statusInformation)) + 'processResponsePdu: origSendRequestHandle %s, _sendPdu() ' + 'failed with %r' % (sendPduHandle, statusInformation)) + cbFun(snmpEngine, origSendRequestHandle, statusInformation['errorIndication'], None, cbCtx) + return if (origMessageProcessingModel != messageProcessingModel or @@ -110,11 +121,14 @@ class CommandGenerator(object): origContextEngineId and origContextEngineId != contextEngineId or origContextName and origContextName != contextName or origPduVersion != pduVersion): + debug.logger & debug.FLAG_APP and debug.logger( - 'processResponsePdu: sendPduHandle %s, request/response data mismatch' % sendPduHandle) + 'processResponsePdu: sendPduHandle %s, request/response ' + 'data mismatch' % sendPduHandle) cbFun(snmpEngine, origSendRequestHandle, 'badResponse', None, cbCtx) + return # User-side API assumes SMIv2 @@ -124,9 +138,12 @@ class CommandGenerator(object): # 3.1.2 if v2c.apiPDU.getRequestID(PDU) != v2c.apiPDU.getRequestID(origPdu): debug.logger & debug.FLAG_APP and debug.logger( - 'processResponsePdu: sendPduHandle %s, request-id/response-id mismatch' % sendPduHandle) + 'processResponsePdu: sendPduHandle %s, request-id/response-id ' + 'mismatch' % sendPduHandle) + cbFun(snmpEngine, origSendRequestHandle, 'badResponse', None, cbCtx) + return cbFun(snmpEngine, origSendRequestHandle, None, PDU, cbCtx) @@ -139,14 +156,18 @@ class CommandGenerator(object): securityLevel) = config.getTargetInfo(snmpEngine, targetName) # Convert timeout in seconds into timeout in timer ticks - timeoutInTicks = float(timeout) / 100 / snmpEngine.transportDispatcher.getTimerResolution() + timeoutInTicks = (float(timeout) / 100 / + snmpEngine.transportDispatcher.getTimerResolution()) + + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder - SnmpEngineID, SnmpAdminString = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( + SnmpEngineID, SnmpAdminString = mibBuilder.importSymbols( 'SNMP-FRAMEWORK-MIB', 'SnmpEngineID', 'SnmpAdminString') # Cast possible strings into bytes if contextEngineId: contextEngineId = SnmpEngineID(contextEngineId) + contextName = SnmpAdminString(contextName) origPDU = PDU @@ -155,6 +176,7 @@ class CommandGenerator(object): if messageProcessingModel == 0: PDU = rfc2576.v2ToV1(PDU) pduVersion = 0 + else: pduVersion = 1 @@ -179,13 +201,14 @@ class CommandGenerator(object): ) debug.logger & debug.FLAG_APP and debug.logger( - 'sendPdu: sendPduHandle %s, timeout %d*10 ms/%d ticks, retry 0 of %d' % ( - sendPduHandle, timeout, timeoutInTicks, retryCount)) + 'sendPdu: sendPduHandle %s, timeout %d*10 ms/%d ticks, retry ' + '0 of %d' % (sendPduHandle, timeout, timeoutInTicks, retryCount)) return sendRequestHandle class GetCommandGenerator(CommandGenerator): + def processResponseVarBinds(self, snmpEngine, sendRequestHandle, errorIndication, PDU, cbCtx): cbFun, cbCtx = cbCtx @@ -208,6 +231,7 @@ class GetCommandGenerator(CommandGenerator): class SetCommandGenerator(CommandGenerator): + def processResponseVarBinds(self, snmpEngine, sendRequestHandle, errorIndication, PDU, cbCtx): cbFun, cbCtx = cbCtx @@ -225,11 +249,12 @@ class SetCommandGenerator(CommandGenerator): v2c.apiPDU.setVarBinds(reqPDU, varBinds) return self.sendPdu(snmpEngine, targetName, contextEngineId, - contextName, reqPDU, - self.processResponseVarBinds, (cbFun, cbCtx)) + contextName, reqPDU, self.processResponseVarBinds, + (cbFun, cbCtx)) class NextCommandGeneratorSingleRun(CommandGenerator): + def processResponseVarBinds(self, snmpEngine, sendRequestHandle, errorIndication, PDU, cbCtx): targetName, contextEngineId, contextName, reqPDU, cbFun, cbCtx = cbCtx @@ -253,6 +278,7 @@ class NextCommandGeneratorSingleRun(CommandGenerator): class NextCommandGenerator(NextCommandGeneratorSingleRun): + def processResponseVarBinds(self, snmpEngine, sendRequestHandle, errorIndication, PDU, cbCtx): targetName, contextEngineId, contextName, reqPDU, cbFun, cbCtx = cbCtx @@ -266,8 +292,10 @@ class NextCommandGenerator(NextCommandGeneratorSingleRun): if v2c.apiPDU.getErrorStatus(PDU): errorIndication, varBinds = None, () + elif not varBindTable: errorIndication, varBinds = errind.emptyResponse, () + else: errorIndication, varBinds = v2c.apiPDU.getNextVarBinds(varBindTable[-1]) @@ -275,9 +303,11 @@ class NextCommandGenerator(NextCommandGeneratorSingleRun): v2c.apiPDU.getErrorStatus(PDU), v2c.apiPDU.getErrorIndex(PDU, muteErrors=True), varBindTable, cbCtx): + debug.logger & debug.FLAG_APP and debug.logger( 'processResponseVarBinds: sendRequestHandle %s, app says to stop walking' % sendRequestHandle) - return # app says enough + + return # app says it's enough if not varBinds: return # no more objects available @@ -294,14 +324,18 @@ class NextCommandGenerator(NextCommandGeneratorSingleRun): except StatusInformation as exc: statusInformation = exc + debug.logger & debug.FLAG_APP and debug.logger( - 'sendVarBinds: sendPduHandle %s: sendPdu() failed with %r' % (sendRequestHandle, statusInformation)) + 'sendVarBinds: sendPduHandle %s: sendPdu() failed with ' + '%r' % (sendRequestHandle, statusInformation)) + cbFun(snmpEngine, sendRequestHandle, statusInformation['errorIndication'], 0, 0, (), cbCtx) class BulkCommandGeneratorSingleRun(CommandGenerator): + def processResponseVarBinds(self, snmpEngine, sendRequestHandle, errorIndication, PDU, cbCtx): (targetName, nonRepeaters, maxRepetitions, @@ -332,6 +366,7 @@ class BulkCommandGeneratorSingleRun(CommandGenerator): class BulkCommandGenerator(BulkCommandGeneratorSingleRun): + def processResponseVarBinds(self, snmpEngine, sendRequestHandle, errorIndication, PDU, cbCtx): (targetName, nonRepeaters, maxRepetitions, @@ -346,21 +381,27 @@ class BulkCommandGenerator(BulkCommandGeneratorSingleRun): if v2c.apiBulkPDU.getErrorStatus(PDU): errorIndication, varBinds = None, () + elif not varBindTable: errorIndication, varBinds = errind.emptyResponse, () + else: errorIndication, varBinds = v2c.apiBulkPDU.getNextVarBinds(varBindTable[-1]) nonRepeaters = v2c.apiBulkPDU.getNonRepeaters(reqPDU) + if nonRepeaters: varBinds = v2c.apiBulkPDU.getVarBinds(reqPDU)[:int(nonRepeaters)] + varBinds[int(nonRepeaters):] - if not cbFun(snmpEngine, sendRequestHandle, errorIndication, - v2c.apiBulkPDU.getErrorStatus(PDU), - v2c.apiBulkPDU.getErrorIndex(PDU, muteErrors=True), - varBindTable, cbCtx): + if not cbFun( + snmpEngine, sendRequestHandle, errorIndication, + v2c.apiBulkPDU.getErrorStatus(PDU), + v2c.apiBulkPDU.getErrorIndex(PDU, muteErrors=True), + varBindTable, cbCtx): + debug.logger & debug.FLAG_APP and debug.logger( 'processResponseVarBinds: sendRequestHandle %s, app says to stop walking' % sendRequestHandle) - return # app says enough + + return # app says it's enough if not varBinds: return # no more objects available @@ -369,16 +410,18 @@ class BulkCommandGenerator(BulkCommandGeneratorSingleRun): v2c.apiBulkPDU.setVarBinds(reqPDU, varBinds) try: - self.sendPdu(snmpEngine, targetName, contextEngineId, - contextName, reqPDU, - self.processResponseVarBinds, - (targetName, nonRepeaters, maxRepetitions, - contextEngineId, contextName, reqPDU, cbFun, cbCtx)) + self.sendPdu( + snmpEngine, targetName, contextEngineId, contextName, reqPDU, + self.processResponseVarBinds, + (targetName, nonRepeaters, maxRepetitions, + contextEngineId, contextName, reqPDU, cbFun, cbCtx)) except StatusInformation as exc: statusInformation = exc + debug.logger & debug.FLAG_APP and debug.logger( - 'processResponseVarBinds: sendPduHandle %s: _sendPdu() failed with %r' % ( - sendRequestHandle, statusInformation)) + 'processResponseVarBinds: sendPduHandle %s: _sendPdu() failed ' + 'with %r' % (sendRequestHandle, statusInformation)) + cbFun(snmpEngine, sendRequestHandle, statusInformation['errorIndication'], 0, 0, (), cbCtx) diff --git a/pysnmp/entity/rfc3413/cmdrsp.py b/pysnmp/entity/rfc3413/cmdrsp.py index 7910b86b..56eaaaf3 100644 --- a/pysnmp/entity/rfc3413/cmdrsp.py +++ b/pysnmp/entity/rfc3413/cmdrsp.py @@ -79,9 +79,8 @@ class CommandResponderBase(object): v2c.apiPDU.setVarBinds(PDU, varBinds) debug.logger & debug.FLAG_APP and debug.logger( - 'sendVarBinds: stateReference %s, errorStatus %s, errorIndex %s, varBinds %s' % ( - stateReference, errorStatus, errorIndex, varBinds) - ) + 'sendVarBinds: stateReference %s, errorStatus %s, errorIndex %s, ' + 'varBinds %s' % (stateReference, errorStatus, errorIndex, varBinds)) self.sendPdu(snmpEngine, stateReference, PDU) @@ -121,9 +120,12 @@ class CommandResponderBase(object): except error.StatusInformation as exc: debug.logger & debug.FLAG_APP and debug.logger( - 'sendPdu: stateReference %s, statusInformation %s' % (stateReference, exc)) - snmpSilentDrops, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMPv2-MIB', - 'snmpSilentDrops') + 'sendPdu: stateReference %s, statusInformation ' + '%s' % (stateReference, exc)) + + snmpSilentDrops, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( + '__SNMPv2-MIB', 'snmpSilentDrops') + snmpSilentDrops.syntax += 1 _getRequestType = rfc1905.GetRequestPDU.tagSet @@ -172,6 +174,7 @@ class CommandResponderBase(object): def _storeAccessContext(snmpEngine): """Copy received message metadata while it lasts""" execCtx = snmpEngine.observer.getExecutionContext('rfc3412.receiveMessage:request') + return { 'securityModel': execCtx['securityModel'], 'securityName': execCtx['securityName'], @@ -205,14 +208,19 @@ class CommandResponderBase(object): # Map ACM errors onto SMI ones except error.StatusInformation as exc: statusInformation = exc + debug.logger & debug.FLAG_APP and debug.logger( - '__verifyAccess: name %s, statusInformation %s' % (name, statusInformation)) + '__verifyAccess: name %s, statusInformation ' + '%s' % (name, statusInformation)) + errorIndication = statusInformation['errorIndication'] + # 3.2.5... if (errorIndication == errind.noSuchView or errorIndication == errind.noAccessEntry or errorIndication == errind.noGroupName): - raise pysnmp.smi.error.AuthorizationError(name=name, idx=context.get('idx')) + raise pysnmp.smi.error.AuthorizationError( + name=name, idx=context.get('idx')) elif errorIndication == errind.otherError: raise pysnmp.smi.error.GenError(name=name, idx=context.get('idx')) @@ -221,16 +229,18 @@ class CommandResponderBase(object): snmpUnknownContexts, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-TARGET-MIB', 'snmpUnknownContexts') snmpUnknownContexts.syntax += 1 + # Request REPORT generation - raise pysnmp.smi.error.GenError(name=name, idx=context.get('idx'), - oid=snmpUnknownContexts.name, - val=snmpUnknownContexts.syntax) + raise pysnmp.smi.error.GenError( + name=name, idx=context.get('idx'), oid=snmpUnknownContexts.name, + val=snmpUnknownContexts.syntax) elif errorIndication == errind.notInView: return True else: raise error.ProtocolError('Unknown ACM error %s' % errorIndication) + else: # rfc2576: 4.1.2.1 if (securityModel == 1 and val is not None and @@ -273,7 +283,6 @@ class CommandResponderBase(object): return errorIndication, errorStatus, errorIndex, varBinds def completeMgmtOperation(self, varBinds, **context): - (errorIndication, errorStatus, errorIndex, varBinds) = self._mapSmiErrors(varBinds, **context) @@ -330,11 +339,6 @@ class NextCommandResponder(CommandResponderBase): def _getManagedObjectsInstances(self, varBinds, **context): """Iterate over Managed Objects fulfilling SNMP query. - Parameters - ---------- - varBinds - context - Returns ------- :py:class:`list` - List of Managed Objects Instances to respond with or @@ -396,7 +400,7 @@ class NextCommandResponder(CommandResponderBase): class BulkCommandResponder(NextCommandResponder): SUPPORTED_PDU_TYPES = (rfc1905.GetBulkRequestPDU.tagSet,) - maxVarBinds = 64 + MAX_VAR_BINDS = 64 def _completeNonRepeaters(self, varBinds, **context): mgmtFun = context['mgmtFun'] @@ -470,7 +474,7 @@ class BulkCommandResponder(NextCommandResponder): R = max(len(varBinds) - N, 0) if R: - M = min(M, self.maxVarBinds // R) + M = min(M, self.MAX_VAR_BINDS // R) debug.logger & debug.FLAG_APP and debug.logger( 'initiateMgmtOperation: N %d, M %d, R %d' % (N, M, R)) diff --git a/pysnmp/entity/rfc3413/config.py b/pysnmp/entity/rfc3413/config.py index c58c74ba..162b70a0 100644 --- a/pysnmp/entity/rfc3413/config.py +++ b/pysnmp/entity/rfc3413/config.py @@ -36,7 +36,8 @@ def getTargetAddr(snmpEngine, snmpTargetAddrName): 'snmpTargetAddrTAddress', 'snmpTargetAddrTimeout', 'snmpTargetAddrRetryCount', 'snmpTargetAddrParams' ) - snmpSourceAddrTAddress, = mibBuilder.importSymbols('PYSNMP-SOURCE-MIB', 'snmpSourceAddrTAddress') + snmpSourceAddrTAddress, = mibBuilder.importSymbols( + 'PYSNMP-SOURCE-MIB', 'snmpSourceAddrTAddress') tblIdx = snmpTargetAddrEntry.getInstIdFromIndices(snmpTargetAddrName) @@ -44,38 +45,46 @@ def getTargetAddr(snmpEngine, snmpTargetAddrName): snmpTargetAddrTDomain = snmpTargetAddrTDomain.getNode( snmpTargetAddrTDomain.name + tblIdx ).syntax + snmpTargetAddrTAddress = snmpTargetAddrTAddress.getNode( snmpTargetAddrTAddress.name + tblIdx ).syntax + snmpTargetAddrTimeout = snmpTargetAddrTimeout.getNode( snmpTargetAddrTimeout.name + tblIdx ).syntax + snmpTargetAddrRetryCount = snmpTargetAddrRetryCount.getNode( snmpTargetAddrRetryCount.name + tblIdx ).syntax + snmpTargetAddrParams = snmpTargetAddrParams.getNode( snmpTargetAddrParams.name + tblIdx ).syntax + snmpSourceAddrTAddress = snmpSourceAddrTAddress.getNode( snmpSourceAddrTAddress.name + tblIdx ).syntax + except NoSuchInstanceError: raise SmiError('Target %s not configured to LCD' % snmpTargetAddrName) transport = snmpEngine.transportDispatcher.getTransport(snmpTargetAddrTDomain) if snmpTargetAddrTDomain[:len(config.SNMP_UDP_DOMAIN)] == config.SNMP_UDP_DOMAIN: - SnmpUDPAddress, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('SNMPv2-TM', - 'SnmpUDPAddress') + SnmpUDPAddress, = mibBuilder.importSymbols('SNMPv2-TM', 'SnmpUDPAddress') + snmpTargetAddrTAddress = transport.ADDRESS_TYPE( SnmpUDPAddress(snmpTargetAddrTAddress) ).setLocalAddress(SnmpUDPAddress(snmpSourceAddrTAddress)) + elif snmpTargetAddrTDomain[:len(config.SNMP_UDP6_DOMAIN)] == config.SNMP_UDP6_DOMAIN: - TransportAddressIPv6, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( - 'TRANSPORT-ADDRESS-MIB', 'TransportAddressIPv6') + TransportAddressIPv6, = mibBuilder.importSymbols('TRANSPORT-ADDRESS-MIB', 'TransportAddressIPv6') + snmpTargetAddrTAddress = transport.ADDRESS_TYPE( TransportAddressIPv6(snmpTargetAddrTAddress) ).setLocalAddress(TransportAddressIPv6(snmpSourceAddrTAddress)) + elif snmpTargetAddrTDomain[:len(config.snmpLocalDomain)] == config.snmpLocalDomain: snmpTargetAddrTAddress = transport.ADDRESS_TYPE( snmpTargetAddrTAddress @@ -126,15 +135,19 @@ def getTargetParams(snmpEngine, paramsName): snmpTargetParamsMPModel = snmpTargetParamsMPModel.getNode( snmpTargetParamsMPModel.name + tblIdx ).syntax + snmpTargetParamsSecurityModel = snmpTargetParamsSecurityModel.getNode( snmpTargetParamsSecurityModel.name + tblIdx ).syntax + snmpTargetParamsSecurityName = snmpTargetParamsSecurityName.getNode( snmpTargetParamsSecurityName.name + tblIdx ).syntax + snmpTargetParamsSecurityLevel = snmpTargetParamsSecurityLevel.getNode( snmpTargetParamsSecurityLevel.name + tblIdx ).syntax + except NoSuchInstanceError: raise SmiError('Parameters %s not configured at LCD' % paramsName) @@ -159,8 +172,8 @@ def getTargetInfo(snmpEngine, snmpTargetAddrName): (snmpTargetParamsMPModel, snmpTargetParamsSecurityModel, snmpTargetParamsSecurityName, - snmpTargetParamsSecurityLevel) = getTargetParams(snmpEngine, - snmpTargetAddrParams) + snmpTargetParamsSecurityLevel) = getTargetParams( + snmpEngine, snmpTargetAddrParams) return (snmpTargetAddrTDomain, snmpTargetAddrTAddress, snmpTargetAddrTimeout, snmpTargetAddrRetryCount, @@ -171,8 +184,8 @@ def getTargetInfo(snmpEngine, snmpTargetAddrName): def getNotificationInfo(snmpEngine, notificationTarget): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder - snmpNotifyEntry, = mibBuilder.importSymbols('SNMP-NOTIFICATION-MIB', - 'snmpNotifyEntry') + snmpNotifyEntry, = mibBuilder.importSymbols( + 'SNMP-NOTIFICATION-MIB', 'snmpNotifyEntry') cache = snmpEngine.getUserContext('getNotificationInfo') if cache is None: @@ -185,10 +198,8 @@ def getNotificationInfo(snmpEngine, notificationTarget): targetToNotifyMap = cache['targetToNotifyMap'] if notificationTarget not in targetToNotifyMap: - (snmpNotifyTag, - snmpNotifyType) = mibBuilder.importSymbols('SNMP-NOTIFICATION-MIB', - 'snmpNotifyTag', - 'snmpNotifyType') + snmpNotifyTag, snmpNotifyType = mibBuilder.importSymbols( + 'SNMP-NOTIFICATION-MIB', 'snmpNotifyTag', 'snmpNotifyType') tblIdx = snmpNotifyEntry.getInstIdFromIndices(notificationTarget) @@ -196,6 +207,7 @@ def getNotificationInfo(snmpEngine, notificationTarget): snmpNotifyTag = snmpNotifyTag.getNode( snmpNotifyTag.name + tblIdx ).syntax + snmpNotifyType = snmpNotifyType.getNode( snmpNotifyType.name + tblIdx ).syntax @@ -216,8 +228,8 @@ def getNotificationInfo(snmpEngine, notificationTarget): def getTargetNames(snmpEngine, tag): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder - snmpTargetAddrEntry, = mibBuilder.importSymbols('SNMP-TARGET-MIB', - 'snmpTargetAddrEntry') + snmpTargetAddrEntry, = mibBuilder.importSymbols( + 'SNMP-TARGET-MIB', 'snmpTargetAddrEntry') cache = snmpEngine.getUserContext('getTargetNames') if cache is None: @@ -226,6 +238,7 @@ def getTargetNames(snmpEngine, tag): if cache['id'] == snmpTargetAddrEntry.branchVersionId: tagToTargetsMap = cache['tagToTargetsMap'] + else: cache['tagToTargetsMap'] = {} @@ -236,10 +249,13 @@ def getTargetNames(snmpEngine, tag): 'SNMP-TARGET-MIB', 'SnmpTagValue', 'snmpTargetAddrName', 'snmpTargetAddrTagList' ) + mibNode = snmpTargetAddrTagList + while True: try: mibNode = snmpTargetAddrTagList.getNextNode(mibNode.name) + except NoSuchInstanceError: break @@ -249,8 +265,10 @@ def getTargetNames(snmpEngine, tag): for _tag in mibNode.syntax.asOctets().split(): _tag = SnmpTagValue(_tag) + if _tag not in tagToTargetsMap: tagToTargetsMap[_tag] = [] + tagToTargetsMap[_tag].append(_snmpTargetAddrName) cache['id'] = snmpTargetAddrEntry.branchVersionId diff --git a/pysnmp/entity/rfc3413/context.py b/pysnmp/entity/rfc3413/context.py index 9a99f284..8c759075 100644 --- a/pysnmp/entity/rfc3413/context.py +++ b/pysnmp/entity/rfc3413/context.py @@ -13,14 +13,20 @@ from pysnmp import error class SnmpContext(object): def __init__(self, snmpEngine, contextEngineId=None): - snmpEngineId, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', - 'snmpEngineID') + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder + + snmpEngineId, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') + if contextEngineId is None: # Default to local snmpEngineId self.contextEngineId = snmpEngineId.syntax + else: self.contextEngineId = snmpEngineId.syntax.clone(contextEngineId) - debug.logger & debug.FLAG_INS and debug.logger('SnmpContext: contextEngineId \"%r\"' % (self.contextEngineId,)) + + debug.logger & debug.FLAG_INS and debug.logger( + 'SnmpContext: contextEngineId %r' % (self.contextEngineId,)) + self.contextNames = { null: snmpEngine.msgAndPduDsp.mibInstrumController # Default name } @@ -29,30 +35,35 @@ class SnmpContext(object): contextName = univ.OctetString(contextName).asOctets() if contextName in self.contextNames: raise error.PySnmpError( - 'Duplicate contextName %s' % contextName - ) + 'Duplicate contextName %s' % contextName) + debug.logger & debug.FLAG_INS and debug.logger( 'registerContextName: registered contextName %r, mibInstrum %r' % (contextName, mibInstrum)) + if mibInstrum is None: self.contextNames[contextName] = self.contextNames[null] + else: self.contextNames[contextName] = mibInstrum def unregisterContextName(self, contextName): contextName = univ.OctetString(contextName).asOctets() + if contextName in self.contextNames: debug.logger & debug.FLAG_INS and debug.logger( 'unregisterContextName: unregistered contextName %r' % contextName) + del self.contextNames[contextName] def getMibInstrum(self, contextName=null): contextName = univ.OctetString(contextName).asOctets() if contextName not in self.contextNames: debug.logger & debug.FLAG_INS and debug.logger('getMibInstrum: contextName %r not registered' % contextName) - raise error.PySnmpError( - 'Missing contextName %s' % contextName - ) + + raise error.PySnmpError('Missing contextName %s' % contextName) + else: debug.logger & debug.FLAG_INS and debug.logger( 'getMibInstrum: contextName %r, mibInstum %r' % (contextName, self.contextNames[contextName])) + return self.contextNames[contextName] diff --git a/pysnmp/entity/rfc3413/ntforg.py b/pysnmp/entity/rfc3413/ntforg.py index e73dbf19..fc1e8c0a 100644 --- a/pysnmp/entity/rfc3413/ntforg.py +++ b/pysnmp/entity/rfc3413/ntforg.py @@ -29,6 +29,7 @@ class NotificationOriginator(object): securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, statusInformation, sendPduHandle, cbInfo): + sendRequestHandle, cbFun, cbCtx = cbInfo # 3.3.6d @@ -39,38 +40,48 @@ class NotificationOriginator(object): origMessageProcessingModel, origSecurityModel, origSecurityName, origSecurityLevel, origContextEngineId, origContextName, origPdu, origTimeout, - origRetryCount, origRetries, origDiscoveryRetries) = self.__pendingReqs.pop(sendPduHandle) + origRetryCount, origRetries, + origDiscoveryRetries) = self.__pendingReqs.pop(sendPduHandle) snmpEngine.transportDispatcher.jobFinished(id(self)) if statusInformation: debug.logger & debug.FLAG_APP and debug.logger( - 'processResponsePdu: sendRequestHandle %s, sendPduHandle %s statusInformation %s' % ( - sendRequestHandle, sendPduHandle, statusInformation)) + 'processResponsePdu: sendRequestHandle %s, sendPduHandle %s ' + 'statusInformation %s' % (sendRequestHandle, sendPduHandle, + statusInformation)) errorIndication = statusInformation['errorIndication'] if errorIndication in (errind.notInTimeWindow, errind.unknownEngineID): origDiscoveryRetries += 1 origRetries = 0 + else: origDiscoveryRetries = 0 origRetries += 1 - if origRetries > origRetryCount or origDiscoveryRetries > self.__options.get('discoveryRetries', 4): + if (origRetries > origRetryCount or + origDiscoveryRetries > self.__options.get('discoveryRetries', 4)): + debug.logger & debug.FLAG_APP and debug.logger( - 'processResponsePdu: sendRequestHandle %s, sendPduHandle %s retry count %d exceeded' % ( + 'processResponsePdu: sendRequestHandle %s, sendPduHandle %s ' + 'retry count %d exceeded' % ( sendRequestHandle, sendPduHandle, origRetries)) + cbFun(snmpEngine, sendRequestHandle, errorIndication, None, cbCtx) + return # Convert timeout in seconds into timeout in timer ticks - timeoutInTicks = float(origTimeout) / 100 / snmpEngine.transportDispatcher.getTimerResolution() + timeoutInTicks = (float(origTimeout) / 100 / + snmpEngine.transportDispatcher.getTimerResolution()) # User-side API assumes SMIv2 if messageProcessingModel == 0: reqPDU = rfc2576.v2ToV1(origPdu) pduVersion = 0 + else: reqPDU = origPdu pduVersion = 1 @@ -85,20 +96,26 @@ class NotificationOriginator(object): reqPDU, True, timeoutInTicks, self.processResponsePdu, (sendRequestHandle, cbFun, cbCtx) ) + except error.StatusInformation as exc: statusInformation = exc + debug.logger & debug.FLAG_APP and debug.logger( - 'processResponsePdu: sendRequestHandle %s: sendPdu() failed with %r ' % ( - sendRequestHandle, statusInformation)) + 'processResponsePdu: sendRequestHandle %s: sendPdu() ' + 'failed with %r ' % (sendRequestHandle, statusInformation)) + cbFun(snmpEngine, sendRequestHandle, statusInformation['errorIndication'], None, cbCtx) + return snmpEngine.transportDispatcher.jobStarted(id(self)) debug.logger & debug.FLAG_APP and debug.logger( - 'processResponsePdu: sendRequestHandle %s, sendPduHandle %s, timeout %d, retry %d of %d' % ( - sendRequestHandle, sendPduHandle, origTimeout, origRetries, origRetryCount)) + 'processResponsePdu: sendRequestHandle %s, sendPduHandle %s, ' + 'timeout %d, retry %d of %d' % ( + sendRequestHandle, sendPduHandle, origTimeout, origRetries, + origRetryCount)) # 3.3.6b self.__pendingReqs[sendPduHandle] = ( @@ -108,6 +125,7 @@ class NotificationOriginator(object): origContextEngineId, origContextName, origPdu, origTimeout, origRetryCount, origRetries, origDiscoveryRetries ) + return # 3.3.6c @@ -129,6 +147,7 @@ class NotificationOriginator(object): if messageProcessingModel == 0: reqPDU = rfc2576.v2ToV1(pdu) pduVersion = 0 + else: reqPDU = pdu pduVersion = 1 @@ -136,7 +155,8 @@ class NotificationOriginator(object): # 3.3.5 if reqPDU.tagSet in rfc3411.CONFIRMED_CLASS_PDUS: # Convert timeout in seconds into timeout in timer ticks - timeoutInTicks = float(timeout) / 100 / snmpEngine.transportDispatcher.getTimerResolution() + timeoutInTicks = (float(timeout) / 100 / + snmpEngine.transportDispatcher.getTimerResolution()) sendRequestHandle = getNextHandle() @@ -158,7 +178,9 @@ class NotificationOriginator(object): securityModel, securityName, securityLevel, contextEngineId, contextName, pdu, timeout, retryCount, 0, 0 ) + snmpEngine.transportDispatcher.jobStarted(id(self)) + else: snmpEngine.msgAndPduDsp.sendPdu( snmpEngine, transportDomain, transportAddress, @@ -180,14 +202,18 @@ class NotificationOriginator(object): self.__pendingNotifications[notificationHandle].remove(sendRequestHandle) debug.logger & debug.FLAG_APP and debug.logger( - 'processResponseVarBinds: notificationHandle %s, sendRequestHandle %s, errorIndication %s, pending requests %s' % ( - notificationHandle, sendRequestHandle, errorIndication, self.__pendingNotifications[notificationHandle])) + 'processResponseVarBinds: notificationHandle %s, sendRequestHandle %s, ' + 'errorIndication %s, pending requests %s' % ( + notificationHandle, sendRequestHandle, errorIndication, + self.__pendingNotifications[notificationHandle])) if not self.__pendingNotifications[notificationHandle]: debug.logger & debug.FLAG_APP and debug.logger( - 'processResponseVarBinds: notificationHandle %s, sendRequestHandle %s -- completed' % ( - notificationHandle, sendRequestHandle)) + 'processResponseVarBinds: notificationHandle %s, sendRequestHandle %s ' + '-- completed' % (notificationHandle, sendRequestHandle)) + del self.__pendingNotifications[notificationHandle] + cbFun(snmpEngine, sendRequestHandle, errorIndication, pdu and v2c.apiPDU.getErrorStatus(pdu) or 0, pdu and v2c.apiPDU.getErrorIndex(pdu, muteErrors=True) or 0, @@ -198,11 +224,14 @@ class NotificationOriginator(object): # Higher-level API to Notification Originator. Supports multiple # targets, automatic var-binding formation and is fully LCD-driven. # + def sendVarBinds(self, snmpEngine, notificationTarget, contextEngineId, contextName, varBinds=(), cbFun=None, cbCtx=None): debug.logger & debug.FLAG_APP and debug.logger( - 'sendVarBinds: notificationTarget %s, contextEngineId %s, contextName "%s", varBinds %s' % ( - notificationTarget, contextEngineId or '', contextName, varBinds)) + 'sendVarBinds: notificationTarget %s, contextEngineId %s, ' + 'contextName "%s", varBinds %s' % ( + notificationTarget, contextEngineId or '', + contextName, varBinds)) mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder @@ -251,6 +280,7 @@ class NotificationOriginator(object): del varBinds[idx + 2] if varBinds[1][0] == snmpTrapOID: varBinds[1] = varBind + else: varBinds.insert(1, varBind) break @@ -261,12 +291,14 @@ class NotificationOriginator(object): sendRequestHandle = -1 - debug.logger & debug.FLAG_APP and debug.logger('sendVarBinds: final varBinds %s' % (varBinds,)) + debug.logger & debug.FLAG_APP and debug.logger( + 'sendVarBinds: final varBinds %s' % (varBinds,)) for targetAddrName in config.getTargetNames(snmpEngine, notifyTag): (transportDomain, transportAddress, timeout, retryCount, params) = config.getTargetAddr(snmpEngine, targetAddrName) + (messageProcessingModel, securityModel, securityName, securityLevel) = config.getTargetParams(snmpEngine, params) @@ -278,13 +310,16 @@ class NotificationOriginator(object): # filterType) = config.getNotifyFilter(filterProfileName) debug.logger & debug.FLAG_APP and debug.logger( - 'sendVarBinds: notificationHandle %s, notifyTag %s yields: transportDomain %s, transportAddress %r, securityModel %s, securityName %s, securityLevel %s' % ( - notificationHandle, notifyTag, transportDomain, transportAddress, securityModel, - securityName, securityLevel)) + 'sendVarBinds: notificationHandle %s, notifyTag %s yields: ' + 'transportDomain %s, transportAddress %r, securityModel %s, ' + 'securityName %s, securityLevel %s' % ( + notificationHandle, notifyTag, transportDomain, transportAddress, + securityModel, securityName, securityLevel)) for varName, varVal in varBinds: if varName in (sysUpTime, snmpTrapOID): continue + try: snmpEngine.accessControlModel[self.ACM_ID].isAccessAllowed( snmpEngine, securityModel, securityName, @@ -292,19 +327,22 @@ class NotificationOriginator(object): ) debug.logger & debug.FLAG_APP and debug.logger( - 'sendVarBinds: ACL succeeded for OID %s securityName %s' % (varName, securityName)) + 'sendVarBinds: ACL succeeded for OID %s securityName %s' % ( + varName, securityName)) except error.StatusInformation: debug.logger & debug.FLAG_APP and debug.logger( - 'sendVarBinds: ACL denied access for OID %s securityName %s, droppping notification' % ( - varName, securityName)) + 'sendVarBinds: ACL denied access for OID %s securityName %s,' + 'dropping notification' % (varName, securityName)) return # 3.3.4 if notifyType == 1: pdu = v2c.SNMPv2TrapPDU() + elif notifyType == 2: pdu = v2c.InformRequestPDU() + else: raise error.ProtocolError('Unknown notify-type %r', notifyType) @@ -321,22 +359,27 @@ class NotificationOriginator(object): except error.StatusInformation as exc: statusInformation = exc + debug.logger & debug.FLAG_APP and debug.logger( - 'sendVarBinds: sendRequestHandle %s: sendPdu() failed with %r' % ( - sendRequestHandle, statusInformation)) - if notificationHandle not in self.__pendingNotifications or \ - not self.__pendingNotifications[notificationHandle]: + 'sendVarBinds: sendRequestHandle %s: sendPdu() failed ' + 'with %r' % (sendRequestHandle, statusInformation)) + + if (notificationHandle not in self.__pendingNotifications or + not self.__pendingNotifications[notificationHandle]): + if notificationHandle in self.__pendingNotifications: del self.__pendingNotifications[notificationHandle] + if cbFun: cbFun(snmpEngine, notificationHandle, statusInformation['errorIndication'], 0, 0, (), cbCtx) + return notificationHandle debug.logger & debug.FLAG_APP and debug.logger( - 'sendVarBinds: notificationHandle %s, sendRequestHandle %s, timeout %d' % ( - notificationHandle, sendRequestHandle, timeout)) + 'sendVarBinds: notificationHandle %s, sendRequestHandle %s, ' + 'timeout %d' % (notificationHandle, sendRequestHandle, timeout)) if notifyType == 2: if notificationHandle not in self.__pendingNotifications: @@ -344,8 +387,8 @@ class NotificationOriginator(object): self.__pendingNotifications[notificationHandle].add(sendRequestHandle) debug.logger & debug.FLAG_APP and debug.logger( - 'sendVarBinds: notificationHandle %s, sendRequestHandle %s, notification(s) sent' % ( - notificationHandle, sendRequestHandle)) + 'sendVarBinds: notificationHandle %s, sendRequestHandle %s, ' + 'notification(s) sent' % (notificationHandle, sendRequestHandle)) return notificationHandle diff --git a/pysnmp/entity/rfc3413/ntfrcv.py b/pysnmp/entity/rfc3413/ntfrcv.py index a4754be2..53cc7ac3 100644 --- a/pysnmp/entity/rfc3413/ntfrcv.py +++ b/pysnmp/entity/rfc3413/ntfrcv.py @@ -31,7 +31,8 @@ class NotificationReceiver(object): def storeSnmpTrapCommunity(snmpEngine, execpoint, variables, cbCtx): self.__snmpTrapCommunity = variables.get('communityName', '') - snmpEngine.observer.registerObserver(storeSnmpTrapCommunity, 'rfc2576.processIncomingMsg') + snmpEngine.observer.registerObserver( + storeSnmpTrapCommunity, 'rfc2576.processIncomingMsg') def close(self, snmpEngine): snmpEngine.msgAndPduDsp.unregisterContextEngineId( @@ -48,6 +49,7 @@ class NotificationReceiver(object): if messageProcessingModel == 0: origPdu = PDU PDU = rfc2576.v1ToV2(PDU, snmpTrapCommunity=self.__snmpTrapCommunity) + else: origPdu = None @@ -89,12 +91,17 @@ class NotificationReceiver(object): except error.StatusInformation as exc: debug.logger & debug.FLAG_APP and debug.logger( 'processPdu: stateReference %s, statusInformation %s' % (stateReference, exc)) - snmpSilentDrops, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMPv2-MIB', - 'snmpSilentDrops') + + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder + + snmpSilentDrops, = mibBuilder.importSymbols( + '__SNMPv2-MIB', 'snmpSilentDrops') + snmpSilentDrops.syntax += 1 elif PDU.tagSet in rfc3411.UNCONFIRMED_CLASS_PDUS: pass + else: raise error.ProtocolError('Unexpected PDU class %s' % PDU.tagSet) diff --git a/pysnmp/hlapi/transport.py b/pysnmp/hlapi/transport.py index 20471633..d75951c6 100644 --- a/pysnmp/hlapi/transport.py +++ b/pysnmp/hlapi/transport.py @@ -27,8 +27,7 @@ class AbstractTransportTarget(object): def __repr__(self): return '%s(%r, timeout=%r, retries=%r, tagList=%r)' % ( self.__class__.__name__, self.transportAddr, - self.timeout, self.retries, self.tagList - ) + self.timeout, self.retries, self.tagList) def getTransportInfo(self): return self.TRANSPORT_DOMAIN, self.transportAddr @@ -55,9 +54,11 @@ class AbstractTransportTarget(object): return self.transport def verifyDispatcherCompatibility(self, snmpEngine): - if not self.PROTO_TRANSPORT.isCompatibleWithDispatcher(snmpEngine.transportDispatcher): - raise error.PySnmpError('Transport %r is not compatible with dispatcher %r' % ( - self.PROTO_TRANSPORT, snmpEngine.transportDispatcher)) + if not self.PROTO_TRANSPORT.isCompatibleWithDispatcher( + snmpEngine.transportDispatcher): + raise error.PySnmpError( + 'Transport %r is not compatible with dispatcher ' + '%r' % (self.PROTO_TRANSPORT, snmpEngine.transportDispatcher)) def _resolveAddr(self, transportAddr): raise NotImplementedError() diff --git a/pysnmp/hlapi/v1arch/asyncio/cmdgen.py b/pysnmp/hlapi/v1arch/asyncio/cmdgen.py index 346b7c76..3e53c05b 100644 --- a/pysnmp/hlapi/v1arch/asyncio/cmdgen.py +++ b/pysnmp/hlapi/v1arch/asyncio/cmdgen.py @@ -4,18 +4,18 @@ # Copyright (c) 2005-2019, Ilya Etingof # License: http://snmplabs.com/pysnmp/license.html # -from pysnmp.hlapi.v1arch.auth import * -from pysnmp.hlapi.varbinds import * -from pysnmp.hlapi.v1arch.asyncio.transport import * -from pysnmp.smi.rfc1902 import * -from pysnmp.proto import api - try: import asyncio except ImportError: import trollius as asyncio +from pysnmp.hlapi.v1arch.auth import * +from pysnmp.hlapi.varbinds import * +from pysnmp.hlapi.v1arch.asyncio.transport import * +from pysnmp.smi.rfc1902 import * +from pysnmp.proto import api + __all__ = ['getCmd', 'nextCmd', 'setCmd', 'bulkCmd', 'isEndOfMib'] VB_PROCESSOR = CommandGeneratorVarBinds() diff --git a/pysnmp/hlapi/v1arch/asyncore/cmdgen.py b/pysnmp/hlapi/v1arch/asyncore/cmdgen.py index e7ddadb2..3a1de67f 100644 --- a/pysnmp/hlapi/v1arch/asyncore/cmdgen.py +++ b/pysnmp/hlapi/v1arch/asyncore/cmdgen.py @@ -4,7 +4,6 @@ # Copyright (c) 2005-2019, Ilya Etingof # License: http://snmplabs.com/pysnmp/license.html # - from pysnmp.hlapi.v1arch.auth import * from pysnmp.hlapi.v1arch.asyncore import * from pysnmp.hlapi.varbinds import * diff --git a/pysnmp/hlapi/v1arch/asyncore/sync/cmdgen.py b/pysnmp/hlapi/v1arch/asyncore/sync/cmdgen.py index a1c3366d..2961a63a 100644 --- a/pysnmp/hlapi/v1arch/asyncore/sync/cmdgen.py +++ b/pysnmp/hlapi/v1arch/asyncore/sync/cmdgen.py @@ -4,11 +4,10 @@ # Copyright (c) 2005-2019, Ilya Etingof # License: http://snmplabs.com/pysnmp/license.html # -from pyasn1.type.univ import Null - from pysnmp.hlapi.v1arch.asyncore import cmdgen from pysnmp.hlapi.varbinds import * from pysnmp.proto.rfc1905 import endOfMibView +from pysnmp.proto.rfc1902 import Null __all__ = ['getCmd', 'nextCmd', 'setCmd', 'bulkCmd'] diff --git a/pysnmp/hlapi/v3arch/asyncio/cmdgen.py b/pysnmp/hlapi/v3arch/asyncio/cmdgen.py index 89420cb2..29d2ca63 100644 --- a/pysnmp/hlapi/v3arch/asyncio/cmdgen.py +++ b/pysnmp/hlapi/v3arch/asyncio/cmdgen.py @@ -31,6 +31,12 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. # +try: + import asyncio + +except ImportError: + import trollius as asyncio + from pysnmp.hlapi.v3arch.auth import * from pysnmp.hlapi.v3arch.context import * from pysnmp.hlapi.v3arch.lcd import * @@ -40,12 +46,6 @@ from pysnmp.entity.rfc3413 import cmdgen from pysnmp.proto.api import v2c from pysnmp.smi.rfc1902 import * -try: - import asyncio - -except ImportError: - import trollius as asyncio - __all__ = ['getCmd', 'nextCmd', 'setCmd', 'bulkCmd', 'isEndOfMib'] VB_PROCESSOR = CommandGeneratorVarBinds() @@ -134,17 +134,20 @@ def getCmd(snmpEngine, authData, transportTarget, contextData, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): lookupMib, future = cbCtx + if future.cancelled(): return + try: - varBindsUnmade = VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, varBinds, - lookupMib) + varBindsUnmade = VB_PROCESSOR.unmakeVarBinds( + snmpEngine.cache, varBinds, lookupMib) + except Exception as e: future.set_exception(e) + else: future.set_result( - (errorIndication, errorStatus, errorIndex, varBindsUnmade) - ) + (errorIndication, errorStatus, errorIndex, varBindsUnmade)) addrName, paramsName = LCD.configure( snmpEngine, authData, transportTarget, contextData.contextName) @@ -157,6 +160,7 @@ def getCmd(snmpEngine, authData, transportTarget, contextData, VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds), __cbFun, (options.get('lookupMib', True), future) ) + return future @@ -240,13 +244,17 @@ def setCmd(snmpEngine, authData, transportTarget, contextData, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): lookupMib, future = cbCtx + if future.cancelled(): return + try: - varBindsUnmade = VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, varBinds, - lookupMib) + varBindsUnmade = VB_PROCESSOR.unmakeVarBinds( + snmpEngine.cache, varBinds, lookupMib) + except Exception as e: future.set_exception(e) + else: future.set_result( (errorIndication, errorStatus, errorIndex, varBindsUnmade) @@ -263,6 +271,7 @@ def setCmd(snmpEngine, authData, transportTarget, contextData, VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds), __cbFun, (options.get('lookupMib', True), future) ) + return future @@ -352,17 +361,20 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData, lookupMib, future = cbCtx if future.cancelled(): return + try: - varBindsUnmade = [VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, - varBindTableRow, - lookupMib) - for varBindTableRow in varBindTable] + varBindsUnmade = [ + VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, varBindTableRow, + lookupMib) + for varBindTableRow in varBindTable + ] + except Exception as e: future.set_exception(e) + else: future.set_result( - (errorIndication, errorStatus, errorIndex, varBindsUnmade) - ) + (errorIndication, errorStatus, errorIndex, varBindsUnmade)) addrName, paramsName = LCD.configure( snmpEngine, authData, transportTarget, contextData.contextName) @@ -375,6 +387,7 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData, VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds), __cbFun, (options.get('lookupMib', True), future) ) + return future @@ -491,20 +504,23 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData, errorIndication, errorStatus, errorIndex, varBindTable, cbCtx): lookupMib, future = cbCtx + if future.cancelled(): return + try: - varBindsUnmade = [VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, - varBindTableRow, - lookupMib) - for varBindTableRow in varBindTable] + varBindsUnmade = [ + VB_PROCESSOR.unmakeVarBinds( + snmpEngine.cache, varBindTableRow, lookupMib) + for varBindTableRow in varBindTable + ] + except Exception as e: future.set_exception(e) else: future.set_result( - (errorIndication, errorStatus, errorIndex, varBindsUnmade) - ) + (errorIndication, errorStatus, errorIndex, varBindsUnmade)) addrName, paramsName = LCD.configure( snmpEngine, authData, transportTarget, contextData.contextName) @@ -517,4 +533,5 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData, VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds), __cbFun, (options.get('lookupMib', True), future) ) + return future diff --git a/pysnmp/hlapi/v3arch/asyncio/transport.py b/pysnmp/hlapi/v3arch/asyncio/transport.py index 0b795163..f897de09 100644 --- a/pysnmp/hlapi/v3arch/asyncio/transport.py +++ b/pysnmp/hlapi/v3arch/asyncio/transport.py @@ -56,11 +56,11 @@ class UdpTransportTarget(AbstractTransportTarget): def _resolveAddr(self, transportAddr): try: - return socket.getaddrinfo(transportAddr[0], - transportAddr[1], - socket.AF_INET, - socket.SOCK_DGRAM, - socket.IPPROTO_UDP)[0][4][:2] + return socket.getaddrinfo( + transportAddr[0], transportAddr[1], + socket.AF_INET, socket.SOCK_DGRAM, + socket.IPPROTO_UDP)[0][4][:2] + except socket.gaierror as exc: raise PySnmpError('Bad IPv4/UDP transport address %s: %s' % ( '@'.join([str(x) for x in transportAddr]), exc)) @@ -116,11 +116,11 @@ class Udp6TransportTarget(AbstractTransportTarget): def _resolveAddr(self, transportAddr): try: - return socket.getaddrinfo(transportAddr[0], - transportAddr[1], - socket.AF_INET6, - socket.SOCK_DGRAM, - socket.IPPROTO_UDP)[0][4][:2] + return socket.getaddrinfo( + transportAddr[0], transportAddr[1], + socket.AF_INET6, socket.SOCK_DGRAM, + socket.IPPROTO_UDP)[0][4][:2] + except socket.gaierror as exc: raise PySnmpError('Bad IPv6/UDP transport address %s: %s' % ( '@'.join([str(x) for x in transportAddr]), exc)) diff --git a/pysnmp/hlapi/v3arch/asyncore/cmdgen.py b/pysnmp/hlapi/v3arch/asyncore/cmdgen.py index 6446bce5..e11e040e 100644 --- a/pysnmp/hlapi/v3arch/asyncore/cmdgen.py +++ b/pysnmp/hlapi/v3arch/asyncore/cmdgen.py @@ -113,24 +113,26 @@ def getCmd(snmpEngine, authData, transportTarget, contextData, def __cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): + lookupMib, cbFun, cbCtx = cbCtx + if cbFun: + varBinds = VB_PROCESSOR.unmakeVarBinds( + snmpEngine.cache, varBinds, lookupMib) + return cbFun(snmpEngine, sendRequestHandle, errorIndication, - errorStatus, errorIndex, - VB_PROCESSOR.unmakeVarBinds( - snmpEngine.cache, varBinds, lookupMib - ), cbCtx) + errorStatus, errorIndex, varBinds, cbCtx) addrName, paramsName = LCD.configure( snmpEngine, authData, transportTarget, contextData.contextName) + varBinds = VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds) + return cmdgen.GetCommandGenerator().sendVarBinds( snmpEngine, addrName, contextData.contextEngineId, - contextData.contextName, - VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds), __cbFun, + contextData.contextName, varBinds, __cbFun, (options.get('lookupMib', True), - options.get('cbFun'), options.get('cbCtx')) - ) + options.get('cbFun'), options.get('cbCtx'))) def setCmd(snmpEngine, authData, transportTarget, contextData, @@ -226,22 +228,25 @@ def setCmd(snmpEngine, authData, transportTarget, contextData, def __cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): + lookupMib, cbFun, cbCtx = cbCtx + + varBinds = VB_PROCESSOR.unmakeVarBinds( + snmpEngine.cache, varBinds, lookupMib) + return cbFun(snmpEngine, sendRequestHandle, errorIndication, - errorStatus, errorIndex, - VB_PROCESSOR.unmakeVarBinds( - snmpEngine.cache, varBinds, lookupMib - ), cbCtx) + errorStatus, errorIndex, varBinds, cbCtx) addrName, paramsName = LCD.configure( snmpEngine, authData, transportTarget, contextData.contextName) + varBinds = VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds) + return cmdgen.SetCommandGenerator().sendVarBinds( snmpEngine, addrName, contextData.contextEngineId, - contextData.contextName, VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds), + contextData.contextName, varBinds, __cbFun, (options.get('lookupMib', True), - options.get('cbFun'), options.get('cbCtx')) - ) + options.get('cbFun'), options.get('cbCtx'))) def nextCmd(snmpEngine, authData, transportTarget, contextData, @@ -338,23 +343,26 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData, def __cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBindTable, cbCtx): + lookupMib, cbFun, cbCtx = cbCtx + + varBindTable = [VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, + varBindTableRow, lookupMib) + for varBindTableRow in varBindTable] + return cbFun(snmpEngine, sendRequestHandle, errorIndication, - errorStatus, errorIndex, - [VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, varBindTableRow, lookupMib) for varBindTableRow in - varBindTable], - cbCtx) + errorStatus, errorIndex, varBindTable, cbCtx) addrName, paramsName = LCD.configure( snmpEngine, authData, transportTarget, contextData.contextName) + varBinds = VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds) + return cmdgen.NextCommandGenerator().sendVarBinds( - snmpEngine, addrName, - contextData.contextEngineId, contextData.contextName, - VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds), - __cbFun, (options.get('lookupMib', True), - options.get('cbFun'), options.get('cbCtx')) - ) + snmpEngine, addrName, contextData.contextEngineId, + contextData.contextName, varBinds, __cbFun, + (options.get('lookupMib', True), options.get('cbFun'), + options.get('cbCtx'))) def bulkCmd(snmpEngine, authData, transportTarget, contextData, @@ -481,19 +489,23 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData, def __cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBindTable, cbCtx): + lookupMib, cbFun, cbCtx = cbCtx + + varBindTable = [VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, + varBindTableRow, lookupMib) + for varBindTableRow in varBindTable] + return cbFun(snmpEngine.cache, sendRequestHandle, errorIndication, - errorStatus, errorIndex, - [VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, varBindTableRow, lookupMib) for varBindTableRow in - varBindTable], cbCtx) + errorStatus, errorIndex, varBindTable, cbCtx) addrName, paramsName = LCD.configure( snmpEngine, authData, transportTarget, contextData.contextName) + varBinds = VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds) + return cmdgen.BulkCommandGenerator().sendVarBinds( snmpEngine, addrName, contextData.contextEngineId, contextData.contextName, nonRepeaters, maxRepetitions, - VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds), __cbFun, - (options.get('lookupMib', True), - options.get('cbFun'), options.get('cbCtx')) - ) + varBinds, __cbFun, (options.get('lookupMib', True), + options.get('cbFun'), options.get('cbCtx'))) diff --git a/pysnmp/hlapi/v3arch/asyncore/ntforg.py b/pysnmp/hlapi/v3arch/asyncore/ntforg.py index 7df0bc08..2e714c08 100644 --- a/pysnmp/hlapi/v3arch/asyncore/ntforg.py +++ b/pysnmp/hlapi/v3arch/asyncore/ntforg.py @@ -152,22 +152,23 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData, # noinspection PyShadowingNames def __cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): + lookupMib, cbFun, cbCtx = cbCtx + + varBinds = VB_PROCESSOR.unmakeVarBinds( + snmpEngine.cache, varBinds, lookupMib) + return cbFun and cbFun( snmpEngine, sendRequestHandle, errorIndication, - errorStatus, errorIndex, - VB_PROCESSOR.unmakeVarBinds( - snmpEngine.cache, varBinds, lookupMib - ), cbCtx - ) + errorStatus, errorIndex, varBinds, cbCtx) notifyName = LCD.configure(snmpEngine, authData, transportTarget, notifyType, contextData.contextName) + varBinds = VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds) + return ntforg.NotificationOriginator().sendVarBinds( snmpEngine, notifyName, contextData.contextEngineId, contextData.contextName, - VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds), __cbFun, - (options.get('lookupMib', True), - options.get('cbFun'), options.get('cbCtx')) - ) + varBinds, __cbFun, (options.get('lookupMib', True), + options.get('cbFun'), options.get('cbCtx'))) diff --git a/pysnmp/hlapi/v3arch/asyncore/sync/cmdgen.py b/pysnmp/hlapi/v3arch/asyncore/sync/cmdgen.py index c0e7a379..6165fa33 100644 --- a/pysnmp/hlapi/v3arch/asyncore/sync/cmdgen.py +++ b/pysnmp/hlapi/v3arch/asyncore/sync/cmdgen.py @@ -108,6 +108,7 @@ def getCmd(snmpEngine, authData, transportTarget, contextData, errorStatus = cbCtx['errorStatus'] errorIndex = cbCtx['errorIndex'] varBinds = cbCtx['varBinds'] + else: errorIndication = errorStatus = errorIndex = None varBinds = [] @@ -214,6 +215,7 @@ def setCmd(snmpEngine, authData, transportTarget, contextData, errorStatus = cbCtx['errorStatus'] errorIndex = cbCtx['errorIndex'] varBinds = cbCtx['varBinds'] + else: errorIndication = errorStatus = errorIndex = None varBinds = [] @@ -363,6 +365,7 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData, if errorIndication: yield (errorIndication, errorStatus, errorIndex, varBinds) return + elif errorStatus: if errorStatus == 2: # Hide SNMPv1 noSuchName error which leaks in here @@ -371,6 +374,7 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData, errorIndex = errorIndex.clone(0) yield (errorIndication, errorStatus, errorIndex, varBinds) return + else: stopFlag = True @@ -570,8 +574,10 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData, if errorIndication: yield (errorIndication, errorStatus, errorIndex, varBindTable and varBindTable[0] or []) + if errorIndication != errind.requestTimedOut: return + elif errorStatus: if errorStatus == 2: # Hide SNMPv1 noSuchName error which leaks in here @@ -580,26 +586,35 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData, errorIndex = errorIndex.clone(0) yield (errorIndication, errorStatus, errorIndex, varBindTable and varBindTable[0] or []) return + else: for row in range(len(varBindTable)): stopFlag = True + if len(varBindTable[row]) != len(initialVars): varBindTable = row and varBindTable[:row - 1] or [] break + for col in range(len(varBindTable[row])): name, val = varBindTable[row][col] + if row: previousVarBinds = varBindTable[row - 1] + if nullVarBinds[col]: varBindTable[row][col] = previousVarBinds[col][0], endOfMibView continue + stopFlag = False + if isinstance(val, Null): varBindTable[row][col] = previousVarBinds[col][0], endOfMibView nullVarBinds[col] = True + if not lexicographicMode and not initialVars[col].isPrefixOf(name): varBindTable[row][col] = previousVarBinds[col][0], endOfMibView nullVarBinds[col] = True + if stopFlag: varBindTable = row and varBindTable[:row - 1] or [] break diff --git a/pysnmp/hlapi/v3arch/asyncore/sync/ntforg.py b/pysnmp/hlapi/v3arch/asyncore/sync/ntforg.py index 2cff18df..b26e2e4a 100644 --- a/pysnmp/hlapi/v3arch/asyncore/sync/ntforg.py +++ b/pysnmp/hlapi/v3arch/asyncore/sync/ntforg.py @@ -143,6 +143,7 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData, errorStatus = cbCtx.get('errorStatus') errorIndex = cbCtx.get('errorIndex') varBinds = cbCtx.get('varBinds', []) + else: errorIndication = errorStatus = errorIndex = None varBinds = [] diff --git a/pysnmp/hlapi/v3arch/asyncore/transport.py b/pysnmp/hlapi/v3arch/asyncore/transport.py index 2cae2d7d..3e03b6af 100644 --- a/pysnmp/hlapi/v3arch/asyncore/transport.py +++ b/pysnmp/hlapi/v3arch/asyncore/transport.py @@ -53,11 +53,10 @@ class UdpTransportTarget(AbstractTransportTarget): def _resolveAddr(self, transportAddr): try: - return socket.getaddrinfo(transportAddr[0], - transportAddr[1], - socket.AF_INET, - socket.SOCK_DGRAM, - socket.IPPROTO_UDP)[0][4][:2] + return socket.getaddrinfo( + transportAddr[0], transportAddr[1], socket.AF_INET, + socket.SOCK_DGRAM, socket.IPPROTO_UDP)[0][4][:2] + except socket.gaierror as exc: raise error.PySnmpError('Bad IPv4/UDP transport address %s: %s' % ( '@'.join([str(x) for x in transportAddr]), exc)) @@ -111,11 +110,10 @@ class Udp6TransportTarget(AbstractTransportTarget): def _resolveAddr(self, transportAddr): try: - return socket.getaddrinfo(transportAddr[0], - transportAddr[1], - socket.AF_INET6, - socket.SOCK_DGRAM, - socket.IPPROTO_UDP)[0][4][:2] + return socket.getaddrinfo( + transportAddr[0], transportAddr[1], socket.AF_INET6, + socket.SOCK_DGRAM, socket.IPPROTO_UDP)[0][4][:2] + except socket.gaierror as exc: raise error.PySnmpError('Bad IPv6/UDP transport address %s: %s' % ( '@'.join([str(x) for x in transportAddr]), exc)) diff --git a/pysnmp/hlapi/v3arch/auth.py b/pysnmp/hlapi/v3arch/auth.py index 7c232221..18b4b328 100644 --- a/pysnmp/hlapi/v3arch/auth.py +++ b/pysnmp/hlapi/v3arch/auth.py @@ -174,48 +174,60 @@ class CommunityData(object): def __init__(self, communityIndex, communityName=None, mpModel=None, contextEngineId=None, contextName=None, tag=None, securityName=None): + if mpModel is not None: self.mpModel = mpModel self.securityModel = mpModel + 1 + self.contextEngineId = contextEngineId + if contextName is not None: self.contextName = contextName + if tag is not None: self.tag = tag + # a single arg is considered as a community name if communityName is None: communityName, communityIndex = communityIndex, None + self.communityName = communityName + # Autogenerate communityIndex if not specified if communityIndex is None: - self.communityIndex = self.securityName = 's%s' % hash( + self.securityName = 's%s' % hash( (self.communityName, self.mpModel, self.contextEngineId, - self.contextName, self.tag) - ) + self.contextName, self.tag)) + + self.communityIndex = self.securityName + else: self.communityIndex = communityIndex - self.securityName = securityName is not None and securityName or communityIndex + + if securityName is None: + self.securityName = communityIndex + + else: + self.securityName = securityName def __hash__(self): raise TypeError('%s is not hashable' % self.__class__.__name__) def __repr__(self): - return '%s(communityIndex=%r, communityName=, mpModel=%r, contextEngineId=%r, contextName=%r, tag=%r, securityName=%r)' % ( - self.__class__.__name__, - self.communityIndex, - self.mpModel, - self.contextEngineId, - self.contextName, - self.tag, - self.securityName - ) + return ('%s(communityIndex=%r, communityName=, mpModel=%r, ' + 'contextEngineId=%r, contextName=%r, tag=%r, securityName=' + '%r)') % (self.__class__.__name__, self.communityIndex, + self.mpModel, self.contextEngineId, self.contextName, + self.tag, self.securityName) def clone(self, communityIndex=None, communityName=None, mpModel=None, contextEngineId=None, contextName=None, tag=None, securityName=None): + # a single arg is considered as a community name if communityName is None: communityName, communityIndex = communityIndex, None + return self.__class__( communityIndex, communityName is None and self.communityName or communityName, @@ -223,8 +235,7 @@ class CommunityData(object): contextEngineId is None and self.contextEngineId or contextEngineId, contextName is None and self.contextName or contextName, tag is None and self.tag or tag, - securityName is None and self.securityName or securityName - ) + securityName is None and self.securityName or securityName) class UsmUserData(object): @@ -306,28 +317,38 @@ class UsmUserData(object): authProtocol=None, privProtocol=None, securityEngineId=None, securityName=None): + self.userName = userName + if securityName is None: self.securityName = userName + else: self.securityName = securityName if authKey is not None: self.authKey = authKey + if authProtocol is None: self.authProtocol = config.USM_AUTH_HMAC96_MD5 + else: self.authProtocol = authProtocol + if self.securityLevel != 'authPriv': self.securityLevel = 'authNoPriv' if privKey is not None: self.privKey = privKey + if self.authProtocol == config.USM_AUTH_NONE: raise error.PySnmpError('Privacy implies authenticity') + self.securityLevel = 'authPriv' + if privProtocol is None: self.privProtocol = config.USM_PRIV_CBC56_DES + else: self.privProtocol = privProtocol @@ -337,19 +358,19 @@ class UsmUserData(object): raise TypeError('%s is not hashable' % self.__class__.__name__) def __repr__(self): - return '%s(userName=%r, authKey=, privKey=, authProtocol=%r, privProtocol=%r, securityEngineId=%r, securityName=%r)' % ( - self.__class__.__name__, - self.userName, - self.authProtocol, - self.privProtocol, + return ('%s(userName=%r, authKey=, privKey=, ' + 'authProtocol=%r, privProtocol=%r, securityEngineId=%r, ' + 'securityName=%r)') % ( + self.__class__.__name__, self.userName, + self.authProtocol, self.privProtocol, self.securityEngineId is None and '' or self.securityEngineId, - self.securityName - ) + self.securityName) def clone(self, userName=None, authKey=None, privKey=None, authProtocol=None, privProtocol=None, securityEngineId=None, securityName=None): + return self.__class__( userName is None and self.userName or userName, authKey is None and self.authKey or authKey, @@ -357,5 +378,4 @@ class UsmUserData(object): authProtocol is None and self.authProtocol or authProtocol, privProtocol is None and self.privProtocol or privProtocol, securityEngineId is None and self.securityEngineId or securityEngineId, - securityName=securityName is None and self.securityName or securityName - ) + securityName=securityName is None and self.securityName or securityName) diff --git a/pysnmp/hlapi/v3arch/lcd.py b/pysnmp/hlapi/v3arch/lcd.py index b3397b0c..0e1eb9c5 100644 --- a/pysnmp/hlapi/v3arch/lcd.py +++ b/pysnmp/hlapi/v3arch/lcd.py @@ -21,10 +21,13 @@ class AbstractLcdConfigurator(object): def _getCache(self, snmpEngine): cacheId = self.__class__.__name__ + cache = snmpEngine.getUserContext(cacheId) + if cache is None: cache = dict([(x, {}) for x in self.cacheKeys]) snmpEngine.setUserContext(**{cacheId: cache}) + return cache def configure(self, snmpEngine, *args, **kwargs): @@ -37,8 +40,10 @@ class AbstractLcdConfigurator(object): class CommandGeneratorLcdConfigurator(AbstractLcdConfigurator): cacheKeys = ['auth', 'parm', 'tran', 'addr'] - def configure(self, snmpEngine, authData, transportTarget, contextName, **options): + def configure(self, snmpEngine, authData, transportTarget, + contextName, **options): cache = self._getCache(snmpEngine) + if isinstance(authData, CommunityData): if authData.communityIndex not in cache['auth']: config.addV1System( @@ -50,9 +55,12 @@ class CommandGeneratorLcdConfigurator(AbstractLcdConfigurator): authData.tag, authData.securityName ) + cache['auth'][authData.communityIndex] = authData + elif isinstance(authData, UsmUserData): authDataKey = authData.userName, authData.securityEngineId + if authDataKey not in cache['auth']: config.addV3User( snmpEngine, @@ -62,37 +70,48 @@ class CommandGeneratorLcdConfigurator(AbstractLcdConfigurator): authData.securityEngineId, securityName=authData.securityName ) + cache['auth'][authDataKey] = authData + else: raise error.PySnmpError('Unsupported authentication object') paramsKey = (authData.securityName, authData.securityLevel, authData.mpModel) + if paramsKey in cache['parm']: paramsName, useCount = cache['parm'][paramsKey] + cache['parm'][paramsKey] = paramsName, useCount + 1 + else: paramsName = 'p%s' % self.nextID() config.addTargetParams( snmpEngine, paramsName, authData.securityName, authData.securityLevel, authData.mpModel ) + cache['parm'][paramsKey] = paramsName, 1 if transportTarget.TRANSPORT_DOMAIN in cache['tran']: transport, useCount = cache['tran'][transportTarget.TRANSPORT_DOMAIN] transportTarget.verifyDispatcherCompatibility(snmpEngine) + cache['tran'][transportTarget.TRANSPORT_DOMAIN] = transport, useCount + 1 + elif config.getTransport(snmpEngine, transportTarget.TRANSPORT_DOMAIN): transportTarget.verifyDispatcherCompatibility(snmpEngine) + else: transport = transportTarget.openClientMode() + config.addTransport( snmpEngine, transportTarget.TRANSPORT_DOMAIN, transport ) + cache['tran'][transportTarget.TRANSPORT_DOMAIN] = transport, 1 transportKey = (paramsName, transportTarget.TRANSPORT_DOMAIN, @@ -105,8 +124,10 @@ class CommandGeneratorLcdConfigurator(AbstractLcdConfigurator): if transportKey in cache['addr']: addrName, useCount = cache['addr'][transportKey] cache['addr'][transportKey] = addrName, useCount + 1 + else: addrName = 'a%s' % self.nextID() + config.addTargetAddr( snmpEngine, addrName, transportTarget.TRANSPORT_DOMAIN, @@ -116,23 +137,30 @@ class CommandGeneratorLcdConfigurator(AbstractLcdConfigurator): transportTarget.retries, transportTarget.tagList ) + cache['addr'][transportKey] = addrName, 1 return addrName, paramsName def unconfigure(self, snmpEngine, authData=None, contextName=null, **options): cache = self._getCache(snmpEngine) + if authData: if isinstance(authData, CommunityData): authDataKey = authData.communityIndex + elif isinstance(authData, UsmUserData): authDataKey = authData.userName, authData.securityEngineId + else: raise error.PySnmpError('Unsupported authentication object') + if authDataKey in cache['auth']: authDataKeys = (authDataKey,) + else: raise error.PySnmpError('Unknown authData %s' % (authData,)) + else: authDataKeys = list(cache['auth'].keys()) @@ -140,35 +168,44 @@ class CommandGeneratorLcdConfigurator(AbstractLcdConfigurator): for authDataKey in authDataKeys: authDataX = cache['auth'][authDataKey] + del cache['auth'][authDataKey] + if isinstance(authDataX, CommunityData): config.delV1System( snmpEngine, authDataX.communityIndex ) + elif isinstance(authDataX, UsmUserData): config.delV3User( snmpEngine, authDataX.userName, authDataX.securityEngineId ) + else: raise error.PySnmpError('Unsupported authentication object') paramsKey = (authDataX.securityName, authDataX.securityLevel, authDataX.mpModel) + if paramsKey in cache['parm']: paramsName, useCount = cache['parm'][paramsKey] + useCount -= 1 + if useCount: cache['parm'][paramsKey] = paramsName, useCount + else: del cache['parm'][paramsKey] - config.delTargetParams( - snmpEngine, paramsName - ) + + config.delTargetParams(snmpEngine, paramsName) + paramsNames.add(paramsName) + else: raise error.PySnmpError('Unknown target %s' % (paramsKey,)) @@ -176,22 +213,30 @@ class CommandGeneratorLcdConfigurator(AbstractLcdConfigurator): for addrKey in addrKeys: addrName, useCount = cache['addr'][addrKey] + useCount -= 1 + if useCount: cache['addr'][addrKey] = addrName, useCount + else: config.delTargetAddr(snmpEngine, addrName) + del cache['addr'][addrKey] + addrNames.add(addrKey) if addrKey[1] in cache['tran']: transport, useCount = cache['tran'][addrKey[1]] + if useCount > 1: useCount -= 1 cache['tran'][addrKey[1]] = transport, useCount + else: config.delTransport(snmpEngine, addrKey[1]) transport.closeTransport() + del cache['tran'][addrKey[1]] return addrNames, paramsNames @@ -204,6 +249,7 @@ class NotificationOriginatorLcdConfigurator(AbstractLcdConfigurator): def configure(self, snmpEngine, authData, transportTarget, notifyType, contextName, **options): cache = self._getCache(snmpEngine) + notifyName = None # Create matching transport tags if not given by user. Not good! @@ -211,79 +257,97 @@ class NotificationOriginatorLcdConfigurator(AbstractLcdConfigurator): transportTarget.tagList = str( hash((authData.securityName, transportTarget.transportAddr)) ) + if isinstance(authData, CommunityData) and not authData.tag: authData.tag = transportTarget.tagList.split()[0] addrName, paramsName = self._cmdGenLcdCfg.configure( snmpEngine, authData, transportTarget, contextName, **options) + tagList = transportTarget.tagList.split() + if not tagList: tagList = [''] + for tag in tagList: notifyNameKey = paramsName, tag, notifyType + if notifyNameKey in cache['name']: notifyName, paramsName, useCount = cache['name'][notifyNameKey] + cache['name'][notifyNameKey] = notifyName, paramsName, useCount + 1 + else: notifyName = 'n%s' % self.nextID() + config.addNotificationTarget( - snmpEngine, - notifyName, - paramsName, - tag, - notifyType - ) + snmpEngine, notifyName, paramsName, tag, notifyType) + cache['name'][notifyNameKey] = notifyName, paramsName, 1 + authDataKey = authData.securityName, authData.securityModel, authData.securityLevel, contextName + if authDataKey in cache['auth']: authDataX, subTree, useCount = cache['auth'][authDataKey] + cache['auth'][authDataKey] = authDataX, subTree, useCount + 1 + else: subTree = (1, 3, 6) - config.addVacmUser(snmpEngine, - authData.securityModel, - authData.securityName, - authData.securityLevel, - (), (), subTree, contextName=contextName) + + config.addVacmUser( + snmpEngine,authData.securityModel, authData.securityName, + authData.securityLevel, (), (), subTree, + contextName=contextName) + cache['auth'][authDataKey] = authData, subTree, 1 return notifyName def unconfigure(self, snmpEngine, authData=None, contextName=null, **options): cache = self._getCache(snmpEngine) + if authData: authDataKey = authData.securityName, authData.securityModel, authData.securityLevel, contextName + if authDataKey in cache['auth']: authDataKeys = (authDataKey,) + else: raise error.PySnmpError('Unknown authData %s' % (authData,)) + else: authDataKeys = tuple(cache['auth']) addrNames, paramsNames = self._cmdGenLcdCfg.unconfigure( snmpEngine, authData, contextName, **options) - notifyAndParamsNames = [(cache['name'][x], x) for x in cache['name'].keys() if x[0] in paramsNames] + notifyAndParamsNames = [ + (cache['name'][x], x) for x in cache['name'].keys() + if x[0] in paramsNames + ] for (notifyName, paramsName, useCount), notifyNameKey in notifyAndParamsNames: useCount -= 1 + if useCount: cache['name'][notifyNameKey] = notifyName, paramsName, useCount + else: - config.delNotificationTarget( - snmpEngine, notifyName, paramsName - ) + config.delNotificationTarget(snmpEngine, notifyName, paramsName) del cache['name'][notifyNameKey] for authDataKey in authDataKeys: authDataX, subTree, useCount = cache['auth'][authDataKey] + useCount -= 1 + if useCount: cache['auth'][authDataKey] = authDataX, subTree, useCount + else: config.delTrapUser( - snmpEngine, authDataX.securityModel, - authDataX.securityName, authDataX.securityLevel, - subTree - ) + snmpEngine, authDataX.securityModel, authDataX.securityName, + authDataX.securityLevel, subTree) + del cache['auth'][authDataKey] diff --git a/pysnmp/hlapi/v3arch/twisted/cmdgen.py b/pysnmp/hlapi/v3arch/twisted/cmdgen.py index 91cfdab2..528c92df 100644 --- a/pysnmp/hlapi/v3arch/twisted/cmdgen.py +++ b/pysnmp/hlapi/v3arch/twisted/cmdgen.py @@ -110,38 +110,41 @@ def getCmd(snmpEngine, authData, transportTarget, contextData, ... >>> react(run) (0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')), DisplayString('SunOS zeus.snmplabs.com 4.1.3_U1 1 sun4m'))]) - >>> - """ def __cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): + lookupMib, deferred = cbCtx + if errorIndication: deferred.errback(Failure(errorIndication)) + else: try: - varBindsUnmade = VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, varBinds, lookupMib) + varBinds = VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, varBinds, lookupMib) except Exception as e: deferred.errback(Failure(e)) else: - deferred.callback((errorStatus, errorIndex, varBindsUnmade)) + deferred.callback((errorStatus, errorIndex, varBinds)) addrName, paramsName = LCD.configure( snmpEngine, authData, transportTarget, contextData.contextName) + varBinds = VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds) + deferred = Deferred() cmdgen.GetCommandGenerator().sendVarBinds( snmpEngine, addrName, contextData.contextEngineId, - contextData.contextName, - VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds), __cbFun, - (options.get('lookupMib', True), deferred) - ) + contextData.contextName, varBinds, __cbFun, + (options.get('lookupMib', True), deferred)) + return deferred + def setCmd(snmpEngine, authData, transportTarget, contextData, *varBinds, **options): """Performs SNMP SET query. @@ -227,38 +230,41 @@ def setCmd(snmpEngine, authData, transportTarget, contextData, ... >>> react(run) (0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')), DisplayString('Linux i386'))]) - >>> - """ def __cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): + lookupMib, deferred = cbCtx + if errorIndication: deferred.errback(Failure(errorIndication)) + else: try: - varBindsUnmade = VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, varBinds, lookupMib) + varBinds = VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, varBinds, lookupMib) except Exception as e: deferred.errback(Failure(e)) else: - deferred.callback((errorStatus, errorIndex, varBindsUnmade)) + deferred.callback((errorStatus, errorIndex, varBinds)) addrName, paramsName = LCD.configure( snmpEngine, authData, transportTarget, contextData.contextName) + varBinds = VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds) + deferred = Deferred() cmdgen.SetCommandGenerator().sendVarBinds( snmpEngine, addrName, contextData.contextEngineId, - contextData.contextName, - VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds), __cbFun, - (options.get('lookupMib', True), deferred) - ) + contextData.contextName, varBinds, __cbFun, + (options.get('lookupMib', True), deferred)) + return deferred + def nextCmd(snmpEngine, authData, transportTarget, contextData, *varBinds, **options): """Performs SNMP GETNEXT query. @@ -352,44 +358,49 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData, ... >>> react(run) (0, 0, [[ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')), DisplayString('SunOS zeus.snmplabs.com 4.1.3_U1 1 sun4m'))]]) - >>> - """ def __cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBindTable, cbCtx): + lookupMib, deferred = cbCtx - if (options.get('ignoreNonIncreasingOid', False) and - errorIndication and isinstance(errorIndication, errind.OidNotIncreasing)): + + if (options.get('ignoreNonIncreasingOid', False) and errorIndication + and isinstance(errorIndication, errind.OidNotIncreasing)): errorIndication = None + if errorIndication: deferred.errback(Failure(errorIndication)) + else: try: - varBindsUnmade = [VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, - varBindTableRow, - lookupMib) - for varBindTableRow in varBindTable] + varBindTable = [ + VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, + varBindTableRow, lookupMib) + for varBindTableRow in varBindTable + ] except Exception as e: deferred.errback(Failure(e)) else: - deferred.callback((errorStatus, errorIndex, varBindsUnmade)) + deferred.callback((errorStatus, errorIndex, varBindTable)) addrName, paramsName = LCD.configure( snmpEngine, authData, transportTarget, contextData.contextName) + varBinds = VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds) + deferred = Deferred() cmdgen.NextCommandGenerator().sendVarBinds( snmpEngine, addrName, contextData.contextEngineId, - contextData.contextName, - VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds), __cbFun, - (options.get('lookupMib', True), deferred) - ) + contextData.contextName, varBinds, __cbFun, + (options.get('lookupMib', True), deferred)) + return deferred + def bulkCmd(snmpEngine, authData, transportTarget, contextData, nonRepeaters, maxRepetitions, *varBinds, **options): """Performs SNMP GETBULK query. @@ -511,41 +522,45 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData, ... >>> react(run) (0, 0, [[ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')), DisplayString('SunOS zeus.snmplabs.com 4.1.3_U1 1 sun4m'))], [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.2.0')), ObjectIdentifier('1.3.6.1.4.1.424242.1.1'))]]) - >>> - """ def __cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBindTable, cbCtx): + lookupMib, deferred = cbCtx - if options.get('ignoreNonIncreasingOid', False) and errorIndication and \ - isinstance(errorIndication, errind.OidNotIncreasing): + + if (options.get('ignoreNonIncreasingOid', False) and errorIndication + and isinstance(errorIndication, errind.OidNotIncreasing)): errorIndication = None + if errorIndication: deferred.errback(Failure(errorIndication)) + else: try: - varBindsUnmade = [VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, - varBindTableRow, - lookupMib) - for varBindTableRow in varBindTable] + varBindTable = [ + VB_PROCESSOR.unmakeVarBinds(snmpEngine.cache, + varBindTableRow, lookupMib) + for varBindTableRow in varBindTable + ] except Exception as e: deferred.errback(Failure(e)) else: - deferred.callback((errorStatus, errorIndex, varBindsUnmade)) + deferred.callback((errorStatus, errorIndex, varBindTable)) addrName, paramsName = LCD.configure( snmpEngine, authData, transportTarget, contextData.contextName) + varBinds = VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds) + deferred = Deferred() cmdgen.BulkCommandGenerator().sendVarBinds( snmpEngine, addrName, contextData.contextEngineId, contextData.contextName, nonRepeaters, maxRepetitions, - VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds), - __cbFun, - (options.get('lookupMib', True), deferred) - ) + varBinds, __cbFun, (options.get('lookupMib', True), + deferred)) + return deferred diff --git a/pysnmp/hlapi/v3arch/twisted/ntforg.py b/pysnmp/hlapi/v3arch/twisted/ntforg.py index 5243c66f..3ea2aa59 100644 --- a/pysnmp/hlapi/v3arch/twisted/ntforg.py +++ b/pysnmp/hlapi/v3arch/twisted/ntforg.py @@ -21,6 +21,7 @@ __all__ = ['sendNotification'] VB_PROCESSOR = NotificationOriginatorVarBinds() LCD = NotificationOriginatorLcdConfigurator() + def sendNotification(snmpEngine, authData, transportTarget, contextData, notifyType, *varBinds, **options): """Sends SNMP notification. @@ -145,27 +146,26 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData, ... >>> react(run) (0, 0, []) - >>> - """ def __cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): + lookupMib, deferred = cbCtx if errorIndication: deferred.errback(Failure(errorIndication)) + else: try: - varBindsUnmade = VB_PROCESSOR.unmakeVarBinds( - snmpEngine.cache, varBinds, lookupMib - ) + varBinds = VB_PROCESSOR.unmakeVarBinds( + snmpEngine.cache, varBinds, lookupMib) except Exception as e: deferred.errback(Failure(e)) else: - deferred.callback((errorStatus, errorIndex, varBindsUnmade)) + deferred.callback((errorStatus, errorIndex, varBinds)) notifyName = LCD.configure(snmpEngine, authData, transportTarget, notifyType, contextData.contextName) @@ -173,15 +173,13 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData, def __trapFun(deferred): deferred.callback((0, 0, [])) + varBinds = VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds) + deferred = Deferred() ntforg.NotificationOriginator().sendVarBinds( - snmpEngine, - notifyName, - contextData.contextEngineId, - contextData.contextName, - VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds), - __cbFun, + snmpEngine, notifyName, contextData.contextEngineId, + contextData.contextName, varBinds, __cbFun, (options.get('lookupMib', True), deferred) ) diff --git a/pysnmp/hlapi/v3arch/twisted/transport.py b/pysnmp/hlapi/v3arch/twisted/transport.py index 11119fc4..71b0337a 100644 --- a/pysnmp/hlapi/v3arch/twisted/transport.py +++ b/pysnmp/hlapi/v3arch/twisted/transport.py @@ -12,6 +12,7 @@ from pysnmp.hlapi.transport import AbstractTransportTarget __all__ = ['UdpTransportTarget'] + class UdpTransportTarget(AbstractTransportTarget): """Creates UDP/IPv4 configuration entry and initialize socket API if needed. @@ -43,18 +44,17 @@ class UdpTransportTarget(AbstractTransportTarget): >>> from pysnmp.hlapi.twisted import UdpTransportTarget >>> UdpTransportTarget(('demo.snmplabs.com', 161)) UdpTransportTarget(('195.218.195.228', 161), timeout=1, retries=5, tagList='') - >>> - """ TRANSPORT_DOMAIN = udp.DOMAIN_NAME PROTO_TRANSPORT = udp.UdpTwistedTransport def _resolveAddr(self, transportAddr): try: - return socket.getaddrinfo(transportAddr[0], - transportAddr[1], - socket.AF_INET, - socket.SOCK_DGRAM, - socket.IPPROTO_UDP)[0][4][:2] + return socket.getaddrinfo( + transportAddr[0], transportAddr[1], socket.AF_INET, + socket.SOCK_DGRAM, socket.IPPROTO_UDP)[0][4][:2] + except socket.gaierror as exc: - raise PySnmpError('Bad IPv4/UDP transport address %s: %s' % ('@'.join([str(x) for x in transportAddr]), exc)) + raise PySnmpError( + 'Bad IPv4/UDP transport address %s: ' + '%s' % ('@'.join(str(x) for x in transportAddr), exc)) diff --git a/pysnmp/hlapi/varbinds.py b/pysnmp/hlapi/varbinds.py index d3742a75..0eed7e50 100644 --- a/pysnmp/hlapi/varbinds.py +++ b/pysnmp/hlapi/varbinds.py @@ -38,7 +38,9 @@ class CommandGeneratorVarBinds(MibViewControllerManager): varBind = ObjectType(*varBind) elif isinstance(varBind[0][0], tuple): # legacy - varBind = ObjectType(ObjectIdentity(varBind[0][0][0], varBind[0][0][1], *varBind[0][1:]), varBind[1]) + varBind = ObjectType( + ObjectIdentity(varBind[0][0][0], varBind[0][0][1], + *varBind[0][1:]), varBind[1]) else: varBind = ObjectType(ObjectIdentity(varBind[0]), varBind[1]) @@ -50,7 +52,10 @@ class CommandGeneratorVarBinds(MibViewControllerManager): def unmakeVarBinds(self, userCache, varBinds, lookupMib=True): if lookupMib: mibViewController = self.getMibViewController(userCache) - varBinds = [ObjectType(ObjectIdentity(x[0]), x[1]).resolveWithMib(mibViewController) for x in varBinds] + varBinds = [ + ObjectType(ObjectIdentity(x[0]), + x[1]).resolveWithMib(mibViewController) + for x in varBinds] return varBinds @@ -85,5 +90,9 @@ class NotificationOriginatorVarBinds(MibViewControllerManager): def unmakeVarBinds(self, userCache, varBinds, lookupMib=False): if lookupMib: mibViewController = self.getMibViewController(userCache) - varBinds = [ObjectType(ObjectIdentity(x[0]), x[1]).resolveWithMib(mibViewController) for x in varBinds] + varBinds = [ + ObjectType(ObjectIdentity(x[0]), + x[1]).resolveWithMib(mibViewController) + for x in varBinds] + return varBinds diff --git a/pysnmp/nextid.py b/pysnmp/nextid.py index f81bc9b6..60a61a11 100644 --- a/pysnmp/nextid.py +++ b/pysnmp/nextid.py @@ -13,30 +13,33 @@ class Integer(object): """Return a next value in a reasonably MT-safe manner""" def __init__(self, maximum, increment=256): - self.__maximum = maximum + self._maximum = maximum if increment >= maximum: increment = maximum - self.__increment = increment - self.__threshold = increment // 2 - e = random.randrange(self.__maximum - self.__increment) - self.__bank = list(range(e, e + self.__increment)) + + self._increment = increment + self._threshold = increment // 2 + + e = random.randrange(self._maximum - self._increment) + + self._bank = list(range(e, e + self._increment)) def __repr__(self): return '%s(%d, %d)' % ( - self.__class__.__name__, - self.__maximum, - self.__increment - ) + self.__class__.__name__, self._maximum, self._increment) def __call__(self): - v = self.__bank.pop(0) - if v % self.__threshold: - return v - else: - # this is MT-safe unless too many (~ increment/2) threads - # bump into this code simultaneously - e = self.__bank[-1] + 1 - if e > self.__maximum: - e = 0 - self.__bank.extend(range(e, e + self.__threshold)) + v = self._bank.pop(0) + + if v % self._threshold: return v + + # Should be MT-safe unless too many (~ increment/2) threads + # bump into this code simultaneously + e = self._bank[-1] + 1 + if e > self._maximum: + e = 0 + + self._bank.extend(range(e, e + self._threshold)) + + return v diff --git a/pysnmp/proto/acmod/rfc3415.py b/pysnmp/proto/acmod/rfc3415.py index fb4c4adf..13d9de12 100644 --- a/pysnmp/proto/acmod/rfc3415.py +++ b/pysnmp/proto/acmod/rfc3415.py @@ -17,65 +17,63 @@ class Vacm(object): _powOfTwoSeq = (128, 64, 32, 16, 8, 4, 2, 1) - def isAccessAllowed(self, - snmpEngine, - securityModel, - securityName, - securityLevel, - viewType, - contextName, - variableName): + def isAccessAllowed(self, snmpEngine, securityModel, securityName, + securityLevel, viewType, contextName, variableName): + mibInstrumController = snmpEngine.msgAndPduDsp.mibInstrumController + mibBuilder = mibInstrumController.mibBuilder debug.logger & debug.FLAG_ACL and debug.logger( - 'isAccessAllowed: securityModel %s, securityName %s, securityLevel %s, viewType %s, contextName %s for variableName %s' % ( - securityModel, securityName, securityLevel, viewType, contextName, variableName)) + 'isAccessAllowed: securityModel %s, securityName %s, ' + 'securityLevel %s, viewType %s, contextName %s for ' + 'variableName %s' % (securityModel, securityName, securityLevel, + viewType, contextName, variableName)) # 3.2.1 - vacmContextEntry, = mibInstrumController.mibBuilder.importSymbols( + vacmContextEntry, = mibBuilder.importSymbols( 'SNMP-VIEW-BASED-ACM-MIB', 'vacmContextEntry') tblIdx = vacmContextEntry.getInstIdFromIndices(contextName) + try: vacmContextEntry.getNode( - vacmContextEntry.name + (1,) + tblIdx - ).syntax + vacmContextEntry.name + (1,) + tblIdx).syntax except NoSuchInstanceError: raise error.StatusInformation(errorIndication=errind.noSuchContext) # 3.2.2 - vacmSecurityToGroupEntry, = mibInstrumController.mibBuilder.importSymbols( + vacmSecurityToGroupEntry, = mibBuilder.importSymbols( 'SNMP-VIEW-BASED-ACM-MIB', 'vacmSecurityToGroupEntry') + tblIdx = vacmSecurityToGroupEntry.getInstIdFromIndices( - securityModel, securityName - ) + securityModel, securityName) try: vacmGroupName = vacmSecurityToGroupEntry.getNode( - vacmSecurityToGroupEntry.name + (3,) + tblIdx - ).syntax + vacmSecurityToGroupEntry.name + (3,) + tblIdx).syntax except NoSuchInstanceError: raise error.StatusInformation(errorIndication=errind.noGroupName) # 3.2.3 - vacmAccessEntry, = mibInstrumController.mibBuilder.importSymbols( - 'SNMP-VIEW-BASED-ACM-MIB', 'vacmAccessEntry' - ) + vacmAccessEntry, = mibBuilder.importSymbols( + 'SNMP-VIEW-BASED-ACM-MIB', 'vacmAccessEntry') # XXX partial context name match tblIdx = vacmAccessEntry.getInstIdFromIndices( - vacmGroupName, contextName, securityModel, securityLevel - ) + vacmGroupName, contextName, securityModel, securityLevel) # 3.2.4 if viewType == 'read': entryIdx = vacmAccessEntry.name + (5,) + tblIdx + elif viewType == 'write': entryIdx = vacmAccessEntry.name + (6,) + tblIdx + elif viewType == 'notify': entryIdx = vacmAccessEntry.name + (7,) + tblIdx + else: raise error.ProtocolError('Unknown view type %s' % viewType) @@ -93,19 +91,20 @@ class Vacm(object): # 3.2.5a vacmViewTreeFamilyEntry, = mibInstrumController.mibBuilder.importSymbols( 'SNMP-VIEW-BASED-ACM-MIB', 'vacmViewTreeFamilyEntry') + tblIdx = vacmViewTreeFamilyEntry.getInstIdFromIndices(viewName) # Walk over entries initialTreeName = treeName = vacmViewTreeFamilyEntry.name + (2,) + tblIdx + maskName = vacmViewTreeFamilyEntry.name + (3,) + tblIdx while True: vacmViewTreeFamilySubtree = vacmViewTreeFamilyEntry.getNextNode( - treeName - ) + treeName) + vacmViewTreeFamilyMask = vacmViewTreeFamilyEntry.getNextNode( - maskName - ) + maskName) treeName = vacmViewTreeFamilySubtree.name maskName = vacmViewTreeFamilyMask.name @@ -125,10 +124,12 @@ class Vacm(object): m = len(mask) - 1 idx = l - 1 + while idx: if (idx > m or mask[idx] and vacmViewTreeFamilySubtree.syntax[idx] != variableName[idx]): break + idx -= 1 if idx: diff --git a/pysnmp/proto/acmod/void.py b/pysnmp/proto/acmod/void.py index 2f8c4e97..e3ee848f 100644 --- a/pysnmp/proto/acmod/void.py +++ b/pysnmp/proto/acmod/void.py @@ -15,17 +15,11 @@ class Vacm(object): """Void Access Control Model""" ACCESS_MODEL_ID = 0 - def isAccessAllowed(self, - snmpEngine, - securityModel, - securityName, - securityLevel, - viewType, - contextName, - variableName): + def isAccessAllowed(self, snmpEngine, securityModel, securityName, + securityLevel, viewType, contextName, variableName): debug.logger & debug.FLAG_ACL and debug.logger( - 'isAccessAllowed: viewType %s for variableName %s - OK' % (viewType, variableName) - ) + 'isAccessAllowed: viewType %s for variableName ' + '%s - OK' % (viewType, variableName)) # rfc3415 3.2.5c return error.StatusInformation(errorIndication=errind.accessAllowed) diff --git a/pysnmp/proto/api/v1.py b/pysnmp/proto/api/v1.py index 827a6a0d..f13920e7 100644 --- a/pysnmp/proto/api/v1.py +++ b/pysnmp/proto/api/v1.py @@ -39,10 +39,18 @@ class VarBindAPI(object): @staticmethod def setOIDVal(varBind, oidVal): oid, val = oidVal[0], oidVal[1] + varBind.setComponentByPosition(0, oid) + if val is None: val = null - varBind.setComponentByPosition(1).getComponentByPosition(1).setComponentByType(val.getTagSet(), val, verifyConstraints=False, matchTags=False, matchConstraints=False, innerFlag=True) + + (varBind.setComponentByPosition(1) + .getComponentByPosition(1) + .setComponentByType(val.getTagSet(), val, + verifyConstraints=False, matchTags=False, + matchConstraints=False, innerFlag=True)) + return varBind @staticmethod @@ -61,14 +69,17 @@ class PDUAPI(object): def setDefaults(self, pdu): pdu.setComponentByPosition( - 0, getNextRequestID(), verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 0, getNextRequestID(), verifyConstraints=False, matchTags=False, + matchConstraints=False) + pdu.setComponentByPosition( - 1, self._errorStatus, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 1, self._errorStatus, verifyConstraints=False, matchTags=False, + matchConstraints=False) + pdu.setComponentByPosition( - 2, self._errorIndex, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 2, self._errorIndex, verifyConstraints=False, matchTags=False, + matchConstraints=False) + pdu.setComponentByPosition(3) @staticmethod @@ -90,12 +101,14 @@ class PDUAPI(object): @staticmethod def getErrorIndex(pdu, muteErrors=False): errorIndex = pdu.getComponentByPosition(2) + if errorIndex > len(pdu[3]): if muteErrors: return errorIndex.clone(len(pdu[3])) + raise error.ProtocolError( - 'Error index out of range: %s > %s' % (errorIndex, len(pdu[3])) - ) + 'Error index out of range: %s > %s' % (errorIndex, len(pdu[3]))) + return errorIndex @staticmethod @@ -119,20 +132,23 @@ class PDUAPI(object): @staticmethod def getVarBinds(pdu): - return [apiVarBind.getOIDVal(varBind) for varBind in pdu.getComponentByPosition(3)] + return [apiVarBind.getOIDVal(varBind) + for varBind in pdu.getComponentByPosition(3)] @staticmethod def setVarBinds(pdu, varBinds): varBindList = pdu.setComponentByPosition(3).getComponentByPosition(3) + varBindList.clear() + for idx, varBind in enumerate(varBinds): if isinstance(varBind, VarBind): varBindList.setComponentByPosition(idx, varBind) + else: varBindList.setComponentByPosition(idx) apiVarBind.setOIDVal( - varBindList.getComponentByPosition(idx), varBind - ) + varBindList.getComponentByPosition(idx), varBind) def getResponse(self, reqPDU): rspPDU = GetResponsePDU() @@ -143,8 +159,10 @@ class PDUAPI(object): def getVarBindTable(self, reqPDU, rspPDU): if apiPDU.getErrorStatus(rspPDU) == 2: varBindRow = [(vb[0], null) for vb in apiPDU.getVarBinds(reqPDU)] + else: varBindRow = apiPDU.getVarBinds(rspPDU) + return [varBindRow] def getNextVarBinds(self, varBinds, errorIndex=None): @@ -173,14 +191,32 @@ class TrapPDUAPI(object): try: import socket agentAddress = IpAddress(socket.gethostbyname(socket.gethostname())) + except Exception: agentAddress = IpAddress('0.0.0.0') + self._networkAddress = NetworkAddress().setComponentByPosition(0, agentAddress) - pdu.setComponentByPosition(0, self._entOid, verifyConstraints=False, matchTags=False, matchConstraints=False) - pdu.setComponentByPosition(1, self._networkAddress, verifyConstraints=False, matchTags=False, matchConstraints=False) - pdu.setComponentByPosition(2, self._genericTrap, verifyConstraints=False, matchTags=False, matchConstraints=False) - pdu.setComponentByPosition(3, self._zeroInt, verifyConstraints=False, matchTags=False, matchConstraints=False) - pdu.setComponentByPosition(4, self._zeroTime, verifyConstraints=False, matchTags=False, matchConstraints=False) + + pdu.setComponentByPosition( + 0, self._entOid, verifyConstraints=False, matchTags=False, + matchConstraints=False) + + pdu.setComponentByPosition( + 1, self._networkAddress, verifyConstraints=False, matchTags=False, + matchConstraints=False) + + pdu.setComponentByPosition( + 2, self._genericTrap, verifyConstraints=False, matchTags=False, + matchConstraints=False) + + pdu.setComponentByPosition( + 3, self._zeroInt, verifyConstraints=False, matchTags=False, + matchConstraints=False) + + pdu.setComponentByPosition( + 4, self._zeroTime, verifyConstraints=False, matchTags=False, + matchConstraints=False) + pdu.setComponentByPosition(5) @staticmethod @@ -197,7 +233,9 @@ class TrapPDUAPI(object): @staticmethod def setAgentAddr(pdu, value): - pdu.setComponentByPosition(1).getComponentByPosition(1).setComponentByPosition(0, value) + (pdu.setComponentByPosition(1) + .getComponentByPosition(1) + .setComponentByPosition(0, value)) @staticmethod def getGenericTrap(pdu): @@ -233,24 +271,28 @@ class TrapPDUAPI(object): @staticmethod def getVarBinds(pdu): - varBinds = [] - for varBind in pdu.getComponentByPosition(5): - varBinds.append(apiVarBind.getOIDVal(varBind)) - return varBinds + return [apiVarBind.getOIDVal(varBind) + for varBind in pdu.getComponentByPosition(5)] @staticmethod def setVarBinds(pdu, varBinds): varBindList = pdu.setComponentByPosition(5).getComponentByPosition(5) + varBindList.clear() + idx = 0 + for varBind in varBinds: if isinstance(varBind, VarBind): varBindList.setComponentByPosition(idx, varBind) + else: varBindList.setComponentByPosition(idx) + apiVarBind.setOIDVal( varBindList.getComponentByPosition(idx), varBind ) + idx += 1 @@ -262,8 +304,14 @@ class MessageAPI(object): _community = univ.OctetString('public') def setDefaults(self, msg): - msg.setComponentByPosition(0, self._version, verifyConstraints=False, matchTags=False, matchConstraints=False) - msg.setComponentByPosition(1, self._community, verifyConstraints=False, matchTags=False, matchConstraints=False) + msg.setComponentByPosition( + 0, self._version, verifyConstraints=False, matchTags=False, + matchConstraints=False) + + msg.setComponentByPosition( + 1, self._community, verifyConstraints=False, matchTags=False, + matchConstraints=False) + return msg @staticmethod @@ -288,14 +336,20 @@ class MessageAPI(object): @staticmethod def setPDU(msg, value): - msg.setComponentByPosition(2).getComponentByPosition(2).setComponentByType(value.getTagSet(), value, verifyConstraints=False, matchTags=False, matchConstraints=False, innerFlag=True) + (msg.setComponentByPosition(2) + .getComponentByPosition(2) + .setComponentByType(value.getTagSet(), value, verifyConstraints=False, + matchTags=False, matchConstraints=False, + innerFlag=True)) def getResponse(self, reqMsg): rspMsg = Message() + self.setDefaults(rspMsg) self.setVersion(rspMsg, self.getVersion(reqMsg)) self.setCommunity(rspMsg, self.getCommunity(reqMsg)) self.setPDU(rspMsg, apiPDU.getResponse(self.getPDU(reqMsg))) + return rspMsg diff --git a/pysnmp/proto/api/v2c.py b/pysnmp/proto/api/v2c.py index 05de2da1..c415ca9a 100644 --- a/pysnmp/proto/api/v2c.py +++ b/pysnmp/proto/api/v2c.py @@ -53,7 +53,8 @@ apiVarBind = v1.apiVarBind class PDUAPI(v1.PDUAPI): _errorStatus = rfc1905.errorStatus.clone(0) - _errorIndex = univ.Integer(0).subtype(subtypeSpec=constraint.ValueRangeConstraint(0, rfc1905.max_bindings)) + _errorIndex = univ.Integer(0).subtype( + subtypeSpec=constraint.ValueRangeConstraint(0, rfc1905.max_bindings)) def getResponse(self, reqPDU): rspPDU = ResponsePDU() @@ -86,14 +87,14 @@ class PDUAPI(v1.PDUAPI): def setEndOfMibError(self, pdu, errorIndex): varBindList = self.getVarBindList(pdu) varBindList[errorIndex - 1].setComponentByPosition( - 1, rfc1905.endOfMibView, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 1, rfc1905.endOfMibView, verifyConstraints=False, matchTags=False, + matchConstraints=False) def setNoSuchInstanceError(self, pdu, errorIndex): varBindList = self.getVarBindList(pdu) varBindList[errorIndex - 1].setComponentByPosition( - 1, rfc1905.noSuchInstance, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 1, rfc1905.noSuchInstance, verifyConstraints=False, matchTags=False, + matchConstraints=False) apiPDU = PDUAPI() @@ -105,15 +106,19 @@ class BulkPDUAPI(PDUAPI): def setDefaults(self, pdu): PDUAPI.setDefaults(self, pdu) + pdu.setComponentByPosition( - 0, getNextRequestID(), verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 0, getNextRequestID(), verifyConstraints=False, matchTags=False, + matchConstraints=False) + pdu.setComponentByPosition( - 1, self._nonRepeaters, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 1, self._nonRepeaters, verifyConstraints=False, matchTags=False, + matchConstraints=False) + pdu.setComponentByPosition( - 2, self._maxRepetitions, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 2, self._maxRepetitions, verifyConstraints=False, matchTags=False, + matchConstraints=False) + pdu.setComponentByPosition(3) @staticmethod @@ -152,9 +157,11 @@ class BulkPDUAPI(PDUAPI): if R: for i in range(0, len(rspVarBinds) - N, R): varBindRow = rspVarBinds[:N] + rspVarBinds[N + i:N + R + i] + # ignore stray OIDs / non-rectangular table if len(varBindRow) == N + R: varBindTable.append(varBindRow) + elif N: varBindTable.append(rspVarBinds[:N]) @@ -175,9 +182,11 @@ class TrapPDUAPI(v1.PDUAPI): def setDefaults(self, pdu): v1.PDUAPI.setDefaults(self, pdu) + varBinds = [(self.sysUpTime, self._zeroTime), # generic trap (self.snmpTrapOID, self._genTrap)] + self.setVarBinds(pdu, varBinds) @@ -188,16 +197,24 @@ class MessageAPI(v1.MessageAPI): _version = rfc1901.version.clone(1) def setDefaults(self, msg): - msg.setComponentByPosition(0, self._version, verifyConstraints=False, matchTags=False, matchConstraints=False) - msg.setComponentByPosition(1, self._community, verifyConstraints=False, matchTags=False, matchConstraints=False) + msg.setComponentByPosition( + 0, self._version, verifyConstraints=False, matchTags=False, + matchConstraints=False) + + msg.setComponentByPosition( + 1, self._community, verifyConstraints=False, matchTags=False, + matchConstraints=False) + return msg def getResponse(self, reqMsg): rspMsg = Message() + self.setDefaults(rspMsg) self.setVersion(rspMsg, self.getVersion(reqMsg)) self.setCommunity(rspMsg, self.getCommunity(reqMsg)) self.setPDU(rspMsg, apiPDU.getResponse(self.getPDU(reqMsg))) + return rspMsg diff --git a/pysnmp/proto/api/verdec.py b/pysnmp/proto/api/verdec.py index e6ec7fd9..142a68c2 100644 --- a/pysnmp/proto/api/verdec.py +++ b/pysnmp/proto/api/verdec.py @@ -18,13 +18,17 @@ def decodeMessageVersion(wholeMsg): wholeMsg, asn1Spec=univ.Sequence(), recursiveFlag=False, substrateFun=lambda a, b, c: (a, b[:c]) ) + ver, wholeMsg = decoder.decode( wholeMsg, asn1Spec=univ.Integer(), recursiveFlag=False, substrateFun=lambda a, b, c: (a, b[:c]) ) + if eoo.endOfOctets.isSameTypeWith(ver): raise ProtocolError('EOO at SNMP version component') + return ver except PyAsn1Error as exc: - raise ProtocolError('Invalid BER at SNMP version component: %s' % exc) + raise ProtocolError('Invalid BER at SNMP version ' + 'component: %s' % exc) diff --git a/pysnmp/proto/cache.py b/pysnmp/proto/cache.py index 9eae19c9..eed689ff 100644 --- a/pysnmp/proto/cache.py +++ b/pysnmp/proto/cache.py @@ -9,30 +9,30 @@ from pysnmp.proto import error class Cache(object): def __init__(self): - self.__cacheRepository = {} + self._cacheRepository = {} def add(self, index, **kwargs): - self.__cacheRepository[index] = kwargs + self._cacheRepository[index] = kwargs return index def pop(self, index): - if index in self.__cacheRepository: - cachedParams = self.__cacheRepository[index] + if index in self._cacheRepository: + cachedParams = self._cacheRepository[index] else: return - del self.__cacheRepository[index] + del self._cacheRepository[index] return cachedParams def update(self, index, **kwargs): - if index not in self.__cacheRepository: + if index not in self._cacheRepository: raise error.ProtocolError( 'Cache miss on update for %s' % kwargs ) - self.__cacheRepository[index].update(kwargs) + self._cacheRepository[index].update(kwargs) def expire(self, cbFun, cbCtx): - for index, cachedParams in list(self.__cacheRepository.items()): + for index, cachedParams in list(self._cacheRepository.items()): if cbFun: if cbFun(index, cachedParams, cbCtx): - if index in self.__cacheRepository: - del self.__cacheRepository[index] + if index in self._cacheRepository: + del self._cacheRepository[index] diff --git a/pysnmp/proto/errind.py b/pysnmp/proto/errind.py index 0c0dcb80..758a9ae1 100644 --- a/pysnmp/proto/errind.py +++ b/pysnmp/proto/errind.py @@ -10,30 +10,34 @@ class ErrorIndication(Exception): """SNMPv3 error-indication values""" def __init__(self, descr=None): - self.__value = self.__descr = self.__class__.__name__[0].lower() + self.__class__.__name__[1:] + self._value = ( + self.__class__.__name__[0].lower() + + self.__class__.__name__[1:]) + self._descr = self._value + if descr: - self.__descr = descr + self._descr = descr def __eq__(self, other): - return self.__value == other + return self._value == other def __ne__(self, other): - return self.__value != other + return self._value != other def __lt__(self, other): - return self.__value < other + return self._value < other def __le__(self, other): - return self.__value <= other + return self._value <= other def __gt__(self, other): - return self.__value > other + return self._value > other def __ge__(self, other): - return self.__value >= other + return self._value >= other def __str__(self): - return self.__descr + return self._descr # SNMP message processing errors @@ -42,84 +46,96 @@ class SerializationError(ErrorIndication): pass -serializationError = SerializationError('SNMP message serialization error') +serializationError = SerializationError( + 'SNMP message serialization error') class DeserializationError(ErrorIndication): pass -deserializationError = DeserializationError('SNMP message deserialization error') +deserializationError = DeserializationError( + 'SNMP message deserialization error') class ParseError(DeserializationError): pass -parseError = ParseError('SNMP message deserialization error') +parseError = ParseError( + 'SNMP message deserialization error') class UnsupportedMsgProcessingModel(ErrorIndication): pass -unsupportedMsgProcessingModel = UnsupportedMsgProcessingModel('Unknown SNMP message processing model ID encountered') +unsupportedMsgProcessingModel = UnsupportedMsgProcessingModel( + 'Unknown SNMP message processing model ID encountered') class UnknownPDUHandler(ErrorIndication): pass -unknownPDUHandler = UnknownPDUHandler('Unhandled PDU type encountered') +unknownPDUHandler = UnknownPDUHandler( + 'Unhandled PDU type encountered') class UnsupportedPDUtype(ErrorIndication): pass -unsupportedPDUtype = UnsupportedPDUtype('Unsupported SNMP PDU type encountered') +unsupportedPDUtype = UnsupportedPDUtype( + 'Unsupported SNMP PDU type encountered') class RequestTimedOut(ErrorIndication): pass -requestTimedOut = RequestTimedOut('No SNMP response received before timeout') +requestTimedOut = RequestTimedOut( + 'No SNMP response received before timeout') class EmptyResponse(ErrorIndication): pass -emptyResponse = EmptyResponse('Empty SNMP response message') +emptyResponse = EmptyResponse( + 'Empty SNMP response message') class NonReportable(ErrorIndication): pass -nonReportable = NonReportable('Report PDU generation not attempted') +nonReportable = NonReportable( + 'Report PDU generation not attempted') class DataMismatch(ErrorIndication): pass -dataMismatch = DataMismatch('SNMP request/response parameters mismatched') +dataMismatch = DataMismatch( + 'SNMP request/response parameters mismatched') class EngineIDMismatch(ErrorIndication): pass -engineIDMismatch = EngineIDMismatch('SNMP engine ID mismatch encountered') +engineIDMismatch = EngineIDMismatch( + 'SNMP engine ID mismatch encountered') class UnknownEngineID(ErrorIndication): pass -unknownEngineID = UnknownEngineID('Unknown SNMP engine ID encountered') +unknownEngineID = UnknownEngineID( + 'Unknown SNMP engine ID encountered') class TooBig(ErrorIndication): @@ -133,14 +149,16 @@ class LoopTerminated(ErrorIndication): pass -loopTerminated = LoopTerminated('Infinite SNMP entities talk terminated') +loopTerminated = LoopTerminated( + 'Infinite SNMP entities talk terminated') class InvalidMsg(ErrorIndication): pass -invalidMsg = InvalidMsg('Invalid SNMP message header parameters encountered') +invalidMsg = InvalidMsg( + 'Invalid SNMP message header parameters encountered') # SNMP security modules errors @@ -149,112 +167,128 @@ class UnknownCommunityName(ErrorIndication): pass -unknownCommunityName = UnknownCommunityName('Unknown SNMP community name encountered') +unknownCommunityName = UnknownCommunityName( + 'Unknown SNMP community name encountered') class NoEncryption(ErrorIndication): pass -noEncryption = NoEncryption('No encryption services configured') +noEncryption = NoEncryption( + 'No encryption services configured') class EncryptionError(ErrorIndication): pass -encryptionError = EncryptionError('Ciphering services not available') +encryptionError = EncryptionError( + 'Ciphering services not available') class DecryptionError(ErrorIndication): pass -decryptionError = DecryptionError('Ciphering services not available or ciphertext is broken') +decryptionError = DecryptionError( + 'Ciphering services not available or ciphertext is broken') class NoAuthentication(ErrorIndication): pass -noAuthentication = NoAuthentication('No authentication services configured') +noAuthentication = NoAuthentication( + 'No authentication services configured') class AuthenticationError(ErrorIndication): pass -authenticationError = AuthenticationError('Ciphering services not available or bad parameters') +authenticationError = AuthenticationError( + 'Ciphering services not available or bad parameters') class AuthenticationFailure(ErrorIndication): pass -authenticationFailure = AuthenticationFailure('Authenticator mismatched') +authenticationFailure = AuthenticationFailure( + 'Authenticator mismatched') class UnsupportedAuthProtocol(ErrorIndication): pass -unsupportedAuthProtocol = UnsupportedAuthProtocol('Authentication protocol is not supported') +unsupportedAuthProtocol = UnsupportedAuthProtocol( + 'Authentication protocol is not supported') class UnsupportedPrivProtocol(ErrorIndication): pass -unsupportedPrivProtocol = UnsupportedPrivProtocol('Privacy protocol is not supported') +unsupportedPrivProtocol = UnsupportedPrivProtocol( + 'Privacy protocol is not supported') class UnknownSecurityName(ErrorIndication): pass -unknownSecurityName = UnknownSecurityName('Unknown SNMP security name encountered') +unknownSecurityName = UnknownSecurityName( + 'Unknown SNMP security name encountered') class UnsupportedSecurityModel(ErrorIndication): pass -unsupportedSecurityModel = UnsupportedSecurityModel('Unsupported SNMP security model') +unsupportedSecurityModel = UnsupportedSecurityModel( + 'Unsupported SNMP security model') class UnsupportedSecurityLevel(ErrorIndication): pass -unsupportedSecurityLevel = UnsupportedSecurityLevel('Unsupported SNMP security level') +unsupportedSecurityLevel = UnsupportedSecurityLevel( + 'Unsupported SNMP security level') class NotInTimeWindow(ErrorIndication): pass -notInTimeWindow = NotInTimeWindow('SNMP message timing parameters not in windows of trust') +notInTimeWindow = NotInTimeWindow( + 'SNMP message timing parameters not in windows of trust') class UnknownUserName(ErrorIndication): pass -unknownUserName = UnknownUserName('Unknown USM user') +unknownUserName = UnknownUserName( + 'Unknown USM user') class WrongDigest(ErrorIndication): pass -wrongDigest = WrongDigest('Wrong SNMP PDU digest') +wrongDigest = WrongDigest( + 'Wrong SNMP PDU digest') class ReportPduReceived(ErrorIndication): pass -reportPduReceived = ReportPduReceived('Remote SNMP engine reported error') +reportPduReceived = ReportPduReceived( + 'Remote SNMP engine reported error') # SNMP access-control errors @@ -263,36 +297,40 @@ class NoSuchView(ErrorIndication): pass -noSuchView = NoSuchView('No such MIB view currently exists') +noSuchView = NoSuchView( + 'No such MIB view currently exists') class NoAccessEntry(ErrorIndication): pass - -noAccessEntry = NoAccessEntry('Access to MIB node denined') +noAccessEntry = NoAccessEntry( + 'Access to MIB node denined') class NoGroupName(ErrorIndication): pass -noGroupName = NoGroupName('No such VACM group configured') +noGroupName = NoGroupName( + 'No such VACM group configured') class NoSuchContext(ErrorIndication): pass -noSuchContext = NoSuchContext('SNMP context now found') +noSuchContext = NoSuchContext( + 'SNMP context now found') class NotInView(ErrorIndication): pass -notInView = NotInView('Requested OID is out of MIB view') +notInView = NotInView( + 'Requested OID is out of MIB view') class AccessAllowed(ErrorIndication): @@ -306,7 +344,8 @@ class OtherError(ErrorIndication): pass -otherError = OtherError('Unspecified SNMP engine error occurred') +otherError = OtherError( + 'Unspecified SNMP engine error occurred') # SNMP Apps errors @@ -315,4 +354,5 @@ class OidNotIncreasing(ErrorIndication): pass -oidNotIncreasing = OidNotIncreasing('OID not increasing') +oidNotIncreasing = OidNotIncreasing( + 'OID not increasing') diff --git a/pysnmp/proto/error.py b/pysnmp/proto/error.py index 52e84642..4847bddf 100644 --- a/pysnmp/proto/error.py +++ b/pysnmp/proto/error.py @@ -23,8 +23,11 @@ class SnmpV3Error(ProtocolError): class StatusInformation(SnmpV3Error): def __init__(self, **kwargs): SnmpV3Error.__init__(self) + self.__errorIndication = kwargs - debug.logger & (debug.FLAG_DSP | debug.FLAG_MP | debug.FLAG_SM | debug.FLAG_ACL) and debug.logger( + + debug.logger & (debug.FLAG_DSP | debug.FLAG_MP | + debug.FLAG_SM | debug.FLAG_ACL) and debug.logger( 'StatusInformation: %s' % kwargs) def __str__(self): diff --git a/pysnmp/proto/mpmod/base.py b/pysnmp/proto/mpmod/base.py index 61b26662..835aca53 100644 --- a/pysnmp/proto/mpmod/base.py +++ b/pysnmp/proto/mpmod/base.py @@ -20,6 +20,7 @@ class AbstractMessageProcessingModel(object): securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, expectResponse, sendPduHandle): + raise error.ProtocolError('method not implemented') def prepareResponseMessage(self, snmpEngine, messageProcessingModel, @@ -27,15 +28,18 @@ class AbstractMessageProcessingModel(object): contextEngineId, contextName, pduVersion, pdu, maxSizeResponseScopedPDU, stateReference, statusInformation): + raise error.ProtocolError('method not implemented') def prepareDataElements(self, snmpEngine, transportDomain, transportAddress, wholeMsg): + raise error.ProtocolError('method not implemented') def releaseStateInformation(self, sendPduHandle): try: self._cache.popBySendPduHandle(sendPduHandle) + except error.ProtocolError: pass # XXX maybe these should all follow some scheme? diff --git a/pysnmp/proto/mpmod/cache.py b/pysnmp/proto/mpmod/cache.py index 0cb343bd..265355a4 100644 --- a/pysnmp/proto/mpmod/cache.py +++ b/pysnmp/proto/mpmod/cache.py @@ -27,25 +27,37 @@ class Cache(object): def pushByStateRef(self, stateReference, **msgInfo): if stateReference in self.__stateReferenceIndex: - raise error.ProtocolError('Cache dup for stateReference=%s at %s' % (stateReference, self)) + raise error.ProtocolError( + 'Cache dup for stateReference=%s at %s' % (stateReference, self)) + expireAt = self.__expirationTimer + 600 + self.__stateReferenceIndex[stateReference] = msgInfo, expireAt # Schedule to expire if expireAt not in self.__expirationQueue: self.__expirationQueue[expireAt] = {} + if 'stateReference' not in self.__expirationQueue[expireAt]: self.__expirationQueue[expireAt]['stateReference'] = {} + self.__expirationQueue[expireAt]['stateReference'][stateReference] = 1 def popByStateRef(self, stateReference): if stateReference in self.__stateReferenceIndex: cacheInfo = self.__stateReferenceIndex[stateReference] + else: - raise error.ProtocolError('Cache miss for stateReference=%s at %s' % (stateReference, self)) + raise error.ProtocolError( + 'Cache miss for stateReference=%s at ' + '%s' % (stateReference, self)) + del self.__stateReferenceIndex[stateReference] + cacheEntry, expireAt = cacheInfo + del self.__expirationQueue[expireAt]['stateReference'][stateReference] + return cacheEntry # Client mode cache handling @@ -56,9 +68,10 @@ class Cache(object): def pushByMsgId(self, msgId, **msgInfo): if msgId in self.__msgIdIndex: raise error.ProtocolError( - 'Cache dup for msgId=%s at %s' % (msgId, self) - ) + 'Cache dup for msgId=%s at %s' % (msgId, self)) + expireAt = self.__expirationTimer + 600 + self.__msgIdIndex[msgId] = msgInfo, expireAt self.__sendPduHandleIdx[msgInfo['sendPduHandle']] = msgId @@ -66,22 +79,29 @@ class Cache(object): # Schedule to expire if expireAt not in self.__expirationQueue: self.__expirationQueue[expireAt] = {} + if 'msgId' not in self.__expirationQueue[expireAt]: self.__expirationQueue[expireAt]['msgId'] = {} + self.__expirationQueue[expireAt]['msgId'][msgId] = 1 def popByMsgId(self, msgId): if msgId in self.__msgIdIndex: cacheInfo = self.__msgIdIndex[msgId] + else: raise error.ProtocolError( - 'Cache miss for msgId=%s at %s' % (msgId, self) - ) + 'Cache miss for msgId=%s at %s' % (msgId, self)) + msgInfo, expireAt = cacheInfo + del self.__sendPduHandleIdx[msgInfo['sendPduHandle']] del self.__msgIdIndex[msgId] + cacheEntry, expireAt = cacheInfo + del self.__expirationQueue[expireAt]['msgId'][msgId] + return cacheEntry def popBySendPduHandle(self, sendPduHandle): @@ -92,11 +112,15 @@ class Cache(object): # Uses internal clock to expire pending messages if self.__expirationTimer in self.__expirationQueue: cacheInfo = self.__expirationQueue[self.__expirationTimer] + if 'stateReference' in cacheInfo: for stateReference in cacheInfo['stateReference']: del self.__stateReferenceIndex[stateReference] + if 'msgId' in cacheInfo: for msgId in cacheInfo['msgId']: del self.__msgIdIndex[msgId] + del self.__expirationQueue[self.__expirationTimer] + self.__expirationTimer += 1 diff --git a/pysnmp/proto/mpmod/rfc2576.py b/pysnmp/proto/mpmod/rfc2576.py index 8bad83c2..36011619 100644 --- a/pysnmp/proto/mpmod/rfc2576.py +++ b/pysnmp/proto/mpmod/rfc2576.py @@ -32,9 +32,11 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, expectResponse, sendPduHandle): + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder - snmpEngineId, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') + snmpEngineId, = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineId = snmpEngineId.syntax # rfc3412: 7.1.1b @@ -42,8 +44,10 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): # serve unique PDU request-id msgID = self._cache.newMsgID() reqID = pdu.getComponentByPosition(0) + debug.logger & debug.FLAG_MP and debug.logger( - 'prepareOutgoingMessage: PDU request-id %s replaced with unique ID %s' % (reqID, msgID)) + 'prepareOutgoingMessage: PDU request-id %s replaced with ' + 'unique ID %s' % (reqID, msgID)) # rfc3412: 7.1.4 # Since there's no SNMP engine identification in v1/2c, @@ -56,17 +60,19 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): contextName = null debug.logger & debug.FLAG_MP and debug.logger( - 'prepareOutgoingMessage: using contextEngineId %r contextName %r' % (contextEngineId, contextName)) + 'prepareOutgoingMessage: using contextEngineId %r contextName ' + '%r' % (contextEngineId, contextName)) # rfc3412: 7.1.6 - scopedPDU = (contextEngineId, contextName, pdu) + scopedPDU = contextEngineId, contextName, pdu msg = self._snmpMsgSpec + msg.setComponentByPosition(0, self.MESSAGE_PROCESSING_MODEL_ID) msg.setComponentByPosition(2) msg.getComponentByPosition(2).setComponentByType( - pdu.tagSet, pdu, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + pdu.tagSet, pdu, verifyConstraints=False, matchTags=False, + matchConstraints=False) # rfc3412: 7.1.7 globalData = (msg,) @@ -74,15 +80,15 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): k = int(securityModel) if k in snmpEngine.securityModels: smHandler = snmpEngine.securityModels[k] + else: raise error.StatusInformation( - errorIndication=errind.unsupportedSecurityModel - ) + errorIndication=errind.unsupportedSecurityModel) # rfc3412: 7.1.9.a & rfc2576: 5.2.1 --> no-op - snmpEngineMaxMessageSize, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', - 'snmpEngineMaxMessageSize') + snmpEngineMaxMessageSize, = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') # fix unique request-id right prior PDU serialization if pdu.tagSet in rfc3411.CONFIRMED_CLASS_PDUS: @@ -90,12 +96,10 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): pdu.setComponentByPosition(0, msgID) # rfc3412: 7.1.9.b - (securityParameters, - wholeMsg) = smHandler.generateRequestMsg( + securityParameters, wholeMsg = smHandler.generateRequestMsg( snmpEngine, self.MESSAGE_PROCESSING_MODEL_ID, globalData, snmpEngineMaxMessageSize.syntax, securityModel, - snmpEngineId, securityName, securityLevel, scopedPDU - ) + snmpEngineId, securityName, securityLevel, scopedPDU) # return original request-id right after PDU serialization if pdu.tagSet in rfc3411.CONFIRMED_CLASS_PDUS: @@ -105,15 +109,16 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): # rfc3412: 7.1.9.c if pdu.tagSet in rfc3411.CONFIRMED_CLASS_PDUS: # XXX rfc bug? why stateReference should be created? - self._cache.pushByMsgId(int(msgID), sendPduHandle=sendPduHandle, - reqID=reqID, snmpEngineId=snmpEngineId, - securityModel=securityModel, - securityName=securityName, - securityLevel=securityLevel, - contextEngineId=contextEngineId, - contextName=contextName, - transportDomain=transportDomain, - transportAddress=transportAddress) + self._cache.pushByMsgId( + int(msgID), sendPduHandle=sendPduHandle, + reqID=reqID, snmpEngineId=snmpEngineId, + securityModel=securityModel, + securityName=securityName, + securityLevel=securityLevel, + contextEngineId=contextEngineId, + contextName=contextName, + transportDomain=transportDomain, + transportAddress=transportAddress) communityName = msg.getComponentByPosition(1) # for observer @@ -128,11 +133,10 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): contextEngineId=contextEngineId, contextName=contextName, communityName=communityName, - pdu=pdu) - ) + pdu=pdu)) + snmpEngine.observer.clearExecutionContext( - snmpEngine, 'rfc2576.prepareOutgoingMessage' - ) + snmpEngine, 'rfc2576.prepareOutgoingMessage') return transportDomain, transportAddress, wholeMsg @@ -142,9 +146,11 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): contextEngineId, contextName, pduVersion, pdu, maxSizeResponseScopedPDU, stateReference, statusInformation): + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder - snmpEngineId, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') + snmpEngineId, = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineId = snmpEngineId.syntax # rfc3412: 7.1.2.b @@ -152,6 +158,7 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): raise error.StatusInformation(errorIndication=errind.nonReportable) cachedParams = self._cache.popByStateRef(stateReference) + msgID = cachedParams['msgID'] reqID = cachedParams['reqID'] contextEngineId = cachedParams['contextEngineId'] @@ -165,7 +172,8 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): transportAddress = cachedParams['transportAddress'] debug.logger & debug.FLAG_MP and debug.logger( - 'prepareResponseMessage: cache read msgID %s transportDomain %s transportAddress %s by stateReference %s' % ( + 'prepareResponseMessage: cache read msgID %s transportDomain %s ' + 'transportAddress %s by stateReference %s' % ( msgID, transportDomain, transportAddress, stateReference)) # rfc3412: 7.1.3 @@ -189,14 +197,15 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): scopedPDU = (contextEngineId, contextName, pdu) debug.logger & debug.FLAG_MP and debug.logger( - 'prepareResponseMessage: using contextEngineId %r contextName %r' % (contextEngineId, contextName)) + 'prepareResponseMessage: using contextEngineId %r contextName ' + '%r' % (contextEngineId, contextName)) msg = self._snmpMsgSpec msg.setComponentByPosition(0, messageProcessingModel) msg.setComponentByPosition(2) msg.getComponentByPosition(2).setComponentByType( - pdu.tagSet, pdu, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + pdu.tagSet, pdu, verifyConstraints=False, matchTags=False, + matchConstraints=False) # att: msgId not set back to PDU as it's up to responder app @@ -206,20 +215,19 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): k = int(securityModel) if k in snmpEngine.securityModels: smHandler = snmpEngine.securityModels[k] + else: raise error.StatusInformation( - errorIndication=errind.unsupportedSecurityModel - ) + errorIndication=errind.unsupportedSecurityModel) # set original request-id right prior to PDU serialization pdu.setComponentByPosition(0, reqID) # rfc3412: 7.1.8.a - (securityParameters, wholeMsg) = smHandler.generateResponseMsg( + securityParameters, wholeMsg = smHandler.generateResponseMsg( snmpEngine, self.MESSAGE_PROCESSING_MODEL_ID, globalData, maxMessageSize, securityModel, snmpEngineId, securityName, - securityLevel, scopedPDU, securityStateReference - ) + securityLevel, scopedPDU, securityStateReference) # recover unique request-id right after PDU serialization pdu.setComponentByPosition(0, msgID) @@ -235,11 +243,10 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): contextName=contextName, securityEngineId=snmpEngineId, communityName=msg.getComponentByPosition(1), - pdu=pdu) - ) + pdu=pdu)) + snmpEngine.observer.clearExecutionContext( - snmpEngine, 'rfc2576.prepareResponseMessage' - ) + snmpEngine, 'rfc2576.prepareResponseMessage') return transportDomain, transportAddress, wholeMsg @@ -247,12 +254,14 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): def prepareDataElements(self, snmpEngine, transportDomain, transportAddress, wholeMsg): + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder # rfc3412: 7.2.2 msg, restOfWholeMsg = decoder.decode(wholeMsg, asn1Spec=self._snmpMsgSpec) - debug.logger & debug.FLAG_MP and debug.logger('prepareDataElements: %s' % (msg.prettyPrint(),)) + debug.logger & debug.FLAG_MP and debug.logger( + 'prepareDataElements: %s' % (msg.prettyPrint(),)) if eoo.endOfOctets.isSameTypeWith(msg): raise error.StatusInformation(errorIndication=errind.parseError) @@ -261,8 +270,10 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): msgVersion = msg.getComponentByPosition(0) # rfc2576: 5.2.1 - snmpEngineMaxMessageSize, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') + snmpEngineMaxMessageSize, = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') communityName = msg.getComponentByPosition(1) + # transportDomain identifies local endpoint securityParameters = (communityName, (transportDomain, transportAddress)) messageProcessingModel = int(msg.getComponentByPosition(0)) @@ -293,7 +304,8 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): ) debug.logger & debug.FLAG_MP and debug.logger( - 'prepareDataElements: SM returned securityEngineId %r securityName %r' % (securityEngineId, securityName)) + 'prepareDataElements: SM returned securityEngineId %r ' + 'securityName %r' % (securityEngineId, securityName)) except error.StatusInformation as exc: statusInformation = exc @@ -305,11 +317,10 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): securityModel=securityModel, securityLevel=securityLevel, securityParameters=securityParameters, - statusInformation=statusInformation) - ) + statusInformation=statusInformation)) + snmpEngine.observer.clearExecutionContext( - snmpEngine, 'rfc2576.prepareDataElements:sm-failure' - ) + snmpEngine, 'rfc2576.prepareDataElements:sm-failure') raise @@ -332,6 +343,7 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): # 7.2.10a try: cachedReqParams = self._cache.popByMsgId(int(msgID)) + except error.ProtocolError: smHandler.releaseStateInformation(securityStateReference) raise error.StatusInformation(errorIndication=errind.dataMismatch) @@ -340,11 +352,12 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): pdu.setComponentByPosition(0, cachedReqParams['reqID']) debug.logger & debug.FLAG_MP and debug.logger( - 'prepareDataElements: unique PDU request-id %s replaced with original ID %s' % ( - msgID, cachedReqParams['reqID'])) + 'prepareDataElements: unique PDU request-id %s replaced with ' + 'original ID %s' % (msgID, cachedReqParams['reqID'])) # 7.2.10b sendPduHandle = cachedReqParams['sendPduHandle'] + else: sendPduHandle = None @@ -363,7 +376,9 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): securityLevel != cachedReqParams['securityLevel'] or contextEngineId != cachedReqParams['contextEngineId'] or contextName != cachedReqParams['contextName']): + smHandler.releaseStateInformation(securityStateReference) + raise error.StatusInformation(errorIndication=errind.dataMismatch) stateReference = None @@ -379,11 +394,10 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): contextName=contextName, securityEngineId=securityEngineId, communityName=communityName, - pdu=pdu) - ) + pdu=pdu)) + snmpEngine.observer.clearExecutionContext( - snmpEngine, 'rfc2576.prepareDataElements:response' - ) + snmpEngine, 'rfc2576.prepareDataElements:response') # rfc3412: 7.2.12c smHandler.releaseStateInformation(securityStateReference) @@ -401,19 +415,23 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): reqID = pdu.getComponentByPosition(0) msgID = self._cache.newMsgID() pdu.setComponentByPosition(0, msgID) + debug.logger & debug.FLAG_MP and debug.logger( - 'prepareDataElements: received PDU request-id %s replaced with unique ID %s' % (reqID, msgID)) + 'prepareDataElements: received PDU request-id %s replaced with ' + 'unique ID %s' % (reqID, msgID)) # rfc3412: 7.2.13a - snmpEngineId, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') + snmpEngineId, = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') + if securityEngineId != snmpEngineId.syntax: smHandler.releaseStateInformation(securityStateReference) raise error.StatusInformation( - errorIndication=errind.engineIDMismatch - ) + errorIndication=errind.engineIDMismatch) # rfc3412: 7.2.13b stateReference = self._cache.newStateReference() + self._cache.pushByStateRef( stateReference, msgVersion=messageProcessingModel, msgID=msgID, reqID=reqID, contextEngineId=contextEngineId, @@ -437,14 +455,14 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): contextName=contextName, securityEngineId=securityEngineId, communityName=communityName, - pdu=pdu) - ) + pdu=pdu)) + snmpEngine.observer.clearExecutionContext( - snmpEngine, 'rfc2576.prepareDataElements:confirmed' - ) + snmpEngine, 'rfc2576.prepareDataElements:confirmed') debug.logger & debug.FLAG_MP and debug.logger( - 'prepareDataElements: cached by new stateReference %s' % stateReference) + 'prepareDataElements: cached by new stateReference ' + '%s' % stateReference) # rfc3412: 7.2.13c return (messageProcessingModel, securityModel, securityName, @@ -469,11 +487,10 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): contextName=contextName, securityEngineId=securityEngineId, communityName=communityName, - pdu=pdu) - ) + pdu=pdu)) + snmpEngine.observer.clearExecutionContext( - snmpEngine, 'rfc2576.prepareDataElements:unconfirmed' - ) + snmpEngine, 'rfc2576.prepareDataElements:unconfirmed') # This is not specified explicitly in RFC smHandler.releaseStateInformation(securityStateReference) @@ -485,6 +502,7 @@ class SnmpV1MessageProcessingModel(AbstractMessageProcessingModel): stateReference) smHandler.releaseStateInformation(securityStateReference) + raise error.StatusInformation(errorIndication=errind.unsupportedPDUtype) diff --git a/pysnmp/proto/mpmod/rfc3412.py b/pysnmp/proto/mpmod/rfc3412.py index 6ff9fa8d..20852db6 100644 --- a/pysnmp/proto/mpmod/rfc3412.py +++ b/pysnmp/proto/mpmod/rfc3412.py @@ -30,49 +30,53 @@ class ScopedPDU(univ.Sequence): componentType = namedtype.NamedTypes( namedtype.NamedType('contextEngineId', univ.OctetString()), namedtype.NamedType('contextName', univ.OctetString()), - namedtype.NamedType('data', rfc1905.PDUs()) - ) + namedtype.NamedType('data', rfc1905.PDUs())) class ScopedPduData(univ.Choice): componentType = namedtype.NamedTypes( namedtype.NamedType('plaintext', ScopedPDU()), - namedtype.NamedType('encryptedPDU', univ.OctetString()), - ) + namedtype.NamedType('encryptedPDU', univ.OctetString())) class HeaderData(univ.Sequence): componentType = namedtype.NamedTypes( - namedtype.NamedType('msgID', - univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, 2147483647))), - namedtype.NamedType('msgMaxSize', - univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(484, 2147483647))), - namedtype.NamedType('msgFlags', univ.OctetString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, 1))), + namedtype.NamedType( + 'msgID', univ.Integer().subtype( + subtypeSpec=constraint.ValueRangeConstraint(0, 2147483647))), + namedtype.NamedType( + 'msgMaxSize', univ.Integer().subtype( + subtypeSpec=constraint.ValueRangeConstraint(484, 2147483647))), + namedtype.NamedType( + 'msgFlags', univ.OctetString().subtype( + subtypeSpec=constraint.ValueSizeConstraint(1, 1))), # NOTE (etingof): constrain SNMPv3 message to only USM+ security models # because SNMPv1/v2c seems incompatible in pysnmp implementation, not sure # if it's intended by the SNMP standard at all... - namedtype.NamedType('msgSecurityModel', - univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(3, 2147483647))) - ) + namedtype.NamedType( + 'msgSecurityModel', univ.Integer().subtype( + subtypeSpec=constraint.ValueRangeConstraint(3, 2147483647)))) class SNMPv3Message(univ.Sequence): componentType = namedtype.NamedTypes( - namedtype.NamedType('msgVersion', - univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, 2147483647))), + namedtype.NamedType( + 'msgVersion', univ.Integer().subtype( + subtypeSpec=constraint.ValueRangeConstraint(0, 2147483647))), namedtype.NamedType('msgGlobalData', HeaderData()), namedtype.NamedType('msgSecurityParameters', univ.OctetString()), - namedtype.NamedType('msgData', ScopedPduData()) - ) + namedtype.NamedType('msgData', ScopedPduData())) # XXX move somewhere? -_snmpErrors = {(1, 3, 6, 1, 6, 3, 15, 1, 1, 1, 0): errind.unsupportedSecurityLevel, - (1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0): errind.notInTimeWindow, - (1, 3, 6, 1, 6, 3, 15, 1, 1, 3, 0): errind.unknownUserName, - (1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0): errind.unknownEngineID, - (1, 3, 6, 1, 6, 3, 15, 1, 1, 5, 0): errind.wrongDigest, - (1, 3, 6, 1, 6, 3, 15, 1, 1, 6, 0): errind.decryptionError} +_snmpErrors = { + (1, 3, 6, 1, 6, 3, 15, 1, 1, 1, 0): errind.unsupportedSecurityLevel, + (1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0): errind.notInTimeWindow, + (1, 3, 6, 1, 6, 3, 15, 1, 1, 3, 0): errind.unknownUserName, + (1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0): errind.unknownEngineID, + (1, 3, 6, 1, 6, 3, 15, 1, 1, 5, 0): errind.wrongDigest, + (1, 3, 6, 1, 6, 3, 15, 1, 1, 6, 0): errind.decryptionError +} class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): @@ -80,26 +84,28 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): SNMP_MSG_SPEC = SNMPv3Message _emptyStr = univ.OctetString('') - _msgFlags = {0: univ.OctetString('\x00'), - 1: univ.OctetString('\x01'), - 3: univ.OctetString('\x03'), - 4: univ.OctetString('\x04'), - 5: univ.OctetString('\x05'), - 7: univ.OctetString('\x07')} + _msgFlags = { + 0: univ.OctetString('\x00'), + 1: univ.OctetString('\x01'), + 3: univ.OctetString('\x03'), + 4: univ.OctetString('\x04'), + 5: univ.OctetString('\x05'), + 7: univ.OctetString('\x07') + } def __init__(self): AbstractMessageProcessingModel.__init__(self) - self.__scopedPDU = ScopedPDU() - self.__engineIdCache = {} - self.__engineIdCacheExpQueue = {} - self.__expirationTimer = 0 + self._scopedPDU = ScopedPDU() + self._engineIdCache = {} + self._engineIdCacheExpQueue = {} + self._expirationTimer = 0 def getPeerEngineInfo(self, transportDomain, transportAddress): k = transportDomain, transportAddress - if k in self.__engineIdCache: - return (self.__engineIdCache[k]['securityEngineId'], - self.__engineIdCache[k]['contextEngineId'], - self.__engineIdCache[k]['contextName']) + if k in self._engineIdCache: + return (self._engineIdCache[k]['securityEngineId'], + self._engineIdCache[k]['contextEngineId'], + self._engineIdCache[k]['contextName']) else: return None, None, None @@ -109,29 +115,35 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, expectResponse, sendPduHandle): - snmpEngineID, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', - 'snmpEngineID') + + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder + + snmpEngineID, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineID = snmpEngineID.syntax # 7.1.1b msgID = self._cache.newMsgID() - debug.logger & debug.FLAG_MP and debug.logger('prepareOutgoingMessage: new msgID %s' % msgID) + debug.logger & debug.FLAG_MP and debug.logger( + 'prepareOutgoingMessage: new msgID %s' % msgID) + + k = transportDomain, transportAddress + if k in self._engineIdCache: + peerSnmpEngineData = self._engineIdCache[k] - k = (transportDomain, transportAddress) - if k in self.__engineIdCache: - peerSnmpEngineData = self.__engineIdCache[k] else: peerSnmpEngineData = None debug.logger & debug.FLAG_MP and debug.logger( - 'prepareOutgoingMessage: peer SNMP engine data %s for transport %s, address %s' % ( - peerSnmpEngineData, transportDomain, transportAddress)) + 'prepareOutgoingMessage: peer SNMP engine data %s ' + 'for transport %s, address ' + '%s' % (peerSnmpEngineData, transportDomain, transportAddress)) # 7.1.4 if contextEngineId is None: if peerSnmpEngineData is None: contextEngineId = snmpEngineID + else: contextEngineId = peerSnmpEngineData['contextEngineId'] # Defaulting contextEngineID to securityEngineId should @@ -144,88 +156,98 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): contextName = self._emptyStr debug.logger & debug.FLAG_MP and debug.logger( - 'prepareOutgoingMessage: using contextEngineId %r, contextName %r' % (contextEngineId, contextName)) + 'prepareOutgoingMessage: using contextEngineId %r, contextName ' + '%r' % (contextEngineId, contextName)) # 7.1.6 - scopedPDU = self.__scopedPDU + scopedPDU = self._scopedPDU scopedPDU.setComponentByPosition(0, contextEngineId) scopedPDU.setComponentByPosition(1, contextName) scopedPDU.setComponentByPosition(2) scopedPDU.getComponentByPosition(2).setComponentByType( - pdu.tagSet, pdu, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + pdu.tagSet, pdu, verifyConstraints=False, matchTags=False, + matchConstraints=False) # 7.1.7 msg = self._snmpMsgSpec # 7.1.7a msg.setComponentByPosition( - 0, self.MESSAGE_PROCESSING_MODEL_ID, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 0, self.MESSAGE_PROCESSING_MODEL_ID, verifyConstraints=False, + matchTags=False, matchConstraints=False) + headerData = msg.setComponentByPosition(1).getComponentByPosition(1) # 7.1.7b - headerData.setComponentByPosition(0, msgID, verifyConstraints=False, matchTags=False, matchConstraints=False) + headerData.setComponentByPosition( + 0, msgID, verifyConstraints=False, matchTags=False, + matchConstraints=False) - snmpEngineMaxMessageSize, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( + snmpEngineMaxMessageSize, = mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') # 7.1.7c # XXX need to coerce MIB value as it has incompatible constraints set headerData.setComponentByPosition( - 1, snmpEngineMaxMessageSize.syntax, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 1, snmpEngineMaxMessageSize.syntax, verifyConstraints=False, + matchTags=False, matchConstraints=False) # 7.1.7d msgFlags = 0 if securityLevel == 1: pass + elif securityLevel == 2: msgFlags |= 0x01 + elif securityLevel == 3: msgFlags |= 0x03 + else: raise error.ProtocolError( - 'Unknown securityLevel %s' % securityLevel - ) + 'Unknown securityLevel %s' % securityLevel) if pdu.tagSet in rfc3411.CONFIRMED_CLASS_PDUS: msgFlags |= 0x04 headerData.setComponentByPosition( - 2, self._msgFlags[msgFlags], verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 2, self._msgFlags[msgFlags], verifyConstraints=False, + matchTags=False, matchConstraints=False) # 7.1.7e # XXX need to coerce MIB value as it has incompatible constraints set headerData.setComponentByPosition(3, int(securityModel)) - debug.logger & debug.FLAG_MP and debug.logger('prepareOutgoingMessage: %s' % (msg.prettyPrint(),)) + debug.logger & debug.FLAG_MP and debug.logger( + 'prepareOutgoingMessage: %s' % (msg.prettyPrint(),)) if securityModel in snmpEngine.securityModels: smHandler = snmpEngine.securityModels[securityModel] + else: raise error.StatusInformation( - errorIndication=errind.unsupportedSecurityModel - ) + errorIndication=errind.unsupportedSecurityModel) # 7.1.9.a if pdu.tagSet in rfc3411.UNCONFIRMED_CLASS_PDUS: securityEngineId = snmpEngineID + else: if peerSnmpEngineData is None: # Force engineID discovery (rfc3414, 4) securityEngineId = securityName = self._emptyStr securityLevel = 1 + # Clear possible auth&priv flags headerData.setComponentByPosition( - 2, self._msgFlags[msgFlags & 0xfc], verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 2, self._msgFlags[msgFlags & 0xfc], verifyConstraints=False, + matchTags=False, matchConstraints=False) + # XXX - scopedPDU = self.__scopedPDU + scopedPDU = self._scopedPDU scopedPDU.setComponentByPosition( - 0, self._emptyStr, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 0, self._emptyStr, verifyConstraints=False, matchTags=False, + matchConstraints=False) scopedPDU.setComponentByPosition(1, contextName) scopedPDU.setComponentByPosition(2) @@ -234,19 +256,22 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): pMod.apiPDU.setDefaults(emptyPdu) scopedPDU.getComponentByPosition(2).setComponentByType( - emptyPdu.tagSet, emptyPdu, verifyConstraints=False, matchTags=False, matchConstraints=False - ) - debug.logger & debug.FLAG_MP and debug.logger('prepareOutgoingMessage: force engineID discovery') + emptyPdu.tagSet, emptyPdu, verifyConstraints=False, + matchTags=False, matchConstraints=False) + + debug.logger & debug.FLAG_MP and debug.logger( + 'prepareOutgoingMessage: force engineID discovery') + else: securityEngineId = peerSnmpEngineData['securityEngineId'] debug.logger & debug.FLAG_MP and debug.logger( - 'prepareOutgoingMessage: securityModel %r, securityEngineId %r, securityName %r, securityLevel %r' % ( - securityModel, securityEngineId, securityName, securityLevel)) + 'prepareOutgoingMessage: securityModel %r, securityEngineId %r, ' + 'securityName %r, securityLevel ' + '%r' % (securityModel, securityEngineId, securityName, securityLevel)) # 7.1.9.b - (securityParameters, - wholeMsg) = smHandler.generateRequestMsg( + securityParameters, wholeMsg = smHandler.generateRequestMsg( snmpEngine, self.MESSAGE_PROCESSING_MODEL_ID, msg, snmpEngineMaxMessageSize.syntax, securityModel, securityEngineId, securityName, securityLevel, scopedPDU @@ -259,15 +284,16 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): # 7.1.9.c if pdu.tagSet in rfc3411.CONFIRMED_CLASS_PDUS: # XXX rfc bug? why stateReference should be created? - self._cache.pushByMsgId(msgID, sendPduHandle=sendPduHandle, - msgID=msgID, snmpEngineID=snmpEngineID, - securityModel=securityModel, - securityName=securityName, - securityLevel=securityLevel, - contextEngineId=contextEngineId, - contextName=contextName, - transportDomain=transportDomain, - transportAddress=transportAddress) + self._cache.pushByMsgId( + msgID, sendPduHandle=sendPduHandle, + msgID=msgID, snmpEngineID=snmpEngineID, + securityModel=securityModel, + securityName=securityName, + securityLevel=securityLevel, + contextEngineId=contextEngineId, + contextName=contextName, + transportDomain=transportDomain, + transportAddress=transportAddress) snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc3412.prepareOutgoingMessage', @@ -292,7 +318,10 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): contextEngineId, contextName, pduVersion, pdu, maxSizeResponseScopedPDU, stateReference, statusInformation): - snmpEngineID, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') + + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder + + snmpEngineID, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineID = snmpEngineID.syntax # 7.1.2.b @@ -309,13 +338,15 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): transportDomain = cachedParams['transportDomain'] transportAddress = cachedParams['transportAddress'] - debug.logger & debug.FLAG_MP and debug.logger('prepareResponseMessage: stateReference %s' % stateReference) + debug.logger & debug.FLAG_MP and debug.logger( + 'prepareResponseMessage: stateReference %s' % stateReference) # 7.1.3 if statusInformation is not None and 'oid' in statusInformation: # 7.1.3a if pdu is None: pduType = None + else: requestID = pdu.getComponentByPosition(0) pduType = pdu.tagSet @@ -325,16 +356,18 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): pduType is not None and pduType not in rfc3411.CONFIRMED_CLASS_PDUS): raise error.StatusInformation( - errorIndication=errind.loopTerminated - ) + errorIndication=errind.loopTerminated) # 7.1.3c reportPDU = rfc1905.ReportPDU() - pMod.apiPDU.setVarBinds(reportPDU, ((statusInformation['oid'], statusInformation['val']),)) + pMod.apiPDU.setVarBinds( + reportPDU, ((statusInformation['oid'], statusInformation['val']),)) pMod.apiPDU.setErrorStatus(reportPDU, 0) pMod.apiPDU.setErrorIndex(reportPDU, 0) + if pdu is None: pMod.apiPDU.setRequestID(reportPDU, 0) + else: # noinspection PyUnboundLocalVariable pMod.apiPDU.setRequestID(reportPDU, requestID) @@ -342,18 +375,21 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): # 7.1.3d.1 if 'securityLevel' in statusInformation: securityLevel = statusInformation['securityLevel'] + else: securityLevel = 1 # 7.1.3d.2 if 'contextEngineId' in statusInformation: contextEngineId = statusInformation['contextEngineId'] + else: contextEngineId = snmpEngineID # 7.1.3d.3 if 'contextName' in statusInformation: contextName = statusInformation['contextName'] + else: contextName = "" @@ -361,7 +397,8 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): pdu = reportPDU debug.logger & debug.FLAG_MP and debug.logger( - 'prepareResponseMessage: prepare report PDU for statusInformation %s' % statusInformation) + 'prepareResponseMessage: prepare report PDU for ' + 'statusInformation %s' % statusInformation) # 7.1.4 if not contextEngineId: contextEngineId = snmpEngineID # XXX impl-dep manner @@ -371,47 +408,54 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): contextName = self._emptyStr debug.logger & debug.FLAG_MP and debug.logger( - 'prepareResponseMessage: using contextEngineId %r, contextName %r' % (contextEngineId, contextName)) + 'prepareResponseMessage: using contextEngineId %r, contextName ' + '%r' % (contextEngineId, contextName)) # 7.1.6 - scopedPDU = self.__scopedPDU + scopedPDU = self._scopedPDU scopedPDU.setComponentByPosition(0, contextEngineId) scopedPDU.setComponentByPosition(1, contextName) scopedPDU.setComponentByPosition(2) scopedPDU.getComponentByPosition(2).setComponentByType( - pdu.tagSet, pdu, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + pdu.tagSet, pdu, verifyConstraints=False, matchTags=False, + matchConstraints=False) # 7.1.7 msg = self._snmpMsgSpec # 7.1.7a msg.setComponentByPosition( - 0, self.MESSAGE_PROCESSING_MODEL_ID, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 0, self.MESSAGE_PROCESSING_MODEL_ID, verifyConstraints=False, + matchTags=False, matchConstraints=False) headerData = msg.setComponentByPosition(1).getComponentByPosition(1) # 7.1.7b - headerData.setComponentByPosition(0, msgID, verifyConstraints=False, matchTags=False, matchConstraints=False) + headerData.setComponentByPosition( + 0, msgID, verifyConstraints=False, matchTags=False, + matchConstraints=False) - snmpEngineMaxMessageSize, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( + snmpEngineMaxMessageSize, = mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') # 7.1.7c # XXX need to coerce MIB value as it has incompatible constraints set headerData.setComponentByPosition( - 1, snmpEngineMaxMessageSize.syntax, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 1, snmpEngineMaxMessageSize.syntax, verifyConstraints=False, + matchTags=False, matchConstraints=False) # 7.1.7d msgFlags = 0 + if securityLevel == 1: pass + elif securityLevel == 2: msgFlags |= 0x01 + elif securityLevel == 3: msgFlags |= 0x03 + else: raise error.ProtocolError('Unknown securityLevel %s' % securityLevel) @@ -419,39 +463,43 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): msgFlags |= 0x04 headerData.setComponentByPosition( - 2, self._msgFlags[msgFlags], verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 2, self._msgFlags[msgFlags], verifyConstraints=False, matchTags=False, + matchConstraints=False) # 7.1.7e headerData.setComponentByPosition( - 3, securityModel, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 3, securityModel, verifyConstraints=False, matchTags=False, + matchConstraints=False) - debug.logger & debug.FLAG_MP and debug.logger('prepareResponseMessage: %s' % (msg.prettyPrint(),)) + debug.logger & debug.FLAG_MP and debug.logger( + 'prepareResponseMessage: %s' % (msg.prettyPrint(),)) if securityModel in snmpEngine.securityModels: smHandler = snmpEngine.securityModels[securityModel] + else: - raise error.StatusInformation(errorIndication=errind.unsupportedSecurityModel) + raise error.StatusInformation( + errorIndication=errind.unsupportedSecurityModel) debug.logger & debug.FLAG_MP and debug.logger( - 'prepareResponseMessage: securityModel %r, securityEngineId %r, securityName %r, securityLevel %r' % ( + 'prepareResponseMessage: securityModel %r, securityEngineId %r, ' + 'securityName %r, securityLevel %r' % ( securityModel, snmpEngineID, securityName, securityLevel)) # 7.1.8a try: - (securityParameters, - wholeMsg) = smHandler.generateResponseMsg( + securityParameters, wholeMsg = smHandler.generateResponseMsg( snmpEngine, self.MESSAGE_PROCESSING_MODEL_ID, msg, snmpEngineMaxMessageSize.syntax, securityModel, snmpEngineID, securityName, securityLevel, scopedPDU, - securityStateReference - ) + securityStateReference) + except error.StatusInformation: # 7.1.8.b raise - debug.logger & debug.FLAG_MP and debug.logger('prepareResponseMessage: SM finished') + debug.logger & debug.FLAG_MP and debug.logger( + 'prepareResponseMessage: SM finished') # Message size constraint verification if len(wholeMsg) > min(snmpEngineMaxMessageSize.syntax, maxMessageSize): @@ -468,11 +516,10 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): contextEngineId=contextEngineId, contextName=contextName, securityEngineId=snmpEngineID, - pdu=pdu) - ) + pdu=pdu)) + snmpEngine.observer.clearExecutionContext( - snmpEngine, 'rfc3412.prepareResponseMessage' - ) + snmpEngine, 'rfc3412.prepareResponseMessage') return transportDomain, transportAddress, wholeMsg @@ -483,11 +530,14 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): # 7.2.2 msg, restOfwholeMsg = decoder.decode(wholeMsg, asn1Spec=self._snmpMsgSpec) - debug.logger & debug.FLAG_MP and debug.logger('prepareDataElements: %s' % (msg.prettyPrint(),)) + debug.logger & debug.FLAG_MP and debug.logger( + 'prepareDataElements: %s' % (msg.prettyPrint(),)) if eoo.endOfOctets.isSameTypeWith(msg): raise error.StatusInformation(errorIndication=errind.parseError) + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder + # 7.2.3 headerData = msg.getComponentByPosition(1) msgVersion = messageProcessingModel = msg.getComponentByPosition(0) @@ -498,12 +548,12 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): securityParameters = msg.getComponentByPosition(2) debug.logger & debug.FLAG_MP and debug.logger( - 'prepareDataElements: msg data msgVersion %s msgID %s securityModel %s' % ( - msgVersion, msgID, securityModel)) + 'prepareDataElements: msg data msgVersion %s msgID %s ' + 'securityModel %s' % (msgVersion, msgID, securityModel)) # 7.2.4 if securityModel not in snmpEngine.securityModels: - snmpUnknownSecurityModels, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( + snmpUnknownSecurityModels, = mibBuilder.importSymbols( '__SNMP-MPD-MIB', 'snmpUnknownSecurityModels') snmpUnknownSecurityModels.syntax += 1 raise error.StatusInformation(errorIndication=errind.unsupportedSecurityModel) @@ -511,22 +561,28 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): # 7.2.5 if msgFlags & 0x03 == 0x00: securityLevel = 1 + elif (msgFlags & 0x03) == 0x01: securityLevel = 2 + elif (msgFlags & 0x03) == 0x03: securityLevel = 3 + else: - snmpInvalidMsgs, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMP-MPD-MIB', 'snmpInvalidMsgs') + snmpInvalidMsgs, = mibBuilder.importSymbols( + '__SNMP-MPD-MIB', 'snmpInvalidMsgs') snmpInvalidMsgs.syntax += 1 raise error.StatusInformation(errorIndication=errind.invalidMsg) if msgFlags & 0x04: reportableFlag = 1 + else: reportableFlag = 0 # 7.2.6 smHandler = snmpEngine.securityModels[securityModel] + try: (securityEngineId, securityName, @@ -535,15 +591,17 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): securityStateReference) = smHandler.processIncomingMsg( snmpEngine, messageProcessingModel, maxMessageSize, securityParameters, securityModel, securityLevel, - wholeMsg, msg - ) - debug.logger & debug.FLAG_MP and debug.logger('prepareDataElements: SM succeeded') + wholeMsg, msg) + + debug.logger & debug.FLAG_MP and debug.logger( + 'prepareDataElements: SM succeeded') except error.StatusInformation as exc: statusInformation = exc debug.logger & debug.FLAG_MP and debug.logger( - 'prepareDataElements: SM failed, statusInformation %s' % statusInformation) + 'prepareDataElements: SM failed, statusInformation ' + '%s' % statusInformation) snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc3412.prepareDataElements:sm-failure', @@ -552,11 +610,10 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): securityModel=securityModel, securityLevel=securityLevel, securityParameters=securityParameters, - statusInformation=statusInformation) - ) + statusInformation=statusInformation)) + snmpEngine.observer.clearExecutionContext( - snmpEngine, 'rfc3412.prepareDataElements:sm-failure' - ) + snmpEngine, 'rfc3412.prepareDataElements:sm-failure') if 'errorIndication' in statusInformation: # 7.2.6a @@ -565,16 +622,20 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): securityStateReference = statusInformation['securityStateReference'] contextEngineId = statusInformation['contextEngineId'] contextName = statusInformation['contextName'] + if 'scopedPDU' in statusInformation: scopedPDU = statusInformation['scopedPDU'] pdu = scopedPDU.getComponentByPosition(2).getComponent() + else: pdu = None + maxSizeResponseScopedPDU = statusInformation['maxSizeResponseScopedPDU'] securityName = None # XXX secmod cache used # 7.2.6a2 stateReference = self._cache.newStateReference() + self._cache.pushByStateRef( stateReference, msgVersion=messageProcessingModel, msgID=msgID, contextEngineId=contextEngineId, @@ -585,8 +646,7 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): msgMaxSize=maxMessageSize, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU, transportDomain=transportDomain, - transportAddress=transportAddress - ) + transportAddress=transportAddress) # 7.2.6a3 try: @@ -594,16 +654,18 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): snmpEngine, 3, securityModel, securityName, securityLevel, contextEngineId, contextName, 1, pdu, maxSizeResponseScopedPDU, stateReference, - statusInformation - ) + statusInformation) + except error.StatusInformation: pass - debug.logger & debug.FLAG_MP and debug.logger('prepareDataElements: error reported') + debug.logger & debug.FLAG_MP and debug.logger( + 'prepareDataElements: error reported') # 7.2.6b if sys.version_info[0] <= 2: raise statusInformation + else: origTraceback = sys.exc_info()[2] @@ -616,31 +678,36 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): del origTraceback else: # Sniff for engineIdCache - k = (transportDomain, transportAddress) - if k not in self.__engineIdCache: + k = transportDomain, transportAddress + if k not in self._engineIdCache: contextEngineId = scopedPDU[0] contextName = scopedPDU[1] + pdus = scopedPDU[2] pdu = pdus.getComponent() + # Here we assume that authentic/default EngineIDs # come only in the course of engine-to-engine communication. if pdu.tagSet in rfc3411.INTERNAL_CLASS_PDUS: - self.__engineIdCache[k] = { + self._engineIdCache[k] = { 'securityEngineId': securityEngineId, 'contextEngineId': contextEngineId, 'contextName': contextName } - expireAt = int(self.__expirationTimer + 300 / snmpEngine.transportDispatcher.getTimerResolution()) - if expireAt not in self.__engineIdCacheExpQueue: - self.__engineIdCacheExpQueue[expireAt] = [] - self.__engineIdCacheExpQueue[expireAt].append(k) + timerResolution = snmpEngine.transportDispatcher.getTimerResolution() + expireAt = int(self._expirationTimer + 300 / timerResolution) + + if expireAt not in self._engineIdCacheExpQueue: + self._engineIdCacheExpQueue[expireAt] = [] + + self._engineIdCacheExpQueue[expireAt].append(k) debug.logger & debug.FLAG_MP and debug.logger( 'prepareDataElements: cache securityEngineId %r for %r %r' % ( securityEngineId, transportDomain, transportAddress)) - snmpEngineID, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') + snmpEngineID, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineID = snmpEngineID.syntax # 7.2.7 XXX PDU would be parsed here? @@ -662,33 +729,39 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): # 7.2.10a try: cachedReqParams = self._cache.popByMsgId(msgID) + except error.ProtocolError: smHandler.releaseStateInformation(securityStateReference) - raise error.StatusInformation( - errorIndication=errind.dataMismatch - ) + raise error.StatusInformation(errorIndication=errind.dataMismatch) + # 7.2.10b sendPduHandle = cachedReqParams['sendPduHandle'] + else: sendPduHandle = None debug.logger & debug.FLAG_MP and debug.logger( - 'prepareDataElements: using sendPduHandle %s for msgID %s' % (sendPduHandle, msgID)) + 'prepareDataElements: using sendPduHandle %s for msgID ' + '%s' % (sendPduHandle, msgID)) # 7.2.11 if pduType in rfc3411.INTERNAL_CLASS_PDUS: # 7.2.11a varBinds = pMod.apiPDU.getVarBinds(pdu) + if varBinds: + errorIndication = _snmpErrors.get( + varBinds[0][0], + errind.ReportPduReceived(varBinds[0][0].prettyPrint())) + statusInformation = error.StatusInformation( - errorIndication=_snmpErrors.get(varBinds[0][0], errind.ReportPduReceived(varBinds[0][0].prettyPrint())), + errorIndication=errorIndication, oid=varBinds[0][0], val=varBinds[0][1], - sendPduHandle=sendPduHandle - ) + sendPduHandle=sendPduHandle) + else: statusInformation = error.StatusInformation( - sendPduHandle=sendPduHandle - ) + sendPduHandle=sendPduHandle) # 7.2.11b (incomplete implementation) @@ -702,11 +775,10 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): contextEngineId=contextEngineId, contextName=contextName, securityEngineId=securityEngineId, - pdu=pdu) - ) + pdu=pdu)) + snmpEngine.observer.clearExecutionContext( - snmpEngine, 'rfc3412.prepareDataElements:internal' - ) + snmpEngine, 'rfc3412.prepareDataElements:internal') # 7.2.11c smHandler.releaseStateInformation(securityStateReference) @@ -730,10 +802,10 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): securityLevel != cachedReqParams['securityLevel'] or contextEngineId != cachedReqParams['contextEngineId'] or contextName != cachedReqParams['contextName']): + smHandler.releaseStateInformation(securityStateReference) - raise error.StatusInformation( - errorIndication=errind.dataMismatch - ) + + raise error.StatusInformation(errorIndication=errind.dataMismatch) snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc3412.prepareDataElements:response', @@ -745,11 +817,10 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): contextEngineId=contextEngineId, contextName=contextName, securityEngineId=securityEngineId, - pdu=pdu) - ) + pdu=pdu)) + snmpEngine.observer.clearExecutionContext( - snmpEngine, 'rfc3412.prepareDataElements:response' - ) + snmpEngine, 'rfc3412.prepareDataElements:response') # 7.2.12c smHandler.releaseStateInformation(securityStateReference) @@ -768,11 +839,11 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): if securityEngineId != snmpEngineID: smHandler.releaseStateInformation(securityStateReference) raise error.StatusInformation( - errorIndication=errind.engineIDMismatch - ) + errorIndication=errind.engineIDMismatch) # 7.2.13b stateReference = self._cache.newStateReference() + self._cache.pushByStateRef( stateReference, msgVersion=messageProcessingModel, msgID=msgID, contextEngineId=contextEngineId, @@ -782,10 +853,10 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): reportableFlag=reportableFlag, msgMaxSize=maxMessageSize, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU, transportDomain=transportDomain, - transportAddress=transportAddress - ) + transportAddress=transportAddress) - debug.logger & debug.FLAG_MP and debug.logger('prepareDataElements: new stateReference %s' % stateReference) + debug.logger & debug.FLAG_MP and debug.logger( + 'prepareDataElements: new stateReference %s' % stateReference) snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc3412.prepareDataElements:confirmed', @@ -797,11 +868,10 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): contextEngineId=contextEngineId, contextName=contextName, securityEngineId=securityEngineId, - pdu=pdu) - ) + pdu=pdu)) + snmpEngine.observer.clearExecutionContext( - snmpEngine, 'rfc3412.prepareDataElements:confirmed' - ) + snmpEngine, 'rfc3412.prepareDataElements:confirmed') # 7.2.13c return (messageProcessingModel, securityModel, securityName, @@ -812,6 +882,7 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): # 7.2.14 if pduType in rfc3411.UNCONFIRMED_CLASS_PDUS: + # Pass new stateReference to let app browse request details stateReference = self._cache.newStateReference() @@ -825,11 +896,10 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): contextEngineId=contextEngineId, contextName=contextName, securityEngineId=securityEngineId, - pdu=pdu) - ) + pdu=pdu)) + snmpEngine.observer.clearExecutionContext( - snmpEngine, 'rfc3412.prepareDataElements:unconfirmed' - ) + snmpEngine, 'rfc3412.prepareDataElements:unconfirmed') # This is not specified explicitly in RFC smHandler.releaseStateInformation(securityStateReference) @@ -841,18 +911,22 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): stateReference) smHandler.releaseStateInformation(securityStateReference) - raise error.StatusInformation( - errorIndication=errind.unsupportedPDUtype - ) - def __expireEnginesInfo(self): - if self.__expirationTimer in self.__engineIdCacheExpQueue: - for engineKey in self.__engineIdCacheExpQueue[self.__expirationTimer]: - del self.__engineIdCache[engineKey] - debug.logger & debug.FLAG_MP and debug.logger('__expireEnginesInfo: expiring %r' % (engineKey,)) - del self.__engineIdCacheExpQueue[self.__expirationTimer] - self.__expirationTimer += 1 + raise error.StatusInformation(errorIndication=errind.unsupportedPDUtype) + + def _expireEnginesInfo(self): + if self._expirationTimer in self._engineIdCacheExpQueue: + + for engineKey in self._engineIdCacheExpQueue[self._expirationTimer]: + del self._engineIdCache[engineKey] + + debug.logger & debug.FLAG_MP and debug.logger( + '__expireEnginesInfo: expiring %r' % (engineKey,)) + + del self._engineIdCacheExpQueue[self._expirationTimer] + + self._expirationTimer += 1 def receiveTimerTick(self, snmpEngine, timeNow): - self.__expireEnginesInfo() + self._expireEnginesInfo() AbstractMessageProcessingModel.receiveTimerTick(self, snmpEngine, timeNow) diff --git a/pysnmp/proto/proxy/rfc2576.py b/pysnmp/proto/proxy/rfc2576.py index 359a3b4f..de5a5fdb 100644 --- a/pysnmp/proto/proxy/rfc2576.py +++ b/pysnmp/proto/proxy/rfc2576.py @@ -102,7 +102,8 @@ def v1ToV2(v1Pdu, origV2Pdu=None, snmpTrapCommunity=''): pduType = v1Pdu.tagSet v2Pdu = V1_TO_V2_PDU_MAP[pduType].clone() - debug.logger & debug.FLAG_PRX and debug.logger('v1ToV2: v1Pdu %s' % v1Pdu.prettyPrint()) + debug.logger & debug.FLAG_PRX and debug.logger( + 'v1ToV2: v1Pdu %s' % v1Pdu.prettyPrint()) v2VarBinds = [] @@ -114,21 +115,24 @@ def v1ToV2(v1Pdu, origV2Pdu=None, snmpTrapCommunity=''): # 3.1.2 genericTrap = v1.apiTrapPDU.getGenericTrap(v1Pdu) if genericTrap == 6: - snmpTrapOIDParam = v1.apiTrapPDU.getEnterprise(v1Pdu) + (0, int(v1.apiTrapPDU.getSpecificTrap(v1Pdu))) + snmpTrapOIDParam = (v1.apiTrapPDU.getEnterprise(v1Pdu) + + (0, int(v1.apiTrapPDU.getSpecificTrap(v1Pdu)))) # 3.1.3 else: snmpTrapOIDParam = v2c.ObjectIdentifier(V1_TO_V2_TRAP_MAP[genericTrap]) # 3.1.4 - v2VarBinds.append((v2c.apiTrapPDU.sysUpTime, sysUpTime)) - v2VarBinds.append((v2c.apiTrapPDU.snmpTrapOID, snmpTrapOIDParam)) v2VarBinds.append( - (v2c.apiTrapPDU.snmpTrapAddress, v1.apiTrapPDU.getAgentAddr(v1Pdu)) - ) - v2VarBinds.append((v2c.apiTrapPDU.snmpTrapCommunity, v2c.OctetString(snmpTrapCommunity))) - v2VarBinds.append((v2c.apiTrapPDU.snmpTrapEnterprise, - v1.apiTrapPDU.getEnterprise(v1Pdu))) + (v2c.apiTrapPDU.sysUpTime, sysUpTime)) + v2VarBinds.append( + (v2c.apiTrapPDU.snmpTrapOID, snmpTrapOIDParam)) + v2VarBinds.append( + (v2c.apiTrapPDU.snmpTrapAddress, v1.apiTrapPDU.getAgentAddr(v1Pdu))) + v2VarBinds.append( + (v2c.apiTrapPDU.snmpTrapCommunity, v2c.OctetString(snmpTrapCommunity))) + v2VarBinds.append( + (v2c.apiTrapPDU.snmpTrapEnterprise, v1.apiTrapPDU.getEnterprise(v1Pdu))) varBinds = v1.apiTrapPDU.getVarBinds(v1Pdu) @@ -142,13 +146,13 @@ def v1ToV2(v1Pdu, origV2Pdu=None, snmpTrapCommunity=''): v1Val = v1Val.getComponent() v2VarBinds.append( - (oid, V1_TO_V2_VALUE_MAP[v1Val.tagSet].clone(v1Val)) - ) + (oid, V1_TO_V2_VALUE_MAP[v1Val.tagSet].clone(v1Val))) if pduType in rfc3411.RESPONSE_CLASS_PDUS: # 4.1.2.2.1&2 errorStatus = int(v1.apiPDU.getErrorStatus(v1Pdu)) errorIndex = int(v1.apiPDU.getErrorIndex(v1Pdu, muteErrors=True)) + if errorStatus == 2: # noSuchName if origV2Pdu.tagSet == v2c.GetNextRequestPDU.tagSet: v2VarBinds = [(o, rfc1905.endOfMibView) for o, v in v2VarBinds] @@ -171,13 +175,15 @@ def v1ToV2(v1Pdu, origV2Pdu=None, snmpTrapCommunity=''): v2c.apiPDU.setVarBinds(v2Pdu, v2VarBinds) - debug.logger & debug.FLAG_PRX and debug.logger('v1ToV2: v2Pdu %s' % v2Pdu.prettyPrint()) + debug.logger & debug.FLAG_PRX and debug.logger( + 'v1ToV2: v2Pdu %s' % v2Pdu.prettyPrint()) return v2Pdu def v2ToV1(v2Pdu, origV1Pdu=None): - debug.logger & debug.FLAG_PRX and debug.logger('v2ToV1: v2Pdu %s' % v2Pdu.prettyPrint()) + debug.logger & debug.FLAG_PRX and debug.logger( + 'v2ToV1: v2Pdu %s' % v2Pdu.prettyPrint()) pduType = v2Pdu.tagSet @@ -224,7 +230,8 @@ def v2ToV1(v2Pdu, origV1Pdu=None): for oid, val in v2VarBinds: # snmpTrapAddress if oid == v2c.apiTrapPDU.snmpTrapAddress: - v1.apiTrapPDU.setAgentAddr(v1Pdu, v1.IpAddress(val)) # v2c.OctetString is more constrained + # v2c.OctetString is more constrained + v1.apiTrapPDU.setAgentAddr(v1Pdu, v1.IpAddress(val)) break else: @@ -232,7 +239,8 @@ def v2ToV1(v2Pdu, origV1Pdu=None): # 3.2.3 if snmpTrapOIDParam in V2_TO_V1_TRAP_MAP: - v1.apiTrapPDU.setGenericTrap(v1Pdu, V2_TO_V1_TRAP_MAP[snmpTrapOIDParam]) + v1.apiTrapPDU.setGenericTrap( + v1Pdu, V2_TO_V1_TRAP_MAP[snmpTrapOIDParam]) else: v1.apiTrapPDU.setGenericTrap(v1Pdu, 6) @@ -273,6 +281,7 @@ def v2ToV1(v2Pdu, origV1Pdu=None): while idx >= 0: # 4.1.2.1 oid, val = v2VarBinds[idx] + if v2c.Counter64.tagSet == val.tagSet: if origV1Pdu.tagSet == v1.GetRequestPDU.tagSet: v1.apiPDU.setErrorStatus(v1Pdu, 2) @@ -298,8 +307,7 @@ def v2ToV1(v2Pdu, origV1Pdu=None): v2ErrorStatus = v2c.apiPDU.getErrorStatus(v2Pdu) if v2ErrorStatus: v1.apiPDU.setErrorStatus( - v1Pdu, V2_TO_V1_ERROR_MAP.get(v2ErrorStatus, 5) - ) + v1Pdu, V2_TO_V1_ERROR_MAP.get(v2ErrorStatus, 5)) v1.apiPDU.setErrorIndex(v1Pdu, v2c.apiPDU.getErrorIndex(v2Pdu, muteErrors=True)) elif pduType in rfc3411.CONFIRMED_CLASS_PDUS: @@ -309,6 +317,7 @@ def v2ToV1(v2Pdu, origV1Pdu=None): # Translate Var-Binds if (pduType in rfc3411.RESPONSE_CLASS_PDUS and v1.apiPDU.getErrorStatus(v1Pdu)): + v1VarBinds = v1.apiPDU.getVarBinds(origV1Pdu) else: @@ -327,6 +336,7 @@ def v2ToV1(v2Pdu, origV1Pdu=None): v1Pdu, v2c.apiPDU.getRequestID(v2Pdu) ) - debug.logger & debug.FLAG_PRX and debug.logger('v2ToV1: v1Pdu %s' % v1Pdu.prettyPrint()) + debug.logger & debug.FLAG_PRX and debug.logger( + 'v2ToV1: v1Pdu %s' % v1Pdu.prettyPrint()) return v1Pdu diff --git a/pysnmp/proto/rfc1155.py b/pysnmp/proto/rfc1155.py index e194f1c0..f78e6dc1 100644 --- a/pysnmp/proto/rfc1155.py +++ b/pysnmp/proto/rfc1155.py @@ -29,15 +29,19 @@ class IpAddress(univ.OctetString): if isinstance(value, str) and len(value) != 4: try: value = [int(x) for x in value.split('.')] - except: + + except Exception: raise error.ProtocolError('Bad IP address syntax %s' % value) + if len(value) != 4: raise error.ProtocolError('Bad IP address syntax') + return univ.OctetString.prettyIn(self, value) def prettyOut(self, value): if value: return '.'.join(['%d' % x for x in self.__class__(value).asNumbers()]) + else: return '' @@ -70,18 +74,24 @@ class NetworkAddress(univ.Choice): if the type of *value* is not allowed for this Choice instance. """ cloned = univ.Choice.clone(self, **kwargs) + if value is not univ.noValue: if isinstance(value, NetworkAddress): value = value.getComponent() + elif not isinstance(value, IpAddress): # IpAddress is the only supported type, perhaps forever because # this is SNMPv1. value = IpAddress(value) + try: tagSet = value.tagSet + except AttributeError: raise PyAsn1Error('component value %r has no tag set' % (value,)) + cloned.setComponentByType(tagSet, value) + return cloned # RFC 1212, section 4.1.6: @@ -94,17 +104,21 @@ class NetworkAddress(univ.Choice): def cloneFromName(self, value, impliedFlag, parentRow, parentIndices): kind = value[0] clone = self.clone() + if kind == 1: clone['internet'] = tuple(value[1:5]) return clone, value[5:] + else: raise SmiError('unknown NetworkAddress type %r' % (kind,)) def cloneAsName(self, impliedFlag, parentRow, parentIndices): kind = self.getName() component = self.getComponent() + if kind == 'internet': return (1,) + tuple(component.asNumbers()) + else: raise SmiError('unknown NetworkAddress type %r' % (kind,)) @@ -145,7 +159,9 @@ class TypeCoercionHackMixIn: # XXX keep this old-style class till pyasn1 types if componentType: if idx >= len(componentType): raise PyAsn1Error('Component type error out of range') + t = componentType[idx].getType() + if not t.getTagSet().isSuperTagSetOf(value.getTagSet()): raise PyAsn1Error('Component type error %r vs %r' % (t, value)) diff --git a/pysnmp/proto/rfc1157.py b/pysnmp/proto/rfc1157.py index b0ddbb08..30a26bc7 100644 --- a/pysnmp/proto/rfc1157.py +++ b/pysnmp/proto/rfc1157.py @@ -27,8 +27,9 @@ class VarBindList(univ.SequenceOf): errorStatus = univ.Integer( - namedValues=namedval.NamedValues(('noError', 0), ('tooBig', 1), ('noSuchName', 2), - ('badValue', 3), ('readOnly', 4), ('genErr', 5))) + namedValues=namedval.NamedValues( + ('noError', 0), ('tooBig', 1), ('noSuchName', 2), + ('badValue', 3), ('readOnly', 4), ('genErr', 5))) class _RequestBase(univ.Sequence): @@ -65,8 +66,10 @@ class SetRequestPDU(_RequestBase): genericTrap = univ.Integer().clone( - namedValues=namedval.NamedValues(('coldStart', 0), ('warmStart', 1), ('linkDown', 2), ('linkUp', 3), - ('authenticationFailure', 4), ('egpNeighborLoss', 5), ('enterpriseSpecific', 6))) + namedValues=namedval.NamedValues( + ('coldStart', 0), ('warmStart', 1), ('linkDown', 2), ('linkUp', 3), + ('authenticationFailure', 4), ('egpNeighborLoss', 5), + ('enterpriseSpecific', 6))) class TrapPDU(univ.Sequence): diff --git a/pysnmp/proto/rfc1902.py b/pysnmp/proto/rfc1902.py index e1c037ee..50252c36 100644 --- a/pysnmp/proto/rfc1902.py +++ b/pysnmp/proto/rfc1902.py @@ -95,7 +95,8 @@ class Integer32(univ.Integer): """ class X(cls): - subtypeSpec = cls.subtypeSpec + constraint.SingleValueConstraint(*values) + subtypeSpec = cls.subtypeSpec + constraint.SingleValueConstraint( + *values) X.__name__ = cls.__name__ return X @@ -106,7 +107,8 @@ class Integer32(univ.Integer): """ class X(cls): - subtypeSpec = cls.subtypeSpec + constraint.ValueRangeConstraint(minimum, maximum) + subtypeSpec = cls.subtypeSpec + constraint.ValueRangeConstraint( + minimum, maximum) X.__name__ = cls.__name__ return X @@ -171,6 +173,7 @@ class Integer(Integer32): *values.values()) X.__name__ = cls.__name__ + return X @@ -234,10 +237,12 @@ class OctetString(univ.OctetString): return self.fixedLength def clone(self, *args, **kwargs): - return univ.OctetString.clone(self, *args, **kwargs).setFixedLength(self.getFixedLength()) + return univ.OctetString.clone( + self, *args, **kwargs).setFixedLength(self.getFixedLength()) def subtype(self, *args, **kwargs): - return univ.OctetString.subtype(self, *args, **kwargs).setFixedLength(self.getFixedLength()) + return univ.OctetString.subtype( + self, *args, **kwargs).setFixedLength(self.getFixedLength()) @classmethod def withSize(cls, minimum, maximum): @@ -245,7 +250,8 @@ class OctetString(univ.OctetString): """ class X(cls): - subtypeSpec = cls.subtypeSpec + constraint.ValueSizeConstraint(minimum, maximum) + subtypeSpec = cls.subtypeSpec + constraint.ValueSizeConstraint( + minimum, maximum) X.__name__ = cls.__name__ return X @@ -328,11 +334,15 @@ class IpAddress(OctetString): if isinstance(value, str) and len(value) != 4: try: value = [int(x) for x in value.split('.')] - except: + + except Exception: raise error.ProtocolError('Bad IP address syntax %s' % value) + value = OctetString.prettyIn(self, value) + if len(value) != 4: raise error.ProtocolError('Bad IP address syntax') + return value def prettyOut(self, value): @@ -340,6 +350,7 @@ class IpAddress(OctetString): return '.'.join( ['%d' % x for x in self.__class__(value).asNumbers()] ) + else: return '' @@ -643,30 +654,44 @@ class Bits(OctetString): def prettyIn(self, bits): if not isinstance(bits, (tuple, list)): return OctetString.prettyIn(self, bits) # raw bitstring + octets = [] + for bit in bits: # tuple of named bits v = self.namedValues.getValue(bit) + if v is None: raise error.ProtocolError('Unknown named bit %s' % bit) + d, m = divmod(v, 8) if d >= len(octets): octets.extend([0] * (d - len(octets) + 1)) + octets[d] |= 0x01 << (7 - m) + return OctetString.prettyIn(self, octets) def prettyOut(self, value): names = [] + ints = self.__class__(value).asNumbers() + for i, v in enumerate(ints): v = ints[i] + j = 7 + while j >= 0: if v & (0x01 << j): name = self.namedValues.getName(i * 8 + 7 - j) + if name is None: name = 'UnknownBit-%s' % (i * 8 + 7 - j,) + names.append(name) + j -= 1 + return ', '.join([str(x) for x in names]) @classmethod diff --git a/pysnmp/proto/rfc1905.py b/pysnmp/proto/rfc1905.py index 6a2637e2..15f56194 100644 --- a/pysnmp/proto/rfc1905.py +++ b/pysnmp/proto/rfc1905.py @@ -90,11 +90,12 @@ class VarBindList(univ.SequenceOf): errorStatus = univ.Integer( namedValues=namedval.NamedValues( - ('noError', 0), ('tooBig', 1), ('noSuchName', 2), ('badValue', 3), ('readOnly', 4), - ('genErr', 5), ('noAccess', 6), ('wrongType', 7), ('wrongLength', 8), - ('wrongEncoding', 9), ('wrongValue', 10), ('noCreation', 11), - ('inconsistentValue', 12), ('resourceUnavailable', 13), ('commitFailed', 14), - ('undoFailed', 15), ('authorizationError', 16), ('notWritable', 17), + ('noError', 0), ('tooBig', 1), ('noSuchName', 2), ('badValue', 3), + ('readOnly', 4), ('genErr', 5), ('noAccess', 6), ('wrongType', 7), + ('wrongLength', 8), ('wrongEncoding', 9), ('wrongValue', 10), + ('noCreation', 11), ('inconsistentValue', 12), + ('resourceUnavailable', 13), ('commitFailed', 14), ('undoFailed', 15), + ('authorizationError', 16), ('notWritable', 17), ('inconsistentName', 18)) ) @@ -105,13 +106,17 @@ class PDU(univ.Sequence): namedtype.NamedType('request-id', rfc1902.Integer32()), namedtype.NamedType('error-status', errorStatus), namedtype.NamedType('error-index', - univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, max_bindings))), + univ.Integer().subtype( + subtypeSpec=constraint.ValueRangeConstraint( + 0, max_bindings))), namedtype.NamedType('variable-bindings', VarBindList()) ) -nonRepeaters = univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, max_bindings)) -maxRepetitions = univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, max_bindings)) +nonRepeaters = univ.Integer().subtype( + subtypeSpec=constraint.ValueRangeConstraint(0, max_bindings)) +maxRepetitions = univ.Integer().subtype( + subtypeSpec=constraint.ValueRangeConstraint(0, max_bindings)) # Base class for bulk PDU diff --git a/pysnmp/proto/rfc3412.py b/pysnmp/proto/rfc3412.py index 7a3baa86..4e0f401c 100644 --- a/pysnmp/proto/rfc3412.py +++ b/pysnmp/proto/rfc3412.py @@ -28,6 +28,7 @@ class MsgAndPduDispatcher(object): self.mibInstrumController = instrum.MibInstrumController( builder.MibBuilder() ) + else: self.mibInstrumController = mibInstrumController @@ -37,25 +38,25 @@ class MsgAndPduDispatcher(object): ) # Requests cache - self.__cache = cache.Cache() + self._cache = cache.Cache() # Registered context engine IDs - self.__appsRegistration = {} + self._appsRegistration = {} # Source of sendPduHandle and cache of requesting apps - self.__sendPduHandle = nextid.Integer(0xffffff) + self._sendPduHandle = nextid.Integer(0xffffff) # To pass transport info to app (legacy) - self.__transportInfo = {} + self._transportInfo = {} # legacy def getTransportInfo(self, stateReference): - if stateReference in self.__transportInfo: - return self.__transportInfo[stateReference] + if stateReference in self._transportInfo: + return self._transportInfo[stateReference] + else: raise error.ProtocolError( - 'No data for stateReference %s' % stateReference - ) + 'No data for stateReference %s' % stateReference) # Application registration with dispatcher @@ -66,42 +67,45 @@ class MsgAndPduDispatcher(object): # 4.3.3 for pduType in pduTypes: - k = (contextEngineId, pduType) - if k in self.__appsRegistration: + k = contextEngineId, pduType + if k in self._appsRegistration: raise error.ProtocolError( - 'Duplicate registration %r/%s' % (contextEngineId, pduType) - ) + 'Duplicate registration %r/%s' % (contextEngineId, pduType)) # 4.3.4 - self.__appsRegistration[k] = processPdu + self._appsRegistration[k] = processPdu debug.logger & debug.FLAG_DSP and debug.logger( - 'registerContextEngineId: contextEngineId %r pduTypes %s' % (contextEngineId, pduTypes)) + 'registerContextEngineId: contextEngineId %r pduTypes ' + '%s' % (contextEngineId, pduTypes)) # 4.4.1 def unregisterContextEngineId(self, contextEngineId, pduTypes): """Unregister application with dispatcher""" + # 4.3.4 if contextEngineId is None: # Default to local snmpEngineId - contextEngineId, = self.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', - 'snmpEngineID') + contextEngineId, = self.mibInstrumController.mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') for pduType in pduTypes: - k = (contextEngineId, pduType) - if k in self.__appsRegistration: - del self.__appsRegistration[k] + k = contextEngineId, pduType + if k in self._appsRegistration: + del self._appsRegistration[k] debug.logger & debug.FLAG_DSP and debug.logger( - 'unregisterContextEngineId: contextEngineId %r pduTypes %s' % (contextEngineId, pduTypes)) + 'unregisterContextEngineId: contextEngineId %r pduTypes ' + '%s' % (contextEngineId, pduTypes)) def getRegisteredApp(self, contextEngineId, pduType): - k = (contextEngineId, pduType) - if k in self.__appsRegistration: - return self.__appsRegistration[k] - k = (null, pduType) - if k in self.__appsRegistration: - return self.__appsRegistration[k] # wildcard + k = contextEngineId, pduType + if k in self._appsRegistration: + return self._appsRegistration[k] + + k = null, pduType + if k in self._appsRegistration: + return self._appsRegistration[k] # wildcard # Dispatcher <-> application API @@ -115,20 +119,23 @@ class MsgAndPduDispatcher(object): """PDU dispatcher -- prepare and serialize a request or notification""" # 4.1.1.2 k = int(messageProcessingModel) + if k in snmpEngine.messageProcessingSubsystems: mpHandler = snmpEngine.messageProcessingSubsystems[k] + else: raise error.StatusInformation( - errorIndication=errind.unsupportedMsgProcessingModel - ) + errorIndication=errind.unsupportedMsgProcessingModel) debug.logger & debug.FLAG_DSP and debug.logger( - 'sendPdu: securityName %s, PDU\n%s' % (securityName, PDU.prettyPrint())) + 'sendPdu: securityName %s, PDU\n' + '%s' % (securityName, PDU.prettyPrint())) # 4.1.1.3 - sendPduHandle = self.__sendPduHandle() + sendPduHandle = self._sendPduHandle() + if expectResponse: - self.__cache.add( + self._cache.add( sendPduHandle, messageProcessingModel=messageProcessingModel, sendPduHandle=sendPduHandle, @@ -137,11 +144,14 @@ class MsgAndPduDispatcher(object): cbCtx=cbCtx ) - debug.logger & debug.FLAG_DSP and debug.logger('sendPdu: current time %d ticks, one tick is %s seconds' % ( - snmpEngine.transportDispatcher.getTimerTicks(), snmpEngine.transportDispatcher.getTimerResolution())) + debug.logger & debug.FLAG_DSP and debug.logger( + 'sendPdu: current time %d ticks, one tick is %s ' + 'seconds' % (snmpEngine.transportDispatcher.getTimerTicks(), + snmpEngine.transportDispatcher.getTimerResolution())) debug.logger & debug.FLAG_DSP and debug.logger( - 'sendPdu: new sendPduHandle %s, timeout %s ticks, cbFun %s' % (sendPduHandle, timeout, cbFun)) + 'sendPdu: new sendPduHandle %s, timeout %s ticks, cbFun ' + '%s' % (sendPduHandle, timeout, cbFun)) origTransportDomain = transportDomain origTransportAddress = transportAddress @@ -157,17 +167,20 @@ class MsgAndPduDispatcher(object): pduVersion, PDU, expectResponse, sendPduHandle ) - debug.logger & debug.FLAG_DSP and debug.logger('sendPdu: MP succeeded') + debug.logger & debug.FLAG_DSP and debug.logger( + 'sendPdu: MP succeeded') + except PySnmpError: if expectResponse: - self.__cache.pop(sendPduHandle) + self._cache.pop(sendPduHandle) self.releaseStateInformation(snmpEngine, sendPduHandle, messageProcessingModel) + raise # 4.1.1.6 if snmpEngine.transportDispatcher is None: if expectResponse: - self.__cache.pop(sendPduHandle) + self._cache.pop(sendPduHandle) raise error.PySnmpError('Transport dispatcher not set') @@ -187,27 +200,30 @@ class MsgAndPduDispatcher(object): try: snmpEngine.transportDispatcher.sendMessage( - outgoingMessage, transportDomain, transportAddress - ) + outgoingMessage, transportDomain, transportAddress) + except PySnmpError: if expectResponse: - self.__cache.pop(sendPduHandle) + self._cache.pop(sendPduHandle) raise - snmpEngine.observer.clearExecutionContext(snmpEngine, 'rfc3412.sendPdu') + snmpEngine.observer.clearExecutionContext( + snmpEngine, 'rfc3412.sendPdu') # Update cache with orignal req params (used for retrying) if expectResponse: - self.__cache.update(sendPduHandle, - transportDomain=origTransportDomain, - transportAddress=origTransportAddress, - securityModel=securityModel, - securityName=securityName, - securityLevel=securityLevel, - contextEngineId=contextEngineId, - contextName=contextName, - pduVersion=pduVersion, - PDU=PDU) + self._cache.update( + sendPduHandle, + transportDomain=origTransportDomain, + transportAddress=origTransportAddress, + securityModel=securityModel, + securityName=securityName, + securityLevel=securityLevel, + contextEngineId=contextEngineId, + contextName=contextName, + pduVersion=pduVersion, + PDU=PDU + ) return sendPduHandle @@ -217,17 +233,20 @@ class MsgAndPduDispatcher(object): contextEngineId, contextName, pduVersion, PDU, maxSizeResponseScopedPDU, stateReference, statusInformation): + # Extract input values and initialize defaults k = int(messageProcessingModel) + if k in snmpEngine.messageProcessingSubsystems: mpHandler = snmpEngine.messageProcessingSubsystems[k] + else: raise error.StatusInformation( - errorIndication=errind.unsupportedMsgProcessingModel - ) + errorIndication=errind.unsupportedMsgProcessingModel) debug.logger & debug.FLAG_DSP and debug.logger( - 'returnResponsePdu: PDU %s' % (PDU and PDU.prettyPrint() or "",)) + 'returnResponsePdu: PDU ' + '%s' % (PDU and PDU.prettyPrint() or "",)) # 4.1.2.2 try: @@ -240,19 +259,26 @@ class MsgAndPduDispatcher(object): statusInformation ) - debug.logger & debug.FLAG_DSP and debug.logger('returnResponsePdu: MP suceeded') + debug.logger & debug.FLAG_DSP and debug.logger( + 'returnResponsePdu: MP suceeded') except error.StatusInformation: # 4.1.2.3 raise + mibBuilder = self.mibInstrumController.mibBuilder + # Handle oversized messages XXX transport constrains? - snmpEngineMaxMessageSize, = self.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', - 'snmpEngineMaxMessageSize') + snmpEngineMaxMessageSize, = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') + if (snmpEngineMaxMessageSize.syntax and len(outgoingMessage) > snmpEngineMaxMessageSize.syntax): - snmpSilentDrops, = self.mibInstrumController.mibBuilder.importSymbols('__SNMPv2-MIB', 'snmpSilentDrops') + + snmpSilentDrops, = mibBuilder.importSymbols( + '__SNMPv2-MIB', 'snmpSilentDrops') snmpSilentDrops.syntax += 1 + raise error.StatusInformation(errorIndication=errind.tooBig) snmpEngine.observer.storeExecutionContext( @@ -271,45 +297,50 @@ class MsgAndPduDispatcher(object): ) # 4.1.2.4 - snmpEngine.transportDispatcher.sendMessage(outgoingMessage, - transportDomain, - transportAddress) + snmpEngine.transportDispatcher.sendMessage( + outgoingMessage, transportDomain, transportAddress) snmpEngine.observer.clearExecutionContext( - snmpEngine, 'rfc3412.returnResponsePdu' - ) + snmpEngine, 'rfc3412.returnResponsePdu') # 4.2.1 def receiveMessage(self, snmpEngine, transportDomain, transportAddress, wholeMsg): """Message dispatcher -- de-serialize message into PDU""" + mibBuilder = self.mibInstrumController.mibBuilder + # 4.2.1.1 - snmpInPkts, = self.mibInstrumController.mibBuilder.importSymbols( - '__SNMPv2-MIB', 'snmpInPkts' - ) + snmpInPkts, = mibBuilder.importSymbols( + '__SNMPv2-MIB', 'snmpInPkts') snmpInPkts.syntax += 1 + restOfWholeMsg = null # XXX fix decoder non-recursive return + # 4.2.1.2 try: - restOfWholeMsg = null # XXX fix decoder non-recursive return msgVersion = verdec.decodeMessageVersion(wholeMsg) except error.ProtocolError: - snmpInASNParseErrs, = self.mibInstrumController.mibBuilder.importSymbols('__SNMPv2-MIB', - 'snmpInASNParseErrs') + snmpInASNParseErrs, = mibBuilder.importSymbols( + '__SNMPv2-MIB', 'snmpInASNParseErrs') snmpInASNParseErrs.syntax += 1 + return null # n.b the whole buffer gets dropped - debug.logger & debug.FLAG_DSP and debug.logger('receiveMessage: msgVersion %s, msg decoded' % msgVersion) + debug.logger & debug.FLAG_DSP and debug.logger( + 'receiveMessage: msgVersion %s, msg decoded' % msgVersion) messageProcessingModel = msgVersion try: - mpHandler = snmpEngine.messageProcessingSubsystems[int(messageProcessingModel)] + mpHandler = snmpEngine.messageProcessingSubsystems[ + int(messageProcessingModel)] except KeyError: - snmpInBadVersions, = self.mibInstrumController.mibBuilder.importSymbols('__SNMPv2-MIB', 'snmpInBadVersions') + snmpInBadVersions, = mibBuilder.importSymbols( + '__SNMPv2-MIB', 'snmpInBadVersions') snmpInBadVersions.syntax += 1 + return restOfWholeMsg # 4.2.1.3 -- no-op @@ -329,48 +360,56 @@ class MsgAndPduDispatcher(object): maxSizeResponseScopedPDU, statusInformation, stateReference) = mpHandler.prepareDataElements( - snmpEngine, transportDomain, transportAddress, wholeMsg - ) + snmpEngine, transportDomain, transportAddress, wholeMsg) - debug.logger & debug.FLAG_DSP and debug.logger('receiveMessage: MP succeded') + debug.logger & debug.FLAG_DSP and debug.logger( + 'receiveMessage: MP succeded') except error.StatusInformation as exc: statusInformation = exc + if 'sendPduHandle' in statusInformation: # Dropped REPORT -- re-run pending reqs queue as some # of them may be waiting for this REPORT debug.logger & debug.FLAG_DSP and debug.logger( - 'receiveMessage: MP failed, statusInformation %s, forcing a retry' % statusInformation) + 'receiveMessage: MP failed, statusInformation %s, ' + 'forcing retry' % statusInformation) + self.__expireRequest( statusInformation['sendPduHandle'], - self.__cache.pop(statusInformation['sendPduHandle']), + self._cache.pop(statusInformation['sendPduHandle']), snmpEngine, - statusInformation - ) + statusInformation) + return restOfWholeMsg except PyAsn1Error as exc: - debug.logger & debug.FLAG_MP and debug.logger('receiveMessage: %s' % exc) - snmpInASNParseErrs, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMPv2-MIB', 'snmpInASNParseErrs') + debug.logger & debug.FLAG_MP and debug.logger( + 'receiveMessage: %s' % exc) + snmpInASNParseErrs, = mibBuilder.importSymbols( + '__SNMPv2-MIB', 'snmpInASNParseErrs') snmpInASNParseErrs.syntax += 1 return restOfWholeMsg - debug.logger & debug.FLAG_DSP and debug.logger('receiveMessage: PDU %s' % PDU.prettyPrint()) + debug.logger & debug.FLAG_DSP and debug.logger( + 'receiveMessage: PDU %s' % PDU.prettyPrint()) # 4.2.2 if sendPduHandle is None: # 4.2.2.1 (request or notification) - debug.logger & debug.FLAG_DSP and debug.logger('receiveMessage: pduType %s' % pduType) + debug.logger & debug.FLAG_DSP and debug.logger( + 'receiveMessage: pduType %s' % pduType) + # 4.2.2.1.1 processPdu = self.getRegisteredApp(contextEngineId, pduType) # 4.2.2.1.2 if processPdu is None: # 4.2.2.1.2.a - snmpUnknownPDUHandlers, = self.mibInstrumController.mibBuilder.importSymbols('__SNMP-MPD-MIB', - 'snmpUnknownPDUHandlers') + snmpUnknownPDUHandlers, = importSymbols( + '__SNMP-MPD-MIB', 'snmpUnknownPDUHandlers') snmpUnknownPDUHandlers.syntax += 1 # 4.2.2.1.2.b @@ -380,7 +419,8 @@ class MsgAndPduDispatcher(object): 'val': snmpUnknownPDUHandlers.syntax } - debug.logger & debug.FLAG_DSP and debug.logger('receiveMessage: unhandled PDU type') + debug.logger & debug.FLAG_DSP and debug.logger( + 'receiveMessage: unhandled PDU type') # 4.2.2.1.2.c try: @@ -391,20 +431,19 @@ class MsgAndPduDispatcher(object): securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, maxSizeResponseScopedPDU, stateReference, - statusInformation - ) + statusInformation) snmpEngine.transportDispatcher.sendMessage( outgoingMessage, destTransportDomain, - destTransportAddress - ) + destTransportAddress) except PySnmpError as exc: debug.logger & debug.FLAG_DSP and debug.logger( 'receiveMessage: report failed, statusInformation %s' % exc) else: - debug.logger & debug.FLAG_DSP and debug.logger('receiveMessage: reporting succeeded') + debug.logger & debug.FLAG_DSP and debug.logger( + 'receiveMessage: reporting succeeded') # 4.2.2.1.2.d return restOfWholeMsg @@ -421,42 +460,44 @@ class MsgAndPduDispatcher(object): securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, - pdu=PDU) - ) + pdu=PDU)) # pass transport info to app (legacy) if stateReference is not None: - self.__transportInfo[stateReference] = ( - transportDomain, transportAddress - ) + self._transportInfo[stateReference] = ( + transportDomain, transportAddress) # 4.2.2.1.3 (asynchronous function) - processPdu(snmpEngine, messageProcessingModel, - securityModel, securityName, securityLevel, - contextEngineId, contextName, pduVersion, - PDU, maxSizeResponseScopedPDU, stateReference) + processPdu( + snmpEngine, messageProcessingModel, securityModel, + securityName, securityLevel, contextEngineId, + contextName, pduVersion, PDU, maxSizeResponseScopedPDU, + stateReference) snmpEngine.observer.clearExecutionContext( - snmpEngine, 'rfc3412.receiveMessage:request' - ) + snmpEngine, 'rfc3412.receiveMessage:request') # legacy if stateReference is not None: - del self.__transportInfo[stateReference] + del self._transportInfo[stateReference] + + debug.logger & debug.FLAG_DSP and debug.logger( + 'receiveMessage: processPdu initiated') - debug.logger & debug.FLAG_DSP and debug.logger('receiveMessage: processPdu initiated') return restOfWholeMsg + else: # 4.2.2.2 (response) # 4.2.2.2.1 - cachedParams = self.__cache.pop(sendPduHandle) + cachedParams = self._cache.pop(sendPduHandle) # 4.2.2.2.2 if cachedParams is None: - snmpUnknownPDUHandlers, = self.mibInstrumController.mibBuilder.importSymbols('__SNMP-MPD-MIB', - 'snmpUnknownPDUHandlers') + snmpUnknownPDUHandlers, = mibBuilder.importSymbols( + '__SNMP-MPD-MIB', 'snmpUnknownPDUHandlers') snmpUnknownPDUHandlers.syntax += 1 + return restOfWholeMsg debug.logger & debug.FLAG_DSP and debug.logger( @@ -476,42 +517,44 @@ class MsgAndPduDispatcher(object): securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, - pdu=PDU) - ) + pdu=PDU)) # 4.2.2.2.4 processResponsePdu = cachedParams['cbFun'] - processResponsePdu(snmpEngine, messageProcessingModel, - securityModel, securityName, securityLevel, - contextEngineId, contextName, pduVersion, - PDU, statusInformation, - cachedParams['sendPduHandle'], - cachedParams['cbCtx']) + processResponsePdu( + snmpEngine, messageProcessingModel, securityModel, + securityName, securityLevel, contextEngineId, contextName, + pduVersion, PDU, statusInformation, + cachedParams['sendPduHandle'], + cachedParams['cbCtx']) snmpEngine.observer.clearExecutionContext( - snmpEngine, 'rfc3412.receiveMessage:response' - ) + snmpEngine, 'rfc3412.receiveMessage:response') - debug.logger & debug.FLAG_DSP and debug.logger('receiveMessage: processResponsePdu succeeded') + debug.logger & debug.FLAG_DSP and debug.logger( + 'receiveMessage: processResponsePdu succeeded') return restOfWholeMsg def releaseStateInformation(self, snmpEngine, sendPduHandle, messageProcessingModel): k = int(messageProcessingModel) + if k in snmpEngine.messageProcessingSubsystems: mpHandler = snmpEngine.messageProcessingSubsystems[k] mpHandler.releaseStateInformation(sendPduHandle) - self.__cache.pop(sendPduHandle) + self._cache.pop(sendPduHandle) # Cache expiration stuff # noinspection PyUnusedLocal def __expireRequest(self, cacheKey, cachedParams, snmpEngine, statusInformation=None): + timeNow = snmpEngine.transportDispatcher.getTimerTicks() + timeoutAt = cachedParams['timeout'] if statusInformation is None and timeNow < timeoutAt: @@ -519,24 +562,25 @@ class MsgAndPduDispatcher(object): processResponsePdu = cachedParams['cbFun'] - debug.logger & debug.FLAG_DSP and debug.logger('__expireRequest: req cachedParams %s' % cachedParams) + debug.logger & debug.FLAG_DSP and debug.logger( + '__expireRequest: req cachedParams %s' % cachedParams) # Fail timed-out requests if not statusInformation: statusInformation = error.StatusInformation( - errorIndication=errind.requestTimedOut - ) + errorIndication=errind.requestTimedOut) + + self.releaseStateInformation( + snmpEngine, cachedParams['sendPduHandle'], + cachedParams['messageProcessingModel']) - self.releaseStateInformation(snmpEngine, - cachedParams['sendPduHandle'], - cachedParams['messageProcessingModel']) + processResponsePdu( + snmpEngine, None, None, None, None, None, None, None, None, + statusInformation, + cachedParams['sendPduHandle'], cachedParams['cbCtx']) - processResponsePdu(snmpEngine, None, None, None, None, None, - None, None, None, statusInformation, - cachedParams['sendPduHandle'], - cachedParams['cbCtx']) return True # noinspection PyUnusedLocal def receiveTimerTick(self, snmpEngine, timeNow): - self.__cache.expire(self.__expireRequest, snmpEngine) + self._cache.expire(self.__expireRequest, snmpEngine) diff --git a/pysnmp/proto/secmod/cache.py b/pysnmp/proto/secmod/cache.py index f5843c50..1859bbad 100644 --- a/pysnmp/proto/secmod/cache.py +++ b/pysnmp/proto/secmod/cache.py @@ -21,10 +21,8 @@ class Cache(object): def pop(self, stateReference): if stateReference in self.__cacheEntries: - securityData = self.__cacheEntries[stateReference] - else: - raise error.ProtocolError( - 'Cache miss for stateReference=%s at %s' % (stateReference, self) - ) - del self.__cacheEntries[stateReference] - return securityData + return self.__cacheEntries.pop(stateReference) + + raise error.ProtocolError( + 'Cache miss for stateReference=%s at ' + '%s' % (stateReference, self)) diff --git a/pysnmp/proto/secmod/eso/priv/aes192.py b/pysnmp/proto/secmod/eso/priv/aes192.py index 7df0a0f5..cbbc748e 100644 --- a/pysnmp/proto/secmod/eso/priv/aes192.py +++ b/pysnmp/proto/secmod/eso/priv/aes192.py @@ -14,7 +14,8 @@ class AesBlumenthal192(aesbase.AbstractAesBlumenthal): http://tools.ietf.org/html/draft-blumenthal-aes-usm-04 """ - SERVICE_ID = (1, 3, 6, 1, 4, 1, 9, 12, 6, 1, 1) # cusmAESCfb192PrivProtocol + # cusmAESCfb192PrivProtocol + SERVICE_ID = (1, 3, 6, 1, 4, 1, 9, 12, 6, 1, 1) KEY_SIZE = 24 @@ -29,5 +30,6 @@ class Aes192(aesbase.AbstractAesReeder): Known to be used by many vendors including Cisco and others. """ - SERVICE_ID = (1, 3, 6, 1, 4, 1, 9, 12, 6, 1, 101) # cusmAESCfb192PrivProtocol (non-standard OID) + # cusmAESCfb192PrivProtocol (non-standard OID) + SERVICE_ID = (1, 3, 6, 1, 4, 1, 9, 12, 6, 1, 101) KEY_SIZE = 24 diff --git a/pysnmp/proto/secmod/eso/priv/aes256.py b/pysnmp/proto/secmod/eso/priv/aes256.py index 94a255ff..7ca42504 100644 --- a/pysnmp/proto/secmod/eso/priv/aes256.py +++ b/pysnmp/proto/secmod/eso/priv/aes256.py @@ -12,7 +12,8 @@ class AesBlumenthal256(aesbase.AbstractAesBlumenthal): http://tools.ietf.org/html/draft-blumenthal-aes-usm-04 """ - SERVICE_ID = (1, 3, 6, 1, 4, 1, 9, 12, 6, 1, 2) # cusmAESCfb256PrivProtocol + # cusmAESCfb256PrivProtocol + SERVICE_ID = (1, 3, 6, 1, 4, 1, 9, 12, 6, 1, 2) KEY_SIZE = 32 @@ -27,5 +28,6 @@ class Aes256(aesbase.AbstractAesReeder): Known to be used by many vendors including Cisco and others. """ - SERVICE_ID = (1, 3, 6, 1, 4, 1, 9, 12, 6, 1, 102) # cusmAESCfb256PrivProtocol (non-standard OID) + # cusmAESCfb256PrivProtocol (non-standard OID) + SERVICE_ID = (1, 3, 6, 1, 4, 1, 9, 12, 6, 1, 102) KEY_SIZE = 32 diff --git a/pysnmp/proto/secmod/eso/priv/aesbase.py b/pysnmp/proto/secmod/eso/priv/aesbase.py index 0c2e5d17..3af30df0 100644 --- a/pysnmp/proto/secmod/eso/priv/aesbase.py +++ b/pysnmp/proto/secmod/eso/priv/aesbase.py @@ -24,19 +24,25 @@ class AbstractAesBlumenthal(aes.Aes): def localizeKey(self, authProtocol, privKey, snmpEngineID): if authProtocol == hmacmd5.HmacMd5.SERVICE_ID: hashAlgo = md5 + elif authProtocol == hmacsha.HmacSha.SERVICE_ID: hashAlgo = sha1 + elif authProtocol in hmacsha2.HmacSha2.HASH_ALGORITHM: hashAlgo = hmacsha2.HmacSha2.HASH_ALGORITHM[authProtocol] + else: raise error.ProtocolError( - 'Unknown auth protocol %s' % (authProtocol,) - ) + 'Unknown auth protocol %s' % (authProtocol,)) - localPrivKey = localkey.localizeKey(privKey, snmpEngineID, hashAlgo) + localPrivKey = localkey.localizeKey( + privKey, snmpEngineID, hashAlgo) - # now extend this key if too short by repeating steps that includes the hashPassphrase step - for count in range(1, int(ceil(self.KEY_SIZE * 1.0 / len(localPrivKey)))): + # now extend this key if too short by repeating steps that includes + # the hashPassphrase step + rounds = int(ceil(self.KEY_SIZE * 1.0 / len(localPrivKey))) + + for _ in range(1, rounds): localPrivKey += hashAlgo(localPrivKey).digest() return localPrivKey[:self.KEY_SIZE] @@ -64,14 +70,16 @@ class AbstractAesReeder(aes.Aes): def localizeKey(self, authProtocol, privKey, snmpEngineID): if authProtocol == hmacmd5.HmacMd5.SERVICE_ID: hashAlgo = md5 + elif authProtocol == hmacsha.HmacSha.SERVICE_ID: hashAlgo = sha1 + elif authProtocol in hmacsha2.HmacSha2.HASH_ALGORITHM: hashAlgo = hmacsha2.HmacSha2.HASH_ALGORITHM[authProtocol] + else: raise error.ProtocolError( - 'Unknown auth protocol %s' % (authProtocol,) - ) + 'Unknown auth protocol %s' % (authProtocol,)) localPrivKey = localkey.localizeKey(privKey, snmpEngineID, hashAlgo) diff --git a/pysnmp/proto/secmod/eso/priv/des3.py b/pysnmp/proto/secmod/eso/priv/des3.py index da84475b..8d193084 100644 --- a/pysnmp/proto/secmod/eso/priv/des3.py +++ b/pysnmp/proto/secmod/eso/priv/des3.py @@ -34,7 +34,8 @@ class Des3(base.AbstractEncryptionService): https://tools.ietf.org/html/draft-reeder-snmpv3-usm-3desede-00 """ - SERVICE_ID = (1, 3, 6, 1, 6, 3, 10, 1, 2, 3) # usm3DESEDEPrivProtocol + # usm3DESEDEPrivProtocol + SERVICE_ID = (1, 3, 6, 1, 6, 3, 10, 1, 2, 3) KEY_SIZE = 32 local_int = random.randrange(0, 0xffffffff) @@ -42,28 +43,34 @@ class Des3(base.AbstractEncryptionService): def hashPassphrase(self, authProtocol, privKey): if authProtocol == hmacmd5.HmacMd5.SERVICE_ID: hashAlgo = md5 + elif authProtocol == hmacsha.HmacSha.SERVICE_ID: hashAlgo = sha1 + elif authProtocol in hmacsha2.HmacSha2.HASH_ALGORITHM: hashAlgo = hmacsha2.HmacSha2.HASH_ALGORITHM[authProtocol] + else: raise error.ProtocolError( - 'Unknown auth protocol %s' % (authProtocol,) - ) + 'Unknown auth protocol %s' % (authProtocol,)) + return localkey.hashPassphrase(privKey, hashAlgo) # 2.1 def localizeKey(self, authProtocol, privKey, snmpEngineID): if authProtocol == hmacmd5.HmacMd5.SERVICE_ID: hashAlgo = md5 + elif authProtocol == hmacsha.HmacSha.SERVICE_ID: hashAlgo = sha1 + elif authProtocol in hmacsha2.HmacSha2.HASH_ALGORITHM: hashAlgo = hmacsha2.HmacSha2.HASH_ALGORITHM[authProtocol] + else: raise error.ProtocolError( - 'Unknown auth protocol %s' % (authProtocol,) - ) + 'Unknown auth protocol %s' % (authProtocol,)) + localPrivKey = localkey.localizeKey(privKey, snmpEngineID, hashAlgo) # now extend this key if too short by repeating steps that includes the hashPassphrase step @@ -75,7 +82,7 @@ class Des3(base.AbstractEncryptionService): return localPrivKey[:self.KEY_SIZE] # 5.1.1.1 - def __getEncryptionKey(self, privKey, snmpEngineBoots): + def _getEncryptionKey(self, privKey, snmpEngineBoots): # 5.1.1.1.1 des3Key = privKey[:24] preIV = privKey[24:32] @@ -94,39 +101,46 @@ class Des3(base.AbstractEncryptionService): ] if self.local_int == 0xffffffff: self.local_int = 0 + else: self.local_int += 1 # salt not yet hashed XXX + iv = map(lambda x, y: x ^ y, salt, preIV.asNumbers()) + return (des3Key.asOctets(), univ.OctetString(salt).asOctets(), - univ.OctetString(map(lambda x, y: x ^ y, salt, preIV.asNumbers())).asOctets()) + univ.OctetString(iv).asOctets()) @staticmethod - def __getDecryptionKey(privKey, salt): + def _getDecryptionKey(privKey, salt): + iv = map( + lambda x, y: x ^ y, salt.asNumbers(), privKey[24:32].asNumbers()) + return (privKey[:24].asOctets(), - univ.OctetString(map(lambda x, y: x ^ y, salt.asNumbers(), privKey[24:32].asNumbers())).asOctets()) + univ.OctetString(iv).asOctets()) # 5.1.1.2 def encryptData(self, encryptKey, privParameters, dataToEncrypt): snmpEngineBoots, snmpEngineTime, salt = privParameters - des3Key, salt, iv = self.__getEncryptionKey( + des3Key, salt, iv = self._getEncryptionKey( encryptKey, snmpEngineBoots ) privParameters = univ.OctetString(salt) - plaintext = dataToEncrypt + univ.OctetString((0,) * (8 - len(dataToEncrypt) % 8)).asOctets() + plaintext = dataToEncrypt + plaintext += univ.OctetString( + (0,) * (8 - len(dataToEncrypt) % 8)).asOctets() try: ciphertext = des3.encrypt(plaintext, des3Key, iv) except PysnmpCryptoError: raise error.StatusInformation( - errorIndication=errind.unsupportedPrivProtocol - ) + errorIndication=errind.unsupportedPrivProtocol) return univ.OctetString(ciphertext), privParameters @@ -136,15 +150,13 @@ class Des3(base.AbstractEncryptionService): if len(salt) != 8: raise error.StatusInformation( - errorIndication=errind.decryptionError - ) + errorIndication=errind.decryptionError) - des3Key, iv = self.__getDecryptionKey(decryptKey, salt) + des3Key, iv = self._getDecryptionKey(decryptKey, salt) if len(encryptedData) % 8 != 0: raise error.StatusInformation( - errorIndication=errind.decryptionError - ) + errorIndication=errind.decryptionError) ciphertext = encryptedData.asOctets() @@ -153,7 +165,6 @@ class Des3(base.AbstractEncryptionService): except PysnmpCryptoError: raise error.StatusInformation( - errorIndication=errind.unsupportedPrivProtocol - ) + errorIndication=errind.unsupportedPrivProtocol) return plaintext diff --git a/pysnmp/proto/secmod/rfc2576.py b/pysnmp/proto/secmod/rfc2576.py index ba11b0fe..92b5eac2 100644 --- a/pysnmp/proto/secmod/rfc2576.py +++ b/pysnmp/proto/secmod/rfc2576.py @@ -4,9 +4,6 @@ # Copyright (c) 2005-2019, Ilya Etingof # License: http://snmplabs.com/pysnmp/license.html # -from pyasn1.codec.ber import encoder -from pyasn1.error import PyAsn1Error - from pysnmp import debug from pysnmp.carrier.asyncore.dgram import udp from pysnmp.carrier.asyncore.dgram import udp6 @@ -15,6 +12,9 @@ from pysnmp.proto import error from pysnmp.proto.secmod import base from pysnmp.smi.error import NoSuchInstanceError +from pyasn1.codec.ber import encoder +from pyasn1.error import PyAsn1Error + class SnmpV1SecurityModel(base.AbstractSecurityModel): SECURITY_MODEL_ID = 1 @@ -26,60 +26,69 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel): # in here. def __init__(self): - self.__transportBranchId = self.__paramsBranchId = self.__communityBranchId = self.__securityBranchId = -1 + self._transportBranchId = -1 + self._paramsBranchId = -1 + self._communityBranchId = -1 + self._securityBranchId = -1 + base.AbstractSecurityModel.__init__(self) def _sec2com(self, snmpEngine, securityName, contextEngineId, contextName): - snmpTargetParamsSecurityName, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder + + snmpTargetParamsSecurityName, = mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'snmpTargetParamsSecurityName') - if self.__paramsBranchId != snmpTargetParamsSecurityName.branchVersionId: - snmpTargetParamsSecurityModel, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( + + if self._paramsBranchId != snmpTargetParamsSecurityName.branchVersionId: + snmpTargetParamsSecurityModel, = mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'snmpTargetParamsSecurityModel') - self.__nameToModelMap = {} + self._nameToModelMap = {} nextMibNode = snmpTargetParamsSecurityName while True: try: - nextMibNode = snmpTargetParamsSecurityName.getNextNode(nextMibNode.name) + nextMibNode = snmpTargetParamsSecurityName.getNextNode( + nextMibNode.name) except NoSuchInstanceError: break instId = nextMibNode.name[len(snmpTargetParamsSecurityName.name):] - mibNode = snmpTargetParamsSecurityModel.getNode(snmpTargetParamsSecurityModel.name + instId) + mibNode = snmpTargetParamsSecurityModel.getNode( + snmpTargetParamsSecurityModel.name + instId) try: - if mibNode.syntax not in self.__nameToModelMap: - self.__nameToModelMap[nextMibNode.syntax] = set() + if mibNode.syntax not in self._nameToModelMap: + self._nameToModelMap[nextMibNode.syntax] = set() - self.__nameToModelMap[nextMibNode.syntax].add(mibNode.syntax) + self._nameToModelMap[nextMibNode.syntax].add(mibNode.syntax) except PyAsn1Error: debug.logger & debug.FLAG_SM and debug.logger( - '_sec2com: table entries %r/%r hashing failed' % ( - nextMibNode.syntax, mibNode.syntax) - ) + '_sec2com: table entries %r/%r hashing ' + 'failed' % (nextMibNode.syntax, mibNode.syntax)) continue - self.__paramsBranchId = snmpTargetParamsSecurityName.branchVersionId + self._paramsBranchId = snmpTargetParamsSecurityName.branchVersionId # invalidate next map as it include this one - self.__securityBranchId = -1 + self._securityBranchId = -1 - snmpCommunityName, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('SNMP-COMMUNITY-MIB', - 'snmpCommunityName') - if self.__securityBranchId != snmpCommunityName.branchVersionId: + snmpCommunityName, = mibBuilder.importSymbols( + 'SNMP-COMMUNITY-MIB', 'snmpCommunityName') + + if self._securityBranchId != snmpCommunityName.branchVersionId: (snmpCommunitySecurityName, snmpCommunityContextEngineId, - snmpCommunityContextName) = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( + snmpCommunityContextName) = mibBuilder.importSymbols( 'SNMP-COMMUNITY-MIB', 'snmpCommunitySecurityName', 'snmpCommunityContextEngineID', 'snmpCommunityContextName' ) - self.__securityMap = {} + self._securityMap = {} nextMibNode = snmpCommunityName @@ -92,54 +101,55 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel): instId = nextMibNode.name[len(snmpCommunityName.name):] - _securityName = snmpCommunitySecurityName.getNode(snmpCommunitySecurityName.name + instId).syntax + _securityName = snmpCommunitySecurityName.getNode( + snmpCommunitySecurityName.name + instId).syntax _contextEngineId = snmpCommunityContextEngineId.getNode( snmpCommunityContextEngineId.name + instId).syntax - _contextName = snmpCommunityContextName.getNode(snmpCommunityContextName.name + instId).syntax + _contextName = snmpCommunityContextName.getNode( + snmpCommunityContextName.name + instId).syntax + + key = _securityName, _contextEngineId, _contextName try: - self.__securityMap[(_securityName, - _contextEngineId, - _contextName)] = nextMibNode.syntax + self._securityMap[key] = nextMibNode.syntax except PyAsn1Error: debug.logger & debug.FLAG_SM and debug.logger( - '_sec2com: table entries %r/%r/%r hashing failed' % ( - _securityName, _contextEngineId, _contextName) - ) + '_sec2com: table entries %r/%r/%r hashing failed' % key) continue - self.__securityBranchId = snmpCommunityName.branchVersionId + self._securityBranchId = snmpCommunityName.branchVersionId debug.logger & debug.FLAG_SM and debug.logger( - '_sec2com: built securityName to communityName map, version %s: %s' % ( - self.__securityBranchId, self.__securityMap)) + '_sec2com: built securityName to communityName map, version ' + '%s: %s' % (self._securityBranchId, self._securityMap)) + + key = securityName, contextEngineId, contextName try: - return self.__securityMap[(securityName, - contextEngineId, - contextName)] + return self._securityMap[key] except KeyError: raise error.StatusInformation( - errorIndication=errind.unknownCommunityName - ) + errorIndication=errind.unknownCommunityName) def _com2sec(self, snmpEngine, communityName, transportInformation): - snmpTargetAddrTAddress, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder + + snmpTargetAddrTAddress, = mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'snmpTargetAddrTAddress') - if self.__transportBranchId != snmpTargetAddrTAddress.branchVersionId: + + if self._transportBranchId != snmpTargetAddrTAddress.branchVersionId: (SnmpTagValue, snmpTargetAddrTDomain, - snmpTargetAddrTagList) = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( + snmpTargetAddrTagList) = mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'SnmpTagValue', 'snmpTargetAddrTDomain', - 'snmpTargetAddrTagList' - ) + 'snmpTargetAddrTagList') - self.__emptyTag = SnmpTagValue('') + self._emptyTag = SnmpTagValue('') - self.__transportToTagMap = {} + self._transportToTagMap = {} nextMibNode = snmpTargetAddrTagList @@ -151,56 +161,64 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel): break instId = nextMibNode.name[len(snmpTargetAddrTagList.name):] - targetAddrTDomain = snmpTargetAddrTDomain.getNode(snmpTargetAddrTDomain.name + instId).syntax - targetAddrTAddress = snmpTargetAddrTAddress.getNode(snmpTargetAddrTAddress.name + instId).syntax + + targetAddrTDomain = snmpTargetAddrTDomain.getNode( + snmpTargetAddrTDomain.name + instId).syntax + targetAddrTAddress = snmpTargetAddrTAddress.getNode( + snmpTargetAddrTAddress.name + instId).syntax targetAddrTDomain = tuple(targetAddrTDomain) - if targetAddrTDomain[:len(udp.SNMP_UDP_DOMAIN)] == udp.SNMP_UDP_DOMAIN: - SnmpUDPAddress, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('SNMPv2-TM', - 'SnmpUDPAddress') + if (targetAddrTDomain[:len(udp.SNMP_UDP_DOMAIN)] == + udp.SNMP_UDP_DOMAIN): + SnmpUDPAddress, = mibBuilder.importSymbols( + 'SNMPv2-TM', 'SnmpUDPAddress') targetAddrTAddress = tuple(SnmpUDPAddress(targetAddrTAddress)) - elif targetAddrTDomain[:len(udp6.SNMP_UDP6_DOMAIN)] == udp6.SNMP_UDP6_DOMAIN: - TransportAddressIPv6, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( + + elif (targetAddrTDomain[:len(udp6.SNMP_UDP6_DOMAIN)] == + udp6.SNMP_UDP6_DOMAIN): + TransportAddressIPv6, = mibBuilder.importSymbols( 'TRANSPORT-ADDRESS-MIB', 'TransportAddressIPv6') + targetAddrTAddress = tuple(TransportAddressIPv6(targetAddrTAddress)) targetAddr = targetAddrTDomain, targetAddrTAddress - targetAddrTagList = snmpTargetAddrTagList.getNode(snmpTargetAddrTagList.name + instId).syntax - if targetAddr not in self.__transportToTagMap: - self.__transportToTagMap[targetAddr] = set() + targetAddrTagList = snmpTargetAddrTagList.getNode( + snmpTargetAddrTagList.name + instId).syntax + + if targetAddr not in self._transportToTagMap: + self._transportToTagMap[targetAddr] = set() try: if targetAddrTagList: - self.__transportToTagMap[targetAddr].update( + self._transportToTagMap[targetAddr].update( [SnmpTagValue(x) - for x in targetAddrTagList.asOctets().split()] - ) + for x in targetAddrTagList.asOctets().split()]) else: - self.__transportToTagMap[targetAddr].add(self.__emptyTag) + self._transportToTagMap[targetAddr].add(self._emptyTag) except PyAsn1Error: debug.logger & debug.FLAG_SM and debug.logger( '_com2sec: table entries %r/%r hashing failed' % ( - targetAddr, targetAddrTagList) - ) + targetAddr, targetAddrTagList)) continue - self.__transportBranchId = snmpTargetAddrTAddress.branchVersionId + self._transportBranchId = snmpTargetAddrTAddress.branchVersionId - debug.logger & debug.FLAG_SM and debug.logger('_com2sec: built transport-to-tag map version %s: %s' % ( - self.__transportBranchId, self.__transportToTagMap)) + debug.logger & debug.FLAG_SM and debug.logger( + '_com2sec: built transport-to-tag map version %s: ' + '%s' % (self._transportBranchId, self._transportToTagMap)) - snmpTargetParamsSecurityName, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( + snmpTargetParamsSecurityName, = mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'snmpTargetParamsSecurityName') - if self.__paramsBranchId != snmpTargetParamsSecurityName.branchVersionId: - snmpTargetParamsSecurityModel, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( + if self._paramsBranchId != snmpTargetParamsSecurityName.branchVersionId: + snmpTargetParamsSecurityModel, = mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'snmpTargetParamsSecurityModel') - self.__nameToModelMap = {} + self._nameToModelMap = {} nextMibNode = snmpTargetParamsSecurityName @@ -213,43 +231,44 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel): instId = nextMibNode.name[len(snmpTargetParamsSecurityName.name):] - mibNode = snmpTargetParamsSecurityModel.getNode(snmpTargetParamsSecurityModel.name + instId) + mibNode = snmpTargetParamsSecurityModel.getNode( + snmpTargetParamsSecurityModel.name + instId) try: - if nextMibNode.syntax not in self.__nameToModelMap: - self.__nameToModelMap[nextMibNode.syntax] = set() + if nextMibNode.syntax not in self._nameToModelMap: + self._nameToModelMap[nextMibNode.syntax] = set() - self.__nameToModelMap[nextMibNode.syntax].add(mibNode.syntax) + self._nameToModelMap[nextMibNode.syntax].add(mibNode.syntax) except PyAsn1Error: debug.logger & debug.FLAG_SM and debug.logger( - '_com2sec: table entries %r/%r hashing failed' % ( - nextMibNode.syntax, mibNode.syntax) - ) + '_com2sec: table entries %r/%r hashing ' + 'failed' % (nextMibNode.syntax, mibNode.syntax)) continue - self.__paramsBranchId = snmpTargetParamsSecurityName.branchVersionId + self._paramsBranchId = snmpTargetParamsSecurityName.branchVersionId # invalidate next map as it include this one - self.__communityBranchId = -1 + self._communityBranchId = -1 debug.logger & debug.FLAG_SM and debug.logger( - '_com2sec: built securityName to securityModel map, version %s: %s' % ( - self.__paramsBranchId, self.__nameToModelMap)) + '_com2sec: built securityName to securityModel map, version ' + '%s: %s' % (self._paramsBranchId, self._nameToModelMap)) + + snmpCommunityName, = mibBuilder.importSymbols( + 'SNMP-COMMUNITY-MIB', 'snmpCommunityName') - snmpCommunityName, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('SNMP-COMMUNITY-MIB', - 'snmpCommunityName') - if self.__communityBranchId != snmpCommunityName.branchVersionId: + if self._communityBranchId != snmpCommunityName.branchVersionId: (snmpCommunitySecurityName, snmpCommunityContextEngineId, snmpCommunityContextName, - snmpCommunityTransportTag) = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( + snmpCommunityTransportTag) = mibBuilder.importSymbols( 'SNMP-COMMUNITY-MIB', 'snmpCommunitySecurityName', 'snmpCommunityContextEngineID', 'snmpCommunityContextName', 'snmpCommunityTransportTag' ) - self.__communityToTagMap = {} - self.__tagAndCommunityToSecurityMap = {} + self._communityToTagMap = {} + self._tagAndCommunityToSecurityMap = {} nextMibNode = snmpCommunityName @@ -262,100 +281,125 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel): instId = nextMibNode.name[len(snmpCommunityName.name):] - securityName = snmpCommunitySecurityName.getNode(snmpCommunitySecurityName.name + instId).syntax + securityName = snmpCommunitySecurityName.getNode( + snmpCommunitySecurityName.name + instId).syntax contextEngineId = snmpCommunityContextEngineId.getNode( snmpCommunityContextEngineId.name + instId).syntax - contextName = snmpCommunityContextName.getNode(snmpCommunityContextName.name + instId).syntax + contextName = snmpCommunityContextName.getNode( + snmpCommunityContextName.name + instId).syntax - transportTag = snmpCommunityTransportTag.getNode(snmpCommunityTransportTag.name + instId).syntax + transportTag = snmpCommunityTransportTag.getNode( + snmpCommunityTransportTag.name + instId).syntax _tagAndCommunity = transportTag, nextMibNode.syntax try: - if _tagAndCommunity not in self.__tagAndCommunityToSecurityMap: - self.__tagAndCommunityToSecurityMap[_tagAndCommunity] = set() + if _tagAndCommunity not in self._tagAndCommunityToSecurityMap: + self._tagAndCommunityToSecurityMap[_tagAndCommunity] = set() - self.__tagAndCommunityToSecurityMap[_tagAndCommunity].add( - (securityName, contextEngineId, contextName) - ) + self._tagAndCommunityToSecurityMap[_tagAndCommunity].add( + (securityName, contextEngineId, contextName)) - if nextMibNode.syntax not in self.__communityToTagMap: - self.__communityToTagMap[nextMibNode.syntax] = set() + if nextMibNode.syntax not in self._communityToTagMap: + self._communityToTagMap[nextMibNode.syntax] = set() - self.__communityToTagMap[nextMibNode.syntax].add(transportTag) + self._communityToTagMap[nextMibNode.syntax].add(transportTag) except PyAsn1Error: debug.logger & debug.FLAG_SM and debug.logger( - '_com2sec: table entries %r/%r hashing failed' % ( - _tagAndCommunity, nextMibNode.syntax) - ) + '_com2sec: table entries %r/%r hashing ' + 'failed' % (_tagAndCommunity, nextMibNode.syntax)) continue - self.__communityBranchId = snmpCommunityName.branchVersionId + self._communityBranchId = snmpCommunityName.branchVersionId debug.logger & debug.FLAG_SM and debug.logger( - '_com2sec: built communityName to tag map (securityModel %s), version %s: %s' % ( - self.SECURITY_MODEL_ID, self.__communityBranchId, self.__communityToTagMap)) + '_com2sec: built communityName to tag map ' + '(securityModel %s), version %s: ' + '%s' % (self.SECURITY_MODEL_ID, self._communityBranchId, + self._communityToTagMap)) debug.logger & debug.FLAG_SM and debug.logger( - '_com2sec: built tag & community to securityName map (securityModel %s), version %s: %s' % ( - self.SECURITY_MODEL_ID, self.__communityBranchId, self.__tagAndCommunityToSecurityMap)) - - if communityName in self.__communityToTagMap: - if transportInformation in self.__transportToTagMap: - tags = self.__transportToTagMap[transportInformation].intersection( - self.__communityToTagMap[communityName]) - elif self.__emptyTag in self.__communityToTagMap[communityName]: - tags = [self.__emptyTag] + '_com2sec: built tag & community to securityName map ' + '(securityModel %s), version %s: ' + '%s' % (self.SECURITY_MODEL_ID, self._communityBranchId, + self._tagAndCommunityToSecurityMap)) + + if communityName in self._communityToTagMap: + if transportInformation in self._transportToTagMap: + tags = self._transportToTagMap[transportInformation].intersection( + self._communityToTagMap[communityName]) + + elif self._emptyTag in self._communityToTagMap[communityName]: + tags = [self._emptyTag] + else: - raise error.StatusInformation(errorIndication=errind.unknownCommunityName) + raise error.StatusInformation( + errorIndication=errind.unknownCommunityName) candidateSecurityNames = [] - for x in [self.__tagAndCommunityToSecurityMap[(t, communityName)] for t in tags]: + securityNamesSets = [ + self._tagAndCommunityToSecurityMap[(t, communityName)] + for t in tags + ] + + for x in securityNamesSets: candidateSecurityNames.extend(list(x)) - # 5.2.1 (row selection in snmpCommunityTable) - # Picks first match but favors entries already in targets table if candidateSecurityNames: - candidateSecurityNames.sort( - key=lambda x, m=self.__nameToModelMap, v=self.SECURITY_MODEL_ID: ( - not int(x[0] in m and v in m[x[0]]), str(x[0])) - ) + candidateSecurityNames.sort(key=self._orderSecurityNames) + chosenSecurityName = candidateSecurityNames[0] # min() + debug.logger & debug.FLAG_SM and debug.logger( - '_com2sec: securityName candidates for communityName \'%s\' are %s; choosing securityName \'%s\'' % ( - communityName, candidateSecurityNames, chosenSecurityName[0])) + '_com2sec: securityName candidates for communityName %s ' + 'are %s; choosing securityName ' + '%s' % (communityName, candidateSecurityNames, + chosenSecurityName[0])) + return chosenSecurityName - raise error.StatusInformation(errorIndication=errind.unknownCommunityName) + raise error.StatusInformation( + errorIndication=errind.unknownCommunityName) + + # 5.2.1 (row selection in snmpCommunityTable) + # Picks first match but favors entries already in targets table + def _orderSecurityNames(self, securityName): + return (not int(securityName[0] in self._nameToModelMap and + self.SECURITY_MODEL_ID in self._nameToModelMap[securityName[0]]), + str(securityName[0])) def generateRequestMsg(self, snmpEngine, messageProcessingModel, globalData, maxMessageSize, securityModel, securityEngineId, securityName, securityLevel, scopedPDU): msg, = globalData + contextEngineId, contextName, pdu = scopedPDU # rfc2576: 5.2.3 - communityName = self._sec2com(snmpEngine, securityName, - contextEngineId, contextName) + communityName = self._sec2com( + snmpEngine, securityName, contextEngineId, contextName) debug.logger & debug.FLAG_SM and debug.logger( - 'generateRequestMsg: using community %r for securityModel %r, securityName %r, contextEngineId %r contextName %r' % ( - communityName, securityModel, securityName, contextEngineId, contextName)) + 'generateRequestMsg: using community %r for securityModel %r, ' + 'securityName %r, contextEngineId %r contextName ' + '%r' % (communityName, securityModel, securityName, + contextEngineId, contextName)) securityParameters = communityName msg.setComponentByPosition(1, securityParameters) msg.setComponentByPosition(2) msg.getComponentByPosition(2).setComponentByType( - pdu.tagSet, pdu, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + pdu.tagSet, pdu, verifyConstraints=False, matchTags=False, + matchConstraints=False) - debug.logger & debug.FLAG_MP and debug.logger('generateRequestMsg: %s' % (msg.prettyPrint(),)) + debug.logger & debug.FLAG_MP and debug.logger( + 'generateRequestMsg: %s' % (msg.prettyPrint(),)) try: return securityParameters, encoder.encode(msg) @@ -363,7 +407,9 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel): except PyAsn1Error as exc: debug.logger & debug.FLAG_MP and debug.logger( 'generateRequestMsg: serialization failure: %s' % exc) - raise error.StatusInformation(errorIndication=errind.serializationError) + + raise error.StatusInformation( + errorIndication=errind.serializationError) def generateResponseMsg(self, snmpEngine, messageProcessingModel, globalData, maxMessageSize, securityModel, @@ -371,21 +417,26 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel): scopedPDU, securityStateReference): # rfc2576: 5.2.2 msg, = globalData + contextEngineId, contextName, pdu = scopedPDU + cachedSecurityData = self._cache.pop(securityStateReference) + communityName = cachedSecurityData['communityName'] debug.logger & debug.FLAG_SM and debug.logger( - 'generateResponseMsg: recovered community %r by securityStateReference %s' % ( - communityName, securityStateReference)) + 'generateResponseMsg: recovered community %r by ' + 'securityStateReference ' + '%s' % (communityName, securityStateReference)) msg.setComponentByPosition(1, communityName) msg.setComponentByPosition(2) msg.getComponentByPosition(2).setComponentByType( - pdu.tagSet, pdu, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + pdu.tagSet, pdu, verifyConstraints=False, matchTags=False, + matchConstraints=False) - debug.logger & debug.FLAG_MP and debug.logger('generateResponseMsg: %s' % (msg.prettyPrint(),)) + debug.logger & debug.FLAG_MP and debug.logger( + 'generateResponseMsg: %s' % (msg.prettyPrint(),)) try: return communityName, encoder.encode(msg) @@ -393,11 +444,14 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel): except PyAsn1Error as exc: debug.logger & debug.FLAG_MP and debug.logger( 'generateResponseMsg: serialization failure: %s' % exc) + raise error.StatusInformation(errorIndication=errind.serializationError) def processIncomingMsg(self, snmpEngine, messageProcessingModel, maxMessageSize, securityParameters, securityModel, securityLevel, wholeMsg, msg): + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder + # rfc2576: 5.2.1 communityName, transportInformation = securityParameters @@ -407,6 +461,7 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel): snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc2576.processIncomingMsg:writable', scope ) + snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc2576.processIncomingMsg:writable' ) @@ -418,16 +473,17 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel): ) except error.StatusInformation: - snmpInBadCommunityNames, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( + snmpInBadCommunityNames, = mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInBadCommunityNames') snmpInBadCommunityNames.syntax += 1 + raise error.StatusInformation( errorIndication=errind.unknownCommunityName, communityName=communityName ) - snmpEngineID, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', - 'snmpEngineID') + snmpEngineID, = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') securityEngineID = snmpEngineID.syntax @@ -440,24 +496,31 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel): contextEngineId=contextEngineId, contextName=contextName) ) + snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc2576.processIncomingMsg' ) debug.logger & debug.FLAG_SM and debug.logger( - 'processIncomingMsg: looked up securityName %r securityModel %r contextEngineId %r contextName %r by communityName %r AND transportInformation %r' % ( - securityName, self.SECURITY_MODEL_ID, contextEngineId, contextName, communityName, transportInformation)) + 'processIncomingMsg: looked up securityName %r securityModel %r ' + 'contextEngineId %r contextName %r by communityName %r ' + 'AND transportInformation ' + '%r' % (securityName, self.SECURITY_MODEL_ID, contextEngineId, + contextName, communityName, transportInformation)) stateReference = self._cache.push(communityName=communityName) scopedPDU = (contextEngineId, contextName, msg.getComponentByPosition(2).getComponent()) + maxSizeResponseScopedPDU = maxMessageSize - 128 + securityStateReference = stateReference debug.logger & debug.FLAG_SM and debug.logger( - 'processIncomingMsg: generated maxSizeResponseScopedPDU %s securityStateReference %s' % ( - maxSizeResponseScopedPDU, securityStateReference)) + 'processIncomingMsg: generated maxSizeResponseScopedPDU ' + '%s securityStateReference ' + '%s' % (maxSizeResponseScopedPDU, securityStateReference)) return (securityEngineID, securityName, scopedPDU, maxSizeResponseScopedPDU, securityStateReference) diff --git a/pysnmp/proto/secmod/rfc3414/auth/hmacmd5.py b/pysnmp/proto/secmod/rfc3414/auth/hmacmd5.py index df3db63f..c3578682 100644 --- a/pysnmp/proto/secmod/rfc3414/auth/hmacmd5.py +++ b/pysnmp/proto/secmod/rfc3414/auth/hmacmd5.py @@ -41,11 +41,13 @@ class HmacMd5(base.AbstractAuthenticationService): # should be in the substrate. Also, it pre-sets digest placeholder # so we hash wholeMsg out of the box. # Yes, that's ugly but that's rfc... - l = wholeMsg.find(TWELVE_ZEROS) - if l == -1: + ln = wholeMsg.find(TWELVE_ZEROS) + + if ln == -1: raise error.ProtocolError('Cant locate digest placeholder') - wholeHead = wholeMsg[:l] - wholeTail = wholeMsg[l + 12:] + + wholeHead = wholeMsg[:ln] + wholeTail = wholeMsg[ln + 12:] # 6.3.1.1 @@ -56,15 +58,13 @@ class HmacMd5(base.AbstractAuthenticationService): # 6.3.1.2c k1 = univ.OctetString( - map(lambda x, y: x ^ y, extendedAuthKey, self.IPAD) - ) + map(lambda x, y: x ^ y, extendedAuthKey, self.IPAD)) # 6.3.1.2d --> no-op # 6.3.1.2e k2 = univ.OctetString( - map(lambda x, y: x ^ y, extendedAuthKey, self.OPAD) - ) + map(lambda x, y: x ^ y, extendedAuthKey, self.OPAD)) # 6.3.1.3 # noinspection PyDeprecation,PyCallingNonCallable @@ -83,15 +83,16 @@ class HmacMd5(base.AbstractAuthenticationService): # 6.3.2.1 & 2 if len(authParameters) != 12: raise error.StatusInformation( - errorIndication=errind.authenticationError - ) + errorIndication=errind.authenticationError) # 6.3.2.3 - l = wholeMsg.find(authParameters.asOctets()) - if l == -1: + ln = wholeMsg.find(authParameters.asOctets()) + if ln == -1: raise error.ProtocolError('Cant locate digest in wholeMsg') - wholeHead = wholeMsg[:l] - wholeTail = wholeMsg[l + 12:] + + wholeHead = wholeMsg[:ln] + wholeTail = wholeMsg[ln + 12:] + authenticatedWholeMsg = wholeHead + TWELVE_ZEROS + wholeTail # 6.3.2.4a @@ -101,15 +102,13 @@ class HmacMd5(base.AbstractAuthenticationService): # 6.3.2.4c k1 = univ.OctetString( - map(lambda x, y: x ^ y, extendedAuthKey, self.IPAD) - ) + map(lambda x, y: x ^ y, extendedAuthKey, self.IPAD)) # 6.3.2.4d --> no-op # 6.3.2.4e k2 = univ.OctetString( - map(lambda x, y: x ^ y, extendedAuthKey, self.OPAD) - ) + map(lambda x, y: x ^ y, extendedAuthKey, self.OPAD)) # 6.3.2.5a # noinspection PyDeprecation,PyCallingNonCallable @@ -125,7 +124,6 @@ class HmacMd5(base.AbstractAuthenticationService): # 6.3.2.6 if mac != authParameters: raise error.StatusInformation( - errorIndication=errind.authenticationFailure - ) + errorIndication=errind.authenticationFailure) return authenticatedWholeMsg diff --git a/pysnmp/proto/secmod/rfc3414/auth/hmacsha.py b/pysnmp/proto/secmod/rfc3414/auth/hmacsha.py index 4d5498d1..76c35af0 100644 --- a/pysnmp/proto/secmod/rfc3414/auth/hmacsha.py +++ b/pysnmp/proto/secmod/rfc3414/auth/hmacsha.py @@ -42,11 +42,12 @@ class HmacSha(base.AbstractAuthenticationService): # should be in the substrate. Also, it pre-sets digest placeholder # so we hash wholeMsg out of the box. # Yes, that's ugly but that's rfc... - l = wholeMsg.find(TWELVE_ZEROS) - if l == -1: + ln = wholeMsg.find(TWELVE_ZEROS) + if ln == -1: raise error.ProtocolError('Cant locate digest placeholder') - wholeHead = wholeMsg[:l] - wholeTail = wholeMsg[l + 12:] + + wholeHead = wholeMsg[:ln] + wholeTail = wholeMsg[ln + 12:] # 7.3.1.2a extendedAuthKey = authKey.asNumbers() + FORTY_FOUR_ZEROS @@ -55,15 +56,13 @@ class HmacSha(base.AbstractAuthenticationService): # 7.3.1.2c k1 = univ.OctetString( - map(lambda x, y: x ^ y, extendedAuthKey, self.IPAD) - ) + map(lambda x, y: x ^ y, extendedAuthKey, self.IPAD)) # 7.3.1.2d -- no-op # 7.3.1.2e k2 = univ.OctetString( - map(lambda x, y: x ^ y, extendedAuthKey, self.OPAD) - ) + map(lambda x, y: x ^ y, extendedAuthKey, self.OPAD)) # 7.3.1.3 d1 = sha1(k1.asOctets() + wholeMsg).digest() @@ -80,15 +79,16 @@ class HmacSha(base.AbstractAuthenticationService): # 7.3.2.1 & 2 if len(authParameters) != 12: raise error.StatusInformation( - errorIndication=errind.authenticationError - ) + errorIndication=errind.authenticationError) # 7.3.2.3 - l = wholeMsg.find(authParameters.asOctets()) - if l == -1: + ln = wholeMsg.find(authParameters.asOctets()) + if ln == -1: raise error.ProtocolError('Cant locate digest in wholeMsg') - wholeHead = wholeMsg[:l] - wholeTail = wholeMsg[l + 12:] + + wholeHead = wholeMsg[:ln] + wholeTail = wholeMsg[ln + 12:] + authenticatedWholeMsg = wholeHead + TWELVE_ZEROS + wholeTail # 7.3.2.4a @@ -98,15 +98,13 @@ class HmacSha(base.AbstractAuthenticationService): # 7.3.2.4c k1 = univ.OctetString( - map(lambda x, y: x ^ y, extendedAuthKey, self.IPAD) - ) + map(lambda x, y: x ^ y, extendedAuthKey, self.IPAD)) # 7.3.2.4d --> no-op # 7.3.2.4e k2 = univ.OctetString( - map(lambda x, y: x ^ y, extendedAuthKey, self.OPAD) - ) + map(lambda x, y: x ^ y, extendedAuthKey, self.OPAD)) # 7.3.2.5a d1 = sha1(k1.asOctets() + authenticatedWholeMsg).digest() @@ -120,7 +118,6 @@ class HmacSha(base.AbstractAuthenticationService): # 7.3.2.6 if mac != authParameters: raise error.StatusInformation( - errorIndication=errind.authenticationFailure - ) + errorIndication=errind.authenticationFailure) return authenticatedWholeMsg diff --git a/pysnmp/proto/secmod/rfc3414/localkey.py b/pysnmp/proto/secmod/rfc3414/localkey.py index 144342fa..bc4faa91 100644 --- a/pysnmp/proto/secmod/rfc3414/localkey.py +++ b/pysnmp/proto/secmod/rfc3414/localkey.py @@ -12,9 +12,12 @@ from pyasn1.type import univ def hashPassphrase(passphrase, hashFunc): passphrase = univ.OctetString(passphrase).asOctets() + hasher = hashFunc() + ringBuffer = passphrase * (64 // len(passphrase) + 1) ringBufferLen = len(ringBuffer) + count = 0 mark = 0 @@ -25,9 +28,11 @@ def hashPassphrase(passphrase, hashFunc): mark = e else: - hasher.update( - ringBuffer[mark:ringBufferLen] + ringBuffer[0:e - ringBufferLen] - ) + chunk = ringBuffer[mark:ringBufferLen] + chunk += ringBuffer[0:e - ringBufferLen] + + hasher.update(chunk) + mark = e - ringBufferLen count += 1 @@ -36,11 +41,13 @@ def hashPassphrase(passphrase, hashFunc): def passwordToKey(passphrase, snmpEngineId, hashFunc): - return localizeKey(hashPassphrase(passphrase, hashFunc), snmpEngineId, hashFunc) + return localizeKey( + hashPassphrase(passphrase, hashFunc), snmpEngineId, hashFunc) def localizeKey(passKey, snmpEngineId, hashFunc): passKey = univ.OctetString(passKey).asOctets() + # noinspection PyDeprecation,PyCallingNonCallable return hashFunc(passKey + snmpEngineId.asOctets() + passKey).digest() diff --git a/pysnmp/proto/secmod/rfc3414/priv/des.py b/pysnmp/proto/secmod/rfc3414/priv/des.py index 5128a662..10058aeb 100644 --- a/pysnmp/proto/secmod/rfc3414/priv/des.py +++ b/pysnmp/proto/secmod/rfc3414/priv/des.py @@ -38,32 +38,39 @@ class Des(base.AbstractEncryptionService): def hashPassphrase(self, authProtocol, privKey): if authProtocol == hmacmd5.HmacMd5.SERVICE_ID: hashAlgo = md5 + elif authProtocol == hmacsha.HmacSha.SERVICE_ID: hashAlgo = sha1 + elif authProtocol in hmacsha2.HmacSha2.HASH_ALGORITHM: hashAlgo = hmacsha2.HmacSha2.HASH_ALGORITHM[authProtocol] + else: raise error.ProtocolError( - 'Unknown auth protocol %s' % (authProtocol,) - ) + 'Unknown auth protocol %s' % (authProtocol,)) + return localkey.hashPassphrase(privKey, hashAlgo) def localizeKey(self, authProtocol, privKey, snmpEngineID): if authProtocol == hmacmd5.HmacMd5.SERVICE_ID: hashAlgo = md5 + elif authProtocol == hmacsha.HmacSha.SERVICE_ID: hashAlgo = sha1 + elif authProtocol in hmacsha2.HmacSha2.HASH_ALGORITHM: hashAlgo = hmacsha2.HmacSha2.HASH_ALGORITHM[authProtocol] + else: raise error.ProtocolError( - 'Unknown auth protocol %s' % (authProtocol,) - ) + 'Unknown auth protocol %s' % (authProtocol,)) + localPrivKey = localkey.localizeKey(privKey, snmpEngineID, hashAlgo) + return localPrivKey[:self.KEY_SIZE] # 8.1.1.1 - def __getEncryptionKey(self, privKey, snmpEngineBoots): + def _getEncryptionKey(self, privKey, snmpEngineBoots): desKey = privKey[:8] preIV = privKey[8:16] @@ -77,42 +84,47 @@ class Des(base.AbstractEncryptionService): self.local_int >> 16 & 0xff, self.local_int >> 8 & 0xff, self.local_int & 0xff] + if self.local_int == 0xffffffff: self.local_int = 0 + else: self.local_int += 1 + iv = map(lambda x, y: x ^ y, salt, preIV.asNumbers()) + return (desKey.asOctets(), univ.OctetString(salt).asOctets(), - univ.OctetString(map(lambda x, y: x ^ y, salt, preIV.asNumbers())).asOctets()) + univ.OctetString(iv).asOctets()) @staticmethod - def __getDecryptionKey(privKey, salt): - return (privKey[:8].asOctets(), - univ.OctetString(map(lambda x, y: x ^ y, salt.asNumbers(), privKey[8:16].asNumbers())).asOctets()) + def _getDecryptionKey(privKey, salt): + iv = map(lambda x, y: x ^ y, salt.asNumbers(), + privKey[8:16].asNumbers()) + + return privKey[:8].asOctets(), univ.OctetString(iv).asOctets() # 8.2.4.1 def encryptData(self, encryptKey, privParameters, dataToEncrypt): snmpEngineBoots, snmpEngineTime, salt = privParameters # 8.3.1.1 - desKey, salt, iv = self.__getEncryptionKey( - encryptKey, snmpEngineBoots - ) + desKey, salt, iv = self._getEncryptionKey(encryptKey, snmpEngineBoots) # 8.3.1.2 privParameters = univ.OctetString(salt) # 8.1.1.2 - plaintext = dataToEncrypt + univ.OctetString((0,) * (8 - len(dataToEncrypt) % 8)).asOctets() + plaintext = dataToEncrypt + plaintext += univ.OctetString( + (0,) * (8 - len(dataToEncrypt) % 8)).asOctets() try: ciphertext = des.encrypt(plaintext, desKey, iv) except PysnmpCryptoError: raise error.StatusInformation( - errorIndication=errind.unsupportedPrivProtocol - ) + errorIndication=errind.unsupportedPrivProtocol) # 8.3.1.3 & 4 return univ.OctetString(ciphertext), privParameters @@ -124,19 +136,17 @@ class Des(base.AbstractEncryptionService): # 8.3.2.1 if len(salt) != 8: raise error.StatusInformation( - errorIndication=errind.decryptionError - ) + errorIndication=errind.decryptionError) # 8.3.2.2 no-op # 8.3.2.3 - desKey, iv = self.__getDecryptionKey(decryptKey, salt) + desKey, iv = self._getDecryptionKey(decryptKey, salt) # 8.3.2.4 -> 8.1.1.3 if len(encryptedData) % 8 != 0: raise error.StatusInformation( - errorIndication=errind.decryptionError - ) + errorIndication=errind.decryptionError) try: # 8.3.2.6 @@ -144,5 +154,4 @@ class Des(base.AbstractEncryptionService): except PysnmpCryptoError: raise error.StatusInformation( - errorIndication=errind.unsupportedPrivProtocol - ) + errorIndication=errind.unsupportedPrivProtocol) diff --git a/pysnmp/proto/secmod/rfc3414/service.py b/pysnmp/proto/secmod/rfc3414/service.py index f9bf056b..0a8f54e5 100644 --- a/pysnmp/proto/secmod/rfc3414/service.py +++ b/pysnmp/proto/secmod/rfc3414/service.py @@ -38,15 +38,26 @@ from pysnmp.smi.error import NoSuchInstanceError class UsmSecurityParameters(rfc1155.TypeCoercionHackMixIn, univ.Sequence): componentType = namedtype.NamedTypes( - namedtype.NamedType('msgAuthoritativeEngineId', univ.OctetString()), - namedtype.NamedType('msgAuthoritativeEngineBoots', - univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, 2147483647))), - namedtype.NamedType('msgAuthoritativeEngineTime', - univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, 2147483647))), - namedtype.NamedType('msgUserName', - univ.OctetString().subtype(subtypeSpec=constraint.ValueSizeConstraint(0, 32))), - namedtype.NamedType('msgAuthenticationParameters', univ.OctetString()), - namedtype.NamedType('msgPrivacyParameters', univ.OctetString()) + namedtype.NamedType( + 'msgAuthoritativeEngineId', univ.OctetString()), + namedtype.NamedType( + 'msgAuthoritativeEngineBoots', + univ.Integer().subtype( + subtypeSpec=constraint.ValueRangeConstraint(0, 2147483647))), + namedtype.NamedType( + 'msgAuthoritativeEngineTime', + univ.Integer().subtype( + subtypeSpec=constraint.ValueRangeConstraint(0, 2147483647))), + namedtype.NamedType( + 'msgUserName', + univ.OctetString().subtype( + subtypeSpec=constraint.ValueSizeConstraint(0, 32))), + namedtype.NamedType( + 'msgAuthenticationParameters', + univ.OctetString()), + namedtype.NamedType( + 'msgPrivacyParameters', + univ.OctetString()) ) @@ -56,10 +67,14 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): AUTH_SERVICES = { hmacmd5.HmacMd5.SERVICE_ID: hmacmd5.HmacMd5(), hmacsha.HmacSha.SERVICE_ID: hmacsha.HmacSha(), - hmacsha2.HmacSha2.SHA224_SERVICE_ID: hmacsha2.HmacSha2(hmacsha2.HmacSha2.SHA224_SERVICE_ID), - hmacsha2.HmacSha2.SHA256_SERVICE_ID: hmacsha2.HmacSha2(hmacsha2.HmacSha2.SHA256_SERVICE_ID), - hmacsha2.HmacSha2.SHA384_SERVICE_ID: hmacsha2.HmacSha2(hmacsha2.HmacSha2.SHA384_SERVICE_ID), - hmacsha2.HmacSha2.SHA512_SERVICE_ID: hmacsha2.HmacSha2(hmacsha2.HmacSha2.SHA512_SERVICE_ID), + hmacsha2.HmacSha2.SHA224_SERVICE_ID: hmacsha2.HmacSha2( + hmacsha2.HmacSha2.SHA224_SERVICE_ID), + hmacsha2.HmacSha2.SHA256_SERVICE_ID: hmacsha2.HmacSha2( + hmacsha2.HmacSha2.SHA256_SERVICE_ID), + hmacsha2.HmacSha2.SHA384_SERVICE_ID: hmacsha2.HmacSha2( + hmacsha2.HmacSha2.SHA384_SERVICE_ID), + hmacsha2.HmacSha2.SHA512_SERVICE_ID: hmacsha2.HmacSha2( + hmacsha2.HmacSha2.SHA512_SERVICE_ID), noauth.NoAuth.SERVICE_ID: noauth.NoAuth(), } @@ -76,21 +91,23 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): def __init__(self): AbstractSecurityModel.__init__(self) - self.__securityParametersSpec = UsmSecurityParameters() - self.__timeline = {} - self.__timelineExpQueue = {} - self.__expirationTimer = 0 - self.__paramsBranchId = -1 + self._securityParametersSpec = UsmSecurityParameters() + self._timeline = {} + self._timelineExpQueue = {} + self._expirationTimer = 0 + self._paramsBranchId = -1 - def __sec2usr(self, snmpEngine, securityName, securityEngineID=None): + def _sec2usr(self, snmpEngine, securityName, securityEngineID=None): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder - usmUserEngineID, = mibBuilder.importSymbols('SNMP-USER-BASED-SM-MIB', - 'usmUserEngineID') - if self.__paramsBranchId != usmUserEngineID.branchVersionId: + + usmUserEngineID, = mibBuilder.importSymbols( + 'SNMP-USER-BASED-SM-MIB', 'usmUserEngineID') + + if self._paramsBranchId != usmUserEngineID.branchVersionId: usmUserName, usmUserSecurityName = mibBuilder.importSymbols( 'SNMP-USER-BASED-SM-MIB', 'usmUserName', 'usmUserSecurityName') - self.__securityToUserMap = {} + self._securityToUserMap = {} nextMibNode = usmUserEngineID @@ -99,108 +116,138 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): nextMibNode = usmUserEngineID.getNextNode(nextMibNode.name) except NoSuchInstanceError: - self.__paramsBranchId = usmUserEngineID.branchVersionId + self._paramsBranchId = usmUserEngineID.branchVersionId + debug.logger & debug.FLAG_SM and debug.logger( - '_sec2usr: built snmpEngineId + securityName to userName map, version %s: %r' % ( - self.__paramsBranchId, self.__securityToUserMap)) + '_sec2usr: built snmpEngineId + securityName to ' + 'userName map, version %s: %r' % ( + self._paramsBranchId, self._securityToUserMap)) break instId = nextMibNode.name[len(usmUserSecurityName.name):] - __engineID = usmUserEngineID.getNode(usmUserEngineID.name + instId).syntax - __userName = usmUserName.getNode(usmUserName.name + instId).syntax - __securityName = usmUserSecurityName.getNode(usmUserSecurityName.name + instId).syntax + _engineID = usmUserEngineID.getNode( + usmUserEngineID.name + instId).syntax + _userName = usmUserName.getNode( + usmUserName.name + instId).syntax + _securityName = usmUserSecurityName.getNode( + usmUserSecurityName.name + instId).syntax - k = __engineID, __securityName + k = _engineID, _securityName # first (lesser) securityName wins - if k not in self.__securityToUserMap: - self.__securityToUserMap[k] = __userName + if k not in self._securityToUserMap: + self._securityToUserMap[k] = _userName if securityEngineID is None: - snmpEngineID, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') + snmpEngineID, = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') securityEngineID = snmpEngineID.syntax try: - userName = self.__securityToUserMap[(securityEngineID, securityName)] + userName = self._securityToUserMap[(securityEngineID, securityName)] + except KeyError: debug.logger & debug.FLAG_SM and debug.logger( - '_sec2usr: no entry exists for snmpEngineId %r, securityName %r' % (securityEngineID, securityName)) + '_sec2usr: no entry exists for snmpEngineId %r, securityName ' + '%r' % (securityEngineID, securityName)) raise NoSuchInstanceError() # emulate MIB lookup debug.logger & debug.FLAG_SM and debug.logger( - '_sec2usr: using userName %r for snmpEngineId %r, securityName %r' % ( - userName, securityEngineID, securityName)) + '_sec2usr: using userName %r for snmpEngineId %r, securityName ' + '%r' % (userName, securityEngineID, securityName)) return userName @staticmethod - def __getUserInfo(mibInstrumController, securityEngineID, userName): - usmUserEntry, = mibInstrumController.mibBuilder.importSymbols( - 'SNMP-USER-BASED-SM-MIB', 'usmUserEntry' - ) + def _getUserInfo(mibInstrumController, securityEngineID, userName): + mibBuilder = mibInstrumController.mibBuilder + + usmUserEntry, = mibBuilder.importSymbols( + 'SNMP-USER-BASED-SM-MIB', 'usmUserEntry') + tblIdx = usmUserEntry.getInstIdFromIndices(securityEngineID, userName) + # Get userName & securityName usmUserName = usmUserEntry.getNode(usmUserEntry.name + (2,) + tblIdx).syntax usmUserSecurityName = usmUserEntry.getNode(usmUserEntry.name + (3,) + tblIdx).syntax + # Get protocols usmUserAuthProtocol = usmUserEntry.getNode(usmUserEntry.name + (5,) + tblIdx).syntax usmUserPrivProtocol = usmUserEntry.getNode(usmUserEntry.name + (8,) + tblIdx).syntax + # Get keys - pysnmpUsmKeyEntry, = mibInstrumController.mibBuilder.importSymbols( - 'PYSNMP-USM-MIB', 'pysnmpUsmKeyEntry' - ) - pysnmpUsmKeyAuthLocalized = pysnmpUsmKeyEntry.getNode(pysnmpUsmKeyEntry.name + (1,) + tblIdx).syntax - pysnmpUsmKeyPrivLocalized = pysnmpUsmKeyEntry.getNode(pysnmpUsmKeyEntry.name + (2,) + tblIdx).syntax + pysnmpUsmKeyEntry, = mibBuilder.importSymbols( + 'PYSNMP-USM-MIB', 'pysnmpUsmKeyEntry') + + pysnmpUsmKeyAuthLocalized = pysnmpUsmKeyEntry.getNode( + pysnmpUsmKeyEntry.name + (1,) + tblIdx).syntax + pysnmpUsmKeyPrivLocalized = pysnmpUsmKeyEntry.getNode( + pysnmpUsmKeyEntry.name + (2,) + tblIdx).syntax + return (usmUserName, usmUserSecurityName, usmUserAuthProtocol, pysnmpUsmKeyAuthLocalized, usmUserPrivProtocol, pysnmpUsmKeyPrivLocalized) - def __cloneUserInfo(self, snmpEngine, securityEngineID, userName): + def _cloneUserInfo(self, snmpEngine, securityEngineID, userName): mibInstrumController = snmpEngine.msgAndPduDsp.mibInstrumController + mibBuilder = mibInstrumController.mibBuilder + + snmpEngineID, = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') - snmpEngineID, = mibInstrumController.mibBuilder.importSymbols( - '__SNMP-FRAMEWORK-MIB', 'snmpEngineID' - ) # Proto entry - usmUserEntry, = mibInstrumController.mibBuilder.importSymbols( - 'SNMP-USER-BASED-SM-MIB', 'usmUserEntry' - ) + usmUserEntry, = mibBuilder.importSymbols( + 'SNMP-USER-BASED-SM-MIB', 'usmUserEntry') + tblIdx1 = usmUserEntry.getInstIdFromIndices( - snmpEngineID.syntax, userName - ) + snmpEngineID.syntax, userName) + # Get proto protocols - usmUserName = usmUserEntry.getNode(usmUserEntry.name + (2,) + tblIdx1) - usmUserSecurityName = usmUserEntry.getNode(usmUserEntry.name + (3,) + tblIdx1) - usmUserCloneFrom = usmUserEntry.getNode(usmUserEntry.name + (4,) + tblIdx1) - usmUserAuthProtocol = usmUserEntry.getNode(usmUserEntry.name + (5,) + tblIdx1) - usmUserPrivProtocol = usmUserEntry.getNode(usmUserEntry.name + (8,) + tblIdx1) + usmUserName = usmUserEntry.getNode( + usmUserEntry.name + (2,) + tblIdx1) + usmUserSecurityName = usmUserEntry.getNode( + usmUserEntry.name + (3,) + tblIdx1) + usmUserCloneFrom = usmUserEntry.getNode( + usmUserEntry.name + (4,) + tblIdx1) + usmUserAuthProtocol = usmUserEntry.getNode( + usmUserEntry.name + (5,) + tblIdx1) + usmUserPrivProtocol = usmUserEntry.getNode( + usmUserEntry.name + (8,) + tblIdx1) + # Get proto keys - pysnmpUsmKeyEntry, = mibInstrumController.mibBuilder.importSymbols( - 'PYSNMP-USM-MIB', 'pysnmpUsmKeyEntry' - ) - pysnmpUsmKeyAuth = pysnmpUsmKeyEntry.getNode(pysnmpUsmKeyEntry.name + (3,) + tblIdx1) - pysnmpUsmKeyPriv = pysnmpUsmKeyEntry.getNode(pysnmpUsmKeyEntry.name + (4,) + tblIdx1) + pysnmpUsmKeyEntry, = mibBuilder.importSymbols( + 'PYSNMP-USM-MIB', 'pysnmpUsmKeyEntry') + + pysnmpUsmKeyAuth = pysnmpUsmKeyEntry.getNode( + pysnmpUsmKeyEntry.name + (3,) + tblIdx1) + pysnmpUsmKeyPriv = pysnmpUsmKeyEntry.getNode( + pysnmpUsmKeyEntry.name + (4,) + tblIdx1) # Create new row from proto values - tblIdx2 = usmUserEntry.getInstIdFromIndices(securityEngineID, userName) + tblIdx2 = usmUserEntry.getInstIdFromIndices( + securityEngineID, userName) # New inactive row mibInstrumController.writeMibObjects( - (usmUserEntry.name + (13,) + tblIdx2, 5), snmpEngine=snmpEngine - ) + (usmUserEntry.name + (13,) + tblIdx2, 5), snmpEngine=snmpEngine) # Set user&securityNames - usmUserEntry.getNode(usmUserEntry.name + (2,) + tblIdx2).syntax = usmUserName.syntax - usmUserEntry.getNode(usmUserEntry.name + (3,) + tblIdx2).syntax = usmUserSecurityName.syntax + usmUserEntry.getNode( + usmUserEntry.name + (2,) + tblIdx2).syntax = usmUserName.syntax + usmUserEntry.getNode( + usmUserEntry.name + (3,) + tblIdx2).syntax = usmUserSecurityName.syntax # Store a reference to original row - usmUserEntry.getNode(usmUserEntry.name + (4,) + tblIdx2).syntax = usmUserCloneFrom.syntax.clone(tblIdx1) + usmUserEntry.getNode( + usmUserEntry.name + (4,) + tblIdx2).syntax = usmUserCloneFrom.syntax.clone(tblIdx1) # Set protocols - usmUserEntry.getNode(usmUserEntry.name + (5,) + tblIdx2).syntax = usmUserAuthProtocol.syntax - usmUserEntry.getNode(usmUserEntry.name + (8,) + tblIdx2).syntax = usmUserPrivProtocol.syntax + usmUserEntry.getNode( + usmUserEntry.name + (5,) + tblIdx2).syntax = usmUserAuthProtocol.syntax + usmUserEntry.getNode( + usmUserEntry.name + (8,) + tblIdx2).syntax = usmUserPrivProtocol.syntax # Activate row mibInstrumController.writeMibObjects( @@ -208,98 +255,124 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): ) # Localize and set keys - pysnmpUsmKeyEntry, = mibInstrumController.mibBuilder.importSymbols( - 'PYSNMP-USM-MIB', 'pysnmpUsmKeyEntry' - ) + pysnmpUsmKeyEntry, = mibBuilder.importSymbols( + 'PYSNMP-USM-MIB', 'pysnmpUsmKeyEntry') pysnmpUsmKeyAuthLocalized = pysnmpUsmKeyEntry.getNode( - pysnmpUsmKeyEntry.name + (1,) + tblIdx2 - ) + pysnmpUsmKeyEntry.name + (1,) + tblIdx2) + if usmUserAuthProtocol.syntax in self.AUTH_SERVICES: localizeKey = self.AUTH_SERVICES[usmUserAuthProtocol.syntax].localizeKey - localAuthKey = localizeKey(pysnmpUsmKeyAuth.syntax, - securityEngineID) + localAuthKey = localizeKey( + pysnmpUsmKeyAuth.syntax, securityEngineID) + else: raise error.StatusInformation( - errorIndication=errind.unsupportedAuthProtocol - ) + errorIndication=errind.unsupportedAuthProtocol) + if localAuthKey is not None: pysnmpUsmKeyAuthLocalized.syntax = pysnmpUsmKeyAuthLocalized.syntax.clone(localAuthKey) + pysnmpUsmKeyPrivLocalized = pysnmpUsmKeyEntry.getNode( - pysnmpUsmKeyEntry.name + (2,) + tblIdx2 - ) + pysnmpUsmKeyEntry.name + (2,) + tblIdx2) + if usmUserPrivProtocol.syntax in self.PRIV_SERVICES: localizeKey = self.PRIV_SERVICES[usmUserPrivProtocol.syntax].localizeKey - localPrivKey = localizeKey(usmUserAuthProtocol.syntax, - pysnmpUsmKeyPriv.syntax, - securityEngineID) + localPrivKey = localizeKey( + usmUserAuthProtocol.syntax, pysnmpUsmKeyPriv.syntax, + securityEngineID) + else: - raise error.StatusInformation(errorIndication=errind.unsupportedPrivProtocol) + raise error.StatusInformation( + errorIndication=errind.unsupportedPrivProtocol) + if localPrivKey is not None: pysnmpUsmKeyPrivLocalized.syntax = pysnmpUsmKeyPrivLocalized.syntax.clone(localPrivKey) + return (usmUserName.syntax, usmUserSecurityName.syntax, usmUserAuthProtocol.syntax, pysnmpUsmKeyAuthLocalized.syntax, usmUserPrivProtocol.syntax, pysnmpUsmKeyPrivLocalized.syntax) - def __generateRequestOrResponseMsg(self, snmpEngine, - messageProcessingModel, - globalData, maxMessageSize, - securityModel, securityEngineID, - securityName, securityLevel, - scopedPDU, securityStateReference): + def _generateRequestOrResponseMsg(self, snmpEngine, + messageProcessingModel, + globalData, maxMessageSize, + securityModel, securityEngineID, + securityName, securityLevel, + scopedPDU, securityStateReference): + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder - snmpEngineID = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax + + snmpEngineID = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax # 3.1.1 if securityStateReference is not None: # 3.1.1a cachedSecurityData = self._cache.pop(securityStateReference) + usmUserName = cachedSecurityData['msgUserName'] + if 'usmUserSecurityName' in cachedSecurityData: usmUserSecurityName = cachedSecurityData['usmUserSecurityName'] + else: usmUserSecurityName = usmUserName + if 'usmUserAuthProtocol' in cachedSecurityData: usmUserAuthProtocol = cachedSecurityData['usmUserAuthProtocol'] + else: usmUserAuthProtocol = noauth.NoAuth.SERVICE_ID + if 'usmUserAuthKeyLocalized' in cachedSecurityData: usmUserAuthKeyLocalized = cachedSecurityData['usmUserAuthKeyLocalized'] + else: usmUserAuthKeyLocalized = None + if 'usmUserPrivProtocol' in cachedSecurityData: usmUserPrivProtocol = cachedSecurityData['usmUserPrivProtocol'] + else: usmUserPrivProtocol = nopriv.NoPriv.SERVICE_ID + if 'usmUserPrivKeyLocalized' in cachedSecurityData: usmUserPrivKeyLocalized = cachedSecurityData['usmUserPrivKeyLocalized'] + else: usmUserPrivKeyLocalized = None + securityEngineID = snmpEngineID - debug.logger & debug.FLAG_SM and debug.logger('__generateRequestOrResponseMsg: user info read from cache') + + debug.logger & debug.FLAG_SM and debug.logger( + '__generateRequestOrResponseMsg: user info read from cache') + elif securityName: # 3.1.1b try: (usmUserName, usmUserSecurityName, usmUserAuthProtocol, usmUserAuthKeyLocalized, usmUserPrivProtocol, - usmUserPrivKeyLocalized) = self.__getUserInfo( + usmUserPrivKeyLocalized) = self._getUserInfo( snmpEngine.msgAndPduDsp.mibInstrumController, securityEngineID, - self.__sec2usr(snmpEngine, securityName, securityEngineID) + self._sec2usr(snmpEngine, securityName, securityEngineID) ) - debug.logger & debug.FLAG_SM and debug.logger('__generateRequestOrResponseMsg: read user info') + debug.logger & debug.FLAG_SM and debug.logger( + '__generateRequestOrResponseMsg: read user info') except NoSuchInstanceError: - pysnmpUsmDiscovery, = mibBuilder.importSymbols('__PYSNMP-USM-MIB', 'pysnmpUsmDiscovery') + pysnmpUsmDiscovery, = mibBuilder.importSymbols( + '__PYSNMP-USM-MIB', 'pysnmpUsmDiscovery') + reportUnknownName = not pysnmpUsmDiscovery.syntax + if not reportUnknownName: try: (usmUserName, usmUserSecurityName, usmUserAuthProtocol, usmUserAuthKeyLocalized, usmUserPrivProtocol, - usmUserPrivKeyLocalized) = self.__cloneUserInfo( - snmpEngine, - securityEngineID, - self.__sec2usr(snmpEngine, securityName) + usmUserPrivKeyLocalized) = self._cloneUserInfo( + snmpEngine, securityEngineID, + self._sec2usr(snmpEngine, securityName) ) except NoSuchInstanceError: @@ -307,31 +380,40 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): if reportUnknownName: raise error.StatusInformation( - errorIndication=errind.unknownSecurityName - ) + errorIndication=errind.unknownSecurityName) - debug.logger & debug.FLAG_SM and debug.logger('__generateRequestOrResponseMsg: clone user info') + debug.logger & debug.FLAG_SM and debug.logger( + '__generateRequestOrResponseMsg: clone user info') except PyAsn1Error as exc: debug.logger & debug.FLAG_SM and debug.logger( '__generateRequestOrResponseMsg: %s' % exc) - snmpInGenErrs, = mibBuilder.importSymbols('__SNMPv2-MIB', 'snmpInGenErrs') + + snmpInGenErrs, = mibBuilder.importSymbols( + '__SNMPv2-MIB', 'snmpInGenErrs') snmpInGenErrs.syntax += 1 - raise error.StatusInformation( - errorIndication=errind.invalidMsg - ) + + raise error.StatusInformation(errorIndication=errind.invalidMsg) + else: # empty username used for engineID discovery usmUserName = usmUserSecurityName = null usmUserAuthProtocol = noauth.NoAuth.SERVICE_ID usmUserPrivProtocol = nopriv.NoPriv.SERVICE_ID + usmUserAuthKeyLocalized = usmUserPrivKeyLocalized = None - debug.logger & debug.FLAG_SM and debug.logger('__generateRequestOrResponseMsg: use empty USM data') + + debug.logger & debug.FLAG_SM and debug.logger( + '__generateRequestOrResponseMsg: use empty USM data') # noinspection PyUnboundLocalVariable debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: local usmUserName %r usmUserSecurityName %r usmUserAuthProtocol %s usmUserPrivProtocol %s securityEngineID %r securityName %r' % ( - usmUserName, usmUserSecurityName, usmUserAuthProtocol, usmUserPrivProtocol, securityEngineID, securityName)) + '__generateRequestOrResponseMsg: local usmUserName %r ' + 'usmUserSecurityName %r usmUserAuthProtocol %s ' + 'usmUserPrivProtocol %s securityEngineID %r ' + 'securityName %r' % ( + usmUserName, usmUserSecurityName, usmUserAuthProtocol, + usmUserPrivProtocol, securityEngineID, securityName)) msg = globalData @@ -340,22 +422,21 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): if (usmUserAuthProtocol == noauth.NoAuth.SERVICE_ID or usmUserPrivProtocol == nopriv.NoPriv.SERVICE_ID): raise error.StatusInformation( - errorIndication=errind.unsupportedSecurityLevel - ) + errorIndication=errind.unsupportedSecurityLevel) # 3.1.3 if securityLevel == 3 or securityLevel == 2: if usmUserAuthProtocol == noauth.NoAuth.SERVICE_ID: raise error.StatusInformation( - errorIndication=errind.unsupportedSecurityLevel - ) + errorIndication=errind.unsupportedSecurityLevel) - securityParameters = self.__securityParametersSpec + securityParameters = self._securityParametersSpec scopedPDUData = msg.setComponentByPosition(3).getComponentByPosition(3) + scopedPDUData.setComponentByPosition( - 0, scopedPDU, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 0, scopedPDU, verifyConstraints=False, matchTags=False, + matchConstraints=False) snmpEngineBoots = snmpEngineTime = 0 @@ -364,161 +445,180 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): # 3.1.6.b if pdu.tagSet in rfc3411.UNCONFIRMED_CLASS_PDUS: - (snmpEngineBoots, - snmpEngineTime) = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineBoots', 'snmpEngineTime') + snmpEngineBoots, snmpEngineTime = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineBoots', + 'snmpEngineTime') snmpEngineBoots = snmpEngineBoots.syntax snmpEngineTime = snmpEngineTime.syntax.clone() debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: read snmpEngineBoots, snmpEngineTime from LCD') + '__generateRequestOrResponseMsg: read snmpEngineBoots, ' + 'snmpEngineTime from LCD') # 3.1.6a - elif securityEngineID in self.__timeline: + elif securityEngineID in self._timeline: (snmpEngineBoots, snmpEngineTime, latestReceivedEngineTime, - latestUpdateTimestamp) = self.__timeline[securityEngineID] + latestUpdateTimestamp) = self._timeline[securityEngineID] debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: read snmpEngineBoots, snmpEngineTime from timeline') + '__generateRequestOrResponseMsg: read snmpEngineBoots, ' + 'snmpEngineTime from timeline') # 3.1.6.c else: debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: assuming zero snmpEngineBoots, snmpEngineTime') + '__generateRequestOrResponseMsg: assuming zero ' + 'snmpEngineBoots, snmpEngineTime') debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: use snmpEngineBoots %s snmpEngineTime %s for securityEngineID %r' % ( + '__generateRequestOrResponseMsg: use snmpEngineBoots %s ' + 'snmpEngineTime %s for securityEngineID %r' % ( snmpEngineBoots, snmpEngineTime, securityEngineID)) # 3.1.4a if securityLevel == 3: if usmUserPrivProtocol in self.PRIV_SERVICES: privHandler = self.PRIV_SERVICES[usmUserPrivProtocol] + else: raise error.StatusInformation( - errorIndication=errind.encryptionError - ) + errorIndication=errind.encryptionError) debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: scopedPDU %s' % scopedPDU.prettyPrint()) + '__generateRequestOrResponseMsg: scopedPDU ' + '%s' % scopedPDU.prettyPrint()) try: dataToEncrypt = encoder.encode(scopedPDU) except PyAsn1Error as exc: debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: scopedPDU serialization error: %s' % exc) + '__generateRequestOrResponseMsg: scopedPDU serialization ' + 'error: %s' % exc) raise error.StatusInformation( - errorIndication=errind.serializationError - ) + errorIndication=errind.serializationError) debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: scopedPDU encoded into %s' % debug.hexdump(dataToEncrypt)) + '__generateRequestOrResponseMsg: scopedPDU encoded into ' + '%s' % debug.hexdump(dataToEncrypt)) # noinspection PyUnboundLocalVariable - (encryptedData, - privParameters) = privHandler.encryptData( + encryptedData, privParameters = privHandler.encryptData( usmUserPrivKeyLocalized, - (snmpEngineBoots, snmpEngineTime, None), dataToEncrypt - ) + (snmpEngineBoots, snmpEngineTime, None), + dataToEncrypt) securityParameters.setComponentByPosition( - 5, privParameters, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 5, privParameters, verifyConstraints=False, matchTags=False, + matchConstraints=False) + scopedPDUData.setComponentByPosition( - 1, encryptedData, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 1, encryptedData, verifyConstraints=False, matchTags=False, + matchConstraints=False) debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: scopedPDU ciphered into %s' % debug.hexdump(encryptedData)) + '__generateRequestOrResponseMsg: scopedPDU ciphered into ' + '%s' % debug.hexdump(encryptedData)) # 3.1.4b elif securityLevel == 1 or securityLevel == 2: securityParameters.setComponentByPosition(5, '') - debug.logger & debug.FLAG_SM and debug.logger('__generateRequestOrResponseMsg: %s' % scopedPDUData.prettyPrint()) + debug.logger & debug.FLAG_SM and debug.logger( + '__generateRequestOrResponseMsg: %s' % scopedPDUData.prettyPrint()) # 3.1.5 securityParameters.setComponentByPosition( - 0, securityEngineID, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 0, securityEngineID, verifyConstraints=False, matchTags=False, + matchConstraints=False) + securityParameters.setComponentByPosition( - 1, snmpEngineBoots, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 1, snmpEngineBoots, verifyConstraints=False, matchTags=False, + matchConstraints=False) + securityParameters.setComponentByPosition( - 2, snmpEngineTime, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 2, snmpEngineTime, verifyConstraints=False, matchTags=False, + matchConstraints=False) # 3.1.7 securityParameters.setComponentByPosition( - 3, usmUserName, verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 3, usmUserName, verifyConstraints=False, matchTags=False, + matchConstraints=False) # 3.1.8a if securityLevel == 3 or securityLevel == 2: if usmUserAuthProtocol in self.AUTH_SERVICES: authHandler = self.AUTH_SERVICES[usmUserAuthProtocol] + else: raise error.StatusInformation( - errorIndication=errind.authenticationFailure - ) + errorIndication=errind.authenticationFailure) # extra-wild hack to facilitate BER substrate in-place re-write securityParameters.setComponentByPosition( - 4, '\x00' * authHandler.digestLength - ) + 4, '\x00' * authHandler.digestLength) debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: %s' % (securityParameters.prettyPrint(),)) + '__generateRequestOrResponseMsg: ' + '%s' % (securityParameters.prettyPrint(),)) try: - msg.setComponentByPosition(2, encoder.encode(securityParameters), verifyConstraints=False) + msg.setComponentByPosition( + 2, encoder.encode(securityParameters), + verifyConstraints=False) except PyAsn1Error as exc: debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: securityParameters serialization error: %s' % exc) + '__generateRequestOrResponseMsg: securityParameters ' + 'serialization error: %s' % exc) + raise error.StatusInformation( - errorIndication=errind.serializationError - ) + errorIndication=errind.serializationError) debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: auth outgoing msg: %s' % msg.prettyPrint()) + '__generateRequestOrResponseMsg: auth outgoing msg: ' + '%s' % msg.prettyPrint()) try: wholeMsg = encoder.encode(msg) except PyAsn1Error as exc: debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: msg serialization error: %s' % exc) + '__generateRequestOrResponseMsg: msg serialization ' + 'error: %s' % exc) + raise error.StatusInformation( - errorIndication=errind.serializationError - ) + errorIndication=errind.serializationError) # noinspection PyUnboundLocalVariable authenticatedWholeMsg = authHandler.authenticateOutgoingMsg( - usmUserAuthKeyLocalized, wholeMsg - ) + usmUserAuthKeyLocalized, wholeMsg) # 3.1.8b else: securityParameters.setComponentByPosition( - 4, '', verifyConstraints=False, matchTags=False, matchConstraints=False - ) + 4, '', verifyConstraints=False, matchTags=False, + matchConstraints=False) debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: %s' % (securityParameters.prettyPrint(),)) + '__generateRequestOrResponseMsg: ' + '%s' % (securityParameters.prettyPrint(),)) try: - msg.setComponentByPosition(2, encoder.encode(securityParameters), verifyConstraints=False, matchTags=False, matchConstraints=False) + msg.setComponentByPosition( + 2, encoder.encode(securityParameters), verifyConstraints=False, + matchTags=False, matchConstraints=False) except PyAsn1Error as exc: debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: secutiryParameters serialization error: %s' % exc) + '__generateRequestOrResponseMsg: securityParameters ' + 'serialization error: %s' % exc) + raise error.StatusInformation( - errorIndication=errind.serializationError - ) + errorIndication=errind.serializationError) try: debug.logger & debug.FLAG_SM and debug.logger( @@ -527,13 +627,16 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): except PyAsn1Error as exc: debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: msg serialization error: %s' % exc) + '__generateRequestOrResponseMsg: msg serialization error: ' + '%s' % exc) + raise error.StatusInformation( - errorIndication=errind.serializationError - ) + errorIndication=errind.serializationError) - debug.logger & debug.FLAG_SM and debug.logger('__generateRequestOrResponseMsg: %s outgoing msg: %s' % ( - securityLevel > 1 and "authenticated" or "plain", debug.hexdump(authenticatedWholeMsg))) + debug.logger & debug.FLAG_SM and debug.logger( + '__generateRequestOrResponseMsg: %s outgoing msg: ' + '%s' % (securityLevel > 1 and "authenticated" or + "plain", debug.hexdump(authenticatedWholeMsg))) # 3.1.9 return msg.getComponentByPosition(2), authenticatedWholeMsg @@ -542,88 +645,99 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): globalData, maxMessageSize, securityModel, securityEngineID, securityName, securityLevel, scopedPDU): - return self.__generateRequestOrResponseMsg(snmpEngine, - messageProcessingModel, - globalData, - maxMessageSize, - securityModel, - securityEngineID, - securityName, - securityLevel, - scopedPDU, - None) + + return self._generateRequestOrResponseMsg( + snmpEngine, messageProcessingModel, globalData, + maxMessageSize, securityModel, securityEngineID, + securityName, securityLevel, scopedPDU, None) def generateResponseMsg(self, snmpEngine, messageProcessingModel, globalData, maxMessageSize, securityModel, securityEngineID, securityName, securityLevel, scopedPDU, securityStateReference): - return self.__generateRequestOrResponseMsg( + + return self._generateRequestOrResponseMsg( snmpEngine, messageProcessingModel, globalData, maxMessageSize, securityModel, securityEngineID, - securityName, securityLevel, scopedPDU, securityStateReference + securityName, securityLevel, scopedPDU, + securityStateReference ) # 3.2 def processIncomingMsg(self, snmpEngine, messageProcessingModel, maxMessageSize, securityParameters, securityModel, securityLevel, wholeMsg, msg): + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder # 3.2.9 -- moved up here to be able to report # maxSizeResponseScopedPDU on error # (48 - maximum SNMPv3 header length) - maxSizeResponseScopedPDU = int(maxMessageSize) - len(securityParameters) - 48 + maxSizeResponseScopedPDU = (int(maxMessageSize) - + len(securityParameters) - 48) debug.logger & debug.FLAG_SM and debug.logger( - 'processIncomingMsg: securityParameters %s' % debug.hexdump(securityParameters)) + 'processIncomingMsg: securityParameters ' + '%s' % debug.hexdump(securityParameters)) # 3.2.1 securityParameters, rest = decoder.decode( - securityParameters, asn1Spec=self.__securityParametersSpec - ) + securityParameters, asn1Spec=self._securityParametersSpec) - debug.logger & debug.FLAG_SM and debug.logger('processIncomingMsg: %s' % (securityParameters.prettyPrint(),)) + debug.logger & debug.FLAG_SM and debug.logger( + 'processIncomingMsg: %s' % (securityParameters.prettyPrint(),)) if eoo.endOfOctets.isSameTypeWith(securityParameters): raise error.StatusInformation(errorIndication=errind.parseError) # 3.2.2 msgAuthoritativeEngineId = securityParameters.getComponentByPosition(0) + securityStateReference = self._cache.push( msgUserName=securityParameters.getComponentByPosition(3) ) debug.logger & debug.FLAG_SM and debug.logger( - 'processIncomingMsg: cache write securityStateReference %s by msgUserName %s' % ( - securityStateReference, securityParameters.getComponentByPosition(3))) + 'processIncomingMsg: cache write securityStateReference %s by ' + 'msgUserName %s' % (securityStateReference, + securityParameters.getComponentByPosition(3))) scopedPduData = msg.getComponentByPosition(3) # Used for error reporting - contextEngineId = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax + contextEngineId = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax contextName = null - snmpEngineID = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax + snmpEngineID = mibBuilder.importSymbols( + '__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax # 3.2.3 if (msgAuthoritativeEngineId != snmpEngineID and - msgAuthoritativeEngineId not in self.__timeline): + msgAuthoritativeEngineId not in self._timeline): + if (msgAuthoritativeEngineId and 4 < len(msgAuthoritativeEngineId) < 33): # 3.2.3a - cloned user when request was sent debug.logger & debug.FLAG_SM and debug.logger( - 'processIncomingMsg: non-synchronized securityEngineID %r' % (msgAuthoritativeEngineId,)) + 'processIncomingMsg: non-synchronized securityEngineID ' + '%r' % (msgAuthoritativeEngineId,)) + else: # 3.2.3b debug.logger & debug.FLAG_SM and debug.logger( 'processIncomingMsg: peer requested snmpEngineID discovery') + usmStatsUnknownEngineIDs, = mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnknownEngineIDs') usmStatsUnknownEngineIDs.syntax += 1 + debug.logger & debug.FLAG_SM and debug.logger( 'processIncomingMsg: null or malformed msgAuthoritativeEngineId') + pysnmpUsmDiscoverable, = mibBuilder.importSymbols( '__PYSNMP-USM-MIB', 'pysnmpUsmDiscoverable') + if pysnmpUsmDiscoverable.syntax: debug.logger & debug.FLAG_SM and debug.logger( 'processIncomingMsg: starting snmpEngineID discovery procedure') @@ -631,10 +745,11 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): # Report original contextName if scopedPduData.getName() != 'plaintext': debug.logger & debug.FLAG_SM and debug.logger( - 'processIncomingMsg: scopedPduData not plaintext %s' % scopedPduData.prettyPrint()) + 'processIncomingMsg: scopedPduData not plaintext ' + '%s' % scopedPduData.prettyPrint()) + raise error.StatusInformation( - errorIndication=errind.unknownEngineID - ) + errorIndication=errind.unknownEngineID) # 7.2.6.a.1 scopedPdu = scopedPduData.getComponent() @@ -653,16 +768,18 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): maxSizeResponseScopedPDU=maxSizeResponseScopedPDU ) else: - debug.logger & debug.FLAG_SM and debug.logger('processIncomingMsg: will not discover EngineID') + debug.logger & debug.FLAG_SM and debug.logger( + 'processIncomingMsg: will not discover EngineID') + # free securityStateReference XXX raise error.StatusInformation( - errorIndication=errind.unknownEngineID - ) + errorIndication=errind.unknownEngineID) msgUserName = securityParameters.getComponentByPosition(3) debug.logger & debug.FLAG_SM and debug.logger( - 'processIncomingMsg: read from securityParams msgAuthoritativeEngineId %r msgUserName %r' % ( + 'processIncomingMsg: read from securityParams ' + 'msgAuthoritativeEngineId %r msgUserName %r' % ( msgAuthoritativeEngineId, msgUserName)) if msgUserName: @@ -673,16 +790,17 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): usmUserAuthProtocol, usmUserAuthKeyLocalized, usmUserPrivProtocol, - usmUserPrivKeyLocalized) = self.__getUserInfo( + usmUserPrivKeyLocalized) = self._getUserInfo( snmpEngine.msgAndPduDsp.mibInstrumController, msgAuthoritativeEngineId, msgUserName ) - debug.logger & debug.FLAG_SM and debug.logger('processIncomingMsg: read user info from LCD') + debug.logger & debug.FLAG_SM and debug.logger( + 'processIncomingMsg: read user info from LCD') except NoSuchInstanceError: debug.logger & debug.FLAG_SM and debug.logger( - 'processIncomingMsg: unknown securityEngineID %r msgUserName %r' % ( - msgAuthoritativeEngineId, msgUserName)) + 'processIncomingMsg: unknown securityEngineID %r ' + 'msgUserName %r' % (msgAuthoritativeEngineId, msgUserName)) usmStatsUnknownUserNames, = mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnknownUserNames') @@ -701,10 +819,15 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): ) except PyAsn1Error as exc: - debug.logger & debug.FLAG_SM and debug.logger('processIncomingMsg: %s' % exc) - snmpInGenErrs, = mibBuilder.importSymbols('__SNMPv2-MIB', 'snmpInGenErrs') + debug.logger & debug.FLAG_SM and debug.logger( + 'processIncomingMsg: %s' % exc) + + snmpInGenErrs, = mibBuilder.importSymbols( + '__SNMPv2-MIB', 'snmpInGenErrs') snmpInGenErrs.syntax += 1 + raise error.StatusInformation(errorIndication=errind.invalidMsg) + else: # empty username used for engineID discovery usmUserName = usmUserSecurityName = null @@ -713,11 +836,14 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): usmUserAuthKeyLocalized = usmUserPrivKeyLocalized = None debug.logger & debug.FLAG_SM and debug.logger( - 'processIncomingMsg: now have usmUserName %r usmUserSecurityName %r usmUserAuthProtocol %r usmUserPrivProtocol %r for msgUserName %r' % ( - usmUserName, usmUserSecurityName, usmUserAuthProtocol, usmUserPrivProtocol, msgUserName)) + 'processIncomingMsg: now have usmUserName %r usmUserSecurityName ' + '%r usmUserAuthProtocol %r usmUserPrivProtocol %r for msgUserName ' + '%r' % (usmUserName, usmUserSecurityName, usmUserAuthProtocol, + usmUserPrivProtocol, msgUserName)) # 3.2.11 (moved up here to let Reports be authenticated & encrypted) self._cache.pop(securityStateReference) + securityStateReference = self._cache.push( msgUserName=securityParameters.getComponentByPosition(3), usmUserSecurityName=usmUserSecurityName, @@ -743,21 +869,24 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): privKey=usmUserPrivKeyLocalized) ) snmpEngine.observer.clearExecutionContext( - snmpEngine, 'rfc3414.processIncomingMsg' - ) + snmpEngine, 'rfc3414.processIncomingMsg') # 3.2.5 if msgAuthoritativeEngineId == snmpEngineID: # Authoritative SNMP engine: make sure securityLevel is sufficient badSecIndication = None + if securityLevel == 3: if usmUserAuthProtocol == noauth.NoAuth.SERVICE_ID: badSecIndication = 'authPriv wanted while auth not expected' + if usmUserPrivProtocol == nopriv.NoPriv.SERVICE_ID: badSecIndication = 'authPriv wanted while priv not expected' + elif securityLevel == 2: if usmUserAuthProtocol == noauth.NoAuth.SERVICE_ID: badSecIndication = 'authNoPriv wanted while auth not expected' + if usmUserPrivProtocol != nopriv.NoPriv.SERVICE_ID: # 4 (discovery phase always uses authenticated messages) if msgAuthoritativeEngineBoots or msgAuthoritativeEngineTime: @@ -766,15 +895,20 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): elif securityLevel == 1: if usmUserAuthProtocol != noauth.NoAuth.SERVICE_ID: badSecIndication = 'noAuthNoPriv wanted while auth expected' + if usmUserPrivProtocol != nopriv.NoPriv.SERVICE_ID: badSecIndication = 'noAuthNoPriv wanted while priv expected' + if badSecIndication: usmStatsUnsupportedSecLevels, = mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnsupportedSecLevels') + usmStatsUnsupportedSecLevels.syntax += 1 + debug.logger & debug.FLAG_SM and debug.logger( - 'processIncomingMsg: reporting inappropriate security level for user %s: %s' % ( - msgUserName, badSecIndication)) + 'processIncomingMsg: reporting inappropriate security ' + 'level for user %s: %s' % (msgUserName, badSecIndication)) + raise error.StatusInformation( errorIndication=errind.unsupportedSecurityLevel, oid=usmStatsUnsupportedSecLevels.name, @@ -791,22 +925,23 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): if securityLevel == 3 or securityLevel == 2: if usmUserAuthProtocol in self.AUTH_SERVICES: authHandler = self.AUTH_SERVICES[usmUserAuthProtocol] + else: raise error.StatusInformation( - errorIndication=errind.authenticationFailure - ) + errorIndication=errind.authenticationFailure) try: authHandler.authenticateIncomingMsg( usmUserAuthKeyLocalized, securityParameters.getComponentByPosition(4), - wholeMsg - ) + wholeMsg) except error.StatusInformation: usmStatsWrongDigests, = mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsWrongDigests') + usmStatsWrongDigests.syntax += 1 + raise error.StatusInformation( errorIndication=errind.authenticationFailure, oid=usmStatsWrongDigests.name, @@ -819,62 +954,81 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): maxSizeResponseScopedPDU=maxSizeResponseScopedPDU ) - debug.logger & debug.FLAG_SM and debug.logger('processIncomingMsg: incoming msg authenticated') + debug.logger & debug.FLAG_SM and debug.logger( + 'processIncomingMsg: incoming msg authenticated') # synchronize time with authed peer - self.__timeline[msgAuthoritativeEngineId] = ( + self._timeline[msgAuthoritativeEngineId] = ( securityParameters.getComponentByPosition(1), securityParameters.getComponentByPosition(2), securityParameters.getComponentByPosition(2), int(time.time()) ) - timerResolution = snmpEngine.transportDispatcher is None and 1.0 or snmpEngine.transportDispatcher.getTimerResolution() - expireAt = int(self.__expirationTimer + 300 / timerResolution) - if expireAt not in self.__timelineExpQueue: - self.__timelineExpQueue[expireAt] = [] - self.__timelineExpQueue[expireAt].append(msgAuthoritativeEngineId) + timerResolution = (snmpEngine.transportDispatcher is None and 1.0 or + snmpEngine.transportDispatcher.getTimerResolution()) + + expireAt = int(self._expirationTimer + 300 / timerResolution) + + if expireAt not in self._timelineExpQueue: + self._timelineExpQueue[expireAt] = [] + + self._timelineExpQueue[expireAt].append(msgAuthoritativeEngineId) debug.logger & debug.FLAG_SM and debug.logger( - 'processIncomingMsg: store timeline for securityEngineID %r' % (msgAuthoritativeEngineId,)) + 'processIncomingMsg: store timeline for securityEngineID ' + '%r' % (msgAuthoritativeEngineId,)) # 3.2.7 if securityLevel == 3 or securityLevel == 2: if msgAuthoritativeEngineId == snmpEngineID: # Authoritative SNMP engine: use local notion (SF bug #1649032) - (snmpEngineBoots, - snmpEngineTime) = mibBuilder.importSymbols( + snmpEngineBoots, snmpEngineTime = mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineBoots', 'snmpEngineTime') + snmpEngineBoots = snmpEngineBoots.syntax snmpEngineTime = snmpEngineTime.syntax.clone() + idleTime = 0 + debug.logger & debug.FLAG_SM and debug.logger( - 'processIncomingMsg: read snmpEngineBoots (%s), snmpEngineTime (%s) from LCD' % ( + 'processIncomingMsg: read snmpEngineBoots (%s), ' + 'snmpEngineTime (%s) from LCD' % ( snmpEngineBoots, snmpEngineTime)) + else: # Non-authoritative SNMP engine: use cached estimates - if msgAuthoritativeEngineId in self.__timeline: + if msgAuthoritativeEngineId in self._timeline: (snmpEngineBoots, snmpEngineTime, latestReceivedEngineTime, - latestUpdateTimestamp) = self.__timeline[ + latestUpdateTimestamp) = self._timeline[ msgAuthoritativeEngineId ] + # time passed since last talk with this SNMP engine idleTime = int(time.time()) - latestUpdateTimestamp + debug.logger & debug.FLAG_SM and debug.logger( - 'processIncomingMsg: read timeline snmpEngineBoots %s snmpEngineTime %s for msgAuthoritativeEngineId %r, idle time %s secs' % ( - snmpEngineBoots, snmpEngineTime, msgAuthoritativeEngineId, idleTime)) + 'processIncomingMsg: read timeline snmpEngineBoots %s ' + 'snmpEngineTime %s for msgAuthoritativeEngineId %r, ' + 'idle time %s secs' % (snmpEngineBoots, snmpEngineTime, + msgAuthoritativeEngineId, + idleTime)) else: raise error.ProtocolError('Peer SNMP engine info missing') # 3.2.7a if msgAuthoritativeEngineId == snmpEngineID: + if (snmpEngineBoots == 2147483647 or snmpEngineBoots != msgAuthoritativeEngineBoots or - abs(idleTime + int(snmpEngineTime) - int(msgAuthoritativeEngineTime)) > 150): + (abs(idleTime + int(snmpEngineTime) + - int(msgAuthoritativeEngineTime))) > 150): + usmStatsNotInTimeWindows, = mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsNotInTimeWindows') usmStatsNotInTimeWindows.syntax += 1 + raise error.StatusInformation( errorIndication=errind.notInTimeWindow, oid=usmStatsNotInTimeWindows.name, @@ -886,6 +1040,7 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): msgUserName=msgUserName, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU ) + # 3.2.7b else: # 3.2.7b.1 @@ -893,48 +1048,60 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): if (msgAuthoritativeEngineBoots > snmpEngineBoots or msgAuthoritativeEngineBoots == snmpEngineBoots and msgAuthoritativeEngineTime > latestReceivedEngineTime): - self.__timeline[msgAuthoritativeEngineId] = ( + self._timeline[msgAuthoritativeEngineId] = ( msgAuthoritativeEngineBoots, msgAuthoritativeEngineTime, msgAuthoritativeEngineTime, int(time.time()) ) - timerResolution = snmpEngine.transportDispatcher is None and 1.0 or snmpEngine.transportDispatcher.getTimerResolution() - expireAt = int(self.__expirationTimer + 300 / timerResolution) - if expireAt not in self.__timelineExpQueue: - self.__timelineExpQueue[expireAt] = [] - self.__timelineExpQueue[expireAt].append(msgAuthoritativeEngineId) + timerResolution = ( + snmpEngine.transportDispatcher is None and 1.0 or + snmpEngine.transportDispatcher.getTimerResolution()) + + expireAt = int(self._expirationTimer + 300 / timerResolution) + + if expireAt not in self._timelineExpQueue: + self._timelineExpQueue[expireAt] = [] + + self._timelineExpQueue[expireAt].append(msgAuthoritativeEngineId) debug.logger & debug.FLAG_SM and debug.logger( - 'processIncomingMsg: stored timeline msgAuthoritativeEngineBoots %s msgAuthoritativeEngineTime %s for msgAuthoritativeEngineId %r' % ( - msgAuthoritativeEngineBoots, msgAuthoritativeEngineTime, msgAuthoritativeEngineId)) + 'processIncomingMsg: stored timeline ' + 'msgAuthoritativeEngineBoots %s ' + 'msgAuthoritativeEngineTime %s for ' + 'msgAuthoritativeEngineId ' + '%r' % (msgAuthoritativeEngineBoots, + msgAuthoritativeEngineTime, + msgAuthoritativeEngineId)) # 3.2.7b.2 if (snmpEngineBoots == 2147483647 or msgAuthoritativeEngineBoots < snmpEngineBoots or msgAuthoritativeEngineBoots == snmpEngineBoots and - abs(idleTime + int(snmpEngineTime) - int(msgAuthoritativeEngineTime)) > 150): + (abs(idleTime + int(snmpEngineTime) + - int(msgAuthoritativeEngineTime))) > 150): + raise error.StatusInformation( errorIndication=errind.notInTimeWindow, - msgUserName=msgUserName - ) + msgUserName=msgUserName) # 3.2.8a if securityLevel == 3: if usmUserPrivProtocol in self.PRIV_SERVICES: privHandler = self.PRIV_SERVICES[usmUserPrivProtocol] + else: raise error.StatusInformation( errorIndication=errind.decryptionError, - msgUserName=msgUserName - ) + msgUserName=msgUserName) + encryptedPDU = scopedPduData.getComponentByPosition(1) + if encryptedPDU is None: # no ciphertext raise error.StatusInformation( errorIndication=errind.decryptionError, - msgUserName=msgUserName - ) + msgUserName=msgUserName) try: decryptedData = privHandler.decryptData( @@ -942,15 +1109,17 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): (securityParameters.getComponentByPosition(1), securityParameters.getComponentByPosition(2), securityParameters.getComponentByPosition(5)), - encryptedPDU - ) + encryptedPDU) + debug.logger & debug.FLAG_SM and debug.logger( - 'processIncomingMsg: PDU deciphered into %s' % debug.hexdump(decryptedData)) + 'processIncomingMsg: PDU deciphered into ' + '%s' % debug.hexdump(decryptedData)) except error.StatusInformation: usmStatsDecryptionErrors, = mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsDecryptionErrors') usmStatsDecryptionErrors.syntax += 1 + raise error.StatusInformation( errorIndication=errind.decryptionError, oid=usmStatsDecryptionErrors.name, @@ -962,31 +1131,32 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): msgUserName=msgUserName, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU ) - scopedPduSpec = scopedPduData.setComponentByPosition(0).getComponentByPosition(0) + scopedPduSpec = scopedPduData.setComponentByPosition( + 0).getComponentByPosition(0) + try: scopedPDU, rest = decoder.decode(decryptedData, asn1Spec=scopedPduSpec) except PyAsn1Error as exc: debug.logger & debug.FLAG_SM and debug.logger( 'processIncomingMsg: scopedPDU decoder failed %s' % exc) + raise error.StatusInformation( errorIndication=errind.decryptionError, - msgUserName=msgUserName - ) + msgUserName=msgUserName) if eoo.endOfOctets.isSameTypeWith(scopedPDU): raise error.StatusInformation( errorIndication=errind.decryptionError, - msgUserName=msgUserName - ) + msgUserName=msgUserName) + else: # 3.2.8b scopedPDU = scopedPduData.getComponentByPosition(0) if scopedPDU is None: # no plaintext raise error.StatusInformation( errorIndication=errind.decryptionError, - msgUserName=msgUserName - ) + msgUserName=msgUserName) debug.logger & debug.FLAG_SM and debug.logger( 'processIncomingMsg: scopedPDU decoded %s' % scopedPDU.prettyPrint()) @@ -995,7 +1165,8 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): securityName = usmUserSecurityName debug.logger & debug.FLAG_SM and debug.logger( - 'processIncomingMsg: cached msgUserName %s info by securityStateReference %s' % ( + 'processIncomingMsg: cached msgUserName %s info by ' + 'securityStateReference %s' % ( msgUserName, securityStateReference)) # Delayed to include details @@ -1003,6 +1174,7 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): usmStatsUnknownUserNames, = mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnknownUserNames') usmStatsUnknownUserNames.syntax += 1 + raise error.StatusInformation( errorIndication=errind.unknownSecurityName, oid=usmStatsUnknownUserNames.name, @@ -1021,14 +1193,18 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): return (msgAuthoritativeEngineId, securityName, scopedPDU, maxSizeResponseScopedPDU, securityStateReference) - def __expireTimelineInfo(self): - if self.__expirationTimer in self.__timelineExpQueue: - for engineIdKey in self.__timelineExpQueue[self.__expirationTimer]: - if engineIdKey in self.__timeline: - del self.__timeline[engineIdKey] - debug.logger & debug.FLAG_SM and debug.logger('__expireTimelineInfo: expiring %r' % (engineIdKey,)) - del self.__timelineExpQueue[self.__expirationTimer] - self.__expirationTimer += 1 + def _expireTimelineInfo(self): + if self._expirationTimer in self._timelineExpQueue: + + for engineIdKey in self._timelineExpQueue[self._expirationTimer]: + if engineIdKey in self._timeline: + del self._timeline[engineIdKey] + debug.logger & debug.FLAG_SM and debug.logger( + '__expireTimelineInfo: expiring %r' % (engineIdKey,)) + + del self._timelineExpQueue[self._expirationTimer] + + self._expirationTimer += 1 def receiveTimerTick(self, snmpEngine, timeNow): - self.__expireTimelineInfo() + self._expireTimelineInfo() diff --git a/pysnmp/proto/secmod/rfc3826/priv/aes.py b/pysnmp/proto/secmod/rfc3826/priv/aes.py index 56f69280..d000f8ed 100644 --- a/pysnmp/proto/secmod/rfc3826/priv/aes.py +++ b/pysnmp/proto/secmod/rfc3826/priv/aes.py @@ -38,66 +38,85 @@ class Aes(base.AbstractEncryptionService): local_int = random.randrange(0, 0xffffffffffffffff) # 3.1.2.1 - def __getEncryptionKey(self, privKey, snmpEngineBoots, snmpEngineTime): - salt = [self.local_int >> 56 & 0xff, - self.local_int >> 48 & 0xff, - self.local_int >> 40 & 0xff, - self.local_int >> 32 & 0xff, - self.local_int >> 24 & 0xff, - self.local_int >> 16 & 0xff, - self.local_int >> 8 & 0xff, - self.local_int & 0xff] + def _getEncryptionKey(self, privKey, snmpEngineBoots, snmpEngineTime): + salt = [ + self.local_int >> 56 & 0xff, + self.local_int >> 48 & 0xff, + self.local_int >> 40 & 0xff, + self.local_int >> 32 & 0xff, + self.local_int >> 24 & 0xff, + self.local_int >> 16 & 0xff, + self.local_int >> 8 & 0xff, + self.local_int & 0xff + ] if self.local_int == 0xffffffffffffffff: self.local_int = 0 + else: self.local_int += 1 - return self.__getDecryptionKey(privKey, snmpEngineBoots, snmpEngineTime, salt) + ( - univ.OctetString(salt).asOctets(),) + key, iv = self._getDecryptionKey( + privKey, snmpEngineBoots, snmpEngineTime, salt) + + return key, iv, univ.OctetString(salt).asOctets() + + def _getDecryptionKey(self, privKey, snmpEngineBoots, + snmpEngineTime, salt): - def __getDecryptionKey(self, privKey, snmpEngineBoots, - snmpEngineTime, salt): snmpEngineBoots, snmpEngineTime, salt = ( - int(snmpEngineBoots), int(snmpEngineTime), salt - ) + int(snmpEngineBoots), int(snmpEngineTime), salt) + + iv = [ + snmpEngineBoots >> 24 & 0xff, + snmpEngineBoots >> 16 & 0xff, + snmpEngineBoots >> 8 & 0xff, + snmpEngineBoots & 0xff, + snmpEngineTime >> 24 & 0xff, + snmpEngineTime >> 16 & 0xff, + snmpEngineTime >> 8 & 0xff, + snmpEngineTime & 0xff + ] - iv = [snmpEngineBoots >> 24 & 0xff, - snmpEngineBoots >> 16 & 0xff, - snmpEngineBoots >> 8 & 0xff, - snmpEngineBoots & 0xff, - snmpEngineTime >> 24 & 0xff, - snmpEngineTime >> 16 & 0xff, - snmpEngineTime >> 8 & 0xff, - snmpEngineTime & 0xff] + salt + iv += salt - return privKey[:self.KEY_SIZE].asOctets(), univ.OctetString(iv).asOctets() + key = privKey[:self.KEY_SIZE].asOctets() + iv = univ.OctetString(iv).asOctets() + + return key, iv def hashPassphrase(self, authProtocol, privKey): if authProtocol == hmacmd5.HmacMd5.SERVICE_ID: hashAlgo = md5 + elif authProtocol == hmacsha.HmacSha.SERVICE_ID: hashAlgo = sha1 + elif authProtocol in hmacsha2.HmacSha2.HASH_ALGORITHM: hashAlgo = hmacsha2.HmacSha2.HASH_ALGORITHM[authProtocol] + else: raise error.ProtocolError( - 'Unknown auth protocol %s' % (authProtocol,) - ) + 'Unknown auth protocol %s' % (authProtocol,)) + return localkey.hashPassphrase(privKey, hashAlgo) def localizeKey(self, authProtocol, privKey, snmpEngineID): if authProtocol == hmacmd5.HmacMd5.SERVICE_ID: hashAlgo = md5 + elif authProtocol == hmacsha.HmacSha.SERVICE_ID: hashAlgo = sha1 + elif authProtocol in hmacsha2.HmacSha2.HASH_ALGORITHM: hashAlgo = hmacsha2.HmacSha2.HASH_ALGORITHM[authProtocol] + else: raise error.ProtocolError( - 'Unknown auth protocol %s' % (authProtocol,) - ) + 'Unknown auth protocol %s' % (authProtocol,)) + localPrivKey = localkey.localizeKey(privKey, snmpEngineID, hashAlgo) + return localPrivKey[:self.KEY_SIZE] # 3.2.4.1 @@ -105,21 +124,20 @@ class Aes(base.AbstractEncryptionService): snmpEngineBoots, snmpEngineTime, salt = privParameters # 3.3.1.1 - aesKey, iv, salt = self.__getEncryptionKey( - encryptKey, snmpEngineBoots, snmpEngineTime - ) + aesKey, iv, salt = self._getEncryptionKey( + encryptKey, snmpEngineBoots, snmpEngineTime) # 3.3.1.3 # PyCrypto seems to require padding - dataToEncrypt = dataToEncrypt + univ.OctetString((0,) * (16 - len(dataToEncrypt) % 16)).asOctets() + padding = univ.OctetString((0,) * (16 - len(dataToEncrypt) % 16)) + dataToEncrypt += padding try: - ciphertext = aes.encrypt(dataToEncrypt, aesKey, iv) + ciphertext = aes.encrypt(dataToEncrypt.asOctets(), aesKey, iv) except PysnmpCryptoError: raise error.StatusInformation( - errorIndication=errind.unsupportedPrivProtocol - ) + errorIndication=errind.unsupportedPrivProtocol) # 3.3.1.4 return univ.OctetString(ciphertext), univ.OctetString(salt) @@ -131,16 +149,15 @@ class Aes(base.AbstractEncryptionService): # 3.3.2.1 if len(salt) != 8: raise error.StatusInformation( - errorIndication=errind.decryptionError - ) + errorIndication=errind.decryptionError) # 3.3.2.3 - aesKey, iv = self.__getDecryptionKey( - decryptKey, snmpEngineBoots, snmpEngineTime, salt - ) + aesKey, iv = self._getDecryptionKey( + decryptKey, snmpEngineBoots, snmpEngineTime, salt) # PyCrypto seems to require padding - encryptedData = encryptedData + univ.OctetString((0,) * (16 - len(encryptedData) % 16)).asOctets() + padding = univ.OctetString((0,) * (16 - len(encryptedData) % 16)) + encryptedData += padding try: # 3.3.2.4-6 @@ -148,5 +165,4 @@ class Aes(base.AbstractEncryptionService): except PysnmpCryptoError: raise error.StatusInformation( - errorIndication=errind.unsupportedPrivProtocol - ) + errorIndication=errind.unsupportedPrivProtocol) diff --git a/pysnmp/proto/secmod/rfc7860/auth/hmacsha2.py b/pysnmp/proto/secmod/rfc7860/auth/hmacsha2.py index 11dd79b3..267db682 100644 --- a/pysnmp/proto/secmod/rfc7860/auth/hmacsha2.py +++ b/pysnmp/proto/secmod/rfc7860/auth/hmacsha2.py @@ -19,19 +19,26 @@ except ImportError: sha224 = sha256 = sha384 = sha512 = NotAvailable() -from pyasn1.type import univ from pysnmp.proto.secmod.rfc3414.auth import base from pysnmp.proto.secmod.rfc3414 import localkey from pysnmp.proto import errind, error +from pyasn1.type import univ # 7.2.4 class HmacSha2(base.AbstractAuthenticationService): - SHA224_SERVICE_ID = (1, 3, 6, 1, 6, 3, 10, 1, 1, 4) # usmHMAC128SHA224AuthProtocol - SHA256_SERVICE_ID = (1, 3, 6, 1, 6, 3, 10, 1, 1, 5) # usmHMAC192SHA256AuthProtocol - SHA384_SERVICE_ID = (1, 3, 6, 1, 6, 3, 10, 1, 1, 6) # usmHMAC256SHA384AuthProtocol - SHA512_SERVICE_ID = (1, 3, 6, 1, 6, 3, 10, 1, 1, 7) # usmHMAC384SHA512AuthProtocol + # usmHMAC128SHA224AuthProtocol + SHA224_SERVICE_ID = (1, 3, 6, 1, 6, 3, 10, 1, 1, 4) + + # usmHMAC192SHA256AuthProtocol + SHA256_SERVICE_ID = (1, 3, 6, 1, 6, 3, 10, 1, 1, 5) + + # usmHMAC256SHA384AuthProtocol + SHA384_SERVICE_ID = (1, 3, 6, 1, 6, 3, 10, 1, 1, 6) + + # usmHMAC384SHA512AuthProtocol + SHA512_SERVICE_ID = (1, 3, 6, 1, 6, 3, 10, 1, 1, 7) KEY_LENGTH = { SHA224_SERVICE_ID: 28, @@ -59,39 +66,43 @@ class HmacSha2(base.AbstractAuthenticationService): def __init__(self, oid): if oid not in self.HASH_ALGORITHM: - raise error.ProtocolError('No SHA-2 authentication algorithm %s available' % (oid,)) - self.__hashAlgo = self.HASH_ALGORITHM[oid] - self.__digestLength = self.DIGEST_LENGTH[oid] - self.__placeHolder = univ.OctetString((0,) * self.__digestLength).asOctets() + raise error.ProtocolError( + 'No SHA-2 authentication algorithm %s available' % (oid,)) + + self._hashAlgo = self.HASH_ALGORITHM[oid] + self._digestLength = self.DIGEST_LENGTH[oid] + self._placeHolder = univ.OctetString( + (0,) * self._digestLength).asOctets() def hashPassphrase(self, authKey): - return localkey.hashPassphrase(authKey, self.__hashAlgo) + return localkey.hashPassphrase(authKey, self._hashAlgo) def localizeKey(self, authKey, snmpEngineID): - return localkey.localizeKey(authKey, snmpEngineID, self.__hashAlgo) + return localkey.localizeKey(authKey, snmpEngineID, self._hashAlgo) @property def digestLength(self): - return self.__digestLength + return self._digestLength # 7.3.1 def authenticateOutgoingMsg(self, authKey, wholeMsg): # 7.3.1.1 - location = wholeMsg.find(self.__placeHolder) + location = wholeMsg.find(self._placeHolder) if location == -1: - raise error.ProtocolError('Can\'t locate digest placeholder') + raise error.ProtocolError('Cannot locate digest placeholder') + wholeHead = wholeMsg[:location] - wholeTail = wholeMsg[location + self.__digestLength:] + wholeTail = wholeMsg[location + self._digestLength:] # 7.3.1.2, 7.3.1.3 try: - mac = hmac.new(authKey.asOctets(), wholeMsg, self.__hashAlgo) + mac = hmac.new(authKey.asOctets(), wholeMsg, self._hashAlgo) except errind.ErrorIndication as exc: raise error.StatusInformation(errorIndication=exc) # 7.3.1.4 - mac = mac.digest()[:self.__digestLength] + mac = mac.digest()[:self._digestLength] # 7.3.1.5 & 6 return wholeHead + mac + wholeTail @@ -99,33 +110,32 @@ class HmacSha2(base.AbstractAuthenticationService): # 7.3.2 def authenticateIncomingMsg(self, authKey, authParameters, wholeMsg): # 7.3.2.1 & 2 - if len(authParameters) != self.__digestLength: + if len(authParameters) != self._digestLength: raise error.StatusInformation( - errorIndication=errind.authenticationError - ) + errorIndication=errind.authenticationError) # 7.3.2.3 location = wholeMsg.find(authParameters.asOctets()) if location == -1: - raise error.ProtocolError('Can\'t locate digest in wholeMsg') + raise error.ProtocolError('Cannot locate digest in wholeMsg') + wholeHead = wholeMsg[:location] - wholeTail = wholeMsg[location + self.__digestLength:] - authenticatedWholeMsg = wholeHead + self.__placeHolder + wholeTail + wholeTail = wholeMsg[location + self._digestLength:] + authenticatedWholeMsg = wholeHead + self._placeHolder + wholeTail # 7.3.2.4 try: - mac = hmac.new(authKey.asOctets(), authenticatedWholeMsg, self.__hashAlgo) + mac = hmac.new(authKey.asOctets(), authenticatedWholeMsg, self._hashAlgo) except errind.ErrorIndication as exc: raise error.StatusInformation(errorIndication=exc) # 7.3.2.5 - mac = mac.digest()[:self.__digestLength] + mac = mac.digest()[:self._digestLength] # 7.3.2.6 if mac != authParameters: raise error.StatusInformation( - errorIndication=errind.authenticationFailure - ) + errorIndication=errind.authenticationFailure) return authenticatedWholeMsg diff --git a/pysnmp/smi/builder.py b/pysnmp/smi/builder.py index 9d75732b..513bc19a 100644 --- a/pysnmp/smi/builder.py +++ b/pysnmp/smi/builder.py @@ -33,25 +33,31 @@ from pysnmp import debug class __AbstractMibSource(object): def __init__(self, srcName): self._srcName = srcName - self.__magic = imp.get_magic() - self.__sfx = {} - self.__inited = None + self._magic = imp.get_magic() + self._sfx = {} + self._inited = None + for sfx, mode, typ in imp.get_suffixes(): - if typ not in self.__sfx: - self.__sfx[typ] = [] - self.__sfx[typ].append((sfx, len(sfx), mode)) - debug.logger & debug.FLAG_BLD and debug.logger('trying %s' % self) + if typ not in self._sfx: + self._sfx[typ] = [] + + self._sfx[typ].append((sfx, len(sfx), mode)) + + debug.logger & debug.FLAG_BLD and debug.logger( + 'trying %s' % self) def __repr__(self): return '%s(%r)' % (self.__class__.__name__, self._srcName) def _uniqNames(self, files): u = set() + for f in files: if f.startswith('__init__.'): continue + for typ in (imp.PY_SOURCE, imp.PY_COMPILED): - for sfx, sfxLen, mode in self.__sfx[typ]: + for sfx, sfxLen, mode in self._sfx[typ]: if f[-sfxLen:] == sfx: u.add(f[:-sfxLen]) return tuple(u) @@ -59,18 +65,23 @@ class __AbstractMibSource(object): # MibSource API follows def fullPath(self, f='', sfx=''): - return self._srcName + (f and (os.sep + f + sfx) or '') + if f: + return os.path.join(self._srcName, f) + sfx + + return self._srcName def init(self): - if self.__inited is None: - self.__inited = self._init() - if self.__inited is self: - self.__inited = True - if self.__inited is True: + if self._inited is None: + self._inited = self._init() + + if self._inited is self: + self._inited = True + + if self._inited is True: return self else: - return self.__inited + return self._inited def listdir(self): return self._listdir() @@ -78,54 +89,62 @@ class __AbstractMibSource(object): def read(self, f): pycTime = pyTime = -1 - for pycSfx, pycSfxLen, pycMode in self.__sfx[imp.PY_COMPILED]: + for pycSfx, pycSfxLen, pycMode in self._sfx[imp.PY_COMPILED]: + + pycFile = f + pycSfx + try: - pycData, pycPath = self._getData(f + pycSfx, pycMode) + pycData, pycPath = self._getData(pycFile, pycMode) except IOError as exc: if ENOENT == -1 or exc.errno == ENOENT: debug.logger & debug.FLAG_BLD and debug.logger( - 'file %s access error: %s' % (f + pycSfx, exc) - ) + 'file %s access error: %s' % (pycFile, exc)) else: - raise error.MibLoadError('MIB file %s access error: %s' % (f + pycSfx, exc)) + raise error.MibLoadError( + 'MIB file %s access error: %s' % (pycFile, exc)) else: - if self.__magic == pycData[:4]: + if self._magic == pycData[:4]: pycData = pycData[4:] pycTime = struct.unpack('= pyTime: return marshal.loads(pycData), pycSfx if pyTime != -1: - modData, pyPath = self._getData(f + pySfx, pyMode) + modData, pyPath = self._getData(pyFile, pyMode) return compile(modData, pyPath, 'exec'), pyPath raise IOError(ENOENT, 'No suitable module found', f) @@ -147,16 +166,21 @@ class __AbstractMibSource(object): class ZipMibSource(__AbstractMibSource): def _init(self): try: - p = __import__(self._srcName, globals(), locals(), ['__init__']) - if hasattr(p, '__loader__') and hasattr(p.__loader__, '_files'): - self.__loader = p.__loader__ + mod = __import__( + self._srcName, globals(), locals(), ['__init__']) + + if (hasattr(mod, '__loader__') and + hasattr(mod.__loader__, '_files')): + self.__loader = mod.__loader__ self._srcName = self._srcName.replace('.', os.sep) return self - elif hasattr(p, '__file__'): + + elif hasattr(mod, '__file__'): # Dir relative to PYTHONPATH - return DirMibSource(os.path.split(p.__file__)[0]).init() + return DirMibSource(os.path.split(mod.__file__)[0]).init() + else: - raise error.MibLoadError('%s access error' % (p,)) + raise error.MibLoadError('%s access error' % (mod,)) except ImportError: # Dir relative to CWD @@ -176,33 +200,40 @@ class ZipMibSource(__AbstractMibSource): return time.mktime(t) def _listdir(self): - l = [] + dirs = [] + # noinspection PyProtectedMember - for f in self.__loader._files.keys(): - d, f = os.path.split(f) - if d == self._srcName: - l.append(f) - return tuple(self._uniqNames(l)) + for path in self.__loader._files: + dr, fl = os.path.split(path) + if dr == self._srcName: + dirs.append(fl) + + return tuple(self._uniqNames(dirs)) def _getTimestamp(self, f): - p = os.path.join(self._srcName, f) + path = os.path.join(self._srcName, f) + # noinspection PyProtectedMember - if p in self.__loader._files: + if path in self.__loader._files: # noinspection PyProtectedMember return self._parseDosTime( - self.__loader._files[p][6], self.__loader._files[p][5] + self.__loader._files[path][6], self.__loader._files[path][5] ) + else: - raise IOError(ENOENT, 'No such file in ZIP archive', p) + raise IOError(ENOENT, 'No such file in ZIP archive', path) def _getData(self, f, mode=None): - p = os.path.join(self._srcName, f) + path = os.path.join(self._srcName, f) + try: - return self.__loader.get_data(p), p + return self.__loader.get_data(path), path # ZIP code seems to return all kinds of errors except Exception as exc: - raise IOError(ENOENT, 'File or ZIP archive %s access error: %s' % (p, exc)) + raise IOError( + ENOENT, 'File or ZIP archive %s access ' + 'error: %s' % (path, exc)) class DirMibSource(__AbstractMibSource): @@ -213,33 +244,35 @@ class DirMibSource(__AbstractMibSource): def _listdir(self): try: return self._uniqNames(os.listdir(self._srcName)) + except OSError as exc: debug.logger & debug.FLAG_BLD and debug.logger( 'listdir() failed for %s: %s' % (self._srcName, exc)) return () def _getTimestamp(self, f): - p = os.path.join(self._srcName, f) + path = os.path.join(self._srcName, f) try: - return os.stat(p)[8] + return os.stat(path)[8] except OSError as exc: - raise IOError(ENOENT, 'No such file: %s' % exc, p) + raise IOError(ENOENT, 'No such file: %s' % exc, path) + + def _getData(self, fl, mode): + path = os.path.join(self._srcName, '*') - def _getData(self, f, mode): - p = os.path.join(self._srcName, '*') try: - if f in os.listdir(self._srcName): # make FS case-sensitive - p = os.path.join(self._srcName, f) - fp = open(p, mode) + if fl in os.listdir(self._srcName): # make FS case-sensitive + path = os.path.join(self._srcName, fl) + fp = open(path, mode) data = fp.read() fp.close() - return data, p + return data, path except (IOError, OSError) as exc: - msg = 'File or directory %s access error: %s' % (p, exc) + msg = 'File or directory %s access error: %s' % (path, exc) else: - msg = 'No such file or directory: %s' % p + msg = 'No such file or directory: %s' % path raise IOError(ENOENT, msg) @@ -260,91 +293,108 @@ class MibBuilder(object): def __init__(self): self.lastBuildId = self._autoName = 0 + sources = [] + for ev in 'PYSNMP_MIB_PKGS', 'PYSNMP_MIB_DIRS', 'PYSNMP_MIB_DIR': if ev in os.environ: for m in os.environ[ev].split(os.pathsep): sources.append(ZipMibSource(m)) + if not sources and self.DEFAULT_MISC_MIBS: for m in self.DEFAULT_MISC_MIBS.split(os.pathsep): sources.append(ZipMibSource(m)) + for m in self.DEFAULT_CORE_MIBS.split(os.pathsep): sources.insert(0, ZipMibSource(m)) + self.mibSymbols = {} - self.__mibSources = [] - self.__modSeen = {} - self.__modPathsSeen = set() - self.__mibCompiler = None + self._mibSources = [] + self._modSeen = {} + self._modPathsSeen = set() + self._mibCompiler = None + self.setMibSources(*sources) # MIB compiler management def getMibCompiler(self): - return self.__mibCompiler + return self._mibCompiler def setMibCompiler(self, mibCompiler, destDir): self.addMibSources(DirMibSource(destDir)) - self.__mibCompiler = mibCompiler + self._mibCompiler = mibCompiler return self # MIB modules management def addMibSources(self, *mibSources): - self.__mibSources.extend([s.init() for s in mibSources]) - debug.logger & debug.FLAG_BLD and debug.logger('addMibSources: new MIB sources %s' % (self.__mibSources,)) + self._mibSources.extend([s.init() for s in mibSources]) + + debug.logger & debug.FLAG_BLD and debug.logger( + 'addMibSources: new MIB sources %s' % (self._mibSources,)) def setMibSources(self, *mibSources): - self.__mibSources = [s.init() for s in mibSources] - debug.logger & debug.FLAG_BLD and debug.logger('setMibSources: new MIB sources %s' % (self.__mibSources,)) + self._mibSources = [s.init() for s in mibSources] + + debug.logger & debug.FLAG_BLD and debug.logger( + 'setMibSources: new MIB sources %s' % (self._mibSources,)) def getMibSources(self): - return tuple(self.__mibSources) + return tuple(self._mibSources) def loadModule(self, modName, **userCtx): """Load and execute MIB modules as Python code""" - for mibSource in self.__mibSources: - debug.logger & debug.FLAG_BLD and debug.logger('loadModule: trying %s at %s' % (modName, mibSource)) + for mibSource in self._mibSources: + debug.logger & debug.FLAG_BLD and debug.logger( + 'loadModule: trying %s at %s' % (modName, mibSource)) + try: codeObj, sfx = mibSource.read(modName) except IOError as exc: debug.logger & debug.FLAG_BLD and debug.logger( - 'loadModule: read %s from %s failed: %s' % (modName, mibSource, exc)) + 'loadModule: read %s from %s failed: ' + '%s' % (modName, mibSource, exc)) continue modPath = mibSource.fullPath(modName, sfx) - if modPath in self.__modPathsSeen: - debug.logger & debug.FLAG_BLD and debug.logger('loadModule: seen %s' % modPath) + if modPath in self._modPathsSeen: + debug.logger & debug.FLAG_BLD and debug.logger( + 'loadModule: seen %s' % modPath) break else: - self.__modPathsSeen.add(modPath) + self._modPathsSeen.add(modPath) - debug.logger & debug.FLAG_BLD and debug.logger('loadModule: evaluating %s' % modPath) + debug.logger & debug.FLAG_BLD and debug.logger( + 'loadModule: evaluating %s' % modPath) - g = {'mibBuilder': self, 'userCtx': userCtx} + g = {'mibBuilder': self, + 'userCtx': userCtx} try: exec(codeObj, g) except Exception: - self.__modPathsSeen.remove(modPath) + self._modPathsSeen.remove(modPath) raise error.MibLoadError( - 'MIB module \'%s\' load error: %s' % (modPath, traceback.format_exception(*sys.exc_info())) - ) + 'MIB module "%s" load error: ' + '%s' % (modPath, traceback.format_exception(*sys.exc_info()))) - self.__modSeen[modName] = modPath + self._modSeen[modName] = modPath - debug.logger & debug.FLAG_BLD and debug.logger('loadModule: loaded %s' % modPath) + debug.logger & debug.FLAG_BLD and debug.logger( + 'loadModule: loaded %s' % modPath) break - if modName not in self.__modSeen: + if modName not in self._modSeen: raise error.MibNotFoundError( - 'MIB file \"%s\" not found in search path (%s)' % ( - modName and modName + ".py[co]", ', '.join([str(x) for x in self.__mibSources])) - ) + 'MIB file "%s" not found in search path ' + '(%s)' % (modName and modName + ".py[co]", ', '.join( + [str(x) for x in self._mibSources]))) return self @@ -353,28 +403,36 @@ class MibBuilder(object): # Build a list of available modules if not modNames: modNames = {} - for mibSource in self.__mibSources: + + for mibSource in self._mibSources: for modName in mibSource.listdir(): modNames[modName] = None + modNames = list(modNames) if not modNames: raise error.MibNotFoundError( - 'No MIB module to load at %s' % (self,) - ) + 'No MIB module to load at %s' % (self,)) for modName in modNames: try: self.loadModule(modName, **userCtx) except error.MibNotFoundError: - if self.__mibCompiler: - debug.logger & debug.FLAG_BLD and debug.logger('loadModules: calling MIB compiler for %s' % modName) - status = self.__mibCompiler.compile(modName, genTexts=self.loadTexts) - errs = '; '.join([hasattr(x, 'error') and str(x.error) or x for x in status.values() if - x in ('failed', 'missing')]) + if self._mibCompiler: + debug.logger & debug.FLAG_BLD and debug.logger( + 'loadModules: calling MIB compiler for %s' % modName) + + status = self._mibCompiler.compile(modName, genTexts=self.loadTexts) + + errs = '; '.join( + hasattr(x, 'error') and str(x.error) or x + for x in status.values() + if x in ('failed', 'missing')) + if errs: - raise error.MibNotFoundError('%s compilation error(s): %s' % (modName, errs)) + raise error.MibNotFoundError( + '%s compilation error(s): %s' % (modName, errs)) # compilation succeeded, MIB might load now self.loadModule(modName, **userCtx) @@ -383,84 +441,103 @@ class MibBuilder(object): def unloadModules(self, *modNames): if not modNames: - modNames = list(self.mibSymbols.keys()) + modNames = list(self.mibSymbols) + for modName in modNames: if modName not in self.mibSymbols: raise error.MibNotFoundError( - 'No module %s at %s' % (modName, self) - ) + 'No module %s at %s' % (modName, self)) + self.unexportSymbols(modName) - self.__modPathsSeen.remove(self.__modSeen[modName]) - del self.__modSeen[modName] - debug.logger & debug.FLAG_BLD and debug.logger('unloadModules: %s' % modName) + self._modPathsSeen.remove(self._modSeen[modName]) + + del self._modSeen[modName] + + debug.logger & debug.FLAG_BLD and debug.logger( + 'unloadModules: %s' % modName) return self def importSymbols(self, modName, *symNames, **userCtx): if not modName: raise error.SmiError( - 'importSymbols: empty MIB module name' - ) - r = () + 'importSymbols: empty MIB module name') + + symbols = [] + for symName in symNames: if modName not in self.mibSymbols: self.loadModules(modName, **userCtx) + if modName not in self.mibSymbols: raise error.MibNotFoundError( - 'No module %s loaded at %s' % (modName, self) - ) + 'No module %s loaded at %s' % (modName, self)) + if symName not in self.mibSymbols[modName]: raise error.SmiError( - 'No symbol %s::%s at %s' % (modName, symName, self) - ) - r = r + (self.mibSymbols[modName][symName],) - return r + 'No symbol %s::%s at %s' % (modName, symName, self)) + + symbols.append(self.mibSymbols[modName][symName]) + + return symbols def exportSymbols(self, modName, *anonymousSyms, **namedSyms): if modName not in self.mibSymbols: self.mibSymbols[modName] = {} + mibSymbols = self.mibSymbols[modName] for symObj in anonymousSyms: debug.logger & debug.FLAG_BLD and debug.logger( - 'exportSymbols: anonymous symbol %s::__pysnmp_%ld' % (modName, self._autoName)) + 'exportSymbols: anonymous symbol %s::' + '__pysnmp_%ld' % (modName, self._autoName)) + mibSymbols['__pysnmp_%ld' % self._autoName] = symObj + self._autoName += 1 + for symName, symObj in namedSyms.items(): if symName in mibSymbols: raise error.SmiError( - 'Symbol %s already exported at %s' % (symName, modName) - ) + 'Symbol %s already exported at %s' % (symName, modName)) + + if (symName != self.moduleID and + not isinstance(symObj, classTypes)): - if symName != self.moduleID and \ - not isinstance(symObj, classTypes): label = symObj.getLabel() + if label: symName = label + else: symObj.setLabel(symName) mibSymbols[symName] = symObj - debug.logger & debug.FLAG_BLD and debug.logger('exportSymbols: symbol %s::%s' % (modName, symName)) + debug.logger & debug.FLAG_BLD and debug.logger( + 'exportSymbols: symbol %s::%s' % (modName, symName)) self.lastBuildId += 1 def unexportSymbols(self, modName, *symNames): if modName not in self.mibSymbols: raise error.SmiError('No module %s at %s' % (modName, self)) + mibSymbols = self.mibSymbols[modName] + if not symNames: symNames = list(mibSymbols.keys()) + for symName in symNames: if symName not in mibSymbols: raise error.SmiError( - 'No symbol %s::%s at %s' % (modName, symName, self) - ) + 'No symbol %s::%s at %s' % (modName, symName, self)) + del mibSymbols[symName] - debug.logger & debug.FLAG_BLD and debug.logger('unexportSymbols: symbol %s::%s' % (modName, symName)) + debug.logger & debug.FLAG_BLD and debug.logger( + 'unexportSymbols: symbol %s::%s' % (modName, symName)) if not self.mibSymbols[modName]: del self.mibSymbols[modName] diff --git a/pysnmp/smi/compiler.py b/pysnmp/smi/compiler.py index 231685f8..6c4d3d11 100644 --- a/pysnmp/smi/compiler.py +++ b/pysnmp/smi/compiler.py @@ -33,9 +33,11 @@ except ImportError as exc: def addMibCompilerDecorator(errorMsg): + def addMibCompiler(mibBuilder, **kwargs): if not kwargs.get('ifAvailable'): - raise error.SmiError('MIB compiler not available: %s' % errorMsg) + raise error.SmiError( + 'MIB compiler not available: %s' % errorMsg) return addMibCompiler @@ -48,18 +50,25 @@ else: if kwargs.get('ifNotAdded') and mibBuilder.getMibCompiler(): return - compiler = MibCompiler(parserFactory(**smiV1Relaxed)(), - PySnmpCodeGen(), - PyFileWriter(kwargs.get('destination') or DEFAULT_DEST)) + compiler = MibCompiler( + parserFactory(**smiV1Relaxed)(), + PySnmpCodeGen(), + PyFileWriter(kwargs.get('destination') or DEFAULT_DEST)) + + compiler.addSources( + *getReadersFromUrls(*kwargs.get('sources') or DEFAULT_SOURCES)) + + compiler.addSearchers( + StubSearcher(*baseMibs)) - compiler.addSources(*getReadersFromUrls(*kwargs.get('sources') or DEFAULT_SOURCES)) + compiler.addSearchers( + *[PyPackageSearcher(x.fullPath()) for x in mibBuilder.getMibSources()]) - compiler.addSearchers(StubSearcher(*baseMibs)) - compiler.addSearchers(*[PyPackageSearcher(x.fullPath()) for x in mibBuilder.getMibSources()]) - compiler.addBorrowers(*[PyFileBorrower(x, genTexts=mibBuilder.loadTexts) for x in - getReadersFromUrls(*kwargs.get('borrowers') or DEFAULT_BORROWERS, - lowcaseMatching=False)]) + compiler.addBorrowers( + *[PyFileBorrower(x, genTexts=mibBuilder.loadTexts) + for x in getReadersFromUrls( + *kwargs.get('borrowers') or DEFAULT_BORROWERS, + lowcaseMatching=False)]) mibBuilder.setMibCompiler( - compiler, kwargs.get('destination') or DEFAULT_DEST - ) + compiler, kwargs.get('destination') or DEFAULT_DEST) diff --git a/pysnmp/smi/error.py b/pysnmp/smi/error.py index 87909b1e..1322a2c5 100644 --- a/pysnmp/smi/error.py +++ b/pysnmp/smi/error.py @@ -23,25 +23,25 @@ class MibNotFoundError(MibLoadError): class MibOperationError(SmiError): def __init__(self, **kwargs): - self.__outArgs = kwargs + self._outArgs = kwargs def __str__(self): - return '%s(%s)' % (self.__class__.__name__, self.__outArgs) + return '%s(%s)' % (self.__class__.__name__, self._outArgs) def __getitem__(self, key): - return self.__outArgs[key] + return self._outArgs[key] def __contains__(self, key): - return key in self.__outArgs + return key in self._outArgs def get(self, key, defVal=None): - return self.__outArgs.get(key, defVal) + return self._outArgs.get(key, defVal) def keys(self): - return self.__outArgs.keys() + return self._outArgs.keys() def update(self, d): - self.__outArgs.update(d) + self._outArgs.update(d) # Aligned with SNMPv2 PDU error-status values diff --git a/pysnmp/smi/indices.py b/pysnmp/smi/indices.py index 677ac97c..f55f7e6a 100644 --- a/pysnmp/smi/indices.py +++ b/pysnmp/smi/indices.py @@ -11,45 +11,50 @@ class OrderedDict(dict): """Ordered dictionary used for indices""" def __init__(self, *args, **kwargs): - self.__keys = [] - self.__dirty = True super(OrderedDict, self).__init__() + + self._keys = [] + self._dirty = True + self._keysLens = [] + if args: self.update(*args) + if kwargs: self.update(**kwargs) def __setitem__(self, key, value): super(OrderedDict, self).__setitem__(key, value) - if key not in self.__keys: - self.__keys.append(key) - self.__dirty = True + if key not in self._keys: + self._keys.append(key) + self._dirty = True def __delitem__(self, key): super(OrderedDict, self).__delitem__(key) - if key in self.__keys: - self.__keys.remove(key) - self.__dirty = True + if key in self._keys: + self._keys.remove(key) + self._dirty = True def clear(self): super(OrderedDict, self).clear() - self.__keys = [] - self.__dirty = True + self._keys = [] + self._dirty = True def keys(self): - if self.__dirty: - self.__order() - return list(self.__keys) + if self._dirty: + self._order() + return list(self._keys) def values(self): - if self.__dirty: - self.__order() - return [self[k] for k in self.__keys] + if self._dirty: + self._order() + return [self[k] for k in self._keys] def items(self): - if self.__dirty: - self.__order() - return [(k, self[k]) for k in self.__keys] + if self._dirty: + self._order() + + return [(k, self[k]) for k in self._keys] def update(self, *args, **kwargs): if args: @@ -57,6 +62,7 @@ class OrderedDict(dict): if hasattr(iterable, 'keys'): for k in iterable: self[k] = iterable[k] + else: for k, v in iterable: self[k] = v @@ -68,16 +74,19 @@ class OrderedDict(dict): def sortingFun(self, keys): keys.sort() - def __order(self): - self.sortingFun(self.__keys) - self.__keysLens = sorted(set(len(k) for k in self.__keys), reverse=True) - self.__dirty = False + def _order(self): + self.sortingFun(self._keys) + + self._keysLens = sorted( + set(len(k) for k in self._keys), reverse=True) + + self._dirty = False def nextKey(self, key): - if self.__dirty: - self.__order() + if self._dirty: + self._order() - keys = self.__keys + keys = self._keys if key in keys: nextIdx = keys.index(key) + 1 @@ -92,30 +101,35 @@ class OrderedDict(dict): raise KeyError(key) def getKeysLens(self): - if self.__dirty: - self.__order() - return self.__keysLens + if self._dirty: + self._order() + + return self._keysLens class OidOrderedDict(OrderedDict): """OID-ordered dictionary used for indices""" def __init__(self, *args, **kwargs): - self.__keysCache = {} OrderedDict.__init__(self, *args, **kwargs) + self._keysCache = {} + def __setitem__(self, key, value): OrderedDict.__setitem__(self, key, value) - if key not in self.__keysCache: + + if key not in self._keysCache: if isinstance(key, tuple): - self.__keysCache[key] = key + self._keysCache[key] = key + else: - self.__keysCache[key] = [int(x) for x in key.split('.') if x] + self._keysCache[key] = [int(x) for x in key.split('.') if x] def __delitem__(self, key): OrderedDict.__delitem__(self, key) - if key in self.__keysCache: - del self.__keysCache[key] + + if key in self._keysCache: + del self._keysCache[key] def sortingFun(self, keys): - keys.sort(key=lambda k, d=self.__keysCache: d[k]) + keys.sort(key=lambda k, d=self._keysCache: d[k]) diff --git a/pysnmp/smi/instrum.py b/pysnmp/smi/instrum.py index aec25adc..342eeb6b 100644 --- a/pysnmp/smi/instrum.py +++ b/pysnmp/smi/instrum.py @@ -38,21 +38,21 @@ class MibInstrumController(AbstractMibInstrumController): STATE_WRITE_CLEANUP = 'writeCleanup' STATE_WRITE_UNDO = 'writeUndo' - fsmReadVar = { + FSM_READ_VAR = { # (state, status) -> newState (STATE_START, STATUS_OK): STATE_READ_TEST, (STATE_READ_TEST, STATUS_OK): STATE_READ_GET, (STATE_READ_GET, STATUS_OK): STATE_STOP, (STATE_ANY, STATUS_ERROR): STATE_STOP } - fsmReadNextVar = { + FSM_READ_NEXT_VAR = { # (state, status) -> newState (STATE_START, STATUS_OK): STATE_READ_TEST_NEXT, (STATE_READ_TEST_NEXT, STATUS_OK): STATE_READ_GET_NEXT, (STATE_READ_GET_NEXT, STATUS_OK): STATE_STOP, (STATE_ANY, STATUS_ERROR): STATE_STOP } - fsmWriteVar = { + FSM_WRITE_VAR = { # (state, status) -> newState (STATE_START, STATUS_OK): STATE_WRITE_TEST, (STATE_WRITE_TEST, STATUS_OK): STATE_WRITE_COMMIT, @@ -79,7 +79,7 @@ class MibInstrumController(AbstractMibInstrumController): def getMibBuilder(self): return self.mibBuilder - def __indexMib(self): + def _indexMib(self): """Rebuild a tree from MIB objects found at currently loaded modules. If currently existing tree is out of date, walk over all Managed Objects @@ -108,7 +108,8 @@ class MibInstrumController(AbstractMibInstrumController): if self.lastBuildId == self.mibBuilder.lastBuildId: return - (MibScalarInstance, MibScalar, MibTableColumn, MibTableRow, + (MibScalarInstance, MibScalar, + MibTableColumn, MibTableRow, MibTable) = self.mibBuilder.importSymbols( 'SNMPv2-SMI', 'MibScalarInstance', 'MibScalar', 'MibTableColumn', 'MibTableRow', 'MibTable' @@ -128,26 +129,36 @@ class MibInstrumController(AbstractMibInstrumController): mibSymbols.sort(key=lambda x: x[0], reverse=True) for modName, mibMod in mibSymbols: + for symObj in mibMod.values(): + if isinstance(symObj, MibTable): tables[symObj.name] = symObj + elif isinstance(symObj, MibTableRow): rows[symObj.name] = symObj + elif isinstance(symObj, MibTableColumn): cols[symObj.name] = symObj + elif isinstance(symObj, MibScalarInstance): instances[symObj.name] = symObj + elif isinstance(symObj, MibScalar): scalars[symObj.name] = symObj # Detach items from each other for symName, parentName in self.lastBuildSyms.items(): + if parentName in scalars: scalars[parentName].unregisterSubtrees(symName) + elif parentName in cols: cols[parentName].unregisterSubtrees(symName) + elif parentName in rows: rows[parentName].unregisterSubtrees(symName) + else: mibTree.unregisterSubtrees(symName) @@ -157,23 +168,29 @@ class MibInstrumController(AbstractMibInstrumController): for inst in instances.values(): if inst.typeName in scalars: scalars[inst.typeName].registerSubtrees(inst) + elif inst.typeName in cols: cols[inst.typeName].registerSubtrees(inst) + else: raise error.SmiError( - 'Orphan MIB scalar instance %r at %r' % (inst, self) - ) + 'Orphan MIB scalar instance %r at ' + '%r' % (inst, self)) + lastBuildSyms[inst.name] = inst.typeName # Attach Table Columns to Table Rows for col in cols.values(): rowName = col.name[:-1] # XXX + if rowName in rows: rows[rowName].registerSubtrees(col) + else: raise error.SmiError( - 'Orphan MIB table column %r at %r' % (col, self) - ) + 'Orphan MIB table column %r at ' + '%r' % (col, self)) + lastBuildSyms[col.name] = rowName # Attach Table Rows to MIB tree @@ -195,7 +212,7 @@ class MibInstrumController(AbstractMibInstrumController): self.lastBuildId = self.mibBuilder.lastBuildId - debug.logger & debug.FLAG_INS and debug.logger('__indexMib: rebuilt') + debug.logger & debug.FLAG_INS and debug.logger('_indexMib: rebuilt') def flipFlopFsm(self, fsmTable, *varBinds, **context): """Read, modify, create or remove Managed Objects Instances. @@ -250,12 +267,12 @@ class MibInstrumController(AbstractMibInstrumController): if err: # Move other errors into the errors sequence errors = context['errors'] + errors.append( {'error': err, 'idx': idx, 'varbind': varBind, - 'state': context['state']} - ) + 'state': context['state']}) context['status'] = self.STATUS_ERROR @@ -271,8 +288,8 @@ class MibInstrumController(AbstractMibInstrumController): count[0] += 1 debug.logger & debug.FLAG_INS and debug.logger( - '_cbFun: var-bind %d, processed %d, expected %d' % ( - idx, count[0], len(varBinds))) + '_cbFun: var-bind %d, processed %d, expected ' + '%d' % (idx, count[0], len(varBinds))) if count[0] < len(varBinds): return @@ -282,7 +299,8 @@ class MibInstrumController(AbstractMibInstrumController): self.flipFlopFsm(fsmTable, *varBinds, **dict(context, cbFun=cbFun)) - debug.logger & debug.FLAG_INS and debug.logger('flipFlopFsm: input var-binds %r' % (varBinds,)) + debug.logger & debug.FLAG_INS and debug.logger( + 'flipFlopFsm: input var-binds %r' % (varBinds,)) mibTree, = self.mibBuilder.importSymbols('SNMPv2-SMI', 'iso') @@ -299,7 +317,7 @@ class MibInstrumController(AbstractMibInstrumController): errors = [] _varBinds = list(varBinds) - self.__indexMib() + self._indexMib() debug.logger & debug.FLAG_INS and debug.logger( 'flipFlopFsm: current state %s, status %s' % (state, status)) @@ -312,10 +330,12 @@ class MibInstrumController(AbstractMibInstrumController): newState = fsmTable[(self.STATE_ANY, status)] except KeyError: - raise error.SmiError('Unresolved FSM state %s, %s' % (state, status)) + raise error.SmiError( + 'Unresolved FSM state %s, %s' % (state, status)) debug.logger & debug.FLAG_INS and debug.logger( - 'flipFlopFsm: state %s status %s -> transitioned into state %s' % (state, status, newState)) + 'flipFlopFsm: state %s status %s -> transitioned into state ' + '%s' % (state, status, newState)) state = newState @@ -324,8 +344,10 @@ class MibInstrumController(AbstractMibInstrumController): context.pop('status', None) context.pop('instances', None) context.pop('varBinds', None) + if cbFun: cbFun(_varBinds, **context) + return # the case of no var-binds @@ -336,16 +358,15 @@ class MibInstrumController(AbstractMibInstrumController): actionFun = getattr(mibTree, state, None) if not actionFun: raise error.SmiError( - 'Unsupported state handler %s at %s' % (state, self) - ) + 'Unsupported state handler %s at ' + '%s' % (state, self)) for idx, varBind in enumerate(varBinds): - actionFun(varBind, - **dict(context, cbFun=_cbFun, - state=state, status=status, - idx=idx, total=len(varBinds), - instances=instances, errors=errors, - varBinds=_varBinds, nextName=None)) + actionFun( + varBind, + **dict(context, cbFun=_cbFun, state=state, status=status, + idx=idx, total=len(varBinds), instances=instances, + errors=errors, varBinds=_varBinds, nextName=None)) debug.logger & debug.FLAG_INS and debug.logger( 'flipFlopFsm: func %s initiated for %r' % (actionFun, varBind)) @@ -354,9 +375,10 @@ class MibInstrumController(AbstractMibInstrumController): def _defaultErrorHandler(varBinds, **context): """Raise exception on any error if user callback is missing""" errors = context.get('errors') + if errors: - error = errors[-1] - raise error['error'] + err = errors[-1] + raise err['error'] def readMibObjects(self, *varBinds, **context): """Read Managed Objects Instances. @@ -410,7 +432,7 @@ class MibInstrumController(AbstractMibInstrumController): if 'cbFun' not in context: context['cbFun'] = self._defaultErrorHandler - self.flipFlopFsm(self.fsmReadVar, *varBinds, **context) + self.flipFlopFsm(self.FSM_READ_VAR, *varBinds, **context) def readNextMibObjects(self, *varBinds, **context): """Read Managed Objects Instances next to the given ones. @@ -470,7 +492,7 @@ class MibInstrumController(AbstractMibInstrumController): if 'cbFun' not in context: context['cbFun'] = self._defaultErrorHandler - self.flipFlopFsm(self.fsmReadNextVar, *varBinds, **context) + self.flipFlopFsm(self.FSM_READ_NEXT_VAR, *varBinds, **context) def writeMibObjects(self, *varBinds, **context): """Create, destroy or modify Managed Objects Instances. @@ -539,4 +561,4 @@ class MibInstrumController(AbstractMibInstrumController): if 'cbFun' not in context: context['cbFun'] = self._defaultErrorHandler - self.flipFlopFsm(self.fsmWriteVar, *varBinds, **context) + self.flipFlopFsm(self.FSM_WRITE_VAR, *varBinds, **context) diff --git a/pysnmp/smi/rfc1902.py b/pysnmp/smi/rfc1902.py index 9a3d4507..40249a1e 100644 --- a/pysnmp/smi/rfc1902.py +++ b/pysnmp/smi/rfc1902.py @@ -4,9 +4,6 @@ # Copyright (c) 2005-2019, Ilya Etingof # License: http://snmplabs.com/pysnmp/license.html # -from pyasn1.error import PyAsn1Error -from pyasn1.type.base import AbstractSimpleAsn1Item - from pysnmp import debug from pysnmp.proto import rfc1902 from pysnmp.proto import rfc1905 @@ -15,6 +12,9 @@ from pysnmp.smi.builder import ZipMibSource from pysnmp.smi.compiler import addMibCompiler from pysnmp.smi.error import SmiError +from pyasn1.error import PyAsn1Error +from pyasn1.type.base import AbstractSimpleAsn1Item + __all__ = ['ObjectIdentity', 'ObjectType', 'NotificationType'] @@ -78,19 +78,22 @@ class ObjectIdentity(object): ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0) >>> ObjectIdentity('IP-MIB', 'ipAdEntAddr', '127.0.0.1', 123) ObjectIdentity('IP-MIB', 'ipAdEntAddr', '127.0.0.1', 123) - """ ST_DIRTY, ST_CLEAN = 1, 2 def __init__(self, *args, **kwargs): - self.__args = args - self.__kwargs = kwargs - self.__mibSourcesToAdd = self.__modNamesToLoad = None - self.__asn1SourcesToAdd = self.__asn1SourcesOptions = None - self.__state = self.ST_DIRTY - self.__indices = self.__oid = self.__label = () - self.__modName = self.__symName = '' - self.__mibNode = None + self._args = args + self._kwargs = kwargs + self._mibSourcesToAdd = None + self._modNamesToLoad = None + self._asn1SourcesToAdd = None + self._asn1SourcesOptions = None + self._state = self.ST_DIRTY + self._indices = () + self._oid = () + self._label = () + self._modName = self._symName = '' + self._mibNode = None def getMibSymbol(self): """Returns MIB variable symbolic identification. @@ -116,12 +119,13 @@ class ObjectIdentity(object): >>> objectIdentity.getMibSymbol() ('SNMPv2-MIB', 'sysDescr', (0,)) >>> - """ - if self.__state & self.ST_CLEAN: - return self.__modName, self.__symName, self.__indices + if self._state & self.ST_CLEAN: + return self._modName, self._symName, self._indices + else: - raise SmiError('%s object not fully initialized' % self.__class__.__name__) + raise SmiError( + '%s object not fully initialized' % self.__class__.__name__) def getOid(self): """Returns OID identifying MIB variable. @@ -143,12 +147,13 @@ class ObjectIdentity(object): >>> objectIdentity.getOid() ObjectName('1.3.6.1.2.1.1.1.0') >>> - """ - if self.__state & self.ST_CLEAN: - return self.__oid + if self._state & self.ST_CLEAN: + return self._oid + else: - raise SmiError('%s object not fully initialized' % self.__class__.__name__) + raise SmiError( + '%s object not fully initialized' % self.__class__.__name__) def getLabel(self): """Returns symbolic path to this MIB variable. @@ -179,21 +184,24 @@ class ObjectIdentity(object): >>> objectIdentity.getOid() ('iso', 'org', 'dod', 'internet', 'mgmt', 'mib-2', 'system', 'sysDescr') >>> - """ - if self.__state & self.ST_CLEAN: - return self.__label + if self._state & self.ST_CLEAN: + return self._label + else: - raise SmiError('%s object not fully initialized' % self.__class__.__name__) + raise SmiError( + '%s object not fully initialized' % self.__class__.__name__) def getMibNode(self): - if self.__state & self.ST_CLEAN: - return self.__mibNode + if self._state & self.ST_CLEAN: + return self._mibNode + else: - raise SmiError('%s object not fully initialized' % self.__class__.__name__) + raise SmiError( + '%s object not fully initialized' % self.__class__.__name__) def isFullyResolved(self): - return self.__state & self.ST_CLEAN + return self._state & self.ST_CLEAN # # A gateway to MIBs manipulation routines @@ -227,16 +235,19 @@ class ObjectIdentity(object): >>> ObjectIdentity('SNMPv2-MIB', 'sysDescr').addAsn1Source('http://mibs.snmplabs.com/asn1/@mib@') ObjectIdentity('SNMPv2-MIB', 'sysDescr') >>> - """ - if self.__asn1SourcesToAdd is None: - self.__asn1SourcesToAdd = asn1Sources + if self._asn1SourcesToAdd is None: + self._asn1SourcesToAdd = asn1Sources + else: - self.__asn1SourcesToAdd += asn1Sources - if self.__asn1SourcesOptions: - self.__asn1SourcesOptions.update(kwargs) + self._asn1SourcesToAdd += asn1Sources + + if self._asn1SourcesOptions: + self._asn1SourcesOptions.update(kwargs) + else: - self.__asn1SourcesOptions = kwargs + self._asn1SourcesOptions = kwargs + return self def addMibSource(self, *mibSources): @@ -266,12 +277,13 @@ class ObjectIdentity(object): >>> ObjectIdentity('SNMPv2-MIB', 'sysDescr').addMibSource('/opt/pysnmp/mibs', 'pysnmp_mibs') ObjectIdentity('SNMPv2-MIB', 'sysDescr') >>> - """ - if self.__mibSourcesToAdd is None: - self.__mibSourcesToAdd = mibSources + if self._mibSourcesToAdd is None: + self._mibSourcesToAdd = mibSources + else: - self.__mibSourcesToAdd += mibSources + self._mibSourcesToAdd += mibSources + return self # provides deferred MIBs load @@ -294,12 +306,13 @@ class ObjectIdentity(object): >>> ObjectIdentity('SNMPv2-MIB', 'sysDescr').loadMibs('IF-MIB', 'TCP-MIB') ObjectIdentity('SNMPv2-MIB', 'sysDescr') >>> - """ - if self.__modNamesToLoad is None: - self.__modNamesToLoad = modNames + if self._modNamesToLoad is None: + self._modNamesToLoad = modNames + else: - self.__modNamesToLoad += modNames + self._modNamesToLoad += modNames + return self # this would eventually be called by an entity which posses a @@ -344,298 +357,382 @@ class ObjectIdentity(object): >>> objectIdentity.resolveWithMib(mibViewController) ObjectIdentity('SNMPv2-MIB', 'sysDescr') >>> - """ - if self.__mibSourcesToAdd is not None: - debug.logger & debug.FLAG_MIB and debug.logger('adding MIB sources %s' % ', '.join(self.__mibSourcesToAdd)) + if self._mibSourcesToAdd is not None: + debug.logger & debug.FLAG_MIB and debug.logger( + 'adding MIB sources %s' % ', '.join(self._mibSourcesToAdd)) + mibViewController.mibBuilder.addMibSources( - *[ZipMibSource(x) for x in self.__mibSourcesToAdd] - ) - self.__mibSourcesToAdd = None + *[ZipMibSource(x) for x in self._mibSourcesToAdd]) + + self._mibSourcesToAdd = None + + if self._asn1SourcesToAdd is None: + addMibCompiler( + mibViewController.mibBuilder, + ifAvailable=True, ifNotAdded=True) - if self.__asn1SourcesToAdd is None: - addMibCompiler(mibViewController.mibBuilder, - ifAvailable=True, ifNotAdded=True) else: debug.logger & debug.FLAG_MIB and debug.logger( - 'adding MIB compiler with source paths %s' % ', '.join(self.__asn1SourcesToAdd)) + 'adding MIB compiler with source paths ' + '%s' % ', '.join(self._asn1SourcesToAdd)) + addMibCompiler( mibViewController.mibBuilder, - sources=self.__asn1SourcesToAdd, - searchers=self.__asn1SourcesOptions.get('searchers'), - borrowers=self.__asn1SourcesOptions.get('borrowers'), - destination=self.__asn1SourcesOptions.get('destination'), - ifAvailable=self.__asn1SourcesOptions.get('ifAvailable'), - ifNotAdded=self.__asn1SourcesOptions.get('ifNotAdded') + sources=self._asn1SourcesToAdd, + searchers=self._asn1SourcesOptions.get('searchers'), + borrowers=self._asn1SourcesOptions.get('borrowers'), + destination=self._asn1SourcesOptions.get('destination'), + ifAvailable=self._asn1SourcesOptions.get('ifAvailable'), + ifNotAdded=self._asn1SourcesOptions.get('ifNotAdded') ) - self.__asn1SourcesToAdd = self.__asn1SourcesOptions = None - if self.__modNamesToLoad is not None: - debug.logger & debug.FLAG_MIB and debug.logger('loading MIB modules %s' % ', '.join(self.__modNamesToLoad)) - mibViewController.mibBuilder.loadModules(*self.__modNamesToLoad) - self.__modNamesToLoad = None + self._asn1SourcesToAdd = self._asn1SourcesOptions = None + + if self._modNamesToLoad is not None: + debug.logger & debug.FLAG_MIB and debug.logger( + 'loading MIB modules %s' % ', '.join(self._modNamesToLoad)) + + mibViewController.mibBuilder.loadModules(*self._modNamesToLoad) + + self._modNamesToLoad = None - if self.__state & self.ST_CLEAN: + if self._state & self.ST_CLEAN: return self - MibScalar, MibTableColumn = mibViewController.mibBuilder.importSymbols('SNMPv2-SMI', 'MibScalar', - 'MibTableColumn') + MibScalar, MibTableColumn = mibViewController.mibBuilder.importSymbols( + 'SNMPv2-SMI', 'MibScalar', 'MibTableColumn') - self.__indices = () + self._indices = () - if isinstance(self.__args[0], ObjectIdentity): - self.__args[0].resolveWithMib(mibViewController) + if isinstance(self._args[0], ObjectIdentity): + self._args[0].resolveWithMib(mibViewController) + + if len(self._args) == 1: # OID or label or MIB module + debug.logger & debug.FLAG_MIB and debug.logger( + 'resolving %s as OID or label' % self._args) - if len(self.__args) == 1: # OID or label or MIB module - debug.logger & debug.FLAG_MIB and debug.logger('resolving %s as OID or label' % self.__args) try: # pyasn1 ObjectIdentifier or sequence of ints or string OID - self.__oid = rfc1902.ObjectName(self.__args[0]) # OID + self._oid = rfc1902.ObjectName(self._args[0]) # OID + except PyAsn1Error: # sequence of sub-OIDs and labels - if isinstance(self.__args[0], (list, tuple)): + if isinstance(self._args[0], (list, tuple)): prefix, label, suffix = mibViewController.getNodeName( - self.__args[0] - ) + self._args[0]) + # string label - elif '.' in self.__args[0]: + elif '.' in self._args[0]: prefix, label, suffix = mibViewController.getNodeNameByOid( - tuple(self.__args[0].split('.')) - ) + tuple(self._args[0].split('.'))) + # MIB module name else: - modName = self.__args[0] + modName = self._args[0] + mibViewController.mibBuilder.loadModules(modName) - if self.__kwargs.get('last'): - prefix, label, suffix = mibViewController.getLastNodeName(modName) + + if self._kwargs.get('last'): + (prefix, label, + suffix) = mibViewController.getLastNodeName(modName) + else: - prefix, label, suffix = mibViewController.getFirstNodeName(modName) + (prefix, label, + suffix) = mibViewController.getFirstNodeName(modName) if suffix: try: - suffix = tuple([int(x) for x in suffix]) + suffix = tuple(int(x) for x in suffix) + except ValueError: - raise SmiError('Unknown object name component %r' % (suffix,)) - self.__oid = rfc1902.ObjectName(prefix + suffix) + raise SmiError( + 'Unknown object name component %r' % (suffix,)) + + self._oid = rfc1902.ObjectName(prefix + suffix) + else: prefix, label, suffix = mibViewController.getNodeNameByOid( - self.__oid - ) + self._oid) debug.logger & debug.FLAG_MIB and debug.logger( - 'resolved %r into prefix %r and suffix %r' % (self.__args, prefix, suffix)) + 'resolved %r into prefix %r and suffix ' + '%r' % (self._args, prefix, suffix)) modName, symName, _ = mibViewController.getNodeLocation(prefix) - self.__modName = modName - self.__symName = symName + self._modName = modName + self._symName = symName - self.__label = label + self._label = label mibNode, = mibViewController.mibBuilder.importSymbols( - modName, symName - ) + modName, symName) - self.__mibNode = mibNode + self._mibNode = mibNode - debug.logger & debug.FLAG_MIB and debug.logger('resolved prefix %r into MIB node %r' % (prefix, mibNode)) + debug.logger & debug.FLAG_MIB and debug.logger( + 'resolved prefix %r into MIB node %r' % (prefix, mibNode)) if isinstance(mibNode, MibTableColumn): # table column if suffix: rowModName, rowSymName, _ = mibViewController.getNodeLocation( mibNode.name[:-1] ) + rowNode, = mibViewController.mibBuilder.importSymbols( rowModName, rowSymName ) - self.__indices = rowNode.getIndicesFromInstId(suffix) + + self._indices = rowNode.getIndicesFromInstId(suffix) + elif isinstance(mibNode, MibScalar): # scalar if suffix: - self.__indices = (rfc1902.ObjectName(suffix),) + self._indices = (rfc1902.ObjectName(suffix),) + else: if suffix: - self.__indices = (rfc1902.ObjectName(suffix),) - self.__state |= self.ST_CLEAN + self._indices = (rfc1902.ObjectName(suffix),) + + self._state |= self.ST_CLEAN - debug.logger & debug.FLAG_MIB and debug.logger('resolved indices are %r' % (self.__indices,)) + debug.logger & debug.FLAG_MIB and debug.logger( + 'resolved indices are %r' % (self._indices,)) return self - elif len(self.__args) > 1: # MIB, symbol[, index, index ...] + + elif len(self._args) > 1: # MIB, symbol[, index, index ...] # MIB, symbol, index, index - if self.__args[0] and self.__args[1]: - self.__modName = self.__args[0] - self.__symName = self.__args[1] + if self._args[0] and self._args[1]: + self._modName = self._args[0] + self._symName = self._args[1] + # MIB, '' - elif self.__args[0]: - mibViewController.mibBuilder.loadModules(self.__args[0]) - if self.__kwargs.get('last'): - prefix, label, suffix = mibViewController.getLastNodeName(self.__args[0]) + elif self._args[0]: + mibViewController.mibBuilder.loadModules(self._args[0]) + + if self._kwargs.get('last'): + (prefix, label, + suffix) = mibViewController.getLastNodeName(self._args[0]) + else: - prefix, label, suffix = mibViewController.getFirstNodeName(self.__args[0]) - self.__modName, self.__symName, _ = mibViewController.getNodeLocation(prefix) + (prefix, label, + suffix) = mibViewController.getFirstNodeName(self._args[0]) + + (self._modName, + self._symName, _) = mibViewController.getNodeLocation(prefix) + # '', symbol, index, index else: - prefix, label, suffix = mibViewController.getNodeName(self.__args[1:]) - self.__modName, self.__symName, _ = mibViewController.getNodeLocation(prefix) + (prefix, label, + suffix) = mibViewController.getNodeName(self._args[1:]) + + (self._modName, + self._symName, _) = mibViewController.getNodeLocation(prefix) mibNode, = mibViewController.mibBuilder.importSymbols( - self.__modName, self.__symName - ) + self._modName, self._symName) - self.__mibNode = mibNode + self._mibNode = mibNode - self.__oid = rfc1902.ObjectName(mibNode.getName()) + self._oid = rfc1902.ObjectName(mibNode.getName()) - prefix, label, suffix = mibViewController.getNodeNameByOid( - self.__oid - ) - self.__label = label + (prefix, label, + suffix) = mibViewController.getNodeNameByOid( + self._oid) + + self._label = label debug.logger & debug.FLAG_MIB and debug.logger( - 'resolved %r into prefix %r and suffix %r' % (self.__args, prefix, suffix)) + 'resolved %r into prefix %r and suffix ' + '%r' % (self._args, prefix, suffix)) if isinstance(mibNode, MibTableColumn): # table rowModName, rowSymName, _ = mibViewController.getNodeLocation( - mibNode.name[:-1] - ) + mibNode.name[:-1]) + rowNode, = mibViewController.mibBuilder.importSymbols( - rowModName, rowSymName - ) - if self.__args[2:]: + rowModName, rowSymName) + + if self._args[2:]: try: - instIds = rowNode.getInstIdFromIndices(*self.__args[2:]) - self.__oid += instIds - self.__indices = rowNode.getIndicesFromInstId(instIds) + instIds = rowNode.getInstIdFromIndices(*self._args[2:]) + self._oid += instIds + self._indices = rowNode.getIndicesFromInstId(instIds) + except PyAsn1Error as exc: - raise SmiError('Instance index %r to OID conversion failure at object %r: %s' % ( - self.__args[2:], mibNode.getLabel(), exc)) - elif self.__args[2:]: # any other kind of MIB node with indices - if self.__args[2:]: + raise SmiError( + 'Instance index %r to OID conversion failure ' + 'at object %r: ' + '%s' % (self._args[2:], mibNode.getLabel(), exc)) + + elif self._args[2:]: # any other kind of MIB node with indices + if self._args[2:]: instId = rfc1902.ObjectName( - '.'.join([str(x) for x in self.__args[2:]]) - ) - self.__oid += instId - self.__indices = (instId,) - self.__state |= self.ST_CLEAN + '.'.join(str(x) for x in self._args[2:])) + + self._oid += instId + + self._indices = (instId,) - debug.logger & debug.FLAG_MIB and debug.logger('resolved indices are %r' % (self.__indices,)) + self._state |= self.ST_CLEAN + + debug.logger & debug.FLAG_MIB and debug.logger( + 'resolved indices are %r' % (self._indices,)) return self + else: raise SmiError('Non-OID, label or MIB symbol') def prettyPrint(self): - if self.__state & self.ST_CLEAN: + if self._state & self.ST_CLEAN: s = rfc1902.OctetString() + return '%s::%s%s%s' % ( - self.__modName, self.__symName, - self.__indices and '.' or '', - '.'.join([x.isSuperTypeOf(s, matchConstraints=False) and '"%s"' % x.prettyPrint() or x.prettyPrint() for x in self.__indices]) - ) + self._modName, self._symName, + self._indices and '.' or '', + '.'.join((x.isSuperTypeOf(s, matchConstraints=False) and + '"%s"' % x.prettyPrint() or + x.prettyPrint()) for x in self._indices)) + else: - raise SmiError('%s object not fully initialized' % self.__class__.__name__) + raise SmiError( + '%s object not fully initialized' % self.__class__.__name__) def __repr__(self): - return '%s(%s)' % (self.__class__.__name__, ', '.join([repr(x) for x in self.__args])) + return '%s(%s)' % (self.__class__.__name__, + ', '.join(repr(x) for x in self._args)) # Redirect some attrs access to the OID object to behave alike def __str__(self): - if self.__state & self.ST_CLEAN: - return str(self.__oid) + if self._state & self.ST_CLEAN: + return str(self._oid) + else: - raise SmiError('%s object not properly initialized' % self.__class__.__name__) + raise SmiError('%s object not properly ' + 'initialized' % self.__class__.__name__) def __eq__(self, other): - if self.__state & self.ST_CLEAN: - return self.__oid == other + if self._state & self.ST_CLEAN: + return self._oid == other + else: - raise SmiError('%s object not properly initialized' % self.__class__.__name__) + raise SmiError('%s object not properly ' + 'initialized' % self.__class__.__name__) def __ne__(self, other): - if self.__state & self.ST_CLEAN: - return self.__oid != other + if self._state & self.ST_CLEAN: + return self._oid != other + else: - raise SmiError('%s object not properly initialized' % self.__class__.__name__) + raise SmiError('%s object not properly ' + 'initialized' % self.__class__.__name__) def __lt__(self, other): - if self.__state & self.ST_CLEAN: - return self.__oid < other + if self._state & self.ST_CLEAN: + return self._oid < other + else: - raise SmiError('%s object not properly initialized' % self.__class__.__name__) + raise SmiError('%s object not properly ' + 'initialized' % self.__class__.__name__) def __le__(self, other): - if self.__state & self.ST_CLEAN: - return self.__oid <= other + if self._state & self.ST_CLEAN: + return self._oid <= other + else: - raise SmiError('%s object not properly initialized' % self.__class__.__name__) + raise SmiError('%s object not properly ' + 'initialized' % self.__class__.__name__) def __gt__(self, other): - if self.__state & self.ST_CLEAN: - return self.__oid > other + if self._state & self.ST_CLEAN: + return self._oid > other + else: - raise SmiError('%s object not properly initialized' % self.__class__.__name__) + raise SmiError('%s object not properly ' + 'initialized' % self.__class__.__name__) def __ge__(self, other): - if self.__state & self.ST_CLEAN: - return self.__oid > other + if self._state & self.ST_CLEAN: + return self._oid > other + else: - raise SmiError('%s object not properly initialized' % self.__class__.__name__) + raise SmiError('%s object not properly ' + 'initialized' % self.__class__.__name__) def __nonzero__(self): - if self.__state & self.ST_CLEAN: - return self.__oid != 0 + if self._state & self.ST_CLEAN: + return self._oid != 0 + else: - raise SmiError('%s object not properly initialized' % self.__class__.__name__) + raise SmiError('%s object not properly ' + 'initialized' % self.__class__.__name__) def __bool__(self): - if self.__state & self.ST_CLEAN: - return bool(self.__oid) + if self._state & self.ST_CLEAN: + return bool(self._oid) + else: - raise SmiError('%s object not properly initialized' % self.__class__.__name__) + raise SmiError('%s object not properly ' + 'initialized' % self.__class__.__name__) def __getitem__(self, i): - if self.__state & self.ST_CLEAN: - return self.__oid[i] + if self._state & self.ST_CLEAN: + return self._oid[i] + else: - raise SmiError('%s object not properly initialized' % self.__class__.__name__) + raise SmiError('%s object not properly ' + 'initialized' % self.__class__.__name__) def __len__(self): - if self.__state & self.ST_CLEAN: - return len(self.__oid) + if self._state & self.ST_CLEAN: + return len(self._oid) + else: - raise SmiError('%s object not properly initialized' % self.__class__.__name__) + raise SmiError('%s object not properly ' + 'initialized' % self.__class__.__name__) def __add__(self, other): - if self.__state & self.ST_CLEAN: - return self.__oid + other + if self._state & self.ST_CLEAN: + return self._oid + other + else: - raise SmiError('%s object not properly initialized' % self.__class__.__name__) + raise SmiError('%s object not properly ' + 'initialized' % self.__class__.__name__) def __radd__(self, other): - if self.__state & self.ST_CLEAN: - return other + self.__oid + if self._state & self.ST_CLEAN: + return other + self._oid + else: - raise SmiError('%s object not properly initialized' % self.__class__.__name__) + raise SmiError('%s object not properly ' + 'initialized' % self.__class__.__name__) def __hash__(self): - if self.__state & self.ST_CLEAN: - return hash(self.__oid) + if self._state & self.ST_CLEAN: + return hash(self._oid) + else: - raise SmiError('%s object not properly initialized' % self.__class__.__name__) + raise SmiError('%s object not properly ' + 'initialized' % self.__class__.__name__) def __getattr__(self, attr): - if self.__state & self.ST_CLEAN: + if self._state & self.ST_CLEAN: if attr in ('asTuple', 'clone', 'subtype', 'isPrefixOf', 'isSameTypeWith', 'isSuperTypeOf', 'getTagSet', 'getEffectiveTagSet', 'getTagMap', 'tagSet', 'index'): - return getattr(self.__oid, attr) + return getattr(self._oid, attr) + raise AttributeError(attr) + else: - raise SmiError('%s object not properly initialized for accessing %s' % (self.__class__.__name__, attr)) + raise SmiError( + '%s object not properly initialized for accessing ' + '%s' % (self.__class__.__name__, attr)) -# A two-element sequence of ObjectIdentity and SNMP data type object class ObjectType(object): """Create an object representing MIB variable. @@ -692,30 +789,35 @@ class ObjectType(object): ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0'), Null('')) >>> ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0), 'Linux i386') ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0), 'Linux i386') - """ ST_DIRTY, ST_CLEAM = 1, 2 def __init__(self, objectIdentity, objectSyntax=rfc1905.unSpecified): if not isinstance(objectIdentity, ObjectIdentity): - raise SmiError('initializer should be ObjectIdentity instance, not %r' % (objectIdentity,)) - self.__args = [objectIdentity, objectSyntax] - self.__state = self.ST_DIRTY + raise SmiError( + 'initializer should be ObjectIdentity instance, ' + 'not %r' % (objectIdentity,)) + + self._args = [objectIdentity, objectSyntax] + self._state = self.ST_DIRTY def __getitem__(self, i): - if self.__state & self.ST_CLEAM: - return self.__args[i] + if self._state & self.ST_CLEAM: + return self._args[i] + else: - raise SmiError('%s object not fully initialized' % self.__class__.__name__) + raise SmiError( + '%s object not fully initialized' % self.__class__.__name__) def __str__(self): return self.prettyPrint() def __repr__(self): - return '%s(%s)' % (self.__class__.__name__, ', '.join([repr(x) for x in self.__args])) + return '%s(%s)' % (self.__class__.__name__, + ', '.join([repr(x) for x in self._args])) def isFullyResolved(self): - return self.__state & self.ST_CLEAM + return self._state & self.ST_CLEAM def addAsn1MibSource(self, *asn1Sources, **kwargs): """Adds path to a repository to search ASN.1 MIB files. @@ -747,7 +849,7 @@ class ObjectType(object): >>> """ - self.__args[0].addAsn1MibSource(*asn1Sources, **kwargs) + self._args[0].addAsn1MibSource(*asn1Sources, **kwargs) return self def addMibSource(self, *mibSources): @@ -779,7 +881,7 @@ class ObjectType(object): >>> """ - self.__args[0].addMibSource(*mibSources) + self._args[0].addMibSource(*mibSources) return self def loadMibs(self, *modNames): @@ -803,7 +905,7 @@ class ObjectType(object): >>> """ - self.__args[0].loadMibs(*modNames) + self._args[0].loadMibs(*modNames) return self def resolveWithMib(self, mibViewController): @@ -842,50 +944,61 @@ class ObjectType(object): >>> """ - if self.__state & self.ST_CLEAM: + if self._state & self.ST_CLEAM: return self - self.__args[0].resolveWithMib(mibViewController) + self._args[0].resolveWithMib(mibViewController) - MibScalar, MibTableColumn = mibViewController.mibBuilder.importSymbols('SNMPv2-SMI', 'MibScalar', - 'MibTableColumn') + MibScalar, MibTableColumn = mibViewController.mibBuilder.importSymbols( + 'SNMPv2-SMI', 'MibScalar', 'MibTableColumn') - if not isinstance(self.__args[0].getMibNode(), + if not isinstance(self._args[0].getMibNode(), (MibScalar, MibTableColumn)): - if not isinstance(self.__args[1], AbstractSimpleAsn1Item): - raise SmiError('MIB object %r is not OBJECT-TYPE (MIB not loaded?)' % (self.__args[0],)) - self.__state |= self.ST_CLEAM + if not isinstance(self._args[1], AbstractSimpleAsn1Item): + raise SmiError('MIB object %r is not OBJECT-TYPE ' + '(MIB not loaded?)' % (self._args[0],)) + + self._state |= self.ST_CLEAM + return self - if isinstance(self.__args[1], (rfc1905.UnSpecified, - rfc1905.NoSuchObject, - rfc1905.NoSuchInstance, - rfc1905.EndOfMibView)): - self.__state |= self.ST_CLEAM + if isinstance(self._args[1], (rfc1905.UnSpecified, + rfc1905.NoSuchObject, + rfc1905.NoSuchInstance, + rfc1905.EndOfMibView)): + self._state |= self.ST_CLEAM return self + syntax = self._args[0].getMibNode().getSyntax() + try: - self.__args[1] = self.__args[0].getMibNode().getSyntax().clone(self.__args[1]) + self._args[1] = syntax.clone(self._args[1]) + except PyAsn1Error as exc: - raise SmiError('MIB object %r having type %r failed to cast value %r: %s' % ( - self.__args[0].prettyPrint(), self.__args[0].getMibNode().getSyntax().__class__.__name__, self.__args[1], - exc)) + raise SmiError( + 'MIB object %r having type %r failed to cast value ' + '%r: %s' % (self._args[0].prettyPrint(), + syntax.__class__.__name__, self._args[1], exc)) - if rfc1902.ObjectIdentifier().isSuperTypeOf(self.__args[1], matchConstraints=False): - self.__args[1] = ObjectIdentity(self.__args[1]).resolveWithMib(mibViewController) + if rfc1902.ObjectIdentifier().isSuperTypeOf( + self._args[1], matchConstraints=False): + self._args[1] = ObjectIdentity( + self._args[1]).resolveWithMib(mibViewController) - self.__state |= self.ST_CLEAM + self._state |= self.ST_CLEAM - debug.logger & debug.FLAG_MIB and debug.logger('resolved %r syntax is %r' % (self.__args[0], self.__args[1])) + debug.logger & debug.FLAG_MIB and debug.logger( + 'resolved %r syntax is %r' % (self._args[0], self._args[1])) return self def prettyPrint(self): - if self.__state & self.ST_CLEAM: - return '%s = %s' % (self.__args[0].prettyPrint(), - self.__args[1].prettyPrint()) + if self._state & self.ST_CLEAM: + return '%s = %s' % (self._args[0].prettyPrint(), + self._args[1].prettyPrint()) else: - raise SmiError('%s object not fully initialized' % self.__class__.__name__) + raise SmiError( + '%s object not fully initialized' % self.__class__.__name__) class NotificationType(object): @@ -956,22 +1069,29 @@ class NotificationType(object): def __init__(self, objectIdentity, instanceIndex=(), objects={}): if not isinstance(objectIdentity, ObjectIdentity): - raise SmiError('initializer should be ObjectIdentity instance, not %r' % (objectIdentity,)) - self.__objectIdentity = objectIdentity - self.__instanceIndex = instanceIndex - self.__objects = objects - self.__varBinds = [] - self.__additionalVarBinds = [] - self.__state = self.ST_DIRTY + raise SmiError( + 'initializer should be ObjectIdentity instance, not ' + '%r' % (objectIdentity,)) + + self._objectIdentity = objectIdentity + self._instanceIndex = instanceIndex + self._objects = objects + self._varBinds = [] + self._additionalVarBinds = [] + self._state = self.ST_DIRTY def __getitem__(self, i): - if self.__state & self.ST_CLEAN: - return self.__varBinds[i] + if self._state & self.ST_CLEAN: + return self._varBinds[i] + else: - raise SmiError('%s object not fully initialized' % self.__class__.__name__) + raise SmiError( + '%s object not fully initialized' % self.__class__.__name__) def __repr__(self): - return '%s(%r, %r, %r)' % (self.__class__.__name__, self.__objectIdentity, self.__instanceIndex, self.__objects) + return '%s(%r, %r, %r)' % ( + self.__class__.__name__, self._objectIdentity, + self._instanceIndex, self._objects) def addVarBinds(self, *varBinds): """Appends variable-binding to notification. @@ -999,13 +1119,17 @@ class NotificationType(object): >>> nt.addVarBinds(ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0))) NotificationType(ObjectIdentity('IP-MIB', 'linkDown'), (), {}) >>> - """ - debug.logger & debug.FLAG_MIB and debug.logger('additional var-binds: %r' % (varBinds,)) - if self.__state & self.ST_CLEAN: - raise SmiError('%s object is already sealed' % self.__class__.__name__) + debug.logger & debug.FLAG_MIB and debug.logger( + 'additional var-binds: %r' % (varBinds,)) + + if self._state & self.ST_CLEAN: + raise SmiError( + '%s object is already sealed' % self.__class__.__name__) + else: - self.__additionalVarBinds.extend(varBinds) + self._additionalVarBinds.extend(varBinds) + return self def addAsn1MibSource(self, *asn1Sources, **kwargs): @@ -1036,9 +1160,8 @@ class NotificationType(object): >>> NotificationType(ObjectIdentity('IF-MIB', 'linkDown'), (), {}).addAsn1Source('http://mibs.snmplabs.com/asn1/@mib@') NotificationType(ObjectIdentity('IF-MIB', 'linkDown'), (), {}) >>> - """ - self.__objectIdentity.addAsn1MibSource(*asn1Sources, **kwargs) + self._objectIdentity.addAsn1MibSource(*asn1Sources, **kwargs) return self def addMibSource(self, *mibSources): @@ -1068,9 +1191,8 @@ class NotificationType(object): >>> NotificationType(ObjectIdentity('IF-MIB', 'linkDown'), (), {}).addMibSource('/opt/pysnmp/mibs', 'pysnmp_mibs') NotificationType(ObjectIdentity('IF-MIB', 'linkDown'), (), {}) >>> - """ - self.__objectIdentity.addMibSource(*mibSources) + self._objectIdentity.addMibSource(*mibSources) return self def loadMibs(self, *modNames): @@ -1092,13 +1214,12 @@ class NotificationType(object): >>> NotificationType(ObjectIdentity('IF-MIB', 'linkDown'), (), {}).loadMibs('IF-MIB', 'TCP-MIB') NotificationType(ObjectIdentity('IF-MIB', 'linkDown'), (), {}) >>> - """ - self.__objectIdentity.loadMibs(*modNames) + self._objectIdentity.loadMibs(*modNames) return self def isFullyResolved(self): - return self.__state & self.ST_CLEAN + return self._state & self.ST_CLEAN def resolveWithMib(self, mibViewController): """Perform MIB variable ID conversion and notification objects expansion. @@ -1136,57 +1257,71 @@ class NotificationType(object): >>> notificationType.resolveWithMib(mibViewController) NotificationType(ObjectIdentity('IF-MIB', 'linkDown'), (), {}) >>> - """ - if self.__state & self.ST_CLEAN: + if self._state & self.ST_CLEAN: return self - self.__objectIdentity.resolveWithMib(mibViewController) + self._objectIdentity.resolveWithMib(mibViewController) - self.__varBinds.append( + self._varBinds.append( ObjectType(ObjectIdentity(v2c.apiTrapPDU.snmpTrapOID), - self.__objectIdentity).resolveWithMib(mibViewController) - ) + self._objectIdentity).resolveWithMib(mibViewController)) - SmiNotificationType, = mibViewController.mibBuilder.importSymbols('SNMPv2-SMI', 'NotificationType') + SmiNotificationType, = mibViewController.mibBuilder.importSymbols( + 'SNMPv2-SMI', 'NotificationType') - mibNode = self.__objectIdentity.getMibNode() + mibNode = self._objectIdentity.getMibNode() varBindsLocation = {} if isinstance(mibNode, SmiNotificationType): + for notificationObject in mibNode.getObjects(): - objectIdentity = ObjectIdentity(*notificationObject + self.__instanceIndex).resolveWithMib( - mibViewController) - self.__varBinds.append( - ObjectType(objectIdentity, - self.__objects.get(notificationObject, rfc1905.unSpecified)).resolveWithMib( - mibViewController) - ) - varBindsLocation[objectIdentity] = len(self.__varBinds) - 1 + objectIdentity = ObjectIdentity( + *notificationObject + self._instanceIndex) + + objectIdentity.resolveWithMib(mibViewController) + + objectType = ObjectType( + objectIdentity, self._objects.get( + notificationObject, rfc1905.unSpecified)) + + objectType.resolveWithMib(mibViewController) + + self._varBinds.append(objectType) + + varBindsLocation[objectIdentity] = len(self._varBinds) - 1 + else: debug.logger & debug.FLAG_MIB and debug.logger( - 'WARNING: MIB object %r is not NOTIFICATION-TYPE (MIB not loaded?)' % (self.__objectIdentity,)) + 'WARNING: MIB object %r is not NOTIFICATION-TYPE (MIB not ' + 'loaded?)' % (self._objectIdentity,)) - for varBinds in self.__additionalVarBinds: + for varBinds in self._additionalVarBinds: if not isinstance(varBinds, ObjectType): varBinds = ObjectType(ObjectIdentity(varBinds[0]), varBinds[1]) + varBinds.resolveWithMib(mibViewController) + if varBinds[0] in varBindsLocation: - self.__varBinds[varBindsLocation[varBinds[0]]] = varBinds + self._varBinds[varBindsLocation[varBinds[0]]] = varBinds + else: - self.__varBinds.append(varBinds) + self._varBinds.append(varBinds) - self.__additionalVarBinds = [] + self._additionalVarBinds = [] - self.__state |= self.ST_CLEAN + self._state |= self.ST_CLEAN - debug.logger & debug.FLAG_MIB and debug.logger('resolved %r into %r' % (self.__objectIdentity, self.__varBinds)) + debug.logger & debug.FLAG_MIB and debug.logger( + 'resolved %r into %r' % (self._objectIdentity, self._varBinds)) return self def prettyPrint(self): - if self.__state & self.ST_CLEAN: - return ' '.join(['%s = %s' % (x[0].prettyPrint(), x[1].prettyPrint()) for x in self.__varBinds]) - else: - raise SmiError('%s object not fully initialized' % self.__class__.__name__) + if self._state & self.ST_CLEAN: + return ' '.join('%s = %s' % (x[0].prettyPrint(), x[1].prettyPrint()) + for x in self._varBinds) + + raise SmiError( + '%s object not fully initialized' % self.__class__.__name__) diff --git a/pysnmp/smi/view.py b/pysnmp/smi/view.py index e9fd405e..46ce5991 100644 --- a/pysnmp/smi/view.py +++ b/pysnmp/smi/view.py @@ -6,13 +6,6 @@ # import sys -from pysnmp import debug -from pysnmp.smi import error -from pysnmp.smi.indices import OidOrderedDict -from pysnmp.smi.indices import OrderedDict - -__all__ = ['MibViewController'] - if sys.version_info[0] <= 2: import types @@ -22,52 +15,69 @@ else: classTypes = (type,) instanceTypes = (object,) +from pysnmp import debug +from pysnmp.smi import error +from pysnmp.smi.indices import OidOrderedDict +from pysnmp.smi.indices import OrderedDict + +__all__ = ['MibViewController'] + class MibViewController(object): def __init__(self, mibBuilder): self.mibBuilder = mibBuilder self.lastBuildId = -1 - self.__mibSymbolsIdx = OrderedDict() + self._mibSymbolsIdx = OrderedDict() # Indexing part + def _sortFun(self, name): + # This is potentially ambiguous mapping. Sort modules in + # ascending age for resolution + mb = self.mibBuilder + + if mb.moduleID in mb.mibSymbols[name]: + mib = mb.mibSymbols[name][mb.moduleID] + revs = mib.getRevisions() + if revs: + return revs[0] + + return '1970-01-01 00:00' + def indexMib(self): if self.lastBuildId == self.mibBuilder.lastBuildId: return - debug.logger & debug.FLAG_MIB and debug.logger('indexMib: re-indexing MIB view') + debug.logger & debug.FLAG_MIB and debug.logger( + 'indexMib: re-indexing MIB view') MibScalarInstance, = self.mibBuilder.importSymbols( - 'SNMPv2-SMI', 'MibScalarInstance' - ) + 'SNMPv2-SMI', 'MibScalarInstance') # # Create indices # # Module name -> module-scope indices - self.__mibSymbolsIdx.clear() + self._mibSymbolsIdx.clear() - # Oid <-> label indices + globMibMod = { + 'oidToLabelIdx': OidOrderedDict(), + 'labelToOidIdx': {}, + 'varToNameIdx': {}, + 'typeToModIdx': OrderedDict(), + 'oidToModIdx': {} + } - # This is potentially ambiguous mapping. Sort modules in - # ascending age for resolution - def __sortFun(x, b=self.mibBuilder): - if b.moduleID in b.mibSymbols[x]: - m = b.mibSymbols[x][b.moduleID] - r = m.getRevisions() - if r: - return r[0] + self._mibSymbolsIdx[''] = globMibMod - return "1970-01-01 00:00" + # Oid <-> label indices - modNames = list(self.mibBuilder.mibSymbols.keys()) - modNames.sort(key=__sortFun) + modNames = sorted(self.mibBuilder.mibSymbols, key=self._sortFun) # Index modules names - for modName in [''] + modNames: - # Modules index - self.__mibSymbolsIdx[modName] = mibMod = { + for modName in modNames: + mibMod = { 'oidToLabelIdx': OidOrderedDict(), 'labelToOidIdx': {}, 'varToNameIdx': {}, @@ -75,76 +85,93 @@ class MibViewController(object): 'oidToModIdx': {} } - if not modName: - globMibMod = mibMod - continue + self._mibSymbolsIdx[modName] = mibMod # Types & MIB vars indices for n, v in self.mibBuilder.mibSymbols[modName].items(): if n == self.mibBuilder.moduleID: # do not index this continue # special symbol + if isinstance(v, classTypes): if n in mibMod['typeToModIdx']: raise error.SmiError( - 'Duplicate SMI type %s::%s, has %s' % (modName, n, mibMod['typeToModIdx'][n]) - ) + 'Duplicate SMI type %s::%s, has ' + '%s' % (modName, n, mibMod['typeToModIdx'][n])) + globMibMod['typeToModIdx'][n] = modName mibMod['typeToModIdx'][n] = modName + elif isinstance(v, instanceTypes): if isinstance(v, MibScalarInstance): continue + if n in mibMod['varToNameIdx']: raise error.SmiError( - 'Duplicate MIB variable %s::%s has %s' % (modName, n, mibMod['varToNameIdx'][n]) - ) + 'Duplicate MIB variable %s::%s has ' + '%s' % (modName, n, mibMod['varToNameIdx'][n])) + globMibMod['varToNameIdx'][n] = v.name mibMod['varToNameIdx'][n] = v.name - # Potentionally ambiguous mapping ahead + + # Potentially ambiguous mapping ahead globMibMod['oidToModIdx'][v.name] = modName mibMod['oidToModIdx'][v.name] = modName globMibMod['oidToLabelIdx'][v.name] = (n,) mibMod['oidToLabelIdx'][v.name] = (n,) + else: raise error.SmiError( - 'Unexpected object %s::%s' % (modName, n) - ) + 'Unexpected object %s::%s' % (modName, n)) # Build oid->long-label index - oidToLabelIdx = self.__mibSymbolsIdx['']['oidToLabelIdx'] - labelToOidIdx = self.__mibSymbolsIdx['']['labelToOidIdx'] + oidToLabelIdx = self._mibSymbolsIdx['']['oidToLabelIdx'] + labelToOidIdx = self._mibSymbolsIdx['']['labelToOidIdx'] + prevOid = () baseLabel = () - for key in oidToLabelIdx.keys(): + + for key in oidToLabelIdx: keydiff = len(key) - len(prevOid) + if keydiff > 0: if prevOid: if keydiff == 1: baseLabel = oidToLabelIdx[prevOid] + else: baseLabel += key[-keydiff:-1] else: baseLabel = () + elif keydiff < 0: baseLabel = () keyLen = len(key) + i = keyLen - 1 + while i: k = key[:i] + if k in oidToLabelIdx: baseLabel = oidToLabelIdx[k] + if i != keyLen - 1: baseLabel += key[i:-1] + break + i -= 1 + # Build oid->long-label index oidToLabelIdx[key] = baseLabel + oidToLabelIdx[key] + # Build label->oid index labelToOidIdx[oidToLabelIdx[key]] = key prevOid = key # Build module-scope oid->long-label index - for mibMod in self.__mibSymbolsIdx.values(): - for oid in mibMod['oidToLabelIdx'].keys(): + for mibMod in self._mibSymbolsIdx.values(): + for oid in mibMod['oidToLabelIdx']: mibMod['oidToLabelIdx'][oid] = oidToLabelIdx[oid] mibMod['labelToOidIdx'][oidToLabelIdx[oid]] = oid @@ -154,9 +181,11 @@ class MibViewController(object): def getOrderedModuleName(self, index): self.indexMib() - modNames = self.__mibSymbolsIdx.keys() + + modNames = self._mibSymbolsIdx if modNames: return modNames[index] + raise error.SmiError('No modules loaded at %s' % self) def getFirstModuleName(self): @@ -167,69 +196,89 @@ class MibViewController(object): def getNextModuleName(self, modName): self.indexMib() + try: - return self.__mibSymbolsIdx.nextKey(modName) + return self._mibSymbolsIdx.nextKey(modName) + except KeyError: raise error.SmiError( - 'No module next to %s at %s' % (modName, self) - ) + 'No module next to %s at %s' % (modName, self)) # MIB tree node management - def __getOidLabel(self, nodeName, oidToLabelIdx, labelToOidIdx): + def _getOidLabel(self, nodeName, oidToLabelIdx, labelToOidIdx): """getOidLabel(nodeName) -> (oid, label, suffix)""" if not nodeName: return nodeName, nodeName, () + if nodeName in labelToOidIdx: return labelToOidIdx[nodeName], nodeName, () + if nodeName in oidToLabelIdx: return nodeName, oidToLabelIdx[nodeName], () + if len(nodeName) < 2: return nodeName, nodeName, () - oid, label, suffix = self.__getOidLabel( - nodeName[:-1], oidToLabelIdx, labelToOidIdx - ) + + oid, label, suffix = self._getOidLabel( + nodeName[:-1], oidToLabelIdx, labelToOidIdx) + suffix = suffix + nodeName[-1:] + resLabel = label + tuple([str(x) for x in suffix]) if resLabel in labelToOidIdx: return labelToOidIdx[resLabel], resLabel, () + resOid = oid + suffix if resOid in oidToLabelIdx: return resOid, oidToLabelIdx[resOid], () + return oid, label, suffix def getNodeNameByOid(self, nodeName, modName=''): self.indexMib() - if modName in self.__mibSymbolsIdx: - mibMod = self.__mibSymbolsIdx[modName] + + if modName in self._mibSymbolsIdx: + mibMod = self._mibSymbolsIdx[modName] + else: raise error.SmiError('No module %s at %s' % (modName, self)) - oid, label, suffix = self.__getOidLabel( - nodeName, mibMod['oidToLabelIdx'], mibMod['labelToOidIdx'] - ) + + oid, label, suffix = self._getOidLabel( + nodeName, mibMod['oidToLabelIdx'], mibMod['labelToOidIdx']) + if oid == label: raise error.NoSuchObjectError( - str='Can\'t resolve node name %s::%s at %s' % - (modName, nodeName, self) - ) + str='Cannot resolve node name %s::%s at ' + '%s' % (modName, nodeName, self)) + debug.logger & debug.FLAG_MIB and debug.logger( - 'getNodeNameByOid: resolved %s:%s -> %s.%s' % (modName, nodeName, label, suffix)) + 'getNodeNameByOid: resolved %s:%s -> ' + '%s.%s' % (modName, nodeName, label, suffix)) + return oid, label, suffix def getNodeNameByDesc(self, nodeName, modName=''): self.indexMib() - if modName in self.__mibSymbolsIdx: - mibMod = self.__mibSymbolsIdx[modName] + + if modName in self._mibSymbolsIdx: + mibMod = self._mibSymbolsIdx[modName] + else: raise error.SmiError('No module %s at %s' % (modName, self)) + if nodeName in mibMod['varToNameIdx']: oid = mibMod['varToNameIdx'][nodeName] + else: raise error.NoSuchObjectError( - str='No such symbol %s::%s at %s' % (modName, nodeName, self) - ) + str='No such symbol %s::%s at ' + '%s' % (modName, nodeName, self)) + debug.logger & debug.FLAG_MIB and debug.logger( - 'getNodeNameByDesc: resolved %s:%s -> %s' % (modName, nodeName, oid)) + 'getNodeNameByDesc: resolved %s:%s -> ' + '%s' % (modName, nodeName, oid)) + return self.getNodeNameByOid(oid, modName) def getNodeName(self, nodeName, modName=''): @@ -238,28 +287,36 @@ class MibViewController(object): try: # First try nodeName as an OID/label return self.getNodeNameByOid(nodeName, modName) + except error.NoSuchObjectError: # ...on failure, try as MIB symbol oid, label, suffix = self.getNodeNameByDesc(nodeName[0], modName) + # ...with trailing suffix return self.getNodeNameByOid(oid + suffix + nodeName[1:], modName) def getOrderedNodeName(self, index, modName=''): self.indexMib() - if modName in self.__mibSymbolsIdx: - mibMod = self.__mibSymbolsIdx[modName] + + if modName in self._mibSymbolsIdx: + mibMod = self._mibSymbolsIdx[modName] + else: raise error.SmiError('No module %s at %s' % (modName, self)) + if not mibMod['oidToLabelIdx']: raise error.NoSuchObjectError( - str='No variables at MIB module %s at %s' % (modName, self) - ) + str='No variables at MIB module %s at ' + '%s' % (modName, self)) + try: oid, label = mibMod['oidToLabelIdx'].items()[index] + except KeyError: raise error.NoSuchObjectError( - str='No symbol at position %s in MIB module %s at %s' % (index, modName, self) - ) + str='No symbol at position %s in MIB module %s at ' + '%s' % (index, modName, self)) + return oid, label, () def getFirstNodeName(self, modName=''): @@ -272,55 +329,67 @@ class MibViewController(object): oid, label, suffix = self.getNodeName(nodeName, modName) try: return self.getNodeName( - self.__mibSymbolsIdx[modName]['oidToLabelIdx'].nextKey(oid) + suffix, modName - ) + self._mibSymbolsIdx[modName]['oidToLabelIdx'].nextKey(oid) + suffix, + modName) + except KeyError: raise error.NoSuchObjectError( - str='No name next to %s::%s at %s' % (modName, nodeName, self) - ) + str='No name next to %s::%s at ' + '%s' % (modName, nodeName, self)) def getParentNodeName(self, nodeName, modName=''): oid, label, suffix = self.getNodeName(nodeName, modName) + if len(oid) < 2: raise error.NoSuchObjectError( - str='No parent name for %s::%s at %s' % - (modName, nodeName, self) - ) + str='No parent name for %s::%s at ' + '%s' % (modName, nodeName, self)) + return oid[:-1], label[:-1], oid[-1:] + suffix def getNodeLocation(self, nodeName, modName=''): oid, label, suffix = self.getNodeName(nodeName, modName) - return self.__mibSymbolsIdx['']['oidToModIdx'][oid], label[-1], suffix + return (self._mibSymbolsIdx['']['oidToModIdx'][oid], label[-1], + suffix) # MIB type management def getTypeName(self, typeName, modName=''): self.indexMib() - if modName in self.__mibSymbolsIdx: - mibMod = self.__mibSymbolsIdx[modName] + + if modName in self._mibSymbolsIdx: + mibMod = self._mibSymbolsIdx[modName] + else: raise error.SmiError( - 'No module %s at %s' % (modName, self) - ) + 'No module %s at %s' % (modName, self)) + if typeName in mibMod['typeToModIdx']: m = mibMod['typeToModIdx'][typeName] + else: raise error.NoSuchObjectError( - str='No such type %s::%s at %s' % (modName, typeName, self) - ) + str='No such type %s::%s at ' + '%s' % (modName, typeName, self)) + return m, typeName def getOrderedTypeName(self, index, modName=''): self.indexMib() - if modName in self.__mibSymbolsIdx: - mibMod = self.__mibSymbolsIdx[modName] + + if modName in self._mibSymbolsIdx: + mibMod = self._mibSymbolsIdx[modName] + else: raise error.SmiError('No module %s at %s' % (modName, self)) + if not mibMod['typeToModIdx']: raise error.NoSuchObjectError( - str='No types at MIB module %s at %s' % (modName, self) - ) - t = mibMod['typeToModIdx'].keys()[index] + str='No types at MIB module %s at ' + '%s' % (modName, self)) + + t = list(mibMod['typeToModIdx'])[index] + return mibMod['typeToModIdx'][t], t def getFirstTypeName(self, modName=''): @@ -331,9 +400,11 @@ class MibViewController(object): def getNextType(self, typeName, modName=''): m, t = self.getTypeName(typeName, modName) + try: - return self.__mibSymbolsIdx[m]['typeToModIdx'].nextKey(t) + return self._mibSymbolsIdx[m]['typeToModIdx'].nextKey(t) + except KeyError: raise error.NoSuchObjectError( - str='No type next to %s::%s at %s' % (modName, typeName, self) - ) + str='No type next to %s::%s at ' + '%s' % (modName, typeName, self)) -- cgit v1.2.1