From 82e1b1a84d62ced461840eba9019cf8b21b8b072 Mon Sep 17 00:00:00 2001 From: elie Date: Mon, 14 Sep 2015 05:45:34 +0000 Subject: some more missing files --- docs/source/examples/contents.rst | 101 +++++++++++++++++ docs/source/faq/getting-peer-information.rst | 32 ++++++ docs/source/faq/how-to-implement-agent-mib.rst | 120 +++++++++++++++++++++ docs/source/faq/ignored-snmp-packets.rst | 89 +++++++++++++++ .../faq/listening-on-multiple-interfaces.rst | 36 +++++++ docs/source/faq/non-printable-snmp-values-apps.rst | 40 +++++++ .../source/faq/non-printable-snmp-values-tools.rst | 44 ++++++++ docs/source/faq/oids-not-increasing.rst | 29 +++++ docs/source/faq/pass-custom-mib-to-manager.rst | 70 ++++++++++++ docs/source/faq/py2exe-throws-error.rst | 45 ++++++++ docs/source/faq/response-values-mib-resolution.rst | 50 +++++++++ .../snmp-data-constraints-verification-failure.rst | 40 +++++++ docs/source/faq/walk-whole-mib.rst | 26 +++++ .../v1arch/asyncore/agent/ntforg/inform-v2c.py | 83 ++++++++++++++ 14 files changed, 805 insertions(+) create mode 100644 docs/source/examples/contents.rst create mode 100644 docs/source/faq/getting-peer-information.rst create mode 100644 docs/source/faq/how-to-implement-agent-mib.rst create mode 100644 docs/source/faq/ignored-snmp-packets.rst create mode 100644 docs/source/faq/listening-on-multiple-interfaces.rst create mode 100644 docs/source/faq/non-printable-snmp-values-apps.rst create mode 100644 docs/source/faq/non-printable-snmp-values-tools.rst create mode 100644 docs/source/faq/oids-not-increasing.rst create mode 100644 docs/source/faq/pass-custom-mib-to-manager.rst create mode 100644 docs/source/faq/py2exe-throws-error.rst create mode 100644 docs/source/faq/response-values-mib-resolution.rst create mode 100644 docs/source/faq/snmp-data-constraints-verification-failure.rst create mode 100644 docs/source/faq/walk-whole-mib.rst create mode 100644 examples/v1arch/asyncore/agent/ntforg/inform-v2c.py diff --git a/docs/source/examples/contents.rst b/docs/source/examples/contents.rst new file mode 100644 index 0000000..8257a32 --- /dev/null +++ b/docs/source/examples/contents.rst @@ -0,0 +1,101 @@ + +Examples scripts +================ + +.. toctree:: + :maxdepth: 2 + +SNMP is not really simple (PySNMP implementation takes over 15K lines of +Python code), but PySNMP tries to isolate the complexities and let you +perform typical SNMP operations in a quick and intuitive way. + +PySNMP offers three groups of programming interfaces to deal with +SNMP protocol. In the order from most consice to most detailed those +APIs are: + +#. High-level API + + .. toctree:: + :maxdepth: 2 + + /examples/v3arch/asyncore/oneliner/contents + +#. Complete implementation of all official Standard SNMP Applications. It + should let you implement any SNMP operation defined in the standard. + + This API comes in several transport varieties. + + #. Most mature and stable transport implementation is based on Python's + bult-in asyncore module. So this API is called Native or Asyncore API. + + .. toctree:: + :maxdepth: 2 + + /examples/v3arch/asyncore/contents + + #. Modern, co-routines based API takes shape of asyncio bindings + (Python 3.3+) or Trollius bindings (Python 2.6-3.4) + + .. toctree:: + :maxdepth: 2 + + /examples/v3arch/asyncio/contents + /examples/v3arch/trollius/contents + + #. Slightly aged, Twisted-based based API. + + .. toctree:: + :maxdepth: 2 + + /examples/v3arch/twisted/contents + +#. Packet-level API that lets you build SNMP messages from Python + objects and exchange them through asyncore transport (or you could + write your own). These interfaces are very low-level and aimed at + a rather specific programming tasks. + + .. toctree:: + :maxdepth: 2 + + /examples/v1arch/asyncore/contents + +Before doing cut&paste of the code below into your Python interpreter, +make sure to install pysnmp and its dependencies by running pip or +easy_install: :: + + # pip pysnmp + +There's a public SNMP responder configured at *demo.snmplabs.com:161* to +let you run PySNMP examples scripts in a cut&paste fashion. If you +wish to use your own SNMP Agent with these scripts, make sure to either +configure your local snmpd and/or snmptrapd or use a valid address and +SNMP credentials of your SNMP Agent in the examples to let them work. + +If you find your PySNMP application behaving unexpectedly, try to enable +a /more or less verbose/ built-in PySNMP debugging by adding the +following snippet of code at the beginning of your application: + +.. code-block:: python + + from pysnmp import debug + + # use specific flags or 'all' for full debugging + debug.setLogger(debug.Debug('dsp', 'msgproc', 'secmode')) + +Then run your app and watch stderr. The Debug initializer enables debugging +for a particular PySNMP subsystem, 'all' enables full debugging. More +specific flags are: + +* io +* dsp +* msgproc +* secmod +* mibbuild +* mibview +* mibinstrum +* acl +* proxy +* app + +For more details on PySNMP programming model and interfaces, please +refer to the documentation. diff --git a/docs/source/faq/getting-peer-information.rst b/docs/source/faq/getting-peer-information.rst new file mode 100644 index 0000000..cf78802 --- /dev/null +++ b/docs/source/faq/getting-peer-information.rst @@ -0,0 +1,32 @@ + +Getting peer address information +-------------------------------- + +Q. How do I find out peer transport address or security information within + my receiving app (CommandResponder or Notification Receiver)? + +A. SNMP architecture forces you to distinguish communicating entities only + on the basis of their community names (SNMPv1/v2c) or + ContextEngineId/ContextName pair (SNMPv3). + + In other words, if one SNMP Manager should anyhow differ from another, + then they should use distinct community names or SNMP contexts. + Transport information should never be used for the identification purposes, + as in some cases it proves to be unreliable (cases include NAT device or + a proxy in the middle, not to mention address spoofing). + + As practice reveals, even perfect design does not always cope well with + the imperfect world. So we had to pinch a logic hole from the scope of an + SNMP app down to transport layer. Now with the + getTransportInfo(stateReference) method call you could get peer transport + information upon receiving its SNMP message. + +.. code-block:: python + + # Callback function for receiving notifications + def cbFun(snmpEngine, + stateReference, + contextEngineId, contextName, + varBinds, + cbCtx): + transportDomain, transportAddress = snmpEngine.msgAndPduDsp.getTransportInfo(stateReference) diff --git a/docs/source/faq/how-to-implement-agent-mib.rst b/docs/source/faq/how-to-implement-agent-mib.rst new file mode 100644 index 0000000..6d2bbb9 --- /dev/null +++ b/docs/source/faq/how-to-implement-agent-mib.rst @@ -0,0 +1,120 @@ + +How to implement MIB at the Agent +--------------------------------- + +Q. How to instantiate static MIB table at my SNMP Agent? + +A. You need to create MibScalarInstance class instances and register + them with your Agent's SNMP engine (mibBuilder, more specifically). + Here's an example code for a IP-MIB table: + +.. code-block:: python + + # SNMP Agent (AKA CommandResponder) is built around SNMP engine object + snmpEngine = engine.SnmpEngine() + + # Import table columns + ( ipAddressAddrType, + ipAddressAddr, + ipAddressIfIndex, + ipAddressType, + ipAddressPrefix, + ipAddressOrigin, + ipAddressStatus, + ipAddressCreated, + ipAddressLastChanged, + ipAddressRowStatus, + ipAddressStorageType ) = snmpEngine.msgAndPduDsp.mibInstrumController + .mibBuilder.importSymbols( + 'IP-MIB', + 'ipAddressAddrType', + 'ipAddressAddr', + 'ipAddressIfIndex', + 'ipAddressType', + 'ipAddressPrefix', + 'ipAddressOrigin', + 'ipAddressStatus', + 'ipAddressCreated', + 'ipAddressLastChanged', + 'ipAddressRowStatus', + 'ipAddressStorageType' + ) + + # Import MibScalarInstance + + MibScalarInstance, = snmpEngine.msgAndPduDsp.mibInstrumController. + mibBuilder.importSymbols('SNMPv2-SMI', 'MibScalarInstance') + + # Create table columns instances + + _ipAddressAddrType = MibScalarInstance( + ipAddressAddrType.name, (1, 4, 1, 2, 3, 4), + ipAddressAddrType.syntax.clone(1) + ) + _ipAddressAddr = MibScalarInstance( + ipAddressAddr.name, (1, 4, 1, 2, 3, 4), + ipAddressAddr.syntax.clone('1.2.3.4') + ) + _ipAddressIfIndex = MibScalarInstance( + ipAddressIfIndex.name, (1, 4, 1, 2, 3, 4), + ipAddressIfIndex.syntax.clone(1) + ) + _ipAddressType = MibScalarInstance( + ipAddressType.name, (1, 4, 1, 2, 3, 4), + ipAddressType.syntax.clone(1) + ) + _ipAddressPrefix = MibScalarInstance( + ipAddressPrefix.name, (1, 4, 1, 2, 3, 4), + ipAddressPrefix.syntax.clone((0,0)) + ) + _ipAddressOrigin = MibScalarInstance( + ipAddressOrigin.name, (1, 4, 1, 2, 3, 4), + ipAddressOrigin.syntax.clone(1) + ) + _ipAddressStatus = MibScalarInstance( + ipAddressStatus.name, (1, 4, 1, 2, 3, 4), + ipAddressStatus.syntax.clone(1) + ) + _ipAddressCreated = MibScalarInstance( + ipAddressCreated.name, (1, 4, 1, 2, 3, 4), + ipAddressCreated.syntax.clone(800) + ) + _ipAddressLastChanged = MibScalarInstance( + ipAddressLastChanged.name, (1, 4, 1, 2, 3, 4), + ipAddressLastChanged.syntax.clone(600) + ) + _ipAddressRowStatus = MibScalarInstance( + ipAddressRowStatus.name, (1, 4, 1, 2, 3, 4), + ipAddressRowStatus.syntax.clone(1) + ) + _ipAddressStorageType = MibScalarInstance( + ipAddressStorageType.name, (1, 4, 1, 2, 3, 4), + ipAddressStorageType.syntax + ) + + # add anonymous column instances + snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.exportSymbols( + '_IP-MIB', + _ipAddressAddrType, + _ipAddressAddr, + _ipAddressIfIndex, + _ipAddressType, + _ipAddressPrefix, + _ipAddressOrigin, + _ipAddressStatus, + _ipAddressCreated, + _ipAddressLastChanged, + _ipAddressRowStatus, + _ipAddressStorageType + ) + + # Command responder code would follow... + + Keep in mind that the values of this table row will not change by + themselves. They basically hold a snapshot of a data set so your + application may have to update them somehow. For example, an app could + periodically lookup particular MibScalarInstance by OID at mibBuilder and + update its "syntax" attribute with a new value. + + There are other ways for building MIB tables that represent dynamic + Managed Objects. diff --git a/docs/source/faq/ignored-snmp-packets.rst b/docs/source/faq/ignored-snmp-packets.rst new file mode 100644 index 0000000..d8eca45 --- /dev/null +++ b/docs/source/faq/ignored-snmp-packets.rst @@ -0,0 +1,89 @@ + +Ignored SNMP packets +-------------------- + +Q. Some network devices do not respond to PySNMP-based management + requests for particular OIDs. + +.. code-block:: bash + + $ pysnmpget -v2c -c public 10.0.0.33 1.3.6.1.2.1.2.2.1.10.3 + SNMPv2-SMI::mib-2.2.2.1.10.3 = Counter32: 1519568842 + $ snmpget.py -v2c -c public 10.0.0.33 1.3.6.1.2.1.2.2.1.10.4 + requestTimedOut + + Meanwhile, tcpcump shows request-response sequence: + +.. code-block:: bash + + 13:33:30.161843 IP 10.0.0.33.snmp > 10.0.0.1.51094: + GetResponse(31) interfaces.ifTable.ifEntry.ifInOctets.3=1532504859 + 13:33:30.161881 IP 10.0.0.33.snmp > 10.0.0.1.51094: + GetResponse(31) interfaces.ifTable.ifEntry.ifInOctets.3=1532504859 + + In some cases, particularily when running v1arch PySNMP code, the + following exception may be thrown on response processing: + +.. code-block:: python + + Traceback (most recent call last): + .... + File "build/bdist.linux-i686/egg/pyasn1/type/base.py", line 64, in + __init__ + File "build/bdist.linux-i686/egg/pyasn1/type/base.py", line 32, in _verifySubtypeSpec + File "build/bdist.linux-i686/egg/pyasn1/type/constraint.py", line 33, in __call__ + pyasn1.type.error.ValueConstraintError: ConstraintsIntersection(ConstraintsIntersection(), ValueRangeConstraint(0, 4294967295)) failed at: ValueRangeConstraint(0, 4294967295) failed at: -1413698940 + +A. This appears to be a [widespread] bug in BER integer encoders. It usually + gets noticed on Counter values as they are constrained to be positive while + wrong encoding yelds them negative. + + Here's broken encoding: + +.. code-block:: python + + >>> decoder.decode('A\x04\xab\xbc\xaa\x84', asn1Spec=rfc1155.Counter()) + Traceback (most recent call last): + ... + pyasn1.type.error.ValueConstraintError: ConstraintsIntersection(ConstraintsIntersection(), ValueRangeConstraint(0, 4294967295)) failed at: ValueRangeConstraint(0, 4294967295) failed at: -1413698940 + +And here's a good one: + +.. code-block:: python + + >>> decoder.decode('A\x05\x00\xab\xbc\xaa\x84', + >>> asn1Spec=rfc1155.Counter()) + (Counter('2881268356'), '') + + Notice the third octet -- positive values must have its highest bit set + to zero. + + Here's an example hack that converts negated values into their positive + complimentaries for Counter type. + +.. code-block:: python + + from pysnmp.proto import rfc1155, rfc1902, api + from pyasn1.codec.ber import encoder, decoder + + # --- hack Counter type + + def counterCloneHack(self, *args): + if args and args[0] < 0: + args = (0xffffffff+args[0]-1,) + args[1:] + + return self.__class__(*args) + + rfc1155.Counter.clone = counterCloneHack + rfc1902.Counter32.clone = counterCloneHack + + Execute this hack before any SNMP message processing occures in your app. + + The bad news is that if this BER encoding bug also affects Integer values, + in that case it is theoretically impossible to fix because, unlike Counter, + Integer values may legally be negative so they could not unconditionally be + converted into positives. + + Therefore the best solutoin would be to get vendors fixing their + BER encoders. + diff --git a/docs/source/faq/listening-on-multiple-interfaces.rst b/docs/source/faq/listening-on-multiple-interfaces.rst new file mode 100644 index 0000000..71cc644 --- /dev/null +++ b/docs/source/faq/listening-on-multiple-interfaces.rst @@ -0,0 +1,36 @@ + +Listening on multiple network interfaces +---------------------------------------- + +Q. I need my receiving entity (CommandResponder or Notification Receiver) + to listen for SNMP messages on multiple network interfaces. How do + I do that with pysnmp? + +A. Simply register multiple network transports with your SNMP engine. + Each transport would be bound to an individual local transport + endpoint (for instance, IP address & UDP port pair). + +.. code-block:: python + + # Security setup would follow + ... + # Setup first transport endpoint + config.addSocketTransport( + snmpEngine, + udp.domainName + (1,), + udp.UdpSocketTransport().openServerMode(('127.0.0.1', 162)) + ) + + # Setup second transport endpoint + config.addSocketTransport( + snmpEngine, + udp.domainName + (2,), + udp.UdpSocketTransport().openServerMode(('192.168.1.1', 162)) + ) + # Receiver callback function implementation and Dispatcher invocation + # would follow + ... + + Notice extended transport domain specification (udp.domainName) in + the code above. There we register each transport endpoint under distinct + OID, however always within the canonical transport domain OID. diff --git a/docs/source/faq/non-printable-snmp-values-apps.rst b/docs/source/faq/non-printable-snmp-values-apps.rst new file mode 100644 index 0000000..cee5166 --- /dev/null +++ b/docs/source/faq/non-printable-snmp-values-apps.rst @@ -0,0 +1,40 @@ + +Garbaged SNMP values (apps) +--------------------------- + +Q. When my PySNMP application prints out fetched values, some of them + come out as a garbage on my screan. Here's my code: + +.. code-block:: python + + for varBind in varBinds: + print(' = '.join([ str(x) for x in varBind ]) + + and the result is: + +.. code-block:: python + + 1.3.6.1.4.1.161.19.3.2.1.63.0 = 50000 + 1.3.6.1.4.1.161.19.3.2.1.4.0 = '\x01\x02\x03\x04' + + The IpAddress type seems to be the only one with this problem. + +A. Always use prettyPrint() method for all pyasn1-based objects -- it + automatically converts ASN1 types to human-friendly form. + +.. code-block:: python + + > > > from pysnmp.proto import rfc1902 + > > > a = rfc1902.IpAddress('1.2.3.4') + > > > str(a) + '\x01\x02\x03\x04' + > > > a + IpAddress('1.2.3.4') + > > > a.prettyPrint() + '1.2.3.4' + > > > rfc1902.IpAddress.prettyPrint(a) + '1.2.3.4' + + See `pyasn1 tutorial `_ for more information + on pyasn1 data model. + diff --git a/docs/source/faq/non-printable-snmp-values-tools.rst b/docs/source/faq/non-printable-snmp-values-tools.rst new file mode 100644 index 0000000..89671e2 --- /dev/null +++ b/docs/source/faq/non-printable-snmp-values-tools.rst @@ -0,0 +1,44 @@ + +Garbaged SNMP values (tools) +---------------------------- + +Q. When fetching data with snmp*.py command-line tools, some values + do not print out nicely: + +.. code-block:: bash + + $ snmpget.py -v2c -c public 127.0.0.1 .1.3.6.1.4.1.14988.1.1.1.2.1.1.0.23.183.34.8.200.3 + SNMPv2-SMI::enterprises.14988.1.1.1.2.1.1.0.23.183.34.8.200.3 = + OctetString: ˇČ + + where Net-SNMP gives nicely formatted human-readable string: + +.. code-block:: bash + + $ snmpget -v2c -c public 127.0.0.1 .1.3.6.1.4.1.14988.1.1.1.2.1.1.0.23.183.34.8.200.3 + SNMPv2-SMI::enterprises.14988.1.1.1.2.1.1.0.23.183.34.8.200.3 = + Hex-STRING: 00 17 B7 22 08 C8 + + What can be done to PySNMP to make it returning HEX data in human-readable? + +A. The difference is that Net-SNMP prints values into hex by-default, + whereas pysnmp does not do that. You can force snmpget.py to work + similarily with the -OT command line parameter. + +.. code-block:: bash + + $ snmpget.py -OT -v2c -c public 127.0.0.1 .1.3.6.1.4.1.14988.1.1.1.2.1.1.0.23. + 183.34.8.200.3 + SNMPv2-SMI::enterprises.14988.1.1.1.2.1.1.0.23.183.34.8.200.3 = + OctetString: 00 17 b7 22 08 c8 + + Another matter is MIB lookup - when snmp*.py tool can use a MIB to figure + out what are the display conventions for particular value type, it will + reformat the value in a human-readable form. + + To let MIB lookup work, please pass appropriate MIB name to snmp*.py + tool through command line: + +.. code-block:: bash + + $ snmpwalk.py -m IP-MIB,IF-MIB -v2c -c public 127.0.0.1 .1.3.6.1.4.1 diff --git a/docs/source/faq/oids-not-increasing.rst b/docs/source/faq/oids-not-increasing.rst new file mode 100644 index 0000000..681fd05 --- /dev/null +++ b/docs/source/faq/oids-not-increasing.rst @@ -0,0 +1,29 @@ + +Dealing with OIDs not increasing error +-------------------------------------- + +Q. I'm walking a particular Agent with the CommandGenerator.nextCmd() + and CommandGenerator.bulkCmd() methods. It works for some OIDs, but + invariably fails at certain OID with the 'OIDs are not increasing' + diagnostics. What does it mean and how do I fix that? + +A. The Agent you are talking to seems to be broken. The 'OIDs are not + increasing' message means that in the course of fetching OIDs from Agent, + Manager receives an OID that is not greater than those used in request. + Due to the nature of GETNEXT/GETBULK algorithm, passing the same or + lesser OID to Manager would result in fetching the same set of OIDs over + and over again effectively creating an infinite loop between Manager + and Agent so they may never reach the end of MIB. So Manager tries + to intervene and prevent loop from happenning. + + If have to work with a broken Agent and prepared some other mean + for stopping GETNEXT/GETBULK app at some point, you could set the + ignoreNonIncreasingOid option at CommandGenerator class instance + to disable OID verification on Manager side. + +.. code-block:: python + + cmdGen = cmdgen.CommandGenerator() + cmdGen.ignoreNonIncreasingOid = True + errorIndication, errorStatus, errorIndex, varBindTable = cmdGen.bulkCmd(...) + diff --git a/docs/source/faq/pass-custom-mib-to-manager.rst b/docs/source/faq/pass-custom-mib-to-manager.rst new file mode 100644 index 0000000..af2d5c0 --- /dev/null +++ b/docs/source/faq/pass-custom-mib-to-manager.rst @@ -0,0 +1,70 @@ + +How to pass custom MIB to the Manager +------------------------------------- + +Q. How to make use of my own MIBs at my Manager application? + +A. First you have to convert your plain-text MIB files into + pysnmp-compliant Python modules using libsmi2pysnmp tool. + + Once you have your own pysnmp MIB files at hand, you'd have to put them + somewhere on the filesystem (possibly bundling them with your application). + In order to let pysnmp engine locating and using these modules, pysnmp + MIB search path has to be modified. + +.. code-block:: python + + from pysnmp.entity.rfc3413.oneliner import cmdgen + from pysnmp.smi import builder + + cmdGen = cmdgen.CommandGenerator() + + mibBuilder = cmdGen.snmpEngine.msgAndPduDsp.mibInstrumController + .mibBuilder + + mibSources = mibBuilder.getMibSources() + ( + builder.DirMibSource('/opt/my_pysnmp_mibs'), + ) + + mibBuilder.setMibSources(*mibSources) + + # Rest of CommandGenerator app would follow + + The same effect could be achieved by exporting the PYSNMP_MIB_DIRS variable + to process environment. Individual directories should be separated with + semicolons. + + In case you'd like to .egg your application or just the pysnmp MIB + modules, the following code would work. + +.. code-block:: python + + from pysnmp.entity.rfc3413.oneliner import cmdgen + from pysnmp.smi import builder + + cmdGen = cmdgen.CommandGenerator() + + mibBuilder = cmdGen.snmpEngine.msgAndPduDsp.mibInstrumController + .mibBuilder + + mibSources = mibBuilder.getMibSources() + ( + builder.ZipMibSource('my_pysnmp_mibs_pkg.mibs'), + ) + + mibBuilder.setMibSources(*mibSources) + + # Rest of CommandGenerator app would follow + + The PYSNMP_MIB_PKGS environment variable holding semicolon-separated + list of modules could also be used for the same purpose. + + Please, note, that Python should be able to import the [.egg] package + holding your MIB modules (my_pysnmp_mibs_pkg in the example above). + That requires either putting your module into site-packages or modifying + Python search math (PYTHONPATH variable). + + Then in your application you could refer to your MIB by its name (when + resolving symbolic names to OIDs) or import MIB explicitly (with + mibBuilder.loadModules()) so that you could resolve OIDs to symbolic + names (as well as other MIB information). + diff --git a/docs/source/faq/py2exe-throws-error.rst b/docs/source/faq/py2exe-throws-error.rst new file mode 100644 index 0000000..7f65620 --- /dev/null +++ b/docs/source/faq/py2exe-throws-error.rst @@ -0,0 +1,45 @@ + +My py2exe app can't find MIBs +----------------------------- + +Q. I packed my pysnmp-based application with py2exe. When I run my app, + it throws a traceback like this: + +.. code-block:: bash + +File "pysnmp\entity\rfc3413\oneliner\cmdgen.pyc", line 116, in __init__ +File "pysnmp\entity\engine.pyc", line 16, in __init__ +File "pysnmp\proto\rfc3412.pyc", line 16, in __init__ +File "pysnmp\smi\builder.pyc", line 143, in __init__ +File "pysnmp\smi\builder.pyc", line 35, in init +File "pysnmp\smi\builder.pyc", line 80, in _init +ImportError: No module named mibs.instances + + PySNMP claims itself to be py2exe-friendly. How to make it working? + +A. You have to list pysnmp MIB directories explicitly at your app's + setup.py so that py2exe would include them into the binary. + +.. code-block:: python + + from distutils.core import setup + import sys + + options = {} + + if "py2exe" in sys.argv: + import py2exe + # fix executables + options['console'] = ['myapp.py'] + # add files not found my modulefinder + options['options'] = { + 'py2exe': { + 'includes': [ + 'pysnmp.smi.mibs.*', + 'pysnmp.smi.mibs.instances.*' + ] + } + } + + setup(**options) + diff --git a/docs/source/faq/response-values-mib-resolution.rst b/docs/source/faq/response-values-mib-resolution.rst new file mode 100644 index 0000000..6863319 --- /dev/null +++ b/docs/source/faq/response-values-mib-resolution.rst @@ -0,0 +1,50 @@ + +Resolve response values at MIB +------------------------------ + +Q. My CommandGenerator app reports OIDs and values in form of PyASN1 + objects. How do I convert them into human-readable, symbolic names + and values? + +A. The most easy to use interface to MIB lookup feature is supported by + PySNMP 4.2.3 and later. Just pass the + +.. code-block:: python + + lookupNames=True, lookupValues=True + + parameters to getCmd(), setCmd(), nextCmd(), bulkCmd() methods of + oneliner CommandGenerator. Then the OIDs in response variable-binding + list will get replaced by similarily looking MibVariable instances, + their prettyPrint() methods return MIB symbols instead of OIDs. + + Response values will still be PyASN1 objects but some may be replaced + by TEXTUAL-CONVENTION decorators what make their prettyPrint() methods + returning even more human-friendly output. + +.. code-block:: python + + >>> from pysnmp.entity.rfc3413.oneliner import cmdgen + >>> + >>> cmdGen = cmdgen.CommandGenerator() + >>> + >>> errorIndication, errorStatus, errorIndex, varBinds = cmdGen.getCmd( + ... cmdgen.CommunityData('public'), + ... cmdgen.UdpTransportTarget(('localhost', 161)), + ... '1.3.6.1.2.1.1.1.0', + ... lookupNames=True, lookupValues=True + ... ) + >>> + >>> name, value = varBinds[0] + >>> name + MibVariable(ObjectName(1.3.6.1.2.1.1.1.0)) + >>> value + DisplayString('Linux saturn 2.6.38.1 Sat Apr 9 23:39:07 CDT 2012 i686') + >>> name.prettyPrint() + 'SNMPv2-MIB::sysDescr."0"' + >>> value.prettyPrint() + 'Linux cray 2.6.37.6-smp #2 SMP Sat Apr 9 23:39:07 CDT 2011 i686' + >>> + + If you are using older PySNMP versions it's strongly recommended to + upgrade to the latest one. diff --git a/docs/source/faq/snmp-data-constraints-verification-failure.rst b/docs/source/faq/snmp-data-constraints-verification-failure.rst new file mode 100644 index 0000000..f489b40 --- /dev/null +++ b/docs/source/faq/snmp-data-constraints-verification-failure.rst @@ -0,0 +1,40 @@ + +SNMP data constraints verification error +---------------------------------------- + +Q. Will PySNMP Manager verify the values it sends to and receives from + a distant Agent against local MIB constraints? + +A. Yes, it can do that. The Manager will verify the values you pass to SET + request against a MIB if: + + The values are not already PyASN1 objects but some basic Python types + (like integer or string). You tell PySNMP engine to load appropriate + MIB where it could lookup the constraints (via the use of MibVariable) + So, the following code fragment makes PySNMP engine loading SNMPv2-MIB + and verifying that the 'new system name' value satisfies sysName + constraints (if any). + +.. code-block:: python + + errorIndication, errorStatus, errorIndex, varBinds = cmdGen.setCmd( + cmdgen.CommunityData('public'), + cmdgen.UdpTransportTarget(('localhost', 161)), + ( cmdgen.MibVariable('SNMPv2-MIB', 'sysName', 0), 'new system name' ) + ) + + To verify the response values, you should pass at least lookupValues flag + to CommandGenerator *cmd() method you use. In the following example + PySNMP will make sure that Agent-supplied value for SNMPv2-MIB::sysName + Managed Object satisfies MIB constraints (if any). + +.. code-block:: python + + errorIndication, errorStatus, errorIndex, varBinds = cmdGen.getCmd( + cmdgen.CommunityData('public'), + cmdgen.UdpTransportTarget(('localhost', 161)), + cmdgen.MibVariable('SNMPv2-MIB', 'sysName', 0), + lookupValues=True + ) + + In case of constraint violation, a PySNMP exception will be raised. diff --git a/docs/source/faq/walk-whole-mib.rst b/docs/source/faq/walk-whole-mib.rst new file mode 100644 index 0000000..5682746 --- /dev/null +++ b/docs/source/faq/walk-whole-mib.rst @@ -0,0 +1,26 @@ + +Walking whole MIB +----------------- + +Q. The nextCmd() and bulkCmd() methods of CommandGenerator app + (oneliner version) stop working once returned OIDs went out of scope of + request OIDs. + + In other words, if I request 1.3.6.1, I would get everything under + the 1.3.6.1 prefix, but not 1.3.6.2. Is there any way to make it walking + the whole MIB? + +A. Yes, just pass the lexicographicMode=True parameter to CommandGenerator + nextCmd() and bulkCmd() methods (introduced in PySNMP 4.2.3+) or set + CommandGenerator.lexicographicMode=True option before calling nextCmd() + and bulkCmd() methods. + +.. code-block:: python + + cmdGen = cmdgen.CommandGenerator() + errorIndication, errorStatus, errorIndex, varBindTable = cmdGen.bulkCmd( + ...., + ...., + ...., + lexicographicMode=True + ) diff --git a/examples/v1arch/asyncore/agent/ntforg/inform-v2c.py b/examples/v1arch/asyncore/agent/ntforg/inform-v2c.py new file mode 100644 index 0000000..4fd7aea --- /dev/null +++ b/examples/v1arch/asyncore/agent/ntforg/inform-v2c.py @@ -0,0 +1,83 @@ +""" +INFORM over multiple transports ++++++++++++++++++++++++++++++++ + +The following script sends SNMP INFORM notification using the following options: + +* with SNMPv2c +* with community name 'public' +* over IPv4/UDP and IPv6/UDP +* send INFORM notification +* to a Manager at 127.0.0.1:162 and [::1]:162 +* with TRAP ID 'coldStart' specified as an OID + +The following Net-SNMP command will produce similar SNMP notification: + +| $ snmpinform -v2c -c public udp:127.0.0.1 0 1.3.6.1.6.3.1.1.5.1 +| $ snmpinform -v2c -c public udp6:[::1] 0 1.3.6.1.6.3.1.1.5.1 + +"""# +from pysnmp.carrier.asynsock.dispatch import AsynsockDispatcher +from pysnmp.carrier.asynsock.dgram import udp, udp6 +from pyasn1.codec.ber import encoder +from pysnmp.proto.api import v2c as pMod + +# Build PDU +reqPDU = pMod.InformRequestPDU() +pMod.apiTrapPDU.setDefaults(reqPDU) + +# Build message +trapMsg = pMod.Message() +pMod.apiMessage.setDefaults(trapMsg) +pMod.apiMessage.setCommunity(trapMsg, 'public') +pMod.apiMessage.setPDU(trapMsg, reqPDU) + +startedAt = time() + +def cbTimerFun(timeNow): + if timeNow - startedAt > 3: + raise Exception("Request timed out") + +def cbRecvFun(transportDispatcher, transportDomain, transportAddress, + wholeMsg, reqPDU=reqPDU): + while wholeMsg: + rspMsg, wholeMsg = decoder.decode(wholeMsg, asn1Spec=pMod.Message()) + rspPDU = pMod.apiMessage.getPDU(rspMsg) + # Match response to request + if pMod.apiPDU.getRequestID(reqPDU)==pMod.apiPDU.getRequestID(rspPDU): + # Check for SNMP errors reported + errorStatus = pMod.apiPDU.getErrorStatus(rspPDU) + if errorStatus: + print(errorStatus.prettyPrint()) + else: + print('INFORM message delivered, response var-binds follow') + for oid, val in pMod.apiPDU.getVarBinds(rspPDU): + print('%s = %s' % (oid.prettyPrint(), val.prettyPrint())) + transportDispatcher.jobFinished(1) + return wholeMsg + +transportDispatcher = AsynsockDispatcher() + +transportDispatcher.registerRecvCbFun(cbRecvFun) +transportDispatcher.registerTimerCbFun(cbTimerFun) + +# UDP/IPv4 +transportDispatcher.registerTransport( + udp.domainName, udp.UdpSocketTransport().openClientMode() +) +transportDispatcher.sendMessage( + encoder.encode(trapMsg), udp.domainName, ('localhost', 162) +) + +# UDP/IPv6 +transportDispatcher.registerTransport( + udp6.domainName, udp6.Udp6SocketTransport().openClientMode() +) +transportDispatcher.sendMessage( + encoder.encode(trapMsg), udp6.domainName, ('::1', 162) +) + +# Dispatcher will finish as all scheduled messages are sent +transportDispatcher.runDispatcher() + +transportDispatcher.closeDispatcher() -- cgit v1.2.1