Compare commits

...

21 Commits

Author SHA1 Message Date
Ilya Etingof acd16a65f8 Disable pypy build in Travis
Because it stopped working.
2018-11-03 19:44:02 +01:00
Ilya Etingof e425da2a0f Disable Travis builds for py 2.6, 3.2 & 3.3
Seems like they discontinued those.
2018-11-03 14:18:59 +01:00
Ilya Etingof 4994111b2b Fix hlapi LCD to include `contextName` (#217)
Fixed hlapi LCD configurator to include `contextName`.
Prior to this fix sending SNMPv3 TRAP with non-default
`contextName` would fail.

This change modifies the signature of the internal
LCD methods.
2018-11-03 12:55:51 +01:00
Ilya Etingof 9ebd0c0fab Expose ASN.1 `Null` type through `rfc1902` module 2018-10-26 08:45:56 +02:00
Ilya Etingof 4aac8b23d5 Use `compile()` before `exec` of MIB modules
This change attaches the file name to the stack frames
what is helpful when reading traceback or debugging
interactively.
2018-10-26 08:45:46 +02:00
Ilya Etingof 602c4dd304 Merge branch 'master' of github.com:etingof/pysnmp 2018-10-26 08:20:37 +02:00
Ilya Etingof 0c0d054e8e
Refactor MIB state machine into asynchronous operations (#210)
Convert to async MIB instrumentation API (#210)

MIB instrumentation API changed to allow for asynchronous
managed objects access. The MIB instrumentation methods
called by the state machine now return immediately and
resume once the callback is called.

The built-in SNMPv2-SMI objects are still synchronous.

This change is a prerequisite for fully asynchronous managed objects
implementation.
2018-10-24 10:14:33 +02:00
Ilya Etingof 40cfd938c4 Fix typos 2018-10-17 23:28:26 +02:00
Ilya Etingof 534a5bb810
Convert to async MIB instrumentation API (#209)
MIB instrumentation API changed to allow for asynchronous
managed objects access. Although built-in SNMPv2-SMI objects
are still synchronous, the MIB instrumentation API is async
what allows users to replace default MIB instrumentation
with their own, potentially asynchronous.

CommandResponder refactored to facilitate asynchronous
MIB instrumentation routines. The `readVars`, `readNextVars`
and `writeVars` MIB controller methods return immediately and
deliver their results via a call back.

SMI/MIB managed objects API overhauled for simplicity and
flexibility breaking backward compatibility.
2018-10-13 20:21:31 +02:00
Ilya Etingof 12138b182c Fix Sphinx markup for USM crypto algorithm IDs 2018-10-06 20:15:39 +02:00
Ilya Etingof 593ff19283 Reformat `isAccessAllowed()` for clarity 2018-10-06 09:32:23 +02:00
Fabrizio Vanni 35e9c6f7a6 Avoid deprecation warnings for asyncio.async() in server mode (#202)
This is actually needed for Python 3.7 which introduces async and await
as  reserved keywords, see https://docs.python.org/3/whatsnew/3.7.html
2018-09-26 11:12:30 +02:00
Ilya Etingof 53e67f9533 Ensure distinct transports if timeout/retries differ
Fix hlapi/v3arch transport target caching to ensure transport targets
are different even if just timeout/retries options differ.
2018-09-20 10:45:38 +02:00
Ilya Etingof da7582db99 Register missing v1arch.asyncore.sync sub-package 2018-09-14 01:30:35 +02:00
Ilya Etingof b334f5cf63 Accommodate changed `.writeVars` signature 2018-09-14 00:53:45 +02:00
Ilya Etingof 6e30bc0457 Release 4.4.6 2018-09-13 23:53:35 +02:00
Ilya Etingof bdc0ac2977
Tolerate non-initialised entries in SNMP community table (#195)
It can happen that SNMP community table contains uninitialized entries.
These entries may stop internal SNMP community table indexing which
is done in rfc2576 to speed up SNMP engine operations when SNMPv1/v2c
is involved. Once a bad entry gets into SNMP community table, all
the rest queries would start failing.

This patch ignores incomplete SNMP community table entries in the
course of building indices.
2018-09-13 23:51:43 +02:00
Ilya Etingof 74434d710c Tolerate duplicate enumerations
Possible duplicate enumerations in `Bits` and `Integer` SMI types
causes pyasn1 exception. This fix reduces duplicates prior to
passing them to pyasn1.
2018-09-09 12:24:39 +02:00
Ilya Etingof b2b10e75c5 Add a CHANGELOG entry for previous fix 2018-09-09 09:40:04 +02:00
Ryan Van Gilder 7cd0b148b1 Fix lcd.unconfigure not removing cached addr value preventing the same target being re-configured (#194) 2018-09-09 09:29:32 +02:00
Ilya Etingof 1537699336 Simplify SNMPv3 TRAP receiver example 2018-09-02 08:45:31 +02:00
32 changed files with 771 additions and 451 deletions

View File

@ -2,22 +2,10 @@ language: python
cache: pip
matrix:
include:
- os: linux
dist: xenial
sudo: false
python: '2.6'
- os: linux
dist: xenial
sudo: false
python: '2.7'
- os: linux
dist: xenial
sudo: false
python: '3.2'
- os: linux
dist: xenial
sudo: false
python: '3.3'
- os: linux
dist: xenial
sudo: false
@ -38,14 +26,14 @@ matrix:
dist: xenial
sudo: false
python: 'nightly'
- os: linux
dist: xenial
sudo: false
python: 'pypy'
- os: linux
dist: xenial
sudo: false
python: 'pypy3'
# - os: linux
# dist: xenial
# sudo: false
# python: 'pypy'
# - os: linux
# dist: xenial
# sudo: false
# python: 'pypy3'
install:
- pip install -r requirements.txt -r devel-requirements.txt -r extra-requirements.txt
- pip install -e .

View File

@ -1,13 +1,15 @@
Revision 5.0.0, released 2018-09-??
Revision 5.0.0, released 2018-10-??
-----------------------------------
- SNMPv3 crypto operations that require external dependencies
made dependent on the optional external
package -- pysnmpcrypto.
- By switching to pysnmpcrypto, pysnmp effectively migrates from
PyCryptodomex to pyca/cryptography whenever available on the
platform.
- Many really old backward-compatibility code snippets removed.
Most importantly:
@ -19,13 +21,22 @@ Revision 5.0.0, released 2018-09-??
- The MIB instrumentation API overhauled in backward incompatible
way:
- MIB instrumentation methods signatures simplified to accept
just var-binds (as var-arg), the rest of the parameters packed
into opaque kwargs
- CommandResponder application passes `snmpEngine` and optionally
user-supplied `cbCtx` object throughout the MIB instrumentation
methods. The goal is to let MIB objects access/modify whatever
custom Python objects they need while being called back.
* MIB instrumentation methods signatures simplified to accept
just var-binds (as var-arg), the rest of the parameters packed
into opaque kwargs
* The `readVars`, `readNextVars` and `writeVars` methods of MIB
instrumentation controller return immediately and deliver their
results via a call back.
* CommandResponder application passes `snmpEngine` and optionally
user-supplied `cbCtx` object throughout the MIB instrumentation
methods. The goal is to let MIB objects access/modify whatever
custom Python objects they need while being called back.
* CommandResponder refactored to facilitate asynchronous
MIB instrumentation routines.
- The high-level API (`hlapi`) extended to cover lightweight SNMP v1arch
in hope to ease the use of packet-level SNMP API.
@ -41,16 +52,37 @@ Revision 5.0.0, released 2018-09-??
automation around building well-formed SNMP messages is and mediating
differences between SNMP versions is not present in this new `v1arch`
layer.
- The signature of the hlapi `.sendNotification()` call has changed
to accept `*varBinds` instead of a sequence of `varBinds`. The rationale
is to unify this method call with similar methods of CommandGenerator.
This change should not compromise backward compatibility with pysnmp 4.
Revision 4.4.6, released 2018-09-XX
Revision 4.4.7, released 2018-11-XX
-----------------------------------
- Exposed ASN.1 `Null` type through `rfc1902` module for convenience.
- Use `compile()` before `exec`'ing MIB modules to attach filename to
the stack frames (ultimately shown in traceback/debugger)
- Fixed hlapi/v3arch transport target caching to ensure transport targets
are different even if just timeout/retries options differ
- Fixed hlapi LCD configurator to include `contextName`. Prior to this fix
sending SNMPv3 TRAP with non-default `contextName` would fail.
Revision 4.4.6, released 2018-09-13
-----------------------------------
- Improved package build and dependency tracking
- Fixed missing LICENSE from the tarball distribution
- Fixed `CommandGeneratorLcdConfigurator.unconfigure()` to fully clean up
internal caches, otherwise repetitive attempts to configure the target
would fail.
- Fix to tolerate possible duplicate enumerations in `Bits` and `Integer`
SMI types.
- Fix to tolerate non-initialised entries in SNMP community table. Once a
bad entry sneaked into the SNMP community table, all the subsequent
SNMP v1/v2c operations failed. The fix ignores incomplete SNMP community
table entries in the course of building indices.
Revision 4.4.5, released 2018-08-05
-----------------------------------

View File

@ -49,10 +49,10 @@ saves its configuration for the lifetime of SNMP engine object.
.. toctree::
:maxdepth: 2
.. autoclass:: pysnmp.hlapi.UdpTransportTarget
.. autoclass:: pysnmp.hlapi.v3arch.UdpTransportTarget
:members: setLocalAddress
.. autoclass:: pysnmp.hlapi.Udp6TransportTarget
.. autoclass:: pysnmp.hlapi.v3arch.Udp6TransportTarget
:members: setLocalAddress
High-level v3arch asyncore
@ -183,7 +183,7 @@ Engine object on input.
.. toctree::
:maxdepth: 2
.. autoclass:: pysnmp.hlapi.SnmpEngine(snmpEngineID=None)
.. autoclass:: pysnmp.hlapi.v3arch.SnmpEngine(snmpEngineID=None)
High-level v3arch auth
----------------------
@ -199,41 +199,47 @@ Community-based
+++++++++++++++
Security Parameters object is Security Model specific. The
:py:class:`~pysnmp.hlapi.CommunityData`
:py:class:`~pysnmp.hlapi.v3arch.CommunityData`
class is used for configuring Community-Based Security Model of SNMPv1/SNMPv2c.
.. toctree::
:maxdepth: 2
.. autoclass:: pysnmp.hlapi.CommunityData(communityIndex, communityName=None, mpModel=1, contextEngineId=None, contextName='', tag='')
.. autoclass:: pysnmp.hlapi.v3arch.CommunityData(communityIndex, communityName=None, mpModel=1, contextEngineId=None, contextName='', tag='')
User-based
++++++++++
The :py:class:`~pysnmp.hlapi.UsmUserData` class provides SNMPv3 User-Based
The :py:class:`~pysnmp.hlapi.v3arch.UsmUserData` class provides SNMPv3 User-Based
Security Model configuration for SNMP v3 systems.
.. autoclass:: pysnmp.hlapi.UsmUserData(userName, authKey=None, privKey=None, authProtocol=usmNoAuthProtocol, privProtocol=usmNoPrivProtocol, securityEngineId=None)
.. autoclass:: pysnmp.hlapi.v3arch.UsmUserData(userName, authKey=None, privKey=None, authProtocol=usmNoAuthProtocol, privProtocol=usmNoPrivProtocol, securityEngineId=None)
Identification of Authentication and Privacy Protocols is done
via constant OIDs:
**Authentication protocol identifiers**
.. autodata:: pysnmp.hlapi.usmNoAuthProtocol
.. autodata:: pysnmp.hlapi.usmHMACMD5AuthProtocol
.. autodata:: pysnmp.hlapi.usmHMACSHAAuthProtocol
.. autodata:: pysnmp.hlapi.usmHMAC128SHA224AuthProtocol
.. autodata:: pysnmp.hlapi.usmHMAC192SHA256AuthProtocol
.. autodata:: pysnmp.hlapi.usmHMAC256SHA384AuthProtocol
.. autodata:: pysnmp.hlapi.usmHMAC384SHA512AuthProtocol
.. autodata:: pysnmp.hlapi.v3arch.usmNoAuthProtocol
.. autodata:: pysnmp.hlapi.v3arch.usmHMACMD5AuthProtocol
.. autodata:: pysnmp.hlapi.v3arch.usmHMACSHAAuthProtocol
.. autodata:: pysnmp.hlapi.v3arch.usmHMAC128SHA224AuthProtocol
.. autodata:: pysnmp.hlapi.v3arch.usmHMAC192SHA256AuthProtocol
.. autodata:: pysnmp.hlapi.v3arch.usmHMAC256SHA384AuthProtocol
.. autodata:: pysnmp.hlapi.v3arch.usmHMAC384SHA512AuthProtocol
.. autodata:: pysnmp.hlapi.usmNoPrivProtocol
.. autodata:: pysnmp.hlapi.usmDESPrivProtocol
.. autodata:: pysnmp.hlapi.usm3DESEDEPrivProtocol
.. autodata:: pysnmp.hlapi.usmAesCfb128Protocol
.. autodata:: pysnmp.hlapi.usmAesCfb192Protocol
.. autodata:: pysnmp.hlapi.usmAesCfb256Protocol
.. autodata:: pysnmp.hlapi.usmAesBlumenthalCfb192Protocol
.. autodata:: pysnmp.hlapi.usmAesBlumenthalCfb256Protocol
**Privacy (encryption) protocol identifiers**
.. autodata:: pysnmp.hlapi.v3arch.usmNoPrivProtocol
.. autodata:: pysnmp.hlapi.v3arch.usmDESPrivProtocol
.. autodata:: pysnmp.hlapi.v3arch.usm3DESEDEPrivProtocol
.. autodata:: pysnmp.hlapi.v3arch.usmAesCfb128Protocol
.. autodata:: pysnmp.hlapi.v3arch.usmAesCfb192Protocol
.. autodata:: pysnmp.hlapi.v3arch.usmAesCfb256Protocol
.. autodata:: pysnmp.hlapi.v3arch.usmAesBlumenthalCfb192Protocol
.. autodata:: pysnmp.hlapi.v3arch.usmAesBlumenthalCfb256Protocol
.. note::
SNMP authentication and encryption keys must be at least *eight*
octets long.
Transport configuration is I/O framework specific and is described in
respective sections.
@ -263,12 +269,12 @@ SNMP engine. See :RFC:`3411#section-3.3.1` for details.
The SNMP context information necessary for this mapping procedure
to operate is supplied through the
:py:class:`~pysnmp.hlapi.CommunityData` object.
:py:class:`~pysnmp.hlapi.v3arch.CommunityData` object.
.. toctree::
:maxdepth: 2
.. autoclass:: pysnmp.hlapi.ContextData
.. autoclass:: pysnmp.hlapi.v3arch.ContextData
High-level v1arch sync
----------------------
@ -435,6 +441,20 @@ data description language. PySNMP types are derived from
.. toctree::
:maxdepth: 2
.. _null:
Null type
+++++++++
.. autoclass:: pysnmp.proto.rfc1902.Null(initializer)
:members:
.. note::
The `NULL` type actually belongs to the base ASN.1 types. It is not defined
in :RFC:`1902#section-2` as an SNMP type. The `Null` type is exposed through
`rfc1902` module just for convenience.
.. _integer32:
Integer32 type

View File

@ -51,13 +51,23 @@ if __name__ == '__main__':
mibInstrum = instrum.MibInstrumController(mibBuilder)
def cbFun(varBinds, **context):
for oid, val in varBinds:
if exval.endOfMib.isSameTypeWith(val):
context['state']['stop'] = True
print('%s = %s' % ('.'.join([str(x) for x in oid]), not val.isValue and 'N/A' or val.prettyPrint()))
context['state']['varBinds'] = varBinds
context = {
'cbFun': cbFun,
'state': {
'varBinds': [((1, 3, 6), None)],
'stop': False
}
}
print('Remote manager read access to MIB instrumentation (table walk)')
varBinds = [((), None)]
while True:
varBinds = mibInstrum.readNextVars(*varBinds)
oid, val = varBinds[0]
if exval.endOfMib.isSameTypeWith(val):
break
print(oid, val.prettyPrint())
while not context['state']['stop']:
mibInstrum.readNextVars(*context['state']['varBinds'], **context)
print('done')

View File

@ -26,24 +26,40 @@ snmpCommunityEntry, = mibBuilder.importSymbols(
instanceId = snmpCommunityEntry.getInstIdFromIndices('my-router')
print('done')
def cbFun(varBinds, **context):
for oid, val in varBinds:
print('%s = %s' % ('.'.join([str(x) for x in oid]), not val.isValue and 'N/A' or val.prettyPrint()))
print('Create/update SNMP-COMMUNITY-MIB::snmpCommunityEntry table row: ')
varBinds = mibInstrum.writeVars(
mibInstrum.writeVars(
(snmpCommunityEntry.name + (2,) + instanceId, 'mycomm'),
(snmpCommunityEntry.name + (3,) + instanceId, 'mynmsname'),
(snmpCommunityEntry.name + (7,) + instanceId, 'volatile')
(snmpCommunityEntry.name + (7,) + instanceId, 'volatile'),
cbFun=cbFun
)
for oid, val in varBinds:
print('%s = %s' % ('.'.join([str(x) for x in oid]), not val.isValue and 'N/A' or val.prettyPrint()))
print('done')
def cbFun(varBinds, **context):
for oid, val in varBinds:
if exval.endOfMib.isSameTypeWith(val):
context['state']['stop'] = True
print('%s = %s' % ('.'.join([str(x) for x in oid]), not val.isValue and 'N/A' or val.prettyPrint()))
context['state']['varBinds'] = varBinds
context = {
'cbFun': cbFun,
'state': {
'varBinds': [((1, 3, 6), None)],
'stop': False
}
}
print('Read whole MIB (table walk)')
varBinds = [((), None)]
while True:
varBinds = mibInstrum.readNextVars(*varBinds)
oid, val = varBinds[0]
if exval.endOfMib.isSameTypeWith(val):
break
print('%s = %s' % ('.'.join([str(x) for x in oid]), not val.isValue and 'N/A' or val.prettyPrint()))
while not context['state']['stop']:
mibInstrum.readNextVars(*context['state']['varBinds'], **context)
print('done')
print('Unloading MIB modules...'),

View File

@ -54,7 +54,9 @@ snmpContext = context.SnmpContext(snmpEngine)
# always echos request var-binds in response.
class EchoMibInstrumController(instrum.AbstractMibInstrumController):
def readVars(self, *varBinds, **context):
return [(ov[0], v2c.OctetString('You queried OID %s' % ov[0])) for ov in varBinds]
cbFun = context.get('cbFun')
if cbFun:
cbFun([(ov[0], v2c.OctetString('You queried OID %s' % ov[0])) for ov in varBinds], **context)
# Create a custom Management Instrumentation Controller and register at

View File

@ -56,7 +56,7 @@ MibScalar, MibScalarInstance = mibBuilder.importSymbols(
class MyStaticMibScalarInstance(MibScalarInstance):
# noinspection PyUnusedLocal,PyUnusedLocal
def getValue(self, name, idx):
def getValue(self, name, idx, **context):
return self.getSyntax().clone(
'Python %s running on a %s platform' % (sys.version, sys.platform)
)

View File

@ -42,15 +42,8 @@ config.addTransport(
# SNMPv3/USM setup
# user: usr-md5-des, auth: MD5, priv DES
config.addV3User(
snmpEngine, 'usr-md5-des',
config.usmHMACMD5AuthProtocol, 'authkey1',
config.usmDESPrivProtocol, 'privkey1'
)
# user: usr-md5-des, auth: MD5, priv DES, securityEngineId: 8000000001020304
# this USM entry is used for TRAP receiving purposes
# this USM entry is configured for TRAP receiving purposes
config.addV3User(
snmpEngine, 'usr-md5-des',
config.usmHMACMD5AuthProtocol, 'authkey1',
@ -58,28 +51,16 @@ config.addV3User(
securityEngineId=v2c.OctetString(hexValue='8000000001020304')
)
# user: usr-md5-none, auth: MD5, priv NONE
config.addV3User(
snmpEngine, 'usr-md5-none',
config.usmHMACMD5AuthProtocol, 'authkey1'
)
# user: usr-md5-none, auth: MD5, priv NONE, securityEngineId: 8000000001020304
# this USM entry is used for TRAP receiving purposes
# this USM entry is configured for TRAP receiving purposes
config.addV3User(
snmpEngine, 'usr-md5-none',
config.usmHMACMD5AuthProtocol, 'authkey1',
securityEngineId=v2c.OctetString(hexValue='8000000001020304')
)
# user: usr-sha-aes128, auth: SHA, priv AES
config.addV3User(
snmpEngine, 'usr-sha-aes128',
config.usmHMACSHAAuthProtocol, 'authkey1',
config.usmAesCfb128Protocol, 'privkey1'
)
# user: usr-sha-aes128, auth: SHA, priv AES, securityEngineId: 8000000001020304
# this USM entry is used for TRAP receiving purposes
# this USM entry is configured for TRAP receiving purposes
config.addV3User(
snmpEngine, 'usr-sha-aes128',
config.usmHMACSHAAuthProtocol, 'authkey1',

View File

@ -96,7 +96,7 @@ class CommandResponder(cmdrsp.CommandResponderBase):
v2c.GetNextRequestPDU.tagSet: cmdgen.NextCommandGeneratorSingleRun(),
v2c.GetBulkRequestPDU.tagSet: cmdgen.BulkCommandGeneratorSingleRun()
}
pduTypes = cmdGenMap.keys() # This app will handle these PDUs
SUPPORTED_PDU_TYPES = cmdGenMap.keys() # This app will handle these PDUs
# SNMP request relay
def handleMgmtOperation(self, snmpEngine, stateReference, contextName,

View File

@ -95,7 +95,7 @@ class CommandResponder(cmdrsp.CommandResponderBase):
v2c.GetNextRequestPDU.tagSet: cmdgen.NextCommandGeneratorSingleRun(),
v2c.GetBulkRequestPDU.tagSet: cmdgen.BulkCommandGeneratorSingleRun()
}
pduTypes = cmdGenMap.keys() # This app will handle these PDUs
SUPPORTED_PDU_TYPES = cmdGenMap.keys() # This app will handle these PDUs
# SNMP request relay
def handleMgmtOperation(self, snmpEngine, stateReference, contextName,

View File

@ -95,7 +95,7 @@ class CommandResponder(cmdrsp.CommandResponderBase):
v2c.GetNextRequestPDU.tagSet: cmdgen.NextCommandGeneratorSingleRun(),
v2c.GetBulkRequestPDU.tagSet: cmdgen.BulkCommandGeneratorSingleRun()
}
pduTypes = cmdGenMap.keys() # This app will handle these PDUs
SUPPORTED_PDU_TYPES = cmdGenMap.keys() # This app will handle these PDUs
# SNMP request relay
def handleMgmtOperation(self, snmpEngine, stateReference, contextName,

View File

@ -98,7 +98,7 @@ class CommandResponder(cmdrsp.CommandResponderBase):
v2c.GetNextRequestPDU.tagSet: cmdgen.NextCommandGeneratorSingleRun(),
v2c.GetBulkRequestPDU.tagSet: cmdgen.BulkCommandGeneratorSingleRun()
}
pduTypes = cmdGenMap.keys() # This app will handle these PDUs
SUPPORTED_PDU_TYPES = cmdGenMap.keys() # This app will handle these PDUs
# SNMP request relay
def handleMgmtOperation(self, snmpEngine, stateReference, contextName,

View File

@ -101,7 +101,11 @@ class DgramAsyncioProtocol(asyncio.DatagramProtocol, AbstractAsyncioTransport):
c = self.loop.create_datagram_endpoint(
lambda: self, local_addr=iface, family=self.sockFamily
)
self._lport = getattr(asyncio, 'async')(c)
# 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

View File

@ -99,7 +99,7 @@ class DgramSocketTransport(AbstractSocketTransport):
except socket.error:
raise error.CarrierError('setsockopt() for IP_TRANSPARENT failed: %s' % sys.exc_info()[1])
except OSError:
raise error.CarrierError('IP_TRANSPARENT socket option requires superusre previleges')
raise error.CarrierError('IP_TRANSPARENT socket option requires superuser priveleges')
debug.logger & debug.flagIO and debug.logger('enableTransparent: %s option IP_TRANSPARENT on socket %s' % (flag and "enabled" or "disabled", self.socket.fileno()))
return self

View File

@ -27,7 +27,9 @@ usmHMAC128SHA224AuthProtocol = hmacsha2.HmacSha2.sha224ServiceID
usmHMAC192SHA256AuthProtocol = hmacsha2.HmacSha2.sha256ServiceID
usmHMAC256SHA384AuthProtocol = hmacsha2.HmacSha2.sha384ServiceID
usmHMAC384SHA512AuthProtocol = hmacsha2.HmacSha2.sha512ServiceID
usmNoAuthProtocol = noauth.NoAuth.serviceID
"""No authentication service"""
# Privacy protocol
usmDESPrivProtocol = des.Des.serviceID
@ -407,7 +409,7 @@ def addContext(snmpEngine, contextName):
vacmContextEntry, tblIdx = __cookVacmContextInfo(snmpEngine, contextName)
snmpEngine.msgAndPduDsp.mibInstrumController.writeVars(
((vacmContextEntry.name + (2,) + tblIdx, 'destroy'),)
(vacmContextEntry.name + (2,) + tblIdx, 'destroy')
)
snmpEngine.msgAndPduDsp.mibInstrumController.writeVars(
(vacmContextEntry.name + (1,) + tblIdx, contextName),
@ -420,7 +422,8 @@ def delContext(snmpEngine, contextName):
vacmContextEntry, tblIdx = __cookVacmContextInfo(snmpEngine, contextName)
snmpEngine.msgAndPduDsp.mibInstrumController.writeVars(
((vacmContextEntry.name + (2,) + tblIdx, 'destroy'),)
(vacmContextEntry.name + (2,) + tblIdx, 'destroy'),
** dict(snmpEngine=snmpEngine)
)
@ -575,12 +578,13 @@ def addVacmUser(snmpEngine, securityModel, securityName, securityLevel,
def delVacmUser(snmpEngine, securityModel, securityName, securityLevel,
readSubTree=(), writeSubTree=(), notifySubTree=()):
readSubTree=(), writeSubTree=(), notifySubTree=(),
contextName=null):
(groupName, securityLevel, readView, writeView,
notifyView) = __cookVacmUserInfo(snmpEngine, securityModel,
securityName, securityLevel)
delVacmGroup(snmpEngine, securityModel, securityName)
delVacmAccess(snmpEngine, groupName, null, securityModel, securityLevel)
delVacmAccess(snmpEngine, groupName, contextName, securityModel, securityLevel)
if readSubTree:
delVacmView(
snmpEngine, readView, readSubTree
@ -594,7 +598,6 @@ def delVacmUser(snmpEngine, securityModel, securityName, securityLevel,
snmpEngine, notifyView, notifySubTree
)
# Notification target setup
def __cookNotificationTargetInfo(snmpEngine, notificationName, paramsName,

View File

@ -15,26 +15,41 @@ from pysnmp import debug
# 3.2
class CommandResponderBase(object):
acmID = 3 # default MIB access control method to use
pduTypes = ()
SUPPORTED_PDU_TYPES = ()
SMI_ERROR_MAP = {
pysnmp.smi.error.NoAccessError: 'noAccess',
pysnmp.smi.error.WrongTypeError: 'wrongType',
pysnmp.smi.error.WrongLengthError: 'wrongLength',
pysnmp.smi.error.WrongEncodingError: 'wrongEncoding',
pysnmp.smi.error.WrongValueError: 'wrongValue',
pysnmp.smi.error.NoCreationError: 'noCreation',
pysnmp.smi.error.InconsistentValueError: 'inconsistentValue',
pysnmp.smi.error.ResourceUnavailableError: 'resourceUnavailable',
pysnmp.smi.error.CommitFailedError: 'commitFailed',
pysnmp.smi.error.UndoFailedError: 'undoFailed',
pysnmp.smi.error.AuthorizationError: 'authorizationError',
pysnmp.smi.error.NotWritableError: 'notWritable',
pysnmp.smi.error.InconsistentNameError: 'inconsistentName'
}
def __init__(self, snmpEngine, snmpContext, cbCtx=None):
snmpEngine.msgAndPduDsp.registerContextEngineId(
snmpContext.contextEngineId, self.pduTypes, self.processPdu
snmpContext.contextEngineId, self.SUPPORTED_PDU_TYPES, self.processPdu
)
self.snmpContext = snmpContext
self.cbCtx = cbCtx
self.__pendingReqs = {}
def handleMgmtOperation(self, snmpEngine, stateReference,
contextName, PDU, acCtx):
pass
def close(self, snmpEngine):
snmpEngine.msgAndPduDsp.unregisterContextEngineId(
self.snmpContext.contextEngineId, self.pduTypes
self.snmpContext.contextEngineId, self.SUPPORTED_PDU_TYPES
)
self.snmpContext = self.__pendingReqs = None
def releaseStateInformation(self, stateReference):
if stateReference in self.__pendingReqs:
del self.__pendingReqs[stateReference]
def sendVarBinds(self, snmpEngine, stateReference,
errorStatus, errorIndex, varBinds):
(messageProcessingModel,
@ -106,10 +121,6 @@ class CommandResponderBase(object):
_setRequestType = rfc1905.SetRequestPDU.tagSet
_counter64Type = rfc1902.Counter64.tagSet
def releaseStateInformation(self, stateReference):
if stateReference in self.__pendingReqs:
del self.__pendingReqs[stateReference]
def processPdu(self, snmpEngine, messageProcessingModel, securityModel,
securityName, securityLevel, contextEngineId, contextName,
pduVersion, PDU, maxSizeResponseScopedPDU, stateReference):
@ -141,63 +152,11 @@ class CommandResponderBase(object):
# 3.2.5
varBinds = v2c.apiPDU.getVarBinds(PDU)
errorStatus, errorIndex = 'noError', 0
debug.logger & debug.flagApp and debug.logger(
'processPdu: stateReference %s, varBinds %s' % (stateReference, varBinds))
try:
self.handleMgmtOperation(snmpEngine, stateReference, contextName, PDU)
# SNMPv2 SMI exceptions
except pysnmp.smi.error.GenError:
errorIndication = sys.exc_info()[1]
debug.logger & debug.flagApp and debug.logger(
'processPdu: stateReference %s, errorIndication %s' % (stateReference, errorIndication))
if 'oid' in errorIndication:
# Request REPORT generation
statusInformation['oid'] = errorIndication['oid']
statusInformation['val'] = errorIndication['val']
# PDU-level SMI errors
except pysnmp.smi.error.NoAccessError:
errorStatus, errorIndex = 'noAccess', sys.exc_info()[1]['idx'] + 1
except pysnmp.smi.error.WrongTypeError:
errorStatus, errorIndex = 'wrongType', sys.exc_info()[1]['idx'] + 1
except pysnmp.smi.error.WrongLengthError:
errorStatus, errorIndex = 'wrongLength', sys.exc_info()[1]['idx'] + 1
except pysnmp.smi.error.WrongEncodingError:
errorStatus, errorIndex = 'wrongEncoding', sys.exc_info()[1]['idx'] + 1
except pysnmp.smi.error.WrongValueError:
errorStatus, errorIndex = 'wrongValue', sys.exc_info()[1]['idx'] + 1
except pysnmp.smi.error.NoCreationError:
errorStatus, errorIndex = 'noCreation', sys.exc_info()[1]['idx'] + 1
except pysnmp.smi.error.InconsistentValueError:
errorStatus, errorIndex = 'inconsistentValue', sys.exc_info()[1]['idx'] + 1
except pysnmp.smi.error.ResourceUnavailableError:
errorStatus, errorIndex = 'resourceUnavailable', sys.exc_info()[1]['idx'] + 1
except pysnmp.smi.error.CommitFailedError:
errorStatus, errorIndex = 'commitFailed', sys.exc_info()[1]['idx'] + 1
except pysnmp.smi.error.UndoFailedError:
errorStatus, errorIndex = 'undoFailed', sys.exc_info()[1]['idx'] + 1
except pysnmp.smi.error.AuthorizationError:
errorStatus, errorIndex = 'authorizationError', sys.exc_info()[1]['idx'] + 1
except pysnmp.smi.error.NotWritableError:
errorStatus, errorIndex = 'notWritable', sys.exc_info()[1]['idx'] + 1
except pysnmp.smi.error.InconsistentNameError:
errorStatus, errorIndex = 'inconsistentName', sys.exc_info()[1]['idx'] + 1
except pysnmp.smi.error.SmiError:
errorStatus, errorIndex = 'genErr', len(varBinds) and 1 or 0
except pysnmp.error.PySnmpError:
self.releaseStateInformation(stateReference)
return
else: # successful request processor must release state info
return
self.sendVarBinds(snmpEngine, stateReference, errorStatus,
errorIndex, varBinds)
self.releaseStateInformation(stateReference)
self.initiateMgmtOperation(snmpEngine, stateReference, contextName, PDU)
@classmethod
def verifyAccess(cls, viewType, varBind, **context):
@ -259,57 +218,146 @@ class CommandResponderBase(object):
# This will cause MibTree to skip this OID-value
raise pysnmp.smi.error.NoAccessError(name=name, idx=context.get('idx'))
def _getMgmtFun(self, contextName):
return lambda *args, **kwargs: None
class GetCommandResponder(CommandResponderBase):
pduTypes = (rfc1905.GetRequestPDU.tagSet,)
def _checkSmiErrors(self, varBinds):
errorIndication = None
errorStatus = errorIndex = 0
# rfc1905: 4.2.1
def handleMgmtOperation(self, snmpEngine, stateReference, contextName, PDU):
# rfc1905: 4.2.1.1
mgmtFun = self.snmpContext.getMibInstrum(contextName).readVars
exception = None
for idx, varBind in enumerate(varBinds):
name, value = varBind
if isinstance(value, tuple): # expect exception tuple
debug.logger & debug.flagApp and debug.logger(
'_checkSmiErrors: exception reported for OID %s exception %s' % (name, value))
if not exception:
exception = value
# reset exception object
varBinds[idx] = name, v2c.null
try:
# TODO: perhaps chain exceptions
if exception:
debug.logger & debug.flagApp and debug.logger(
'_checkSmiErrors: re-raising exception %s' % (exception,))
raise exception[1].with_traceback(exception[2])
# SNMPv2 SMI exceptions
except pysnmp.smi.error.GenError:
errorIndication = sys.exc_info()[1]
debug.logger & debug.flagApp and debug.logger(
'_checkSmiErrors: errorIndication %s' % (errorIndication,))
except pysnmp.smi.error.SmiError:
exc_type, exc_obj, trb = sys.exc_info()
errorStatus = self.SMI_ERROR_MAP.get(exc_type, 'genErr')
try:
errorIndex = exc_obj['idx'] + 1
except IndexError:
errorIndex = len(varBinds) and 1 or 0
return errorIndication, errorStatus, errorIndex
def completeMgmtOperation(self, varBinds, **context):
try:
(errorIndication,
errorStatus, errorIndex) = self._checkSmiErrors(varBinds)
except pysnmp.error.PySnmpError:
self.releaseStateInformation(context['stateReference'])
return
stateReference = context['stateReference']
if errorIndication:
statusInformation = self.__pendingReqs[stateReference]['statusInformation']
try:
# Request REPORT generation
statusInformation['oid'] = errorIndication['oid']
statusInformation['val'] = errorIndication['val']
except KeyError:
pass
self.sendVarBinds(context['snmpEngine'], stateReference,
errorStatus, errorIndex, varBinds)
self.releaseStateInformation(stateReference)
def initiateMgmtOperation(self, snmpEngine, stateReference, contextName, PDU):
varBinds = v2c.apiPDU.getVarBinds(PDU)
context = dict(snmpEngine=snmpEngine, acFun=self.verifyAccess, cbCtx=self.cbCtx)
mgmtFun = self._getMgmtFun(contextName)
rspVarBinds = mgmtFun(*varBinds, **context)
context = dict(snmpEngine=snmpEngine,
stateReference=stateReference,
acFun=self.verifyAccess,
cbFun=self.completeMgmtOperation,
cbCtx=self.cbCtx)
self.sendVarBinds(snmpEngine, stateReference, 0, 0, rspVarBinds)
self.releaseStateInformation(stateReference)
mgmtFun(*varBinds, **context)
class GetCommandResponder(CommandResponderBase):
SUPPORTED_PDU_TYPES = (rfc1905.GetRequestPDU.tagSet,)
# rfc1905: 4.2.1
def _getMgmtFun(self, contextName):
return self.snmpContext.getMibInstrum(contextName).readVars
class NextCommandResponder(CommandResponderBase):
pduTypes = (rfc1905.GetNextRequestPDU.tagSet,)
SUPPORTED_PDU_TYPES = (rfc1905.GetNextRequestPDU.tagSet,)
# rfc1905: 4.2.2
def handleMgmtOperation(self, snmpEngine, stateReference, contextName, PDU):
# rfc1905: 4.2.2.1
mgmtFun = self.snmpContext.getMibInstrum(contextName).readNextVars
varBinds = v2c.apiPDU.getVarBinds(PDU)
context = dict(snmpEngine=snmpEngine, acFun=self.verifyAccess, cbCtx=self.cbCtx)
while True:
rspVarBinds = mgmtFun(*varBinds, **context)
try:
self.sendVarBinds(snmpEngine, stateReference, 0, 0, rspVarBinds)
except error.StatusInformation:
idx = sys.exc_info()[1]['idx']
varBinds[idx] = (rspVarBinds[idx][0], varBinds[idx][1])
else:
break
self.releaseStateInformation(stateReference)
def _getMgmtFun(self, contextName):
return self.snmpContext.getMibInstrum(contextName).readNextVars
class BulkCommandResponder(CommandResponderBase):
pduTypes = (rfc1905.GetBulkRequestPDU.tagSet,)
SUPPORTED_PDU_TYPES = (rfc1905.GetBulkRequestPDU.tagSet,)
maxVarBinds = 64
def _getMgmtFun(self, contextName):
return self.snmpContext.getMibInstrum(contextName).readNextVars
def _completeNonRepeaters(self, varBinds, **context):
context['rspVarBinds'][:] = varBinds
if context['counters']['M'] and context['counters']['R']:
context['cbFun'] = self.completeMgmtOperation
mgmtFun = self._getMgmtFun(context['contextName'])
mgmtFun(*context['reqVarBinds'], **context)
else:
CommandResponderBase.completeMgmtOperation(self, context['rspVarBinds'], **context)
def completeMgmtOperation(self, varBinds, **context):
context['rspVarBinds'].extend(varBinds)
context['counters']['M'] -= 1
if context['counters']['M'] and context['counters']['R']:
mgmtFun = self._getMgmtFun(context['contextName'])
context['cbFun'] = self.completeMgmtOperation
mgmtFun(*varBinds[-context['counters']['R']:], **context)
else:
CommandResponderBase.completeMgmtOperation(self, context['rspVarBinds'], **context)
# rfc1905: 4.2.3
def handleMgmtOperation(self, snmpEngine, stateReference, contextName, PDU):
def initiateMgmtOperation(self, snmpEngine, stateReference, contextName, PDU):
nonRepeaters = v2c.apiBulkPDU.getNonRepeaters(PDU)
if nonRepeaters < 0:
nonRepeaters = 0
@ -318,68 +366,42 @@ class BulkCommandResponder(CommandResponderBase):
if maxRepetitions < 0:
maxRepetitions = 0
reqVarBinds = v2c.apiPDU.getVarBinds(PDU)
varBinds = v2c.apiPDU.getVarBinds(PDU)
N = min(int(nonRepeaters), len(reqVarBinds))
N = min(int(nonRepeaters), len(varBinds))
M = int(maxRepetitions)
R = max(len(reqVarBinds) - N, 0)
R = max(len(varBinds) - N, 0)
if R:
M = min(M, self.maxVarBinds // R)
debug.logger & debug.flagApp and debug.logger('handleMgmtOperation: N %d, M %d, R %d' % (N, M, R))
debug.logger & debug.flagApp and debug.logger(
'initiateMgmtOperation: N %d, M %d, R %d' % (N, M, R))
mgmtFun = self.snmpContext.getMibInstrum(contextName).readNextVars
mgmtFun = self._getMgmtFun(contextName)
context = dict(snmpEngine=snmpEngine, acFun=self.verifyAccess, cbCtx=self.cbCtx)
context = dict(snmpEngine=snmpEngine,
stateReference=stateReference,
contextName=contextName,
acFun=self.verifyAccess,
cbFun=self._completeNonRepeaters,
cbCtx=self.cbCtx,
reqVarBinds=varBinds[N:],
counters={'M': M, 'R': R},
rspVarBinds=[])
if N:
# TODO(etingof): manage all PDU var-binds in a single call
rspVarBinds = mgmtFun(*reqVarBinds[:N], **context)
else:
rspVarBinds = []
varBinds = reqVarBinds[-R:]
while M and R:
rspVarBinds.extend(mgmtFun(*varBinds, **context))
varBinds = rspVarBinds[-R:]
M -= 1
if len(rspVarBinds):
self.sendVarBinds(snmpEngine, stateReference, 0, 0, rspVarBinds)
self.releaseStateInformation(stateReference)
else:
raise pysnmp.smi.error.SmiError()
mgmtFun(*varBinds[:N], **context)
class SetCommandResponder(CommandResponderBase):
pduTypes = (rfc1905.SetRequestPDU.tagSet,)
SUPPORTED_PDU_TYPES = (rfc1905.SetRequestPDU.tagSet,)
# rfc1905: 4.2.5
def handleMgmtOperation(self, snmpEngine, stateReference, contextName, PDU):
mgmtFun = self.snmpContext.getMibInstrum(contextName).writeVars
SMI_ERROR_MAP = CommandResponderBase.SMI_ERROR_MAP.copy()
varBinds = v2c.apiPDU.getVarBinds(PDU)
# turn missing OIDs into access denial
SMI_ERROR_MAP[pysnmp.smi.error.NoSuchObjectError] = 'notWritable'
SMI_ERROR_MAP[pysnmp.smi.error.NoSuchInstanceError] = 'notWritable'
instrumError = None
context = dict(snmpEngine=snmpEngine, acFun=self.verifyAccess, cbCtx=self.cbCtx)
# rfc1905: 4.2.5.1-13
try:
rspVarBinds = mgmtFun(*varBinds, **context)
except (pysnmp.smi.error.NoSuchObjectError,
pysnmp.smi.error.NoSuchInstanceError):
instrumError = pysnmp.smi.error.NotWritableError()
instrumError.update(sys.exc_info()[1])
else:
self.sendVarBinds(snmpEngine, stateReference, 0, 0, rspVarBinds)
self.releaseStateInformation(stateReference)
if instrumError:
raise instrumError
# rfc1905: 4.2.5.1-13
def _getMgmtFun(self, contextName):
return self.snmpContext.getMibInstrum(contextName).writeVars

View File

@ -14,12 +14,12 @@ from pysnmp import debug
# 3.4
class NotificationReceiver(object):
pduTypes = (v1.TrapPDU.tagSet, v2c.SNMPv2TrapPDU.tagSet,
v2c.InformRequestPDU.tagSet)
SUPPORTED_PDU_TYPES = (v1.TrapPDU.tagSet, v2c.SNMPv2TrapPDU.tagSet,
v2c.InformRequestPDU.tagSet)
def __init__(self, snmpEngine, cbFun, cbCtx=None):
snmpEngine.msgAndPduDsp.registerContextEngineId(
null, self.pduTypes, self.processPdu # '' is a wildcard
null, self.SUPPORTED_PDU_TYPES, self.processPdu # '' is a wildcard
)
self.__snmpTrapCommunity = ''
@ -33,7 +33,7 @@ class NotificationReceiver(object):
def close(self, snmpEngine):
snmpEngine.msgAndPduDsp.unregisterContextEngineId(
null, self.pduTypes
null, self.SUPPORTED_PDU_TYPES
)
self.__cbFun = self.__cbCtx = None

View File

@ -7,9 +7,54 @@
from pysnmp.proto.rfc1902 import *
from pysnmp.proto.rfc1905 import NoSuchInstance, NoSuchObject, EndOfMibView
from pysnmp.smi.rfc1902 import *
from pysnmp.hlapi.v3arch.auth import *
from pysnmp.hlapi.v3arch import auth
from pysnmp.hlapi.v3arch.context import *
from pysnmp.entity.engine import *
# default is synchronous asyncore-based API
from pysnmp.hlapi.v3arch.asyncore.sync import *
usmNoAuthProtocol = auth.usmNoAuthProtocol
"""No Authentication Protocol"""
usmHMACMD5AuthProtocol = auth.usmHMACMD5AuthProtocol
"""The HMAC-MD5-96 Digest Authentication Protocol (:RFC:`3414#section-6`)"""
usmHMACSHAAuthProtocol = auth.usmHMACSHAAuthProtocol
"""The HMAC-SHA-96 Digest Authentication Protocol AKA SHA-1 (:RFC:`3414#section-7`)"""
usmHMAC128SHA224AuthProtocol = auth.usmHMAC128SHA224AuthProtocol
"""The HMAC-SHA-2 Digest Authentication Protocols (:RFC:`7860`)"""
usmHMAC192SHA256AuthProtocol = auth.usmHMAC192SHA256AuthProtocol
"""The HMAC-SHA-2 Digest Authentication Protocols (:RFC:`7860`)"""
usmHMAC256SHA384AuthProtocol = auth.usmHMAC256SHA384AuthProtocol
"""The HMAC-SHA-2 Digest Authentication Protocols (:RFC:`7860`)"""
usmHMAC384SHA512AuthProtocol = auth.usmHMAC384SHA512AuthProtocol
"""The HMAC-SHA-2 Digest Authentication Protocols (:RFC:`7860`)"""
usmNoPrivProtocol = auth.usmNoPrivProtocol
"""No Privacy Protocol"""
usmDESPrivProtocol = auth.usmDESPrivProtocol
"""The CBC-DES Symmetric Encryption Protocol (:RFC:`3414#section-8`)"""
usm3DESEDEPrivProtocol = auth.usm3DESEDEPrivProtocol
"""The 3DES-EDE Symmetric Encryption Protocol (`draft-reeder-snmpv3-usm-3desede-00 <https:://tools.ietf.org/html/draft-reeder-snmpv3-usm-3desede-00#section-5>`_)"""
usmAesCfb128Protocol = auth.usmAesCfb128Protocol
"""The CFB128-AES-128 Symmetric Encryption Protocol (:RFC:`3826#section-3`)"""
usmAesCfb192Protocol = auth.usmAesCfb192Protocol
"""The CFB128-AES-192 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 <https:://tools.ietf.org/html/draft-blumenthal-aes-usm-04#section-3>`_) with Reeder key localization"""
usmAesCfb256Protocol = auth.usmAesCfb256Protocol
"""The CFB128-AES-256 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 <https:://tools.ietf.org/html/draft-blumenthal-aes-usm-04#section-3>`_) with Reeder key localization"""
usmAesBlumenthalCfb192Protocol = auth.usmAesBlumenthalCfb192Protocol
"""The CFB128-AES-192 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 <https:://tools.ietf.org/html/draft-blumenthal-aes-usm-04#section-3>`_)"""
usmAesBlumenthalCfb256Protocol = auth.usmAesBlumenthalCfb256Protocol
"""The CFB128-AES-256 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 <https:://tools.ietf.org/html/draft-blumenthal-aes-usm-04#section-3>`_)"""

View File

@ -145,7 +145,8 @@ def getCmd(snmpEngine, authData, transportTarget, contextData,
(errorIndication, errorStatus, errorIndex, varBindsUnmade)
)
addrName, paramsName = lcd.configure(snmpEngine, authData, transportTarget)
addrName, paramsName = lcd.configure(
snmpEngine, authData, transportTarget, contextData.contextName)
future = asyncio.Future()
@ -250,7 +251,8 @@ def setCmd(snmpEngine, authData, transportTarget, contextData,
(errorIndication, errorStatus, errorIndex, varBindsUnmade)
)
addrName, paramsName = lcd.configure(snmpEngine, authData, transportTarget)
addrName, paramsName = lcd.configure(
snmpEngine, authData, transportTarget, contextData.contextName)
future = asyncio.Future()
@ -361,7 +363,8 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData,
(errorIndication, errorStatus, errorIndex, varBindsUnmade)
)
addrName, paramsName = lcd.configure(snmpEngine, authData, transportTarget)
addrName, paramsName = lcd.configure(
snmpEngine, authData, transportTarget, contextData.contextName)
future = asyncio.Future()
@ -501,7 +504,8 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData,
(errorIndication, errorStatus, errorIndex, varBindsUnmade)
)
addrName, paramsName = lcd.configure(snmpEngine, authData, transportTarget)
addrName, paramsName = lcd.configure(
snmpEngine, authData, transportTarget, contextData.contextName)
future = asyncio.Future()

View File

@ -152,8 +152,8 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData,
)
notifyName = lcd.configure(
snmpEngine, authData, transportTarget, notifyType
)
snmpEngine, authData, transportTarget, notifyType,
contextData.contextName)
future = asyncio.Future()

View File

@ -121,7 +121,8 @@ def getCmd(snmpEngine, authData, transportTarget, contextData,
snmpEngine.cache, varBinds, lookupMib
), cbCtx)
addrName, paramsName = lcd.configure(snmpEngine, authData, transportTarget)
addrName, paramsName = lcd.configure(
snmpEngine, authData, transportTarget, contextData.contextName)
return cmdgen.GetCommandGenerator().sendVarBinds(
snmpEngine, addrName, contextData.contextEngineId,
@ -232,7 +233,8 @@ def setCmd(snmpEngine, authData, transportTarget, contextData,
snmpEngine.cache, varBinds, lookupMib
), cbCtx)
addrName, paramsName = lcd.configure(snmpEngine, authData, transportTarget)
addrName, paramsName = lcd.configure(
snmpEngine, authData, transportTarget, contextData.contextName)
return cmdgen.SetCommandGenerator().sendVarBinds(
snmpEngine, addrName, contextData.contextEngineId,
@ -343,7 +345,9 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData,
varBindTable],
cbCtx)
addrName, paramsName = lcd.configure(snmpEngine, authData, transportTarget)
addrName, paramsName = lcd.configure(
snmpEngine, authData, transportTarget, contextData.contextName)
return cmdgen.NextCommandGenerator().sendVarBinds(
snmpEngine, addrName,
contextData.contextEngineId, contextData.contextName,
@ -483,7 +487,8 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData,
[vbProcessor.unmakeVarBinds(snmpEngine.cache, varBindTableRow, lookupMib) for varBindTableRow in
varBindTable], cbCtx)
addrName, paramsName = lcd.configure(snmpEngine, authData, transportTarget)
addrName, paramsName = lcd.configure(
snmpEngine, authData, transportTarget, contextData.contextName)
return cmdgen.BulkCommandGenerator().sendVarBinds(
snmpEngine, addrName, contextData.contextEngineId,

View File

@ -162,7 +162,7 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData,
)
notifyName = lcd.configure(snmpEngine, authData, transportTarget,
notifyType)
notifyType, contextData.contextName)
return ntforg.NotificationOriginator().sendVarBinds(
snmpEngine, notifyName,

View File

@ -151,35 +151,50 @@ class CommunityData(object):
securityName is None and self.securityName or securityName
)
#: No Authentication Protocol.
usmNoAuthProtocol = config.usmNoAuthProtocol
#: The HMAC-MD5-96 Digest Authentication Protocol (:RFC:`3414#section-6`)
usmHMACMD5AuthProtocol = config.usmHMACMD5AuthProtocol
#: The HMAC-SHA-96 Digest Authentication Protocol (:RFC:`3414#section-7`)
usmHMACSHAAuthProtocol = config.usmHMACSHAAuthProtocol
#: The HMAC-SHA-2 Digest Authentication Protocols (:RFC:`7860`)
usmHMAC128SHA224AuthProtocol = config.usmHMAC128SHA224AuthProtocol
usmHMAC192SHA256AuthProtocol = config.usmHMAC192SHA256AuthProtocol
usmHMAC256SHA384AuthProtocol = config.usmHMAC256SHA384AuthProtocol
usmHMAC384SHA512AuthProtocol = config.usmHMAC384SHA512AuthProtocol
"""No Authentication Protocol"""
usmHMACMD5AuthProtocol = config.usmHMACMD5AuthProtocol
"""The HMAC-MD5-96 Digest Authentication Protocol (:RFC:`3414#section-6`)"""
usmHMACSHAAuthProtocol = config.usmHMACSHAAuthProtocol
"""The HMAC-SHA-96 Digest Authentication Protocol AKA SHA-1 (:RFC:`3414#section-7`)"""
usmHMAC128SHA224AuthProtocol = config.usmHMAC128SHA224AuthProtocol
"""The HMAC-SHA-2 Digest Authentication Protocols (:RFC:`7860`)"""
usmHMAC192SHA256AuthProtocol = config.usmHMAC192SHA256AuthProtocol
"""The HMAC-SHA-2 Digest Authentication Protocols (:RFC:`7860`)"""
usmHMAC256SHA384AuthProtocol = config.usmHMAC256SHA384AuthProtocol
"""The HMAC-SHA-2 Digest Authentication Protocols (:RFC:`7860`)"""
usmHMAC384SHA512AuthProtocol = config.usmHMAC384SHA512AuthProtocol
"""The HMAC-SHA-2 Digest Authentication Protocols (:RFC:`7860`)"""
#: No Privacy Protocol.
usmNoPrivProtocol = config.usmNoPrivProtocol
#: The CBC-DES Symmetric Encryption Protocol (:RFC:`3414#section-8`)
"""No Privacy Protocol"""
usmDESPrivProtocol = config.usmDESPrivProtocol
#: The 3DES-EDE Symmetric Encryption Protocol (`draft-reeder-snmpv3-usm-3desede-00 <https://tools.ietf.org/html/draft-reeder-snmpv3-usm-3desede-00#section-5>`_)
"""The CBC-DES Symmetric Encryption Protocol (:RFC:`3414#section-8`)"""
usm3DESEDEPrivProtocol = config.usm3DESEDEPrivProtocol
#: The CFB128-AES-128 Symmetric Encryption Protocol (:RFC:`3826#section-3`)
"""The 3DES-EDE Symmetric Encryption Protocol (`draft-reeder-snmpv3-usm-3desede-00 <https:://tools.ietf.org/html/draft-reeder-snmpv3-usm-3desede-00#section-5>`_)"""
usmAesCfb128Protocol = config.usmAesCfb128Protocol
#: The CFB128-AES-192 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 <https://tools.ietf.org/html/draft-blumenthal-aes-usm-04#section-3>`_) with Reeder key localization
"""The CFB128-AES-128 Symmetric Encryption Protocol (:RFC:`3826#section-3`)"""
usmAesCfb192Protocol = config.usmAesCfb192Protocol
#: The CFB128-AES-256 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 <https://tools.ietf.org/html/draft-blumenthal-aes-usm-04#section-3>`_) with Reeder key localization
"""The CFB128-AES-192 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 <https:://tools.ietf.org/html/draft-blumenthal-aes-usm-04#section-3>`_) with Reeder key localization"""
usmAesCfb256Protocol = config.usmAesCfb256Protocol
#: The CFB128-AES-192 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 <https://tools.ietf.org/html/draft-blumenthal-aes-usm-04#section-3>`_)
"""The CFB128-AES-256 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 <https:://tools.ietf.org/html/draft-blumenthal-aes-usm-04#section-3>`_) with Reeder key localization"""
usmAesBlumenthalCfb192Protocol = config.usmAesBlumenthalCfb192Protocol
#: The CFB128-AES-256 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 <https://tools.ietf.org/html/draft-blumenthal-aes-usm-04#section-3>`_)
"""The CFB128-AES-192 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 <https:://tools.ietf.org/html/draft-blumenthal-aes-usm-04#section-3>`_)"""
usmAesBlumenthalCfb256Protocol = config.usmAesBlumenthalCfb256Protocol
"""The CFB128-AES-256 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 <https:://tools.ietf.org/html/draft-blumenthal-aes-usm-04#section-3>`_)"""
class UsmUserData(object):

View File

@ -8,6 +8,8 @@ from pysnmp.entity import config
from pysnmp import nextid, error
from pysnmp.hlapi.v3arch.auth import *
from pyasn1.compat.octets import null
__all__ = ['CommandGeneratorLcdConfigurator',
'NotificationOriginatorLcdConfigurator']
@ -24,17 +26,17 @@ class AbstractLcdConfigurator(object):
snmpEngine.setUserContext(**{cacheId: cache})
return cache
def configure(self, snmpEngine, authData, transportTarget, *options):
def configure(self, snmpEngine, *args, **kwargs):
pass
def unconfigure(self, snmpEngine, authData=None):
def unconfigure(self, snmpEngine, *args, **kwargs):
pass
class CommandGeneratorLcdConfigurator(AbstractLcdConfigurator):
cacheKeys = ['auth', 'parm', 'tran', 'addr']
def configure(self, snmpEngine, authData, transportTarget, *options):
def configure(self, snmpEngine, authData, transportTarget, contextName, **options):
cache = self._getCache(snmpEngine)
if isinstance(authData, CommunityData):
if authData.communityIndex not in cache['auth']:
@ -94,7 +96,10 @@ class CommandGeneratorLcdConfigurator(AbstractLcdConfigurator):
transportKey = (paramsName, transportTarget.transportDomain,
transportTarget.transportAddr,
transportTarget.tagList)
transportTarget.timeout,
transportTarget.retries,
transportTarget.tagList,
transportTarget.iface)
if transportKey in cache['addr']:
addrName, useCount = cache['addr'][transportKey]
@ -114,7 +119,7 @@ class CommandGeneratorLcdConfigurator(AbstractLcdConfigurator):
return addrName, paramsName
def unconfigure(self, snmpEngine, authData=None):
def unconfigure(self, snmpEngine, authData=None, contextName=null, **options):
cache = self._getCache(snmpEngine)
if authData:
if isinstance(authData, CommunityData):
@ -175,7 +180,7 @@ class CommandGeneratorLcdConfigurator(AbstractLcdConfigurator):
cache['addr'][addrKey] = addrName, useCount
else:
config.delTargetAddr(snmpEngine, addrName)
del cache['addr'][addrKey]
addrNames.add(addrKey)
if addrKey[1] in cache['tran']:
@ -195,9 +200,9 @@ class NotificationOriginatorLcdConfigurator(AbstractLcdConfigurator):
cacheKeys = ['auth', 'name']
_cmdGenLcdCfg = CommandGeneratorLcdConfigurator()
def configure(self, snmpEngine, authData, transportTarget, *options):
def configure(self, snmpEngine, authData, transportTarget, notifyType,
contextName, **options):
cache = self._getCache(snmpEngine)
notifyType = options and options[0] or 'trap'
notifyName = None
# Create matching transport tags if not given by user. Not good!
@ -208,7 +213,8 @@ class NotificationOriginatorLcdConfigurator(AbstractLcdConfigurator):
if isinstance(authData, CommunityData) and not authData.tag:
authData.tag = transportTarget.tagList.split()[0]
addrName, paramsName = self._cmdGenLcdCfg.configure(snmpEngine, authData, transportTarget)
addrName, paramsName = self._cmdGenLcdCfg.configure(
snmpEngine, authData, transportTarget, contextName, **options)
tagList = transportTarget.tagList.split()
if not tagList:
tagList = ['']
@ -227,7 +233,7 @@ class NotificationOriginatorLcdConfigurator(AbstractLcdConfigurator):
notifyType
)
cache['name'][notifyNameKey] = notifyName, paramsName, 1
authDataKey = authData.securityName, authData.securityModel
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
@ -237,23 +243,24 @@ class NotificationOriginatorLcdConfigurator(AbstractLcdConfigurator):
authData.securityModel,
authData.securityName,
authData.securityLevel,
(), (), subTree)
(), (), subTree, contextName=contextName)
cache['auth'][authDataKey] = authData, subTree, 1
return notifyName
def unconfigure(self, snmpEngine, authData=None):
def unconfigure(self, snmpEngine, authData=None, contextName=null, **options):
cache = self._getCache(snmpEngine)
if authData:
authDataKey = authData.securityName, authData.securityModel
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'].keys())
authDataKeys = tuple(cache['auth'])
addrNames, paramsNames = self._cmdGenLcdCfg.unconfigure(snmpEngine, authData)
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]

View File

@ -128,7 +128,8 @@ def getCmd(snmpEngine, authData, transportTarget, contextData,
else:
deferred.callback((errorStatus, errorIndex, varBindsUnmade))
addrName, paramsName = lcd.configure(snmpEngine, authData, transportTarget)
addrName, paramsName = lcd.configure(
snmpEngine, authData, transportTarget, contextData.contextName)
deferred = Deferred()
@ -244,7 +245,8 @@ def setCmd(snmpEngine, authData, transportTarget, contextData,
else:
deferred.callback((errorStatus, errorIndex, varBindsUnmade))
addrName, paramsName = lcd.configure(snmpEngine, authData, transportTarget)
addrName, paramsName = lcd.configure(
snmpEngine, authData, transportTarget, contextData.contextName)
deferred = Deferred()
@ -374,7 +376,8 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData,
else:
deferred.callback((errorStatus, errorIndex, varBindsUnmade))
addrName, paramsName = lcd.configure(snmpEngine, authData, transportTarget)
addrName, paramsName = lcd.configure(
snmpEngine, authData, transportTarget, contextData.contextName)
deferred = Deferred()
@ -532,7 +535,8 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData,
else:
deferred.callback((errorStatus, errorIndex, varBindsUnmade))
addrName, paramsName = lcd.configure(snmpEngine, authData, transportTarget)
addrName, paramsName = lcd.configure(
snmpEngine, authData, transportTarget, contextData.contextName)
deferred = Deferred()

View File

@ -166,9 +166,8 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData,
else:
deferred.callback((errorStatus, errorIndex, varBindsUnmade))
notifyName = lcd.configure(
snmpEngine, authData, transportTarget, notifyType
)
notifyName = lcd.configure(snmpEngine, authData, transportTarget,
notifyType, contextData.contextName)
def __trapFun(deferred):
deferred.callback((0, 0, []))

View File

@ -8,14 +8,14 @@ from pysnmp.smi.error import NoSuchInstanceError
from pysnmp.proto import errind, error
from pysnmp import debug
__powOfTwoSeq = [128, 64, 32, 16, 8, 4, 2, 1]
# 3.2
class Vacm(object):
"""View-based Access Control Model"""
accessModelID = 3
_powOfTwoSeq = (128, 64, 32, 16, 8, 4, 2, 1)
def isAccessAllowed(self,
snmpEngine,
securityModel,
@ -31,25 +31,30 @@ class Vacm(object):
securityModel, securityName, securityLevel, viewType, contextName, variableName))
# 3.2.1
vacmContextEntry, = mibInstrumController.mibBuilder.importSymbols('SNMP-VIEW-BASED-ACM-MIB', 'vacmContextEntry')
vacmContextEntry, = mibInstrumController.mibBuilder.importSymbols(
'SNMP-VIEW-BASED-ACM-MIB', 'vacmContextEntry')
tblIdx = vacmContextEntry.getInstIdFromIndices(contextName)
try:
vacmContextName = vacmContextEntry.getNode(
vacmContextEntry.getNode(
vacmContextEntry.name + (1,) + tblIdx
).syntax
except NoSuchInstanceError:
raise error.StatusInformation(errorIndication=errind.noSuchContext)
# 3.2.2
vacmSecurityToGroupEntry, = mibInstrumController.mibBuilder.importSymbols('SNMP-VIEW-BASED-ACM-MIB',
'vacmSecurityToGroupEntry')
vacmSecurityToGroupEntry, = mibInstrumController.mibBuilder.importSymbols(
'SNMP-VIEW-BASED-ACM-MIB', 'vacmSecurityToGroupEntry')
tblIdx = vacmSecurityToGroupEntry.getInstIdFromIndices(
securityModel, securityName
)
try:
vacmGroupName = vacmSecurityToGroupEntry.getNode(
vacmSecurityToGroupEntry.name + (3,) + tblIdx
).syntax
except NoSuchInstanceError:
raise error.StatusInformation(errorIndication=errind.noGroupName)
@ -57,6 +62,7 @@ class Vacm(object):
vacmAccessEntry, = mibInstrumController.mibBuilder.importSymbols(
'SNMP-VIEW-BASED-ACM-MIB', 'vacmAccessEntry'
)
# XXX partial context name match
tblIdx = vacmAccessEntry.getInstIdFromIndices(
vacmGroupName, contextName, securityModel, securityLevel
@ -74,51 +80,62 @@ class Vacm(object):
try:
viewName = vacmAccessEntry.getNode(entryIdx).syntax
except NoSuchInstanceError:
raise error.StatusInformation(errorIndication=errind.noAccessEntry)
if not len(viewName):
if not viewName:
raise error.StatusInformation(errorIndication=errind.noSuchView)
# XXX split onto object & instance ?
# 3.2.5a
vacmViewTreeFamilyEntry, = mibInstrumController.mibBuilder.importSymbols('SNMP-VIEW-BASED-ACM-MIB',
'vacmViewTreeFamilyEntry')
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 1:
while True:
vacmViewTreeFamilySubtree = vacmViewTreeFamilyEntry.getNextNode(
treeName
)
vacmViewTreeFamilyMask = vacmViewTreeFamilyEntry.getNextNode(
maskName
)
treeName = vacmViewTreeFamilySubtree.name
maskName = vacmViewTreeFamilyMask.name
if initialTreeName != treeName[:len(initialTreeName)]:
# 3.2.5b
raise error.StatusInformation(errorIndication=errind.notInView)
l = len(vacmViewTreeFamilySubtree.syntax)
if l > len(variableName):
continue
if vacmViewTreeFamilyMask.syntax:
mask = []
for c in vacmViewTreeFamilyMask.syntax.asNumbers():
mask = mask + [b & c for b in __powOfTwoSeq]
mask.extend([b & c for b in self._powOfTwoSeq])
m = len(mask) - 1
idx = l - 1
while idx:
if idx > m or mask[idx] and \
vacmViewTreeFamilySubtree.syntax[idx] != variableName[idx]:
if (idx > m or mask[idx] and
vacmViewTreeFamilySubtree.syntax[idx] != variableName[idx]):
break
idx -= 1
if idx:
continue # no match
else: # no mask
if vacmViewTreeFamilySubtree.syntax != variableName[:l]:
continue # no match
# 3.2.5c
return error.StatusInformation(errorIndication=errind.accessAllowed)

View File

@ -10,7 +10,32 @@ from pysnmp.proto import rfc1155, error
__all__ = ['Opaque', 'TimeTicks', 'Bits', 'Integer', 'OctetString',
'IpAddress', 'Counter64', 'Unsigned32', 'Gauge32', 'Integer32',
'ObjectIdentifier', 'Counter32']
'ObjectIdentifier', 'Counter32', 'Null']
class Null(univ.Null):
"""Creates an instance of SNMP Null class.
:py:class:`~pysnmp.proto.rfc1902.Null` type represents the absence
of value.
Parameters
----------
initializer: str
Python string object. Must be an empty string.
Raises
------
PyAsn1Error :
On constraint violation or bad initializer.
Examples
--------
>>> from pysnmp.proto.rfc1902 import *
>>> Null('')
Null('')
>>>
"""
class Integer32(univ.Integer):
@ -128,12 +153,17 @@ class Integer(Integer32):
@classmethod
def withNamedValues(cls, **values):
"""Creates a subclass with discreet named values constraint.
"""Create a subclass with discreet named values constraint.
Reduce fully duplicate enumerations along the way.
"""
enums = set(cls.namedValues.items())
enums.update(values.items())
class X(cls):
namedValues = cls.namedValues + namedval.NamedValues(*values.items())
subtypeSpec = cls.subtypeSpec + constraint.SingleValueConstraint(*values.values())
namedValues = namedval.NamedValues(*enums)
subtypeSpec = cls.subtypeSpec + constraint.SingleValueConstraint(
*values.values())
X.__name__ = cls.__name__
return X
@ -600,7 +630,7 @@ class Bits(OctetString):
def __new__(cls, *args, **kwargs):
if 'namedValues' in kwargs:
Bits = cls.withNamedBits(**kwargs.pop('namedValues'))
Bits = cls.withNamedBits(**dict(kwargs.pop('namedValues')))
return Bits(*args, **kwargs)
return OctetString.__new__(cls)
@ -637,10 +667,14 @@ class Bits(OctetString):
@classmethod
def withNamedBits(cls, **values):
"""Creates a subclass with discreet named bits constraint.
Reduce fully duplicate enumerations along the way.
"""
enums = set(cls.namedValues.items())
enums.update(values.items())
class X(cls):
namedValues = cls.namedValues + namedval.NamedValues(*values.items())
namedValues = namedval.NamedValues(*enums)
X.__name__ = cls.__name__
return X

View File

@ -38,7 +38,7 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel):
nextMibNode = snmpTargetParamsSecurityName
while 1:
while True:
try:
nextMibNode = snmpTargetParamsSecurityName.getNextNode(nextMibNode.name)
@ -49,10 +49,18 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel):
mibNode = snmpTargetParamsSecurityModel.getNode(snmpTargetParamsSecurityModel.name + instId)
if mibNode.syntax not in self.__nameToModelMap:
self.__nameToModelMap[nextMibNode.syntax] = set()
try:
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.flagSM and debug.logger(
'_sec2com: table entries %r/%r hashing failed' % (
nextMibNode.syntax, mibNode.syntax)
)
continue
self.__paramsBranchId = snmpTargetParamsSecurityName.branchVersionId
@ -72,7 +80,8 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel):
self.__securityMap = {}
nextMibNode = snmpCommunityName
while 1:
while True:
try:
nextMibNode = snmpCommunityName.getNextNode(nextMibNode.name)
@ -88,9 +97,17 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel):
_contextName = snmpCommunityContextName.getNode(snmpCommunityContextName.name + instId).syntax
self.__securityMap[(_securityName,
_contextEngineId,
_contextName)] = nextMibNode.syntax
try:
self.__securityMap[(_securityName,
_contextEngineId,
_contextName)] = nextMibNode.syntax
except PyAsn1Error:
debug.logger & debug.flagSM and debug.logger(
'_sec2com: table entries %r/%r/%r hashing failed' % (
_securityName, _contextEngineId, _contextName)
)
continue
self.__securityBranchId = snmpCommunityName.branchVersionId
@ -123,11 +140,14 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel):
self.__transportToTagMap = {}
nextMibNode = snmpTargetAddrTagList
while True:
try:
nextMibNode = snmpTargetAddrTagList.getNextNode(nextMibNode.name)
except NoSuchInstanceError:
break
instId = nextMibNode.name[len(snmpTargetAddrTagList.name):]
targetAddrTDomain = snmpTargetAddrTDomain.getNode(snmpTargetAddrTDomain.name + instId).syntax
targetAddrTAddress = snmpTargetAddrTAddress.getNode(snmpTargetAddrTAddress.name + instId).syntax
@ -142,17 +162,29 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel):
TransportAddressIPv6, = snmpEngine.msgAndPduDsp.mibInstrumController.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()
if targetAddrTagList:
self.__transportToTagMap[targetAddr].update(
[SnmpTagValue(x)
for x in targetAddrTagList.asOctets().split()]
try:
if targetAddrTagList:
self.__transportToTagMap[targetAddr].update(
[SnmpTagValue(x)
for x in targetAddrTagList.asOctets().split()]
)
else:
self.__transportToTagMap[targetAddr].add(self.__emptyTag)
except PyAsn1Error:
debug.logger & debug.flagSM and debug.logger(
'_com2sec: table entries %r/%r hashing failed' % (
targetAddr, targetAddrTagList)
)
else:
self.__transportToTagMap[targetAddr].add(self.__emptyTag)
continue
self.__transportBranchId = snmpTargetAddrTAddress.branchVersionId
@ -161,6 +193,7 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel):
snmpTargetParamsSecurityName, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols(
'SNMP-TARGET-MIB', 'snmpTargetParamsSecurityName')
if self.__paramsBranchId != snmpTargetParamsSecurityName.branchVersionId:
snmpTargetParamsSecurityModel, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols(
'SNMP-TARGET-MIB', 'snmpTargetParamsSecurityModel')
@ -180,10 +213,18 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel):
mibNode = snmpTargetParamsSecurityModel.getNode(snmpTargetParamsSecurityModel.name + instId)
if nextMibNode.syntax not in self.__nameToModelMap:
self.__nameToModelMap[nextMibNode.syntax] = set()
try:
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.flagSM and debug.logger(
'_com2sec: table entries %r/%r hashing failed' % (
nextMibNode.syntax, mibNode.syntax)
)
continue
self.__paramsBranchId = snmpTargetParamsSecurityName.branchVersionId
@ -209,6 +250,7 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel):
self.__tagAndCommunityToSecurityMap = {}
nextMibNode = snmpCommunityName
while True:
try:
nextMibNode = snmpCommunityName.getNextNode(nextMibNode.name)
@ -229,17 +271,25 @@ class SnmpV1SecurityModel(base.AbstractSecurityModel):
_tagAndCommunity = transportTag, nextMibNode.syntax
if _tagAndCommunity not in self.__tagAndCommunityToSecurityMap:
self.__tagAndCommunityToSecurityMap[_tagAndCommunity] = set()
try:
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.flagSM and debug.logger(
'_com2sec: table entries %r/%r hashing failed' % (
_tagAndCommunity, nextMibNode.syntax)
)
continue
self.__communityBranchId = snmpCommunityName.branchVersionId

View File

@ -263,7 +263,7 @@ class MibBuilder(object):
self.mibSymbols = {}
self.__mibSources = []
self.__modSeen = {}
self.__modPathsSeen = {}
self.__modPathsSeen = set()
self.__mibCompiler = None
self.setMibSources(*sources)
@ -306,19 +306,19 @@ class MibBuilder(object):
debug.logger & debug.flagBld and debug.logger('loadModule: seen %s' % modPath)
break
else:
self.__modPathsSeen[modPath] = 1
self.__modPathsSeen.add(modPath)
debug.logger & debug.flagBld and debug.logger('loadModule: evaluating %s' % modPath)
g = {'mibBuilder': self, 'userCtx': userCtx}
try:
exec (modData, g)
exec(compile(modData, modPath, 'exec'), g)
except Exception:
del self.__modPathsSeen[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

View File

@ -6,6 +6,8 @@
#
import sys
import traceback
import functools
from pysnmp import nextid
from pysnmp.smi import error
from pysnmp import debug
@ -24,39 +26,59 @@ class AbstractMibInstrumController(object):
class MibInstrumController(AbstractMibInstrumController):
STATUS_OK = 'ok'
STATUS_ERROR = 'err'
STATE_START = 'start'
STATE_STOP = 'stop'
STATE_ANY = '*'
# These states are actually methods of the MIB objects
STATE_READ_TEST = 'readTest'
STATE_READ_GET = 'readGet'
STATE_READ_TEST_NEXT = 'readTestNext'
STATE_READ_GET_NEXT = 'readGetNext'
STATE_WRITE_TEST = 'writeTest'
STATE_WRITE_COMMIT = 'writeCommit'
STATE_WRITE_CLEANUP = 'writeCleanup'
STATE_WRITE_UNDO = 'writeUndo'
fsmReadVar = {
# ( state, status ) -> newState
('start', 'ok'): 'readTest',
('readTest', 'ok'): 'readGet',
('readGet', 'ok'): 'stop',
('*', 'err'): 'stop'
(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 = {
# ( state, status ) -> newState
('start', 'ok'): 'readTestNext',
('readTestNext', 'ok'): 'readGetNext',
('readGetNext', 'ok'): 'stop',
('*', 'err'): 'stop'
(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 = {
# ( state, status ) -> newState
('start', 'ok'): 'writeTest',
('writeTest', 'ok'): 'writeCommit',
('writeCommit', 'ok'): 'writeCleanup',
('writeCleanup', 'ok'): 'readTest',
(STATE_START, STATUS_OK): STATE_WRITE_TEST,
(STATE_WRITE_TEST, STATUS_OK): STATE_WRITE_COMMIT,
(STATE_WRITE_COMMIT, STATUS_OK): STATE_WRITE_CLEANUP,
(STATE_WRITE_CLEANUP, STATUS_OK): STATE_READ_TEST,
# Do read after successful write
('readTest', 'ok'): 'readGet',
('readGet', 'ok'): 'stop',
(STATE_READ_TEST, STATUS_OK): STATE_READ_GET,
(STATE_READ_GET, STATUS_OK): STATE_STOP,
# Error handling
('writeTest', 'err'): 'writeCleanup',
('writeCommit', 'err'): 'writeUndo',
('writeUndo', 'ok'): 'readTest',
(STATE_WRITE_TEST, STATUS_ERROR): STATE_WRITE_CLEANUP,
(STATE_WRITE_COMMIT, STATUS_ERROR): STATE_WRITE_UNDO,
(STATE_WRITE_UNDO, STATUS_OK): STATE_READ_TEST,
# Ignore read errors (removed columns)
('readTest', 'err'): 'stop',
('readGet', 'err'): 'stop',
('*', 'err'): 'stop'
(STATE_READ_TEST, STATUS_ERROR): STATE_STOP,
(STATE_READ_GET, STATUS_ERROR): STATE_STOP,
(STATE_ANY, STATUS_ERROR): STATE_STOP
}
FSM_CONTEXT = '_fsmContext'
FSM_SESSION_ID = nextid.Integer(0xffffffff)
def __init__(self, mibBuilder):
self.mibBuilder = mibBuilder
self.lastBuildId = -1
@ -183,82 +205,121 @@ class MibInstrumController(AbstractMibInstrumController):
# MIB instrumentation
def flipFlopFsm(self, fsmTable, *varBinds, **context):
self.__indexMib()
def _flipFlopFsmCb(self, varBind, **context):
fsmContext = context[self.FSM_CONTEXT]
debug.logger & debug.flagIns and debug.logger('flipFlopFsm: input var-binds %r' % (varBinds,))
varBinds = fsmContext['varBinds']
idx = context.pop('idx')
if idx >= 0:
fsmContext['count'] += 1
varBinds[idx] = varBind
debug.logger & debug.flagIns and debug.logger(
'_flipFlopFsmCb: var-bind %d, processed %d, expected %d' % (idx, fsmContext['count'], len(varBinds)))
if fsmContext['count'] < len(varBinds):
return
debug.logger & debug.flagIns and debug.logger(
'_flipFlopFsmCb: finished, output %r' % (varBinds,))
fsmCallable = fsmContext['fsmCallable']
fsmCallable(**context)
def flipFlopFsm(self, fsmTable, *varBinds, **context):
try:
fsmContext = context[self.FSM_CONTEXT]
except KeyError:
self.__indexMib()
fsmContext = context[self.FSM_CONTEXT] = dict(
sessionId=self.FSM_SESSION_ID(),
varBinds=list(varBinds[:]),
fsmCallable=functools.partial(self.flipFlopFsm, fsmTable, *varBinds),
state=self.STATE_START, status=self.STATUS_OK
)
debug.logger & debug.flagIns and debug.logger('flipFlopFsm: input var-binds %r' % (varBinds,))
mibTree, = self.mibBuilder.importSymbols('SNMPv2-SMI', 'iso')
outputVarBinds = []
state, status = 'start', 'ok'
origExc = origTraceback = None
while True:
k = state, status
if k in fsmTable:
fsmState = fsmTable[k]
state = fsmContext['state']
status = fsmContext['status']
debug.logger & debug.flagIns and debug.logger(
'flipFlopFsm: current state %s, status %s' % (state, status))
try:
newState = fsmTable[(state, status)]
except KeyError:
try:
newState = fsmTable[(self.STATE_ANY, status)]
except KeyError:
raise error.SmiError('Unresolved FSM state %s, %s' % (state, status))
debug.logger & debug.flagIns and debug.logger(
'flipFlopFsm: state %s status %s -> new state %s' % (state, status, newState))
state = newState
if state == self.STATE_STOP:
context.pop(self.FSM_CONTEXT, None)
cbFun = context.get('cbFun')
if cbFun:
varBinds = fsmContext['varBinds']
cbFun(varBinds, **context)
return
fsmContext.update(state=state, count=0)
# the case of no var-binds
if not varBinds:
return self._flipFlopFsmCb(None, idx=-1, **context)
mgmtFun = getattr(mibTree, state, None)
if not mgmtFun:
raise error.SmiError(
'Unsupported state handler %s at %s' % (state, self)
)
for idx, varBind in enumerate(varBinds):
try:
# TODO: managed objects to run asynchronously
#mgmtFun(varBind, idx=idx, **context)
self._flipFlopFsmCb(mgmtFun(varBind, idx=idx, **context), idx=idx, **context)
except error.SmiError:
exc = sys.exc_info()
debug.logger & debug.flagIns and debug.logger(
'flipFlopFsm: fun %s exception %s for %r with traceback: %s' % (
mgmtFun, exc[0], varBind, traceback.format_exception(*exc)))
varBind = varBind[0], exc
fsmContext['status'] = self.STATUS_ERROR
self._flipFlopFsmCb(varBind, idx=idx, **context)
return
else:
k = '*', status
if k in fsmTable:
fsmState = fsmTable[k]
else:
raise error.SmiError(
'Unresolved FSM state %s, %s' % (state, status)
)
debug.logger & debug.flagIns and debug.logger(
'flipFlopFsm: state %s status %s -> fsmState %s' % (state, status, fsmState))
state = fsmState
status = 'ok'
if state == 'stop':
break
for idx, (name, val) in enumerate(varBinds):
mgmtFun = getattr(mibTree, state, None)
if not mgmtFun:
raise error.SmiError(
'Unsupported state handler %s at %s' % (state, self)
)
context['idx'] = idx
try:
# Convert to tuple to avoid ObjectName instantiation
# on subscription
rval = mgmtFun((tuple(name), val), **context)
except error.SmiError:
exc_t, exc_v, exc_tb = sys.exc_info()
debug.logger & debug.flagIns and debug.logger(
'flipFlopFsm: fun %s exception %s for %s=%r with traceback: %s' % (
mgmtFun, exc_t, name, val, traceback.format_exception(exc_t, exc_v, exc_tb)))
if origExc is None: # Take the first exception
origExc, origTraceback = exc_v, exc_tb
status = 'err'
break
else:
debug.logger & debug.flagIns and debug.logger(
'flipFlopFsm: fun %s suceeded for %s=%r' % (mgmtFun, name, val))
if rval is not None:
outputVarBinds.append((rval[0], rval[1]))
if origExc:
if sys.version_info[0] <= 2:
raise origExc
else:
try:
raise origExc.with_traceback(origTraceback)
finally:
# Break cycle between locals and traceback object
# (seems to be irrelevant on Py3 but just in case)
del origTraceback
return outputVarBinds
debug.logger & debug.flagIns and debug.logger(
'flipFlopFsm: func %s initiated for %r' % (mgmtFun, varBind))
def readVars(self, *varBinds, **context):
return self.flipFlopFsm(self.fsmReadVar, *varBinds, **context)
self.flipFlopFsm(self.fsmReadVar, *varBinds, **context)
def readNextVars(self, *varBinds, **context):
return self.flipFlopFsm(self.fsmReadNextVar, *varBinds, **context)
self.flipFlopFsm(self.fsmReadNextVar, *varBinds, **context)
def writeVars(self, *varBinds, **context):
return self.flipFlopFsm(self.fsmWriteVar, *varBinds, **context)
self.flipFlopFsm(self.fsmWriteVar, *varBinds, **context)

View File

@ -154,6 +154,7 @@ params.update({
'pysnmp.hlapi',
'pysnmp.hlapi.v1arch',
'pysnmp.hlapi.v1arch.asyncore',
'pysnmp.hlapi.v1arch.asyncore.sync',
'pysnmp.hlapi.v3arch',
'pysnmp.hlapi.v3arch.asyncio',
'pysnmp.hlapi.v3arch.asyncore',