snmpsim-0.4.5/0000775006321400632140000000000013412164240013405 5ustar ietingofietingofsnmpsim-0.4.5/docs/0000775006321400632140000000000013412164240014335 5ustar ietingofietingofsnmpsim-0.4.5/docs/source/0000775006321400632140000000000013412164240015635 5ustar ietingofietingofsnmpsim-0.4.5/docs/source/.static/0000775006321400632140000000000013412164240017202 5ustar ietingofietingofsnmpsim-0.4.5/docs/source/.static/logo.svg0000664006321400632140000003276313175435562020714 0ustar ietingofietingof snmpsim-0.4.5/docs/source/managing-simulation-data.rst0000664006321400632140000001173113217212752023251 0ustar ietingofietingof .. _managing-simulation-data: Simulation data =============== SNMP agent simulation revolves around the contents of *.snmprec* files. .. _snmprec: File format ----------- The *.snmprec* file format is optimised to be compact, human-readable and inexpensive to parse. It's also important to store full and exact response information in a most intact form. Here's an example data file content: .. code-block:: bash 1.3.6.1.2.1.1.1.0|4|Linux 2.6.25.5-smp SMP Tue Jun 19 14:58:11 CDT 2007 i686 1.3.6.1.2.1.1.2.0|6|1.3.6.1.4.1.8072.3.2.10 1.3.6.1.2.1.1.3.0|67|233425120 1.3.6.1.2.1.2.2.1.6.2|4x|00127962f940 1.3.6.1.2.1.4.22.1.3.2.192.21.54.7|64x|c3dafe61 There is a pipe-separated triplet of *OID|tag|value* items where: * OID is a dot-separated set of numbers * Tag is a BER-encoded ASN.1 tag. A modifier can be appended to the tag number. The following modifiers are known: - *x* when the value is hexified (e.g. '0102') - *e* when the value is a Python string literal (e.g. '\x01\x02hello') - Colon-separated reference to a variation module * The value is either a printable string or a hexified string or a raw Python string. Unless it's a number. Valid tag values and their corresponding ASN.1/SNMP types are: * 2 - Integer32 * 4 - OCTET STRING * 5 - NULL * 6 - OBJECT IDENTIFIER * 64 - IpAddress * 65 - Counter32 * 66 - Gauge32 * 67 - TimeTicks * 68 - Opaque * 70 - Counter64 .. _datafile.py: Managing data files ------------------- The *datafile.py* tool is designed to perform a few handy operations on the data files. If you possess *.snmpwalk* or *.sapwalk* snapshots and wish to convert them into Simulator's native *.snmprec* data file format (what can be required for using variation modules), run the *datafile.py* tool like this: .. code-block:: bash $ datafile.py --input-file=linux.snmpwalk --source-record-type=snmpwalk 1.3.6.1.2.1.1.1.0|4|Linux cray 2.6.37.6-smp #2 SMP Sat Apr 9 23:39:07 CDT 2011 i686 1.3.6.1.2.1.1.2.0|6|1.3.6.1.4.1.8072.3.2.10 1.3.6.1.2.1.1.3.0|67|121722922 1.3.6.1.2.1.1.4.0|4|Root (configure /etc/snmp/snmp.local.conf) 1.3.6.1.2.1.1.5.0|4|new system name 1.3.6.1.2.1.1.6.0|4|KK12 (edit /etc/snmp/snmpd.conf) 1.3.6.1.2.1.1.8.0|67|0 1.3.6.1.2.1.1.9.1.2.1|6|1.3.6.1.6.3.11.2.3.1.1 1.3.6.1.2.1.1.9.1.2.2|6|1.3.6.1.6.3.15.2.1.1 1.3.6.1.2.1.1.9.1.2.3|6|1.3.6.1.6.3.10.3.1.1 ... # Records: written 3711, filtered out 0, deduplicated 0, broken 0, variated 0 SNMP Simulator requires data files to be sorted (by OID) and containing no duplicate OIDs. In case your data file does not comply with these requirements for some reason, you could pass it through the *datafile.py* tool to fix data file: .. code-block:: bash $ datafile.py --input-file=tcp-mib.snmprec --sort-records --ignore-broken-records --deduplicate-records 1.3.6.1.2.1.6.1.0|2|1 1.3.6.1.2.1.6.2.0|2|4 1.3.6.1.2.1.6.3.0|2|2 1.3.6.1.2.1.6.4.0|2|4 ... 1.3.6.1.2.1.6.20.1.2.2.0.432|4| 1.3.6.1.2.1.6.20.1.3.2.0.432|66|80 1.3.6.1.2.1.6.20.1.4.2.0.432|66|1524968792 # Records: written 33, filtered out 0, deduplicated 0, broken 0, variated 0 If you have a huge data file and wish to use just a part of it for simulation purposes, datafile.py tool could cut a slice form a data file and store records in a new one: .. code-block:: bash $ datafile.py --input-file=tcp-mib.snmprec --start-oid=1.3.6.1.2.1.6.13 --stop-oid=1.3.6.1.2.1.6.14 1.3.6.1.2.1.6.13.1.1.72.192.51.208.2.234.233.215.7.3|2|1 1.3.6.1.2.1.6.13.1.2.72.192.51.208.2.234.233.215.7.3|64x|8b896863 1.3.6.1.2.1.6.13.1.3.72.192.51.208.2.234.233.215.7.3|2|3 1.3.6.1.2.1.6.13.1.4.72.192.51.208.2.234.233.215.7.3|64x|4f1182fe 1.3.6.1.2.1.6.13.1.5.72.192.51.208.2.234.233.215.7.3|2|3 # Records: written 5, filtered out 28, deduplicated 0, broken 0, variated 0 Merge of multiple data files into a single data file is also supported: .. code-block:: bash $ datafile.py --input-file=tcp-mib.snmprec --input-file=udp-mib.snmprec --sort-records --deduplicate-records 1.3.6.1.2.1.6.1.0|2|1 1.3.6.1.2.1.6.2.0|2|4 1.3.6.1.2.1.6.3.0|2|2 1.3.6.1.2.1.6.4.0|2|4 ... 1.3.6.1.2.1.7.8.0|70|3896031866066683889 1.3.6.1.2.1.7.9.0|70|3518073560493506800 # Records: written 49, filtered out 0, deduplicated 0, broken 0, variated 0 Having string values more human-readable may be more convenient in the course of adjusting simulation data, debugging etc. By default, strings in simulation data are hexified. By passing such *.snmprec* file through the *datafile.py --escaped-strings* call, you can convert your *.snmprec* data into Python string literal representation: .. code-block:: bash $ head data/sample.snmprec 1.3.6.1.2.1.55.1.5.1.8.2|4x|00127962f940 $ $ datafile.py --source-record-type=snmprec --input-file=data/sample.snmprec --escaped-strings 1.3.6.1.2.1.55.1.5.1.8.2|4e|\x00\x12yb\xf9@ # Records: written 1, filtered out 0, deduplicated 0, broken 0, variated 0 snmpsim-0.4.5/docs/source/simulating-agents.rst0000664006321400632140000003544613217212752022043 0ustar ietingofietingof .. _simulating-agents: Simulating SNMP Agents ====================== The *snmpsimd.py* program performs actual SNMP agent simulation based on the simulation data provided. .. _simulation-data-location: Simulation data --------------- SNMP agents simulation data ends up in :ref:`.snmprec ` files. Once SNMP request comes in, SNMP Simulator :ref:`constructs .snmprec file path ` and tries to locate it by searching through the following directories: * ~/.snmpsim/data * /usr/local/share/snmpsim/data * {python-package-root}/data On Windows search paths are: * \Document and Settings\{user}\Application Data\SNMP Simulator\Data * \Program Files\SNMP Simulator\Data * {python-package-root}/data These directories are searched in the specified order till the first match. For example, a set up collection of *.snmprec* files would look like: .. code-block:: bash $ cd /usr/local/share $ find snmpsim/data snmpsim/data snmpsim/data/public.snmprec snmpsim/data/mib2dev snmpsim/data/mib2dev/ip-mib.snmprec snmpsim/data/mib2dev/host-resources-mib.snmprec snmpsim/data/mib2dev/tcp-mib.snmprec snmpsim/data/foreignformats snmpsim/data/foreignformats/linux.snmpwalk snmpsim/data/foreignformats/winxp.sapwalk snmpsim/data/variation snmpsim/data/variation/subprocess.snmprec snmpsim/data/variation/virtualtable.snmprec snmpsim/data/recorded snmpsim/data/recorded/linksys-system.snmprec snmpsim/data/recorded/udp-endpoint-table-walk.snmprec ... .. note:: There're also a bunch of .dbm files created and maintained automatically in a temporary directory. These .dbm files are used by the Simulator for fast OID lookup in a data file. .. _snmpsimd.py: SNMP Simulator daemon --------------------- The *snmpsimd.py* tool hosts multiple independent SNMP Command Responders. It can run multiple SNMP engines exchanging data over multiple network interfaces. Each SNMP engine instance can serve many independent sets of SNMP management objects (MIBs) sourced from :ref:`local .snmprec files ` or :ref:`variation modules `. .. _multiple-listen-interfaces: Multiple network interfaces +++++++++++++++++++++++++++ SNMP Simulator daemon can listen at multiple local IP interfaces and/or UDP ports. Just pass multiple *--agent-udpv4-endpoint* / *--agent-udpv6-endpoint* command line parameters carrying addresses to listen on. Whenever you wish Simulator to listen on thousands of local interfaces and/or ports, use the *--agent-udpv4-endpoints-list* / *--agent-udpv6-endpoints-list* options. These options expect to refer to a plain text file containing newline-separated list of transport endpoints for Simulator to listen on. .. code-block:: bash $ snmpsimd.py --agent-udpv4-endpoint=127.0.0.1:1024 \ --agent-udpv6-endpoint='[::1]:1161' Scanning "/home/user/.snmpsim/variation" directory for variation modules... no directory Scanning "/usr/local/share/snmpsim/variation" directory for variation modules... 8 more modules found Initializing variation modules: notification... OK sql... FAILED: database type not specified numeric... OK subprocess... OK delay... OK multiplex... OK error... OK writecache... OK Scanning "/home/user/.snmpsim/data" directory for *.snmpwalk, *.MVC, *.sapwalk, *.snmprec, *.dump data files... no directory Scanning "/usr/local/share/snmpsim/data" directory for *.snmpwalk, *.MVC, *.sapwalk, *.snmprec, *.dump data files... ================================================================== Index /tmp/snmpsim/usr_local_share_snmpsim_data_public.dbm does not exist for data file data/public.snmprec Building index /tmp/snmpsim/usr_local_share_snmpsim_data_public.dbm for data file /usr/local/share/snmpsim/data/public.snmprec (open flags "n")...... 133 entries indexed Data file /usr/local/share/snmpsim/data/public.snmprec, dbhash-indexed, closed SNMPv1/2c community name: public SNMPv3 context name: 4c9184f37cff01bcdc32dc486ec36961 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Index /tmp/snmpsim/usr_local_share_snmpsim_data_recorded_linksys-system.dbm does not exist for data file /usr/local/share/snmpsim/data/recorded/ linksys-system.snmprec Building index /tmp/snmpsim/usr_local_share_snmpsim_data_recorded_linksys- system.dbm for data file /usr/local/share/snmpsim/data/recorded/linksys- system.snmprec (open flags "n")......6 entries indexed Data file /usr/local/share/snmpsim/data/recorded/linksys-system.snmprec, dbhash-indexed, closed SNMPv1/2c community name: recorded/linksys-system SNMPv3 context name: 1a764f7fd0e7b0bf98bada8fe723e488 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ... ... ... SNMPv3 credentials: Username: simulator Authentication key: auctoritas Authentication protocol: MD5 Encryption (privacy) key: privatus Encryption protocol: DES Listening at: UDP/IPv4 endpoint 127.0.0.1:1024, transport ID 1.3.6.1.6.1.1.0 UDP/IPv6 endpoint ::1:1161, transport ID 1.3.6.1.2.1.100.1.2.0 .. note:: An unprivileged port *1024* has been chosen in this example to avoid running *snmpsimd.py* process as root. By this point you can run you favorite SNMP Manager to talk to either of the two simulated devices through whatever transport you prefer. For instance, to talk to simulated Linux box over SNMP v2 through UDP over IPv4 run: .. code-block:: bash $ snmpwalk -On -v2c -c recorded/linksys-system localhost:1161 1.3.6 .1.3.6.1.2.1.1.1.0 = STRING: BEFSX41 .1.3.6.1.2.1.1.2.0 = OID: .1.3.6.1.4.1.3955.1.1 .1.3.6.1.2.1.1.3.0 = Timeticks: (638239) 1:46:22.39 .1.3.6.1.2.1.1.4.0 = STRING: Linksys .1.3.6.1.2.1.1.5.0 = STRING: isp-gw .1.3.6.1.2.1.1.6.0 = STRING: 4, Petersburger strasse, Berlin, Germany .1.3.6.1.2.1.1.8.0 = Timeticks: (4) 0:00:00.04 .1.3.6.1.2.1.1.8.0 = No more variables left in this MIB View ... To walk simulated 3com switch over SNMPv3 we'd run: .. code-block:: bash $ snmpwalk -On -v3 -n recorded/linksys-system \ -l authPriv -u simulator -A auctoritas -X privatus \ localhost:1161 1.3.6 .1.3.6.1.2.1.1.1.0 = STRING: BEFSX41 .1.3.6.1.2.1.1.2.0 = OID: .1.3.6.1.4.1.3955.1.1 .1.3.6.1.2.1.1.3.0 = Timeticks: (638239) 1:46:22.39 .1.3.6.1.2.1.1.4.0 = STRING: Linksys .1.3.6.1.2.1.1.5.0 = STRING: isp-gw .1.3.6.1.2.1.1.6.0 = STRING: 4, Petersburger strasse, Berlin, Germany .1.3.6.1.2.1.1.8.0 = Timeticks: (4) 0:00:00.04 .1.3.6.1.2.1.1.8.0 = No more variables left in this MIB View ... .. note:: The *-n * parameter passed to the *snmpwalk* tool addresses specific simulated device at SNMP Simulator daemon. .. _multiple-usm-users: Multiple USM users ++++++++++++++++++ It is also possible to configure many SNMPv3 (USM) users to Simulator. Each set of *--v3-user*, *--v3-auth-key*, *--v3-priv-key* parameters adds one SNMPv3 user to Simulator. There is no correlation between SNMPv3 users and simulated resources, all users have the same view of the Simulator and the same access permissions. But you can use SNMPv3 contextNames and/or transport endpoints for addressing different data files e.g. simulated SNMP agents. .. code-block:: bash $ snmpsimd.py --agent-udpv4-endpoint=127.0.0.1 \ --v3-user=wallace --v3-auth-key=testkey123 --v3-priv-key=testkey839 \ --v3-user=gromit --v3-auth-key=testkey564 --v3-priv-key=testkey6534 Scanning "/home/user/.snmpsim/variation" directory for variation modules... ... SNMPv3 EngineID 0x80004fb8056372617927fb76cc ------------------------------------------------------------------ SNMPv3 USM SecurityName: wallace SNMPv3 USM authentication key: testkey123, authentication protocol: MD5 SNMPv3 USM encryption (privacy) key: testkey839, encryption protocol: DES ------------------------------------------------------------------ SNMPv3 USM SecurityName: gromit SNMPv3 USM authentication key: testkey564, authentication protocol: MD5 SNMPv3 USM encryption (privacy) key: testkey6534, encryption protocol: DES Listening at UDP/IPv4 endpoint 127.0.0.1:161, transport ID 1.3.6.1.6.1.1.0 ... SNMP simulator supports many SNMPv3 authentication and encryption algorithms. For each user you can configure any authentication and any encryption (privacy) algorithm. .. _auth-algos: The following authentication algorithms are currently supported (via *--v3-auth-proto=* option): +--------+----------------+-------------+ | *ID* | *Algorithm* | *Reference* | +--------+----------------+-------------+ | NONE | - | RFC3414 | +--------+----------------+-------------+ | MD5 | HMAC MD5 | RFC3414 | +--------+----------------+-------------+ | SHA | HMAC SHA-1 128 | RFC3414 | +--------+----------------+-------------+ | SHA224 | HMAC SHA-2 224 | RFC7860 | +--------+----------------+-------------+ | SHA256 | HMAC SHA-2 256 | RFC7860 | +--------+----------------+-------------+ | SHA384 | HMAC SHA-2 384 | RFC7860 | +--------+----------------+-------------+ | SHA512 | HMAC SHA-2 512 | RFC7860 | +--------+----------------+-------------+ .. _priv-algos: The following privacy (encryption) algorithms are currently supported (via *--v3-priv-proto=* option): +------------+------------------------+----------------------+ | *ID* | *Algorithm* | *Reference* | +------------+------------------------+----------------------+ | NONE | - | RFC3414 | +------------+------------------------+----------------------+ | DES | DES | RFC3414 | +------------+------------------------+----------------------+ | AES | AES CFB 128 | RFC3826 | +------------+------------------------+----------------------+ | AES192 | AES CFB 192 | RFC Draft | +------------+------------------------+----------------------+ | AES256 | AES CFB 256 | RFC Draft | +------------+------------------------+----------------------+ | AES192BLMT | AES CFB 192 Blumenthal | RFC Draft | +------------+------------------------+----------------------+ | AES256BLMT | AES CFB 256 Blumenthal | RFC Draft | +------------+------------------------+----------------------+ | 3DES | Triple DES EDE | RFC Draft | +------------+------------------------+----------------------+ .. note:: The AES192, AES256 and 3DES are implemented based on `Blumenthal `_ and `Reeder `_ draft RFCs. Another configurable parameter is SNMPv3 snmpEngineId value. It's normally automatically generated but can also be configured through command line. .. code-block:: bash $ snmpsimd.py --agent-udpv4-endpoint=127.0.0.1 --v3-engine-id=010203040505060809 Scanning "/home/user/.snmpsim/variation" directory for variation modules... ... SNMPv3 EngineID 0x010203040505060809 ------------------------------------------------------------------ SNMPv3 USM SecurityName: simulator SNMPv3 USM authentication key: auctoritas, authentication protocol: MD5 SNMPv3 USM encryption (privacy) key: privatus, encryption protocol: DES Listening at UDP/IPv4 endpoint 127.0.0.1:161, transport ID 1.3.6.1.6.1.1.0 .. note:: The *SnmpEngineId* value has to follow `certain format `_. .. _multiple-snmp-engine-ids: Multiple SNMP engines +++++++++++++++++++++ SNMP Simulator could run many independent SNMP engines all within a single daemon process. SNMP managers could address particular SNMP Engine instance by querying it at a transport endpoint to which SNMP Engine is bound. Each SNMP Engine will have its own set of USM users and could serve its own *--data-dir* (or they can share a single directory). The logic of configuring specific parameters to different SNMP engines is to "scope" SNMP Engine parameters (like users, transports, data directory) within its *--v3-engine-id* fragment of Simulator command-line sequence of options. For example: .. code-block:: bash $ snmpsimd.py \ --v3-engine-id=010203040505060809 \ --v3-user=wallace --v3-auth-key=testkey123 \ --agent-udpv4-endpoint=127.0.0.1:1161 \ --v3-engine-id=090807060504030201 \ --v3-user=gromit --v3-auth-key=testkey564 \ --agent-udpv4-endpoint=127.0.0.1:1162 Scanning "/home/user/.snmpsim/variation" directory for variation modules... ... SNMPv3 EngineID: 0x010203040505060809 ------------------------------------------------------------------ SNMPv3 USM SecurityName: wallace SNMPv3 USM authentication key: testkey123, authentication protocol: MD5 Listening at UDP/IPv4 endpoint 127.0.0.1:1161, transport ID 1.3.6.1.6.1.1.0 ... SNMPv3 EngineID: 0x090807060504030201 ------------------------------------------------------------------ SNMPv3 USM SecurityName: gromit SNMPv3 USM authentication key: testkey564, authentication protocol: MD5 Listening at UDP/IPv4 endpoint 127.0.0.1:1162, transport ID 1.3.6.1.6.1.1.1 Likewise, to make particular SNMP Engine working with specific data directory, another, more specific, *--data-dir* option could be passed after the *--v3-engine-id* option. .. _running-options: Invocation options ++++++++++++++++++ To make Simulator listening on SNMP-standard UDP port 161 on a UNIX system, you have to invoke it as root but in the same time have to specify some non-privileged UNIX user and group to switch into upon port allocation: .. code-block:: bash # snmpsimd.py --agent-udpv4-endpoint=127.0.0.1:161 \ --process-user=simulator --process-group=simulator On UNIX systems Simulator can be run as a daemon. Make sure to re-direct its console output into syslog: .. code-block:: bash # snmpsimd.py --agent-udpv4-endpoint=127.0.0.1:161 \ --process-user=simulator --process-group=simulator \ --daemonize --logging-method=syslog:local1:debug .. _logging-options: Logging options +++++++++++++++ Most of the scripts shipped with the SNMP Simulator package can log to a remote syslog server over TCP or UDP: .. code-block:: bash # snmpsimd.py --agent-udpv4-endpoint=127.0.0.1:161 \ --process-user=simulator --process-group=simulator \ --daemonize --logging-method=syslog:local1:debug:192.168.1.1:514:udp Finally, Simulator can simply log to a local log file: .. code-block:: bash # snmpsimd.py --agent-udpv4-endpoint=127.0.0.1:161 \ --process-user=simulator --process-group=simulator \ --daemonize --logging-method=file:/var/log/snmpsimd.log snmpsim-0.4.5/docs/source/license.rst0000664006321400632140000000007713175435562020033 0ustar ietingofietingof .. _license: License ======= .. include:: ../../LICENSE.txt snmpsim-0.4.5/docs/source/recording-with-variation-modules.rst0000664006321400632140000003571213175435562025002 0ustar ietingofietingof .. _recording-with-variation-modules: Recording with variation modules ================================ Some valuable simulation information may also be collected in the process of recording snapshots off the live SNMP Agent. Examples include changes in the set of OIDs in time, changes in numeric values, request processing times and so on. To facilitate capturing such information, some of the stock variation modules support snapshots recording mode. To invoke a variation module while recording SNMP Agent with the :ref:`snmprec.py ` tool, pass its name via the *--variation-module* command-line option. Additional variation module parameters could also be passed through the *--variation-module-options* switch. The following standard modules support the recording feature: * The :ref:`numeric ` module produces a non-decreasing sequence of integers over time * The :ref:`sql ` module reads/writes var-binds from/to a SQL database * The :ref:`redis ` module reads/writes var-binds from/to a no-SQL key-value store * The :ref:`delay ` module delays SNMP response by specified or random time * The :ref:`multiplex ` module uses a time series of *.snmprec* files picking one at a time. .. _record-numeric: Numeric module -------------- The numeric module can be used for capturing initial values of Managed Objects and calculating a coefficient to a linear function in attempt to approximate live values changes in time. In case value change law is not linear, custom approximation function should be used instead. The numeric module supports the following comma-separated key:value options whilst running in recording mode: * *taglist* - a dash-separated list of *.snmprec* tags indicating SNMP value types to apply numeric module to. Valid tags are: - 2 - Integer - 65 - Counter32 - 66 - Gauge32 - 67 - TimeTicks - 70 - Counter64 Default is empty list. * *iterations* - number of recording cycles to run over the same portion of SNMP agent MIB. There's no point in values beyond 2 for purposes of modelling approximation function. Default is 1. * *period* - Agent walk period in seconds. Default is 10 seconds. * *addon* - a single *.snmprec* record scope *key=value* parameter for the *numeric* module to be used whilst running in variation mode. Multiple add-on parameters can be used. Default is empty. Examples ++++++++ In the examples the :ref:`snmprec.py ` tool will be used. .. code-block:: bash $ snmprec.py --agent-udpv4-endpoint=demo.snmplabs.com \ --start-oid=1.3.6.1.2.1.2 --stop-oid=1.3.6.1.2.1.3 \ --variation-module=numeric \ --variation-module-options=taglist:65,iterations:2,period:15 \ Scanning "/usr/local/share/snmpsim/variation" directory for variation modules...numeric module loaded SNMP version 2c Community name: public Querying UDP/IPv4 agent at demo.snmplabs.com:161 Initializing variation module: numeric...OK numeric: waiting 0.77 sec(s), 111 OIDs dumped, 1 iterations remaining... ... 1.3.6.1.2.1.2.2.1.6.4|4x|008d120f4fa4 1.3.6.1.2.1.2.2.1.7.1|2|1 1.3.6.1.2.1.2.2.1.9.2|67|0 1.3.6.1.2.1.2.2.1.10.1|65:numeric|rate=3374,initial=641734,increasing=1 1.3.6.1.2.1.2.2.1.10.2|65:numeric|rate=0,initial=0,increasing=1 1.3.6.1.2.1.2.2.1.10.4|65:numeric|rate=1159,initial=32954879,increasing=1 1.3.6.1.2.1.2.2.1.11.1|65:numeric|rate=86,initial=12238,increasing=1 1.3.6.1.2.1.2.2.1.21.1|66|0 ... Shutting down variation modules: numeric...OK OIDs dumped: 224, elapsed: 15.53 sec, rate: 20.00 OIDs/sec In the above example we have run two iterations against a subset of Managed Objects at an Agent requesting numeric module to configure itself into generated *.snmprec* data for Counter32-typed objects (ID 65). Produced *.snmprec* file could be used for simulation as-is or edited by hand to change variation module behaviour on on a per-OID basis. .. _record-delay: Delay module ------------ The delay module can be used for capturing request processing time when recording SNMP agent. Examples ++++++++ .. code-block:: bash $ snmprec.py --agent-udpv4-endpoint=demo.snmplabs.com \ --start-oid=1.3.6.1.2.1.2 --stop-oid=1.3.6.1.2.1.3 \ --variation-module=delay Scanning "/usr/local/share/snmpsim/variation" directory for variation modules...delay module loaded SNMP version 2c Community name: public Querying UDP/IPv4 agent at demo.snmplabs.com:161 Initializing variation module: delay...OK 1.3.6.1.2.1.2.1.0|2:delay|value=5,wait=8 1.3.6.1.2.1.2.2.1.1.1|2:delay|value=1,wait=32 1.3.6.1.2.1.2.2.1.6.4|4x:delay|hexvalue=008d120f4fa4,wait=20 ... Shutting down variation modules: delay...OK OIDs dumped: 224, elapsed: 15.53 sec, rate: 20.00 OIDs/sec Produced *.snmprec* file could be used for Simulation as-is or edited by hand to change delay variation. .. _record-multiplex: Multiplex module ---------------- The multiplex module can record a series of snapshots at specified period of time. Recorded *.snmprec* snapshots could then be used for simulation by multiplex module. The multiplex module supports the following comma-separated *key:value* options whilst running in recording mode: * *dir* - directory for produced *.snmprec* files * *iterations* - number of recording cycles to run over the same portion of SNMP agent MIB. There's no point in values beyond 2 for purposes of modelling approximation function. Default is 1. * *period* - Agent walk period in seconds. Default is 10 seconds. * *addon* - a single *.snmprec* record scope *key=value* parameter for the *multiplex* module to be used whilst running in variation mode. Multiple add-on parameters can be used. Default is empty. Examples ++++++++ .. code-block:: bash $ snmprec.py --agent-udpv4-endpoint=demo.snmplabs.com \ --start-oid=1.3.6.1.2.1.2 --stop-oid=1.3.6.1.2.1.3 \ --output-file=data/multiplex.snmprec \ --variation-module=multiplex \ --variation-module-options=dir:data/multiplex,iterations:5,period:15 Scanning "/usr/local/share/snmpsim/variation" directory for variation modules...multiplex module loaded SNMP version 2c Community name: public Querying UDP/IPv4 agent at demo.snmplabs.com:161 Initializing variation module: multiplex...OK multiplex: writing into data/multiplex/00000.snmprec file... multiplex: waiting 14.78 sec(s), 45 OIDs dumped, 5 iterations remaining... ... multiplex: writing into data/multiplex/00005.snmprec file... Shutting down variation modules: multiplex...OK OIDs dumped: 276, elapsed: 75.76 sec, rate: 3.64 OIDs/sec Besides individual *.snmprec* snapshots, the "main" *.snmprec* file will also be written: .. code-block:: bash $ cat data/multiplex.snmprec 1.3.6.1.2.1.2|:multiplex|period=15.00,dir=data/multiplex where the multiplex module is configured for specific OID subtree (actually, specified in *--start-oid*). Although multiplex-generated *.snmprec* files can also be addressed directly by Simulator, to benefit from the time series nature of the collected data, it's better to simulate based on the "main" *.snmprec* file and the multiplex variation module. .. _record-sql: SQL module ---------- The *sql* module can record a snapshot of SNMP agent's set of Managed Objects and store it in a SQL database. Recorded snapshots could then be used for simulation by the *sql* module running in variation mode. Module configuration parameters described on the :ref:`simulation ` page are also applicable to the recording. Examples ++++++++ Running with SQLite DB backend: .. code-block:: bash $ snmprec.py --agent-udpv4-endpoint=demo.snmplabs.com --start-oid=1.3.6.1.2.1.2 --stop-oid=1.3.6.1.2.1.3 --output-file=data/sql.snmprec --variation-module=sql --variation-module-options=dbtype:sqlite3,database:/tmp/snmpsim.db,dbtable:snmprec Scanning "/usr/local/share/snmpsim/variation" directory for variation modules... sql module loaded SNMP version 2c Community name: public Querying UDP/IPv4 agent at demo.snmplabs.com:161 Initializing variation module: sql...OK Shutting down variation modules: sql...OK OIDs dumped: 45, elapsed: 0.21 sec, rate: 213.00 OIDs/sec By this point you'd get the *data/sql.snmprec* file where *sql* module is configured for OID subtree (taken from *--start-oid* parameter): .. code-block:: bash $ cat data/sql.snmprec 1.3.6.1.2.1.2.2|:sql|snmprec and SQLite database */tmp/snmpsim.db* having SQL table "snmprec" with the following contents: .. code-block:: bash $ sqlite3 /tmp/snmpsim.db SQLite version 3.7.5 sqlite> .schema snmprec CREATE TABLE snmprec (oid text, tag text, value text, maxaccess text); sqlite> select * from snmprec limit 1; 1. 3. 6. 1. 2. 1. 2. 2. 1. 1. 1|2|1|read-write .. note:: The OID is formatted in a way that each sub-oid is left-padded with up to 8 spaces (must be 10 chars in total) to make the ordering work properly with standard SQL sorting. The following :ref:`snmprec.py ` call push snapshots into MySQL database using native MySQL's Connector/Python driver: .. code-block:: bash $ snmprec.py --agent-udpv4-endpoint=demo.snmplabs.com \ --output-file=data/sql.snmprec \ --variation-module=sql \ --variation-module-options=dbtype:mysql.connector,host:127.0.0.1, \ port:3306,user:snmpsim,password:snmpsim,database:snmpsim The above code assumes that you have the `MySQL Connector/Python driver `_ installed on the recording machine and a MySQL server running at 127.0.0.1 with MySQL user/password snmpsim/snmpsim having sufficient permissions for creating new tables. Another variation of MySQL server installation setup on a UNIX system employs UNIX domain socket for client-server communication. In that case the following command-line for :ref:`snmprec.py ` might work: .. code-block:: bash $ snmprec.py --agent-udpv4-endpoint=demo.snmplabs.com \ --output-file=data/sql.snmprec \ --variation-module=sql --variation-module-options=dbtype:mysql.connector,unix_socket: \ /var/run/mysql/mysql.sock,user:snmpsim,password:snmpsim,database:snmpsim Alternatively, the `MySQL for Python `_ package could be used for SNMP Simulator's MySQL connection: .. code-block:: bash $ snmprec.py --agent-udpv4-endpoint=demo.snmplabs.com \ --output-file=data/sql.snmprec \ --variation-module=sql \ --variation-module-options=dbtype:MySQLdb,host:127.0.0.1,port:3306, \ user:snmpsim,passwd:snmpsim,db:snmpsim Similar call but with the `PostgreSQL `_ DB as a backend data store: .. code-block:: bash $ snmprec.py --agent-udpv4-endpoint=demo.snmplabs.com \ --output-file=data/sql.snmprec \ --variation-module=sql \ --variation-module-options=dbtype:psycopg2,database:snmpsim,user:snmpsim, \ password:snmpsim,dbtable:snmprec With the example above, the assumption is that you have the `Psycopg `_ module installed, PostgreSQL server running locally (accessed through default UNIX domain socket), DB user/password are snmpsim/snmpsim and this user has sufficient permissions to create new database tables (snmprec table will be created). When *sql* variation module is invoked in :ref:`simulaiton ` context, it can read, create and modify individual rows in the SQL database we just created. You could also modify the contents of such SQL tables, create SQL triggers to react to certain changes elsewhere. .. _record-redis: Redis module ------------ The *redis* module can record one or more snapshots of SNMP agent's set of Managed Objects and store it in `Redis key-value store `_. Recorded snapshots could then be replayed by *redis* module running in :ref:`variation mode `. Redis database schema and module configuration parameters explained on the :ref:`variation ` page is also applicable to the recording mode. The *redis* module supports the following comma-separated *key:value* options whilst running in recording mode: * *host* - Redis hostname or IP address. * *port* - Redis TCP port the server is listening on. * *unix_socket* - UNIX domain socket Redis server is listening on. * *db* - Redis database number. * *password* - Redis database admission password. * *key-spaces-id* - key spaces ID to use for recording a single or a series of snapshots * *iterations* - number of recording cycles to run over the same portion of SNMP agent MIB. There's no point in values beyond 2 for purposes of modelling approximation function. Default is 1. * *period* - Agent walk period in seconds. Default is 10 seconds. * *evalsha* - Redis server side `Lua script `_ to use for storing oid-value pairs in Redis. If this option is not given, bare Redis SET commands will be used instead. Examples ++++++++ Make the *redis* module for recording five snapshots of a demo SNMP Agent: .. code-block:: bash $ snmprec.py --agent-udpv4-endpoint=demo.snmplabs.com \ --start-oid=1.3.6.1.2.1.2 --stop-oid=1.3.6.1.2.1.3 \ --output-file=data/redis.snmprec \ --variation-module=redis \ --variation-module-options=host:127.0.0.1,port:6379,db:0,key-spaces-id:1111, \ iterations:5,period:30 Scanning "variation" directory for variation modules... Variation module "redis" loaded SNMP version 2c, Community name: public Querying UDP/IPv4 agent at 195.218.195.228:161 Initializing variation module... redis: using key-spaces-id 1111 Variation module "redis" initialization OK Sending initial GETNEXT request.... redis: done with key-space 0000001116 redis: 4 iterations remaining 85 OIDs dumped, waiting 30.00 sec(s)... redis: done with key-space 0000001115 redis: 3 iterations remaining 171 OIDs dumped, waiting 30.00 sec(s)... redis: done with key-space 0000001114 redis: 2 iterations remaining 257 OIDs dumped, waiting 30.00 sec(s)... redis: done with key-space 0000001113 redis: 1 iterations remaining 343 OIDs dumped, waiting 30.00 sec(s)... redis: done with key-space 0000001112 redis: 0 iterations remaining Shutting down variation module redis... Variation module redis shutdown OK OIDs dumped: 603, elapsed: 329.22 sec, rate: 0.00 OIDs/sec By this point you'd get the *data/redis.snmprec* file where *redis* module is configured for OID subtree (taken from the *--start-oid* parameter): .. code-block:: bash $ cat data/redis.snmprec 1.3.6|:redis|period=30.00,key-spaces-id=1111 When *redis* variation module is invoked in the :ref:`variation context `, it can read, create and modify individual OID-value pairs in Redis database we've just created. snmpsim-0.4.5/docs/source/contents.rst0000664006321400632140000000506613345010600020226 0ustar ietingofietingof SNMP Agent Simulator ==================== .. toctree:: :maxdepth: 2 SNMP Simulator tool can simulate many thousands of different SNMP speaking devices on a network. It is primarily used for testing and development purposes. It is free, open source and immediately available to anyone for whatever purpose free of charge. How to use SNMP Simulator ------------------------- Try the fast lane if you are fluent with network management matters. .. toctree:: :maxdepth: 2 /quickstart Documentation ------------- .. toctree:: :maxdepth: 2 /simulating-agents /managing-simulation-data /addressing-agents /simulation-with-variation-modules /building-simulation-data /recording-with-variation-modules /tips-and-tricks Source code & Changelog ----------------------- Project source code is hosted at `GitHub `_. Everyone is welcome to fork and contribute back! We maintain detailed :doc:`log of changes ` to our software. Download -------- The easiest way to download and install SNMP simulator is to `pip install` the latest version from PyPI: .. code-block:: bash $ virtualenv venv $ source venv/bin/activate $ pip install snmpsim Alternatively, you can `download `_ the latest release from GitHub or `PyPI `_. License ------- The SNMP Simulator software is distributed under 2-clause :doc:`BSD license `. Development ----------- Our development plans and new features we consider for eventual implementation are tracked on the :doc:`future features ` page. Free simulation service ----------------------- We setup :doc:`publicly available SNMP Simulator ` instance at `Digital Ocean `_ cloud to serve SNMP simulation services to you - our fellow SNMP developers and testers. The service is hosted in the U.S. (west coast) and should be available to everyone free of charge. If you are considering signing up with Digital Ocean for their hosting services, `the voucher `_ will get you $10 credit and that would benefit our service hosting as well. ;-) Contact ------- In case of questions or troubles using SNMP Simulator, please open up an `issue `_ at GitHub or ask at `Stack Overflow `_ . You can also try browsing the mailing list `archives `_. snmpsim-0.4.5/docs/source/simulation-with-variation-modules.rst0000664006321400632140000010657413345010600025174 0ustar ietingofietingof .. _simulation-with-variation-modules: Simulation with variation modules ================================= Without variation modules, simulated SNMP Agents are always static in terms of data returned to SNMP Managers. They are also read-only. By configuring particular OIDs or whole subtrees to be routed to variation modules, that allows you to make returned data changing over time. Another way of using variation modules is to gather data from some external source such as an SQL database or executed process or distant web-service. It's also possible to modify simulated values through SNMP SET operation and store modified values in a database so they will persist over Simulator restarts. Variation modules may be used for triggering events at other systems. For instance the *notification* module will send SNMP TRAP/INFORM SNMP messages to pre-configured SNMP Managers on SNMP SET request arrival to *snmpsimd.py*. Finally, variation module API let you develop your own code in Python to fulfill your special needs and use your variation module with stock Simulator. .. _configuring-simulation-with-variation-modules: Configuring variation modules ----------------------------- To make use of a variation module you will have to *edit* existing or create a new data file adding reference to a variation module into the *tag* field by means of :ref:`recording variation modules `. Remember :ref:`.snmprec file format ` is a sequence of lines having the *OID|TAG|VALUE* fields? With variation module in use, the *TAG* field complies to its own sub-format - *TAG-ID[:MODULE-ID]*. Examples ++++++++ The following .snmprec file contents will invoke the *writecache* module and cast its returned values into ASN.1 OCTET STRING (4) and INTEGER (2) respectively: .. code-block:: bash 1.3.6.1.2.1.1.3.0|2:volatilecache|value=42 Whenever a subtree is routed to a variation module, *TAG-ID* part is left out as there might be no single type for all values within a subtree. Thus the empty *TAG-ID* sub-field serves as an indicator of a subtree. For example, the following data file will serve all OIDs under 1.3.6.1.2.1.1 prefix to the "sql" variation module: .. code-block:: bash 1.3.6.1.2.1.1|:sql|snmprec The value part is passed to variation module as-is. It is typically holds some module-specific configuration or initialization values. Another example: the following .snmprec line invokes the "notification" variation module instructing it to send SNMP INFORM message to SNMP manager at 127.0.01:162 over SNMPv3 with specific SNMP params: .. code-block:: bash 1.3.6.1.2.1.1.3.0|67:notification|version=3,user=usr-md5-des,\ authkey=authkey1,privkey=privkey1,host=127.0.0.1,ntftype=inform,\ trapoid=1.3.6.1.6.3.1.1.5.2,value=123456 The standard variation modules are installed into the Python site-packages directory. User can pass Simulator an alternative modules directory through the command line. Simulator will load and bootstrap all variation modules it finds. Some modules can accept initialization parameters (like database connection credentials) through *snmpsimd.py* *--variation-module-options* command-line parameter. For example, the following Simulator invocation will configure its *sql* variation module to use sqlite database (sqlite3 Python module) and /var/tmp/snmpsim.db database file: .. code-block:: bash $ snmpsimd.py --variation-module-options=sql:dbtype:sqlite3,\ database:/var/tmp/snmpsim.db IF you are using multiple database connections or database types all through the *sql* variation module, you could refer to each module instance in *.snmprec* files through a so-called variation module alias. The following command-line runs Simulator with two instances of the *involatilecache* variation module (dbA & dbB) each instance using distinct database file for storing their persistent values: .. code-block:: bash $ snmpsimd.py --variation-module-options=writecache=dbA:file:/var/tmp/fileA.db \ --variation-module-options=writecache=dbB:file:/var/tmp/fileB.db The syntax for *--variation-module-options=* module configuration string is comma-separated list of semicolon-separated name:value pairs: .. code-block:: bash --variation-module-options=> With exception for the first semicolon (which is considered to be a part of module reference), the rest of separators could potentially intervene with values. In that case user could use a doubled or tripled separator tokens as an escaping aid: .. code-block:: bash $ snmpsimd.py --variation-module-options=writecache:file::C:\TEMP\fileA.db The same separator escaping method works for module options in *.snmprec* value field. The only difference is that *.snmprec* value syntax uses equal sign and commands as separators. .. _standard-variation-modules: Standard variation modules -------------------------- The following variation modules are shipped with SNMP Simulator: * The :ref:`numeric ` module produces a non-decreasing sequence of integers over time * The :ref:`notification ` module sends SNMP TRAP/INFORM messages to distant SNMP entity * The :ref:`writecache ` module accepts and stores (in memory/file) SNMP variable-bindings being modified through SNMP SET command * The :ref:`sql ` module reads/writes var-binds from/to a SQL database * The :ref:`redis ` module reads/writes var-binds from/to a no-SQL key-value store * The :ref:`delay ` module delays SNMP response by specified or random time * The :ref:`error ` module flag errors in SNMP response PDU * The :ref:`multiplex ` module uses a time series of .snmprec files picking one at a time. * The :ref:`subprocess ` module executes external process and puts its stdout values into response .. _variate-numeric: Numeric module ++++++++++++++ The numeric module maintains and returns a changing in time integer value. The law and rate of changing is configurable. This module is per-OID stateful and configurable. The numeric module accepts the following comma-separated key=value parameters in *.snmprec* value field: * min - the minimum value ever stored and returned by this module. Default is 0. * max - the maximum value ever stored and returned by this module. Default is 2\*\*32 or 2\*\*64 (Counter64 type). * initial - initial value. Default is min. * atime - if non-zero, uses current time for value generation, not Simulator uptime. * wrap - if zero, generated value will freeze when reaching 'max'. Otherwise generated value is reset to 'min'. * function - defines elapsed-time-to-generated-value relationship. Can be any of reasonably suitable mathematical function from the math module such as sin, log, pow etc. The only requirement is that used function accepts a single integer argument. Default is x = f(x). * rate - elapsed time scaling factor. Default is 1. * scale - function value scaling factor. Default is 1. * offset - constant value by which the return value increases on each invocation. Default is 0. * deviation - random deviation maximum. Default is 0 which means no deviation. * cumulative - if non-zero sums up previous value with the newly generated one. This is important when simulating COUNTER values. This module generates values by execution of the following formula: .. code-block:: python TIME = TIMENOW if atime else UPTIME v = function(TIME * rate) * scale + offset + RAND(-deviation, deviation) v = v + prev_v if cumulative else v Examples ~~~~~~~~ .. code-block:: bash # COUNTER object 1.3.6.1.2.1.2.2.1.13.1|65:numeric|scale=10,deviation=1,function=cos,cumulative=1,wrap=1 # GAUGE object 1.3.6.1.2.1.2.2.1.14.1|66:numeric|min=5,max=50,initial=25 You are welcome to try the *numeric* module in action at our online :ref:`public SNMP simulation service `: .. code-block:: bash $ snmpget -v2c -c variation/virtualtable demo.snmplabs.com \ IF-MIB::ifLastChange.1 IF-MIB::ifInOctets.1 IF-MIB::ifLastChange.1 = Timeticks: (16808012) 1 day, 22:41:20.12 IF-MIB::ifInOctets.1 = Counter32: 30374688 The numeric module can be used for simulating INTEGER, Counter32, Counter64, Gauge32, TimeTicks objects. .. _variate-delay: Delay module ++++++++++++ The delay module postpones SNMP request processing for specified number of milliseconds. Delay module accepts the following comma-separated *key=value* parameters in *.snmprec* value field: * *value* - holds the var-bind value to be included into SNMP response. In case of a string value containing commas, use the *hexvalue* key instead. * *hexvalue* - holds the var-bind value as a sequence of ASCII codes in hex form. Before putting it into var-bind, hexvalue contents will be converted into ASCII text. * *wait* - specifies for how many milliseconds to delay SNMP response. Default is 500ms. If the value exceeds 999999, request will never be answered (PDU will be dropped right away). * *deviation* - random delay deviation ranges (ms). Default is 0 which means no deviation. * *vlist* - a list of triples *comparison:constant:delay* to use on SET operation for choosing delay based on value supplied in request. The following comparison operators are supported: *eq*, *lt*, *gt*. * *tlist* - a list of triples *comparison:time:delay* to use for choosing request delay based on time of day (seconds, UNIX time). The following comprison operators are supported: *eq*, *lt*, *gt*. .. note:: Optional tag modifier in :ref:`.snmprec file ` is ignored by this variation module. Examples ~~~~~~~~ The following entry makes Simulator responding with an integer value of 6 delayed by 0.1sec +- 0.2 sec (negative delays are casted into zeros): .. code-block:: bash 1.3.6.1.2.1.2.2.1.3.1|2:delay|value=6,wait=100,deviation=200 Here the hexvalue takes shape of an OCTET STRING value '0:12:79:62:f9:40' delayed by exactly 0.8 sec: .. code-block:: bash 1.3.6.1.2.1.2.2.1.6.1|4:delay|hexvalue=00127962f940,wait=800 This entry drops PDU right away so the Manager will timed out: .. code-block:: bash 1.3.6.1.2.1.2.2.1.7.1|2:delay|wait=1000000 The following entry uses module default on GET/GETNEXT/GETBULK operations. However delays response by 0.1 sec if request value is exactly 0 and delays response by 1 sec on value equal to 1. .. code-block:: bash 1.3.6.1.2.1.2.2.1.8.1|2:delay|vlist=eq:0:100:eq:1:1000,value=1 The entry that follows uses module default on GET/GETNEXT/GETBULK operations, however delays response by 0.001 sec if request value is exactly 100, uses module default on values >= 100 but <= 300 (0.5 sec), and drops request on values > 300: .. code-block:: bash 1.3.6.1.2.1.2.2.1.9.1|67:delay|vlist=lt:100:1:gt:300:1000000,value=150 The next example will simulate an unavailable Agent past 01.04.2013 (1364860800 in UNIX time): .. code-block:: bash 1.3.6.1.2.1.2.2.1.10.1|67:delay|tlist=gt:1364860800:1000000,value=150 .. note:: Since SNMP Simulator is internally an asynchronous, single-thread application, any delayed response will block all concurrent requests processing as well. .. _variate-error: Error module ++++++++++++ The error module flags a configured error at SNMP response PDU. Error module accepts the following comma-separated key=value parameters in *.snmprec* value field: * *op* - either of *get*, *set* or *any* values to indicate SNMP operation that would trigger error response. Here *get* also enables GETNEXT and GETBULK operations. Default is *any*. * *value* - holds the var-bind value to be included into SNMP response. In case of a string value containing commas, use the *hexvalue* key instead. * *hexvalue* - holds the var-bind value as a sequence of ASCII codes in hex form. Before putting it into var-bind, hexvalue contents will be converted into ASCII text. * *status* - specifies error to be flagged. The following SNMP errors codes are supported: - *genError* - *noAccess* - *wrongType* - *wrongValue* - *noCreation* - *inconsistentValue* - *resourceUnavailable* - *commitFailed* - *undoFailed* - *authorizationError* - *notWritable* - *inconsistentName* - *noSuchObject* - *noSuchInstance* - *endOfMib* * *vlist* - a list of triples (comparison:constant:error) to use as an access list for SET values. The following comparison operators are supported: - *eq* - *lt* - *gt* The following SNMP errors are supported (case-insensitive): - *genError* - *noAccess* - *wrongType* - *wrongValue* - *noCreation* - *inconsistentValue* - *resourceUnavailable* - *commitFailed* - *undoFailed* - *authorizationError* - *notWritable* - *inconsistentName* - *noSuchObject* - *noSuchInstance* - *endOfMib* .. note:: Optional tag modifier in :ref:`.snmprec file ` is ignored by this variation module. Examples ~~~~~~~~ .. code-block:: bash 1.3.6.1.2.1.2.2.1.1.1|2:error|op=get,status=authorizationError,value=1 1.3.6.1.2.1.2.2.1.2.1|4:error|op=set,status=commitfailed,hexvalue=00127962f940 1.3.6.1.2.1.2.2.1.3.1|2:error|vlist=gt:2:wrongvalue,value=1 1.3.6.1.2.1.2.2.1.6.1|4:error|status=noaccess The first entry flags *authorizationError* on GET* and no error on SET. Second entry flags *commitfailed* on SET but responds without errors to GET*. Third entry fails with *wrongvalue* only on SET with values > 2. Finally, forth entry always flags *noaccess* error. .. _variate-writecache: Writecache module +++++++++++++++++ The *writecache* module lets you make particular OID at a *.snmprec* file writable via SNMP SET operation. The new value will be stored in Simulator process's memory or disk-based data store and communicated back on SNMP GET/GETNEXT/GETBULK operations. Data saved in disk-based data store will NOT be lost upon Simulator restart. Module initialization allows for passing a name of a database file to be used as a disk-based data store: .. code-block:: bash $ snmpsimd.py --variation-module-options=writecache:file:/tmp/shelves.db All modifed values will be kept and then subsequently used on a per-OID basis in the specified file. If data store file is not specified, the *writecache* module will keep all its data in [volatile] memory. The *writecache* module accepts the following comma-separated *key=value* parameters in *.snmprec* value field: * *value* - holds the var-bind value to be included into SNMP response. In case of a string value containing commas, use *hexvalue* instead. * *hexvalue* - holds the var-bind value as a sequence of ASCII codes in hex form. Before putting it into var-bind, hexvalue contents will be converted into ASCII text. * *vlist* - a list of triples *comparison:constant:error* to use as an access list for SET values. The following comparison operators are supported: - *eq* - *lt* - *gt* The following SNMP errors are supported (case-insensitive): - *genError* - *noAccess* - *wrongType* - *wrongValue* - *noCreation* - *inconsistentValue* - *resourceUnavailable* - *commitFailed* - *undoFailed* - *authorizationError* - *notWritable* - *inconsistentName* - *noSuchObject* - *noSuchInstance* - *endOfMib* .. note:: Optional tag modifier in :ref:`.snmprec file ` is ignored by this variation module. Examples ~~~~~~~~ .. code-block:: bash 1.3.6.1.2.1.1.3.0|2:writecache|value=42 In the above configuration, the initial value is 42 and can be modified by the *snmpset* command (assuming correct community name and Simulator is running locally). .. code-block:: bash $ snmpset -v2c -c community localhost 1.3.6.1.2.1.1.3.0 i 24 A more complex example involves using an access list. The following example allows only values of 1 and 2 to be SET: .. code-block:: bash 1.3.6.1.2.1.1.3.0|2:writecache|value=42,vlist=lt:1:wrongvalue:gt:2:wrongvalue Any other SET values will result in SNNP WrongValue error in response. .. note:: An attempt to SET a value of incompatible type will also result in error. .. _variate-multiplex: Multiplex module ++++++++++++++++ The multiplex module allows you to serve many snapshots for a single Agent picking just one snapshot at a time for answering SNMP request. That simulates a more natural Agent behaviour including the set of OIDs changing in time. This module is usually configured to serve an OID subtree in an *.snmprec* file entry. The multiplex module accepts the following comma-separated *key=value* parameters in *.snmprec* value field: * *dir* - path to *.snmprec* files directory. If path is not absolute, it is interpreted relative to Simulator's *--data-dir*. The *.snmprec* files names here must have numerical names ordered by time. * *period* - specifies for how long to use each *.snmprec* snapshot before switching to the next one. Default is 60 seconds. * *wrap* - if true, instructs the module to cycle through all available *.snmprec* files. If false, the system stops switching *.snmprec* files as it reaches the last one. Default is false. * *control* - defines a new OID to be used for switching *.snmprec* file via SNMP SET command. Examples ~~~~~~~~ .. code-block:: bash 1.3.6.1.2.1.2|:multiplex|dir=variation/snapshots,period=10.0 1.3.6.1.3.1.1|4|snmprec The variation/snapshots/ directory contents is a name-ordered collection of *.snmprec* files: .. code-block:: bash $ ls -l /usr/local/share/snmpsim/data/variation/snapshots -rw-r--r-- 1 root staff 3145 Mar 30 22:52 00000.snmprec -rw-r--r-- 1 root staff 3145 Mar 30 22:52 00001.snmprec -rw-r--r-- 1 root staff 3145 Mar 30 22:52 00002.snmprec ... Simulator can use each of these files only once through its configured time series. To make it cycling over them, use *wrap* option. The *.snmprec* files served by the multiplex module can not include references to variation modules. In cases when automatic, time-based *.snmprec* multiplexing is not applicable for simulation purposes, *.snmprec* selection can be configured:

.. code-block:: bash 1.3.6.1.2.1.2|:multiplex|dir=variation/snapshots,control=1.3.6.1.2.1.2.999 The following command will switch multiplex module to use the first *.snmprec* file for simulation: .. code-block:: bash $ snmpset -v2c -c variation/multiplex localhost 1.3.6.1.2.1.2.999 i 0 Whenever *control* OID is present in multiplex module options, the time-based multiplexing will not be used. .. _variate-subprocess: Subprocess module +++++++++++++++++ The *subprocess* module can be used to execute an external program passing it request data and using its stdout output as a response value. Module invocation supports passing a *shell* option which (if true) makes Simulator using shell for subprocess invocation. Default is True on Windows platform and False on all others. .. warning:: With *shell=True*, UNIX shell gets into the pipeline what compromises security. .. code-block:: bash $ snmpsimd.py --variation-module-options=subprocess:shell:1 Value part of *.snmprec* line should contain space-separated path to external program executable followed by optional command-line parameters. SNMP request parameters could be passed to the program to be executed by means of macro variables. With subprocess module, macro variables names always carry '@' sign at front and back (e.g. @MACRO@). Macros ~~~~~~ * *@DATAFILE@* - resolves into the *.snmprec* file selected by SNMP Simulator for serving current request * *@OID@* - resolves into an OID of *.snmprec* line selected for serving current request * *@TAG@* - resolves into the component of *.snmprec* line selected for serving current request * *@ORIGOID@* - resolves into currently processed var-bind OID * *@ORIGTAG@* - resolves into value type of currently processed var-bind * *@ORIGVALUE@* - resolves into value of currently processed var-bind * *@SETFLAG@* - resolves into '1' on SNMP SET, '0' otherwise * *@NEXTFLAG@* - resolves into '1' on SNMP GETNEXT/GETBULK, '0' otherwise * *@SUBTREEFLAG@* - resolves into '1' if the *.snmprec* file line selected for processing current request serves a subtree of OIDs rather than a single specific OID * *@TRANSPORTDOMAIN@* - SNMP transport domain as an OID. It has a one-to-one relationship with local interfaces Simulator is configured to listen at * *@TRANSPORTADDRESS@* - peer transport address * *@SECURITYMODEL@* - SNMPv3 Security Model * *@SECURITYNAME@* - SNMPv3 Security Name * *@SECURITYLEVEL@* - SNMPv3 Security Level * *@CONTEXTNAME@* - SNMPv3 Context Name Examples ~~~~~~~~ .. code-block:: bash 1.3.6.1.2.1.1.1.0|4:subprocess|echo SNMP Context is @DATAFILE@, received \ request for @ORIGOID@, matched @OID@, received tag/value \ "@ORIGTAG@"/"@ORIGVALUE@", would return value tagged @TAG@, SET request \ flag is @SETFLAG@, next flag is @NEXTFLAG@, subtree flag is \ @SUBTREEFLAG@ 1.3.6.1.2.1.1.3.0|2:subprocess|date +%s The first entry simply packs all current macro variables contents as a response string my printing them to stdout with echo, second entry invokes the UNIX date command instructing it to report elapsed UNIX epoch time. Note *.snmprec* tag values -- executed program's stdout will be casted into appropriate type depending of tag indication. .. _variate-notification: Notification module +++++++++++++++++++ The *notification* module can send SNMP TRAP/INFORM notifications to distant SNMP engines by way of serving SNMP request sent to Simulator. In other words, SNMP message sent to Simulator can trigger sending TRAP/INFORM message to pre-configured targets. .. note:: No new process is created when sending SNMP notification -- *snmpsimd*'s own SNMP engine is reused. The *notification* module accepts the following comma-separated *key=value* parameters in *.snmprec* value field: * *value* - holds the variable-bindings value to be included into SNMP response message. * *op* - either of *get*, *set* or *any* values to indicate SNMP operation that would trigger notification. Here *get* also enables GETNEXT and GETBULK operations. Default is *set*. * *vlist* - a list of pairs *comparison:constant* to use as event triggering criteria to be compared against SET values. The following comparisons are supported: *eq*, *lt*, *gt*. * *version* - SNMP version to use (1,2c,3). * *ntftype* - indicates notification type. Either *trap* or *inform*. * *community* - SNMP community name. For v1, v2c only. Default is *public*. * *trapoid* - SNMP TRAP PDU element. Default is *coldStar*. * *uptime* - SNMP TRAP PDU element. Default is local SNMP engine uptime. * *agentaddress* - SNMP TRAP PDU element. For v1 only. Default is local SNMP engine address. * *enterprise* - SNMP TRAP PDU element. For v1 only. * *user* - USM username. For v3 only. * *authproto* - USM auth protocol. For v3 only. Either *md5* or *sha*. Default is *md5*. * *authkey* - USM auth key. For v3 only. * *privproto* - USM encryption protocol. For v3 only. Either *des* or *aes*. Default is *des*. * *privkey* - USM encryption key. For v3 only. * *proto* - transport protocol. Either *udp* or *udp6*. Default is *udp*. * *host*- hostname or network address to send notification to. * *port* - UDP port to send notification to. Default is 162. * *varbinds* - a semicolon-separated list of *OID:TAG:VALUE:OID:TAG:VALUE...* of var-binds to add into SNMP TRAP PDU. The following *TAG* values are recognized: - *s* - OctetString (expects character string) - *h* - OctetString (expects hex string) - *i* - Integer32 - *o* - ObjectName - *a* - IpAddress - *u* - Unsigned32 - *g* - Gauge32 - *t* - TimeTicks - *b* - Bits - *I* - Counter64 .. note:: Optional tag modifier in :ref:`.snmprec file ` is ignored by this variation module. Examples ~~~~~~~~ The following three *.snmprec* lines will send SNMP v1, v2c and v3 notifications whenever Simulator is processing GET* and/or SET request for configured OIDs: .. code-block:: bash 1.3.6.1.2.1.1.1.0|4:notification|op=get,version=1,community=public,\ proto=udp,host=127.0.0.1,port=162,ntftype=trap,\ trapoid=1.3.6.1.4.1.20408.4.1.1.2.0.432,uptime=12345,agentaddress=127.0.0.1,\ enterprise=1.3.6.1.4.1.20408.4.1.1.2,\ varbinds=1.3.6.1.2.1.1.1.0:s:snmpsim agent:1.3.6.1.2.1.1.3.0:i:42,\ value=SNMPv1 trap sender 1.3.6.1.2.1.1.2.0|6:notification|op=set,version=2c,community=public,\ host=127.0.0.1,ntftype=trap,trapoid=1.3.6.1.6.3.1.1.5.1,\ varbinds=1.3.6.1.2.1.1.1.0:s:snmpsim agent:1.3.6.1.2.1.1.3.0:i:42,\ value=1.3.6.1.1.1 1.3.6.1.2.1.1.3.0|67:notification|version=3,user=usr-md5-des,authkey=authkey1,\ privkey=privkey1,host=127.0.0.1,ntftype=inform,trapoid=1.3.6.1.6.3.1.1.5.2,\ value=123456 .. note:: The delivery status of INFORM notifications is not communicated back to the SNMP Manager working with Simulator. .. _variate-sql: SQL module ++++++++++ The *sql* module lets you keep subtrees of OIDs and their values in a relational database. All SNMP operations are supported including transactional SET. Module invocation requires passing database type (sqlite3, psycopg2, MySQL and any other compliant to `Python DB-API `_ and importable as a Python module) and connect string which is database dependant. Besides DB-specific connect string key-value parameters, sql module supports the following comma-separated key:value options whilst running in recording mode: * *dbtype* - SQL DBMS type in form of Python DPI API-compliant module. It will be imported into Python as specified. * *dbtable* - Default SQL table name to use for storing recorded snapshot. It is used if table name is not specified in *.snmprec* file. * *isolationlevel* - SQL transaction `isolation level `_. Allowed values are: - *0* - READ UNCOMMITTED - *1* - READ COMMITTED - *2* - REPEATABLE READ - *3* - SERIALIZABLE Default is READ COMMITTED. Database connection ~~~~~~~~~~~~~~~~~~~ For SQLite database invocation use the following command: .. code-block:: bash $ snmpsimd.py --variation-module-options=sql:dbtype:sqlite3,database:/var/tmp/sqlite.db To use a MySQL database for OID/value storage, the following Simulator invocation would work: .. code-block:: bash $ snmpsimd.py --variation-module-options=sql:dbtype:mysql.connector,\ host:127.0.0.1,port:3306,user:snmpsim,password:snmpsim,database:snmpsim assuming you have the `MySQL Connector/Python driver `_ is installed on the SNMP Simulator machine and a MySQL server running at 127.0.0.1 with MySQL user/password snmpsim/snmpsim having full access to a database *snmpsim* Another variation of MySQL server installation setup on a UNIX system employs UNIX domain socket for client-server communication. In that case the following command-line for *.snmprec* might work: .. code-block:: bash $ snmpsimd.py --variation-module-options=sql:dbtype:mysql.connector, unix_socket:/var/run/mysql/mysql.sock,user:snmpsim,password:snmpsim, database:snmpsim Alternatively, the `MySQL for Python `_ package can be used for Simulator to MySQL connection: .. code-block:: bash $ snmpsimd.py --variation-module-options=sql:dbtype:MySQLdb,host:127.0.0.1, port:3306,user:snmpsim,passwd:snmpsim,db:snmpsim If you wish to use `PostgresSQL `_ database for OID/value storage, the following command line will do the job: .. code-block:: bash $ snmpsimd.py --variation-module-options=sql:dbtype:psycopg2, user:snmpsim,password:snmpsim,database:snmpsim assuming you have the `Psycopg Python adapter `_ is installed on the SNMP Simulator machine and a PostgreSQL server running locally (accessed through default UNIX domain socket) with PostgreSQL user/password snmpsim/snmpsim having full access to a database *snmpsim*. Simulation data configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The *.snmprec* value is expected to hold database table name to keep all OID-value pairs served within selected *.snmprec* line. This table can either be created automatically whenever *sql* module is invoked in :ref:`recording mode ` or can be created and populated by hand. In the latter case table layout should be as follows: .. code-block:: bash CREATE TABLE (oid text, tag text, value text, maxaccess text) The most usual setup is to keep many OID-value pairs in a database table referred to by a *.snmprec* line serving a subtree of OIDs: .. code-block:: bash 1.3.6.1.2.1.1|:sql|snmprec In the above case all OIDs under 1.3.6.1.2.1.1 prefix will be handled by a sql module using 'snmprec' table. .. note:: To make SQL's ORDER BY clause working with OIDs, each sub-OID stored in the database (in case of manual database population) must be left-padded with a good bunch of spaces (each sub-OID width is 10 characters). .. _variate-redis: Redis module ++++++++++++ The *redis* module lets you keep subtrees of OIDs and their values in a no-SQL key-value store. Besides complete SNMP operations support, Redis server-side Lua scripts are also supported at both variation and :ref:`recording ` stages. For redis variation module to work you must also have the `redis-py `_ Python module installed on your system. Module invocation requires passing Redis database connection string. The following parameters are supported: * *host* - Redis hostname or IP address. * *port* - Redis TCP port the server is listening on. * *unix_socket* - UNIX domain socket Redis server is listening on. * *db* - Redis database number. * *password* - Redis database admission password. .. code-block:: bash $ snmpsimd.py --variation-module-options=redis:host:127.0.0.1,port:6379,db:0 SNMP variable-bindings recorded by Simulator in a single recording session is placed into a dedicated key namespace called "key space". This allows for keeping many versions of the same oid-value pair either belonging to different Agents or recorded at different times. These key spaces are organized by pre-pending a session-unique "key space" to each key put into Redis. Simulator keeps recorded SNMP var-binds in three types of Redis data structures: * Redis `String `_ where each key is composed from key space and an OID joint with a dash *-*. Values are SNMP data type tag and value in :ref:`snmprec format `. This is where simulation data is stored. * Redis `LIST `_ object keyed *|oids_ordering* where each element is a key from the String above. The purpose of this structure is to order OIDs what is important for serving SNMP GETNEXT/GETBULK queries. * Redis `LIST `_ object keyed ** where each element is a from the LIST above. The purpose of this structure is to consolidate many key spaces into a sequence to form simulation data time series and ease switching key spaces during simulation. The data structure above can be created manually or automatically whenever redis module is invoked in :ref:`recording mode `. .. note:: To make string-typed OIDs comparable, sub-OIDs of original OIDs must be left-padded with a good bunch of spaces (up to 9) so that 1.3.6 will become ' 1. 3. 6'. The .snmprec value is expected to hold more Redis database access parameters, specific to OID-value pairs served within selected *.snmprec* line. * *key-spaces-id* - Redis key used to store a sequence of key-spaces referring to oid-value collections used for simulation. * *period* - number of seconds to switch from one key-space to another within the key-spaces-id list. * *evalsha* - Redis server side `Lua script `_ to use for accessing oid-value pairs stored in Redis. If this option is not given, bare Redis GET/SET commands will be used instead. Examples ~~~~~~~~ The most usual setup is to keep many OID-value pairs in a Redis database referred to by a *.snmprec* line serving a subtree of OIDs: .. code-block:: bash 1.3.6.1.2.1.1|:redis|key-spaces-id=1234 In the above case all OIDs under 1.3.6.1.2.1.1 prefix will be handled by redis module using key spaces stored in "1234" Redis list. For example, the "1234" keyed list can hold the following key spaces: ["4321", "4322", "4323"]. Then the following keys can be stored for 1.3.6.1.2.1.1.3.0 OID: .. code-block:: bash "4321-<9 spaces>.1<9 spaces>.3<9 spaces>.6 ... <9 spaces>.3<9 spaces>.0" = "67|812981" "4322-<9 spaces>.1<9 spaces>.3<9 spaces>.6 ... <9 spaces>.3<9 spaces>.0" = "67|813181" "4323-<9 spaces>.1<9 spaces>.3<9 spaces>.6 ... <9 spaces>.3<9 spaces>.0" = "67|814233" If *period* parameter is passed through the *.snmprec* record, Simulator will automatically change key space every *period* seconds when gathering data for SNMP responses. The *key-spaces-id* Redis list can also be manipulated by an external application at any moment for the purpose of switching key spaces while Simulator is running. Simulated values can also be modified on-the-fly by an external application. However, when adding/removing OIDs, not just modifying simulation data, care must be taken to keep the -oids_ordering list ordered and synchronized with the collection of -OID keys being used for storing simulation data. Besides using an external application for modifying simulation data, custom `Lua script `_ can be used for dynamic response and/or stored data modification. For example, the following *.snmprec* entry will invoke server-side Lua script stored under the name of "d94bf1756cda4f55bac9fe9bb872f" when getting/setting Redis keys: .. code-block:: bash 1.3.6.1.2.1.1|:redis|key-spaces-id=1234,evalsha=d94bf1756cda4f55bac9fe9bb872f Here's an example Lua script, carrying no additional logic, stored at Redis server using the `SCRIPT LOAD `_ Redis command: .. code-block:: bash $ redis-cli 127.0.0.1:6379> script load " if table.getn(ARGV) > 0 then return redis.call('set', KEYS[1], ARGV[1]) else return redis.call('get', KEYS[1]) end " "d94bf1756cda4f55bac9fe9bb872f" 127.0.0.1:6379> SNMP Simulator will perform SET/GET operations through its *evalsha* script like this: .. code-block:: bash $ redis-cli 127.0.0.1:6379> evalsha "d94bf1756cda4f55bac9fe9bb872f" 1 "4321|1. 3. 6. 1. 2. 1. 2. 1. 1. 0" "4|linksys router" 127.0.0.1:6379> evalsha "d94bf1756cda4f55bac9fe9bb872f" 1 "4321|1. 3. 6. 1. 2. 1. 2. 1. 1. 0" "4|linksys router" 127.0.0.1:6379> A much more complex Lua scripts could be written to dynamically modify other parts of the database, sending messages to other Redis-backed applications through Redis's `Publish/Subscribe `_ facility. Writing variation modules ------------------------- Whenever you consider coding your own variation module, take a look at the existing ones. The API is very simple - it basically takes three Python functions (init, process, shutdown) where process() is expected to return a var-bind pair per each invocation. snmpsim-0.4.5/docs/source/addressing-agents.rst0000664006321400632140000001424513175435562022015 0ustar ietingofietingof .. _addressing-simulation-data: Addressing SNMP agents ====================== Sometimes SNMP managers can't easily change community name to address particular simulated device instance as mention in the previous section. Or it may be useful to present the same simulated device to different SNMP managers differently. .. _v2c-style-variation: Legacy mode ----------- When running in the *--v2c-arch* mode, SNMP Simulator attempts to find a *.snmprec* file to fulfill a request by probing files in paths constructed from pieces of request data. The path construction occurs by these rules and in this order: 1. *community / transport-ID / source-address* .snmprec 2. *community / transport-ID* .snmprec 3. *community* .snmprec In other words, SNMP Simulator first tries to take community name, destination and source addresses into account. If that does not match any existing file, the next probe would use community name and destination address. The last resort is to probe files by just community name, as described in previous chapters. Transport ID is an OID that also identifies local transport endpoint (e.g. protocol, local address and port Simulator is listening on). It is reported by the Simulator on startup for each endpoint it is listening on. .. code-block:: bash $ snmpsimd.py --agent-udpv4-endpoint=127.0.0.1:1024 \ --agent-udpv6-endpoint='[::1]:1161' ... SNMPv3 credentials: Username: simulator Authentication key: auctoritas Authentication protocol: MD5 Encryption (privacy) key: privatus Encryption protocol: DES Listening at: UDP/IPv4 endpoint 127.0.0.1:1024, transport ID 1.3.6.1.6.1.1.0 UDP/IPv6 endpoint ::1:1161, transport ID 1.3.6.1.2.1.100.1.2.0 When mapping source-address into a file, the following transformation rules apply: * UDP/IPv4: 192.168.1.1 remains 192.168.1.1 * UDP/IPv6: fe80::12e:410f:40d1:2d13 becomes fe80__12e_410f_40d1_2d13 * UNIX local domain sockets: /tmp/snmpmanager.FAB24243 becomes tmp/snmpmanager.FAB24243 For example, to make Simulator reporting from particular file to a Manager at 192.168.1.10 whenever community name "public" is used and queries are sent to Simulator over UDP/IPv4 to 192.168.1.1 interface (which is reported by Simulator under transport ID 1.3.6.1.6.1.1.0), device file *public/1.3.6.1.6.1.1.0/192.168.1.10.snmprec* would be used for building responses. .. _v3-style-variation: SNMPv3 mode ----------- When Simulator is NOT running in *--v2c-arch* mode, e.g. SNMPv3 engine is used, similar rules apply to SNMPv3 context name rather than to SNMPv1/2c community name. In that case device file path construction would work like this: 1. *context-name / transport-ID / source-address* .snmprec 2. *context-name / transport-ID* .snmprec 3. *context-name* .snmprec For example, to make Simulator reporting from particular file to a Manager at 192.168.1.10 whenever context-name is an empty string and queries are sent to Simulator over UDP/IPv4 to 192.168.1.1 interface (which is reported by Simulator under transport ID 1.3.6.1.6.1.1.0), device file *1.3.6.1.6.1.1.0/192.168.1.10.snmprec* would be used for building responses. .. _sharing-snmprec-files: Sharing .snmprec files ---------------------- If a symbolic link is used as a data file, it would serve as an alternative CommunityName/ContextName for the Managed Objects collection read from the snapshot file being pointed to: .. code-block:: bash $ ls -l public.snmprec -rw-r--r-- 1 root users 8036 Mar 12 23:26 public.snmprec $ ln -s public.snmprec private.snmprec $ ls -l private.snmprec lrwxrwxrwx 1 root users 14 Apr 5 20:58 private.snmprec -> public.snmprec Shared device files are mentioned explicitly on *snmpsimd.py* startup: .. code-block:: bash $ snmpsimd.py --agent-udpv4-endpoint=127.0.0.1:1161 Scanning "/home/root/.snmpsim/variation" directory for variation modules... no directory Scanning "/usr/local/share/snmpsim/variation" directory for variation modules... 8 more modules found Initializing variation modules: notification... OK sql... FAILED: database type not specified numeric... OK subprocess... OK delay... OK multiplex... OK error... OK writecache... OK Scanning "/usr/local/share/snmpsim/data" directory for *.snmpwalk, *.MVC, *.sapwalk, *.snmprec, *.dump data files... ================================================================== Data file /usr/local/share/snmpsim/data/public.snmprec, dbhash-indexed, closed SNMPv1/2c community name: public SNMPv3 context name: 4c9184f37cff01bcdc32dc486ec36961 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Shared data file data/public.snmprec, dbhash-indexed, closed SNMPv1/2c community name: private SNMPv3 context name: 2c17c6393771ee3048ae34d6b380c5ec -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ... SNMPv3 credentials: Username: simulator Authentication key: auctoritas Authentication protocol: MD5 Encryption (privacy) key: privatus Encryption protocol: DES Listening at: UDP/IPv4 endpoint 127.0.0.1:1161, transport ID 1.3.6.1.6.1.1.0 Now Managers can then use different credentials to access and modify the same set of Managed Objects. .. code-block:: bash $ snmpwalk -On -v2c -c public localhost:1161 1.3.6 .1.3.6.1.2.1.1.1.0 = STRING: Device description .1.3.6.1.2.1.1.2.0 = OID: .1.3.6.1.4.1.34547 .1.3.6.1.2.1.1.3.0 = Timeticks: (78171676) 9 days, 1:08:36.76 .1.3.6.1.2.1.1.4.0 = STRING: The Owner .1.3.6.1.2.1.1.5.0 = STRING: DEVICE-192.168.1.1 .1.3.6.1.2.1.1.6.0 = STRING: TheCloud .1.3.6.1.2.1.1.7.0 = INTEGER: 72 ... $ snmpwalk -On -v2c -c private localhost:1161 1.3.6 .1.3.6.1.2.1.1.1.0 = STRING: Device description .1.3.6.1.2.1.1.2.0 = OID: .1.3.6.1.4.1.34547 .1.3.6.1.2.1.1.3.0 = Timeticks: (78171676) 9 days, 1:08:36.76 .1.3.6.1.2.1.1.4.0 = STRING: The Owner .1.3.6.1.2.1.1.5.0 = STRING: DEVICE-192.168.1.1 .1.3.6.1.2.1.1.6.0 = STRING: TheCloud .1.3.6.1.2.1.1.7.0 = INTEGER: 72 ... Obviously, *snmpwalk* output is exactly the same for different community names being used. snmpsim-0.4.5/docs/source/tips-and-tricks.rst0000664006321400632140000001361113175435562021423 0ustar ietingofietingof Tips and tricks =============== Here we have a handful of observations and advices based on user feedback and field deployment. .. _tips-multiple-instances: Multiple instances ------------------ SNMP Simulator is designed to simulate tens of thousands of SNMP Agents at once. However, it is more optimized for large number of simulated devices than to high sustainability under high load. The reason is that, internally, SNMP Simulator is a single-threaded application meaning it can only process a single request at once. On top of that, some variation modules may bring additional delay to request processing what may cause subsequent requests to build up in input queue and contribute to increasing latency. A simple receipt aimed at maximizing throughput and minimizing latency is to run multiple instances of the *snmpsimd.py* bound to distinct IP interfaces or ports what effectively makes SNMP Simulator executing multiple requests at once for as long as they are sent towards different *snmpsimd.py* instances. Here is how we invoke two *snmpsimd.py* instances at different IP interfaces serving the same set of data files: .. code-block:: bash # snmpsimd.py --agent-udpv4-endpoint=127.0.0.1 \ --agent-udpv4-endpoint=127.0.0.2 \ --transport-id-offset=1 \ --data-dir=/usr/local/share/snmpsim/data \ --cache-dir=/var/tmp/snmpsim-A/cache \ --v2c-arch \ --process-user=nobody --process-group=nogroup \ --daemonize && # snmpsimd.py --agent-udpv4-endpoint=127.0.0.3 \ --agent-udpv4-endpoint=127.0.0.4 \ --transport-id-offset=3 \ --data-dir=/usr/local/share/snmpsim/data \ --cache-dir=/var/tmp/snmpsim-B/cache \ --v2c-arch \ --process-user=nobody --process-group=nogroup \ --daemonize && Several things to note here: * The *snmpsimd.py* instances share common data directory however use their own, dedicated cache directories. * Each *snmpsimd.py* instance is listening on multiple IP interfaces (for the purpose of :ref:`address-based ` simulation) * The transport ID's are configured explicitly making the following *--data-dir* layout possible: .. code-block:: bash $ tree data data |-- public | |-- 1.3.6.1.6.1.1.1.snmprec |-- public | |-- 1.3.6.1.6.1.1.2.snmprec |-- public | |-- 1.3.6.1.6.1.1.3.snmprec |-- public |-- 1.3.6.1.6.1.1.4.snmprec The end result is that each simulated Agent is available by a dedicated IP address (represented by a transport ID) and common SNMPv1/v2c community name *public*. .. note:: To make use of IP address based Agent addressing feature the *--v2c-arch* mode is used. .. _tips-file-based-configuration: File-based configuration ------------------------ The above setup can be scaled to as many IP interfaces as you can bring up on your system. A really large number of IP interfaces might exceed the length of the command-line. In that case it's advised to use the *--args-from-file=*; option to pass local IP addresses for Simulator to listen on. .. code-block:: bash # head ips.txt --agent-udpv4-endpoint=127.0.0.1:161 --agent-udpv4-endpoint=127.0.0.2:161 --agent-udpv4-endpoint=127.0.0.3:161 ... --agent-udpv4-endpoint=127.0.1.254:161 # snmpsimd.py --args-from-file=ips.txt \ --data-dir=/usr/local/share/snmpsim/data \ --v2c-arch \ --process-user=nobody --process-group=nogroup \ --daemonize & .. note:: Other parameters can also be present in the file passed to Simulator with the *--args-from-file* option. For the :ref:`address-based ` simulation it makes to design your *--data-dir* layout matching transport ID's of the addresses listed in the *ips.txt* file as shown above. .. _tips-listing-simulated-devices: Listing simulated agents ------------------------ When simulating a large pool of devices or if your Simulator runs on a distant machine, it is convenient to have a directory of all simulated devices and their community/context names. Simulator maintains this information within its internal, dedicated SNMP context 'index': .. code-block:: bash $ snmpwalk -On -v2c -c index localhost:1161 .1.3.6 .1.3.6.1.4.1.20408.999.1.1.1 = STRING: "./data/127.0.0.1@public.snmprec" .1.3.6.1.4.1.20408.999.1.2.1 = STRING: "data/127.0.0.1@public" .1.3.6.1.4.1.20408.999.1.3.1 = STRING: "9535d96c66759362b3521f4e273fc749" or .. code-block:: bash $ snmpwalk -O n -l authPriv -u simulator -A auctoritas -X privatus -n index localhost:1161 .1.3.6 .1.3.6.1.4.1.20408.999.1.1.1 = STRING: "./data/127.0.0.1@public.snmprec" .1.3.6.1.4.1.20408.999.1.2.1 = STRING: "data/127.0.0.1@public" .1.3.6.1.4.1.20408.999.1.3.1 = STRING: "9535d96c66759362b3521f4e273fc749" Where first column holds device file path, second - community string, and third - SNMPv3 context name. .. _tips-faster-response: Faster response --------------- The SNMPv3 architecture is inherently computationally heavy what makes SNMPv3 operations slower that SNMPv1/v2c ones. The SNMP Simulator can run faster when it uses a much lighter and lower-level SNMPv1/v2c architecture at the expense of not supporting v3 operations. Use the *--v2c-arch* command line parameter to switch *snmpsimd.py* into SNMPv1/v2c operation mode. .. _tips-quick-startup: Quicker startup --------------- When Simulator runs over thousands of device files, startup may take time (tens of seconds). Most of it goes into configuring SNMPv1/v2c credentials into SNMPv3 engine so startup time can be dramatically reduced by either using *--v2c-arch* mode or by turning off SNMPv1/v2c configuration at SNMPv3 engine with *--v3-only* command-line flag. snmpsim-0.4.5/docs/source/public-snmp-agent-simulator.rst0000664006321400632140000005101613217212752023741 0ustar ietingofietingof .. _snmp-simulation-service: SNMP simulation service ======================= Free and publicly available SNMP simulation service is set up at *demo.snmplabs.com*. .. _simulated-snmp-engines: SNMP engines ------------ There are four independent SNMP engines configured at different UDP ports: +--------------------------------+-------------------+----------------+ | **SNMP Engine ID** | **Hostname** | **UDP port** | +--------------------------------+-------------------+----------------+ | 0x80004fb805636c6f75644dab22cc | demo.snmplabs.com | 161 (standard) | +--------------------------------+-------------------+----------------+ | 0x80004fb805636c6f75644dab22cd | demo.snmplabs.com | 1161 | +--------------------------------+-------------------+----------------+ | 0x80004fb805636c6f75644dab22ce | demo.snmplabs.com | 2161 | +--------------------------------+-------------------+----------------+ | 0x80004fb805636c6f75644dab22cf | demo.snmplabs.com | 3161 | +--------------------------------+-------------------+----------------+ .. note:: The simulation service is implemented by two independent UNIX processes. One process runs the first SNMP engine (*0x80004fb805636c6f75644dab22cc*) while the rest of SNMP engines in the table above are all local to the second SNMP simulator process. .. _simulated-community-names: SNMP community names -------------------- Each of the :ref:`SNMP engines ` supports a :ref:`bunch of SNMP community names ` to address distinct simulated SNMP agent. To start with, the conventional **public** and **private** SNMP community names are available as well. .. _simulated-usm-users: SNMPv3 USM users ---------------- Each :ref:`SNMP engines ` has the following USM users configured to it. We support many SNMPv3 encryption protocol combinations indexed by USM user name. +------------------------+---------------------------+----------------------+-------------------------+------------------+ | USM Security Name | Authentication protocol | Authentication key | Encryption protocol | Encryption key | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-none-none | - | - | - | - | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-md5-none | MD5 | authkey1 | - | - | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-md5-des | MD5 | authkey1 | DES | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-md5-3des | MD5 | authkey1 | Triple DES | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-md5-aes | MD5 | authkey1 | AES (128bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-md5-aes128 | MD5 | authkey1 | AES (128bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-md5-aes192 | MD5 | authkey1 | AES Reeder (192bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-md5-aes192-blmt | MD5 | authkey1 | AES Blumenthal (192bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-md5-aes256 | MD5 | authkey1 | AES Reeder (256bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-md5-aes256-blmt | MD5 | authkey1 | AES Blumenthal (256bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha-none | SHA1 (96/160bit) | authkey1 | - | - | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha-des | SHA1 (96/160bit) | authkey1 | DES | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha-3des | SHA1 (96/160bit) | authkey1 | Triple DES | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha-aes | SHA1 (96/160bit) | authkey1 | AES (128bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha-aes128 | SHA1 (96/160bit) | authkey1 | AES (128bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha-aes192 | SHA1 (96/160bit) | authkey1 | AES Reeder (192bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha-aes192-blmt | SHA1 (96/160bit) | authkey1 | AES Blumenthal (192bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha-aes256 | SHA1 (96/160bit) | authkey1 | AES Reeder (256bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha-aes256-blmt | SHA1 (96/160bit) | authkey1 | AES Blumenthal (256bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha224-none | SHA2 (128/224bit) | authkey1 | - | - | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha224-des | SHA2 (128/224bit) | authkey1 | DES | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha224-3des | SHA2 (128/224bit) | authkey1 | Triple DES | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha224-aes | SHA2 (128/224bit) | authkey1 | AES (128bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha224-aes128 | SHA2 (128/224bit) | authkey1 | AES (128bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha224-aes192 | SHA2 (128/224bit) | authkey1 | AES Reeder (192bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha224-aes192-blmt | SHA2 (128/224bit) | authkey1 | AES Blumenthal (192bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha224-aes256 | SHA2 (128/224bit) | authkey1 | AES Reeder (256bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha224-aes256-blmt | SHA2 (128/224bit) | authkey1 | AES Blumenthal (256bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha256-none | SHA2 (192/256bit) | authkey1 | - | - | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha256-des | SHA2 (192/256bit) | authkey1 | DES | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha256-3des | SHA2 (192/256bit) | authkey1 | Triple DES | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha256-aes | SHA2 (192/256bit) | authkey1 | AES (128bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha256-aes128 | SHA2 (192/256bit) | authkey1 | AES (192bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha256-aes192 | SHA2 (192/256bit) | authkey1 | AES Reeder (192bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha256-aes192-blmt | SHA2 (192/256bit) | authkey1 | AES Blumenthal (192bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha256-aes256 | SHA2 (192/256bit) | authkey1 | AES Reeder (256bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha256-aes256-blmt | SHA2 (192/256bit) | authkey1 | AES Blumenthal (256bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha384-none | SHA2 (256/384bit) | authkey1 | - | - | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha384-des | SHA2 (256/384bit) | authkey1 | DES | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha384-aes | SHA2 (256/384bit) | authkey1 | AES (128bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha384-aes128 | SHA2 (256/384bit) | authkey1 | AES (128bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha384-aes192 | SHA2 (256/384bit) | authkey1 | AES Reeder (192bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha384-aes192-blmt | SHA2 (256/384bit) | authkey1 | AES Blumenthal (192bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha384-aes256 | SHA2 (256/384bit) | authkey1 | AES Reeder (256bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha384-aes256-blmt | SHA2 (256/384bit) | authkey1 | AES Blumenthal (256bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha512-none | SHA2 (384/512bit) | authkey1 | - | - | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha512-des | SHA2 (384/512bit) | authkey1 | DES | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha512-3des | SHA2 (384/512bit) | authkey1 | Triple DES | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha512-aes | SHA2 (384/512bit) | authkey1 | AES (128bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha512-aes192 | SHA2 (384/512bit) | authkey1 | AES Reeder (192bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha512-aes192-blmt | SHA2 (384/512bit) | authkey1 | AES Blumenthal (192bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha512-aes256 | SHA2 (384/512bit) | authkey1 | AES Reeder (256bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ | usr-sha512-aes256-blmt | SHA2 (384/512bit) | authkey1 | AES Blumenthal (256bit) | privkey1 | +------------------------+---------------------------+----------------------+-------------------------+------------------+ .. note:: The *Triple DES* authentication algorithm is implemented according to `draft-reeder-snmpv3-usm-3desede-00 `_. The AES-based privacy algorithms with key size 192bit+ are implemented along the lines of `draft-blumenthal-aes-usm-04 `_) with either Reeder or Blumenthal key localization. .. _simulated-data: Simulation data --------------- Each of the :ref:`SNMP engines ` simulate multiple SNMP agents addressable by the following SNMP query parameters: +--------------------------------------------------------------------+------------------------------------+------------------------------------+ | **SNMP agent** | **SNMP community** | **SNMP context name** | +--------------------------------------------------------------------+------------------------------------+------------------------------------+ | Dynamically variated, writable SNMP Agent | public | - | +--------------------------------------------------------------------+------------------------------------+------------------------------------+ | Static snapshot of a Linux host | recorded/linux-full-walk | a172334d7d97871b72241397f713fa12 | +--------------------------------------------------------------------+------------------------------------+------------------------------------+ | Static snapshot of a Windows XP PC | foreignformats/winxp2 | da761cfc8c94d3aceef4f60f049105ba | +--------------------------------------------------------------------+------------------------------------+------------------------------------+ | Series of static snapshots of live IF-MIB::interfaces | variation/multiplex | 1016117d6836664ee15b9b2af5642c3c | +--------------------------------------------------------------------+------------------------------------+------------------------------------+ | Simulated IF-MIB::interfaces table with ever increasing counters | variation/virtualtable | 329a935947144eb87ad0cdc5e08927b1 | +--------------------------------------------------------------------+------------------------------------+------------------------------------+ TRAP sink --------- Besides simulated SNMP Agents we are also running a multilingual SNMP Notification Receiver. It will consume and optionally acknowledge SNMP TRAP/INFORM messages you might send to *demo.snmplabs.com:162*. SNMPv1/v2c community name is **public**. Configured SNMPv3 USM users and keys are :ref:`the same ` as for SNMP agents. Keep in mind that our SNMPv3 TRAP receiving service is configured for authoritative SNMP engine ID **8000000001020304**. You would have to explicitly configure it to your SNMP notification originator. Obviously, you won't get any response from your TRAP messages, however you will get an acknowledgement for the INFORM packets you send us. Examples -------- To query simulated live *IF-MIB::interfaces* over SNMPv2c use the following command: .. code-block:: bash $ snmpwalk -v2c -c variation/virtualtable demo.snmplabs.com IF-MIB::interfaces Some of the simulated objects are configured writable so you can experiment with SNMP SET: .. code-block:: bash $ snmpwalk -v2c -c public demo.snmplabs.com system ... SNMPv2-MIB::sysORDescr.1 = STRING: Please modify me SNMPv2-MIB::sysORUpTime.1 = Timeticks: (1) 0:00:00.01 $ $ snmpset -v2c -c private demo.snmplabs.com \ SNMPv2-MIB::sysORDescr.1 = 'Here is my new note' SNMPv2-MIB::sysORDescr.1 = STRING: Here is my new note $ snmpset -v2c -c private demo.snmplabs.com \ SNMPv2-MIB::sysORUpTime.1 = 321 SNMPv2-MIB::sysORUpTime.1 = Timeticks: (321) 0:00:03.21 $ snmpwalk -v2c -c public demo.snmplabs.com system ... SNMPv2-MIB::sysORDescr.1 = STRING: Here is my new note SNMPv2-MIB::sysORUpTime.1 = Timeticks: (321) 0:00:03.21 The above table is not complete, you could always figure out the most actual list of simulated SNMP Agents by fetching relevant SNMP table off the SNMP Simulator: .. code-block:: bash $ snmpwalk -v2c -c index demo.snmplabs.com 1.3.6 SNMPv2-SMI::enterprises.20408.999.1.1.1 = STRING: "/usr/snmpsim/data/1.3.6.1.6.1.1.0/127.0.0.1.snmprec" SNMPv2-SMI::enterprises.20408.999.1.1.2 = STRING: "/usr/snmpsim/data/public.snmprec" SNMPv2-SMI::enterprises.20408.999.1.1.3 = STRING: "/usr/snmpsim/data/foreignformats/winxp2.sapwalk" ... Example SNMPv3 TRAP would look like this: .. code-block:: bash $ snmptrap -v3 -l authPriv -u usr-md5-des -A authkey1 -X privkey1 \ -e 8000000001020304 demo.snmplabs.com \ 12345 1.3.6.1.4.1.20408.4.1.1.2 1.3.6.1.2.1.1.1.0 s hello Normal SNMP engine ID discovery would work for SNMP INFORMs, hence securityEngineId should not be used: .. code-block:: bash $ snmpinform -v3 -l authPriv -u usr-md5-des -A authkey1 -X privkey1 \ demo.snmplabs.com 12345 \ 1.3.6.1.4.1.20408.4.1.1.2 1.3.6.1.2.1.1.1.0 s hello Be advised that this is a free, experimental service provided as-is without any guarantees on its reliability and correctness. Its use is generally covered by SNMP Simulator :doc:`/license`. In case of any troubles or suggestions, please `open up a `_ GitHub issue. snmpsim-0.4.5/docs/source/building-simulation-data.rst0000664006321400632140000004247013175435562023302 0ustar ietingofietingof .. _building-simulation-data: Building simulation data ======================== Simulation data can be put together by :ref:`SNMP walking donor agent `, :ref:`wire-tapping SNMP traffic ` or :ref:`generating from MIBs `. Regular output from :ref:`Net-SNMP snmpwalk ` or :ref:`Agent Pro ` tools can be used as-is. Finally, *.snmprec* files can be created by hand in a text editor or automatically generated by some in-house script based on whatever data you got. Walking SNMP agent ------------------ One way to obtain simulation data is to snapshot some existing SNMP agent by running the *snmprec.py* tool against your prototype SNMP device. This tool will execute a series of SNMP GETNEXT queries for a specified range of OIDs over a chosen SNMP protocol version and store response data in a .snmprec file. .. _snmprec.py: The donor SNMP agent recording session would look like this: .. code-block:: bash $ snmprec.py --agent-udpv4-endpoint=192.168.1.1 --start-oid=1.3.6.1.2.1 \ --stop-oid=1.3.6.1.2.1.5 --output-file=snmpsim/data/recorded/linksys- \ system.snmprec Scanning "/usr/local/share/snmpsim/variation" directory for variation modules... none requested SNMP version 2c Community name: public Querying UDP/IPv4 agent at 192.168.1.1:161 Sending initial GETNEXT request.... OIDs dumped: 304, elapsed: 1.94 sec, rate: 157.00 OIDs/sec $ $ ls -l data/recorded/linksys-system.snmprec -rw-r--r-- 1 root users 16252 Oct 26 14:49 data/recorded/linksys-system.snmprec $ $ head data/recorded/linksys-system.snmprec 1.3.6.1.2.1.1.1.0|4|BEFSX41 1.3.6.1.2.1.1.2.0|6|1.3.6.1.4.1.3955.1.1 1.3.6.1.2.1.1.3.0|67|638239 1.3.6.1.2.1.1.4.0|4|Linksys 1.3.6.1.2.1.1.5.0|4|isp-gw 1.3.6.1.2.1.1.6.0|4|4, Petersburger strasse, Berlin, Germany 1.3.6.1.2.1.1.8.0|67|4 The *snmprec.py* tool can run over SNMPv1, v2c and v3. To configure SNMPv3 USM user authentication and privacy algorithms, :ref:`follow the instructions ` for *snmpsimd.py*. No special requirements exist for device file name and location. Just keep in mind that at simulation time, *snmpsimd.py* treats *.snmprec* file path as SNMPv1/v2c community name or SNMPv3 context name. If you don't readily have some SNMP agent to play with, you're welcome to use our publicly available :ref:`SNMP Simulator instance `. .. code-block:: bash $ snmprec.py --agent-udpv4-endpoint=demo.snmplabs.com --community=public SNMP version 2c, Community name: public Querying UDP/IPv4 agent at 195.218.195.228:161 Sending initial GETNEXT request.... 1.3.6.1.2.1.1.1.0|4|SunOS zeus.snmplabs.com 4.1.3_U1 1 sun4m 1.3.6.1.2.1.1.2.0|6|1.3.6.1.4.1.20408 1.3.6.1.2.1.1.3.0|67|137765775 1.3.6.1.2.1.1.4.0|4|SNMP Laboratories, info@snmplabs.com 1.3.6.1.2.1.1.5.0|4|zeus.snmplabs.com 1.3.6.1.2.1.1.6.0|4|San Francisco, California, United States ... 1.3.6.1.2.1.11.31.0|65|0 1.3.6.1.2.1.11.32.0|65|0 OIDs dumped: 86, elapsed: 2.00 sec, rate: 42.00 OIDs/sec .. note:: For better performance, consider using *GETBULK* SNMP command by passing *--use-getbulk* option to the *snmprec.py* tool. Faster recording may deliver more consistent SNMP objects state. Since *.snmprec* is a plain text file, you can always edit it in your text editor. For mass changes consider using the :ref:`datafile.py` tool. .. _mib2dev.py: MIB-based synthesis ------------------- The other way to produce simulation data is to run the *mib2dev.py* tool against virtually any MIB file. With that method you do not have to have a donor device and the values, that would otherwise be reported by the donor SNMP agent, will instead be chosen randomly. Keep in mind that you may run into either of two issues with these randomly chosen values: * Some MIB data suggest certain correlation between formally unrelated pieces of information. Such relationships may be described informally, e.g. in natural language in the Description field. The automated values generation procedure has no chance to assure proper correlations, in that case the overall snapshot may appear inconsistent. * Some data types specified in the MIB may impose certain restrictions on the type instance values. For example an integer-typed Managed Object may be allowed to be either 0 or 12. If a guessed value turns out to be 2, it will be incompatible with this type. While it is possible to introspect type objects and generate a compliant value, the *mib2dev.py* tool does not do that [yet]. A non-compliant value will result an exception on MIB node instantiation. In that case the *mib2dev.py* tool will revert to an interactive mode and ask you for a compliant value. * When building snapshots from MIBs you are not simulating the actual values the SNMP agent is reporting. With MIB-based simulation you can basically simulate the collection of OIDs, not the dependencies between them or their interplay. On the bright side, the *mib2dev.py* tool will respect Managed Object type (e.g type associated with the OIDs), and produce valid indices for the MIB tables. Examples ++++++++ Here we produce simulation data for a portion of OID space of SNMPv2-MIB: .. code-block:: bash $ mib2dev.py --mib-module=SNMPv2-MIB --start-oid=1.3.6.1.2.1.1.1 \ --stop-oid=1.3.6.1.2.1.1.8 # MIB module: SNMPv2-MIB 1.3.6.1.2.1.1.1.0|4|Portez ce vieux 1.3.6.1.2.1.1.2.0|6|1.3.6.1.3.39.232.14.10.84.109.1 1.3.6.1.2.1.1.3.0|67|350728093 1.3.6.1.2.1.1.4.0|4|whisky 1.3.6.1.2.1.1.5.0|4| 1.3.6.1.2.1.1.6.0|4|whisky au juge blond 1.3.6.1.2.1.1.7.0|2|4 1.3.6.1.2.1.1.8.0|67|3138976393 # End of SNMPv2-MIB, 8 OID(s) dumped The *mib2dev.py* tool can also generate values for SNMP conceptual tables. It's doing that by iterating over table definition in MIB for specified number of times. The following command will analyze given MIB and produce two rows for the *IF-MIB::ifTable* table: .. code-block:: bash $ mib2dev.py --mib-module=IF-MIB --start-oid=1.3.6.1.2.1.2.2 \ --stop-oid=1.3.6.1.2.1.2.3 --table-size=2 # MIB module: IF-MIB # Starting table IF-MIB::ifTable (1.3.6.1.2.1.2.2) # Synthesizing row #1 of table 1.3.6.1.2.1.2.2.1 # Finished table 1.3.6.1.2.1.2.2.1 (2 rows) 1.3.6.1.2.1.2.2.1.1.12|2|12 1.3.6.1.2.1.2.2.1.1.26|2|26 1.3.6.1.2.1.2.2.1.2.12|4|vieux whisky 1.3.6.1.2.1.2.2.1.2.26|4|ce vieux whisky au juge 1.3.6.1.2.1.2.2.1.3.12|2|29 1.3.6.1.2.1.2.2.1.3.26|2|1 1.3.6.1.2.1.2.2.1.4.12|2|28 1.3.6.1.2.1.2.2.1.4.26|2|16 1.3.6.1.2.1.2.2.1.5.12|66|3029607807 1.3.6.1.2.1.2.2.1.5.26|66|3150811331 1.3.6.1.2.1.2.2.1.6.12|4| 1.3.6.1.2.1.2.2.1.6.26|4| 1.3.6.1.2.1.2.2.1.7.12|2|1 1.3.6.1.2.1.2.2.1.7.26|2|1 1.3.6.1.2.1.2.2.1.8.12|2|6 1.3.6.1.2.1.2.2.1.8.26|2|5 1.3.6.1.2.1.2.2.1.9.12|67|2871454194 1.3.6.1.2.1.2.2.1.9.26|67|496156868 1.3.6.1.2.1.2.2.1.10.12|65|1488410552 1.3.6.1.2.1.2.2.1.10.26|65|3473823260 1.3.6.1.2.1.2.2.1.11.12|65|1727276906 1.3.6.1.2.1.2.2.1.11.26|65|342963679 1.3.6.1.2.1.2.2.1.12.12|65|1511248359 1.3.6.1.2.1.2.2.1.12.26|65|2207653511 1.3.6.1.2.1.2.2.1.13.12|65|4226165132 1.3.6.1.2.1.2.2.1.13.26|65|36536957 1.3.6.1.2.1.2.2.1.14.12|65|130591184 1.3.6.1.2.1.2.2.1.14.26|65|1852726355 1.3.6.1.2.1.2.2.1.15.12|65|3301920138 1.3.6.1.2.1.2.2.1.15.26|65|470729731 1.3.6.1.2.1.2.2.1.16.12|65|4148984503 1.3.6.1.2.1.2.2.1.16.26|65|953020685 1.3.6.1.2.1.2.2.1.17.12|65|1569764479 1.3.6.1.2.1.2.2.1.17.26|65|2095562772 1.3.6.1.2.1.2.2.1.18.12|65|238446444 1.3.6.1.2.1.2.2.1.18.26|65|3268308217 1.3.6.1.2.1.2.2.1.19.12|65|3230500934 1.3.6.1.2.1.2.2.1.19.26|65|566234076 1.3.6.1.2.1.2.2.1.20.12|65|3549197996 1.3.6.1.2.1.2.2.1.20.26|65|2834484035 1.3.6.1.2.1.2.2.1.21.12|66|68812076 1.3.6.1.2.1.2.2.1.21.26|66|1903146216 1.3.6.1.2.1.2.2.1.22.12|6|1.3.6.1.3 1.3.6.1.2.1.2.2.1.22.26|6|1.3.6.1.3.231.101.247.88 # End of IF-MIB, 44 OID(s) dumped The range of values for automatic and random selection can be controlled on a per-type basis with the *--counter-range*, *--counter64-range*, *--gauge-range*, *--timeticks-range*, *--unsigned-range*, *--integer32-range* options. Words for strings generations can be passed via *--string-pool* option. .. code-block:: bash $ mib2dev.py --mib-module=UDP-MIB --table-size=1 --counter-range=0,100 \ --unsigned-range=100,200 # MIB module: UDP-MIB # Starting table UDP-MIB::udpTable (1.3.6.1.2.1.7.5) # Finished table 1.3.6.1.2.1.7.5.1 (1 rows) # Starting table UDP-MIB::udpEndpointTable (1.3.6.1.2.1.7.7) # Finished table 1.3.6.1.2.1.7.7.1 (1 rows) 1.3.6.1.2.1.7.1.0|65|66 1.3.6.1.2.1.7.2.0|65|49 1.3.6.1.2.1.7.3.0|65|91 1.3.6.1.2.1.7.4.0|65|14 1.3.6.1.2.1.7.5.1.1.169.148.104.225.14|64x|a99468e1 1.3.6.1.2.1.7.5.1.2.169.148.104.225.14|2|14 1.3.6.1.2.1.7.7.1.1.4.0.127.2.0.137.182|2|4 1.3.6.1.2.1.7.7.1.2.4.0.127.2.0.137.182|4| 1.3.6.1.2.1.7.7.1.3.4.0.127.2.0.137.182|66|127 1.3.6.1.2.1.7.7.1.4.4.0.127.2.0.137.182|2|2 1.3.6.1.2.1.7.7.1.5.4.0.127.2.0.137.182|4| 1.3.6.1.2.1.7.7.1.6.4.0.127.2.0.137.182|66|137 1.3.6.1.2.1.7.7.1.7.4.0.127.2.0.137.182|66|182 1.3.6.1.2.1.7.7.1.8.4.0.127.2.0.137.182|66|185 1.3.6.1.2.1.7.8.0|70|9808059939656837207 1.3.6.1.2.1.7.9.0|70|10931009272993024622 # End of UDP-MIB, 16 OID(s) dumped If you wish to specify each value rather then rely on automatic random selection, use *--manual-value* command line switch. If you would rather have *mib2dev.py* tool to work out all the values by itself, consider raising the *--automatic-values* max probes value (default is 5000 probes). .. _pcap2dev.py: Snooping SNMP traffic --------------------- SNMP traffic traveling in a network can also be a source of simulation data. The *pcap2dev.py* tool can snoop live or process captured traffic finding SNMP Response messages there and using OID-value pairs for building *.snmprec* files. Since many SNMP agents can generate traffic over network within the a snooping sessions, the *pcap2dev.py* tool is designed to classify captured SNMP traffic on the per-Agent basis and build dedicated data file for each Agent seen on the network. The *--output-dir=* command-line option specifies a directory where *pcap2dev.py* tool would put generated data files into. Data files paths are crafted so that Simulator would act closer to the prototype Agents meaning: 1. Data files for each Agent is put under a separate directory resembling Simulator's transport IDs which correspond to UDP ports Simulator is listening on. 2. Original SNMPv1/v2c community names are preserved. Imagine we have two SNMP Agents (192.168.1.1 & 192.168.1.2) sending responses over a network we are snooping on. Here's a tcpdump report just to illustrate the idea: .. code-block:: bash # tcpdump -i lo listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytes 20:05:20.799706 IP 192.168.1.9.55803 > 192.168.1.1.snmp: GetRequest(28) system .sysDescr.0 20:05:20.800027 IP 192.168.1.1.snmp > 192.168.1.9.55803: GetResponse(92) system.sysDescr.0="Linux jupiter 2.6.37.6-smp #2 SMP Fri May 17 22:03:50 CDT 2013 i686" 20:05:21.125421 IP 192.168.1.9.55803 > 192.168.1.2.snmp: GetRequest(28) system.sysDescr.0 20:05:21.924022 IP 192.168.1.2.snmp > 192.168.1.9.55803: GetResponse(92) system.sysDescr.0="Linux saturn 2.6.37.4-smp #2 SMP Fri May 10 21:31:32 CDT 2013 i686" The *pcap2dev* tool would create two directories with fixed prefix (1.3.6.1.6.1.1) and increasing suffix parts (0 & 1) to put generated data files for each Agent there. That is, all data files for Agent 192.168.1.1 would go under 1.3.6.1.6.1.1.0/ while data files for Agent 192.168.1.2 would end up in 1.3.6.1.6.1.1.1/. Snooped SNMP communities also take part in data file path creation -- they appear as a last component of the path. For example, if Agent 192.168.1.1 used SNMP communities 'wallace' and 'gromit' (on different occasions) and Agent 192.168.1.2 responded with community 'cheese', generated data files would look like this: .. code-block:: bash $ tree /tmp/recording /tmp/recording |--- 1.3.6.1.6.1.1.0 | | | ---- gromit.snmprec | | | ---- wallace.snmprec | |--- 1.3.6.1.6.1.1.1 | ---- cheese.snmprec To build data files from a network capture file, use *--capture-file=* command-line option. Capture file format should be either `pcap or pcap-ng `_. Most capturing tools (like `tcpdump `_) support these file formats. You could also use `tcpdump filter `_ as a parameter to *--packet-filter=* option to narrow packets selection criteria. Default packet filter is *udp and src port 161*. Examples ++++++++ With all that theory in mind, we can now run a live snooping session: .. code-block:: bash # pcap2dev.py --output-dir=/tmp/recording --listen-interface=lo Listening on interface lo in non-promiscuous mode Applying packet filter "udp and src port 161" Listening on interface "lo", kill me when you are done. ^C Shutting down process... Creating simulation context 1.3.6.1.6.1.1.0/gromit at /tmp/recording/1.3.6.1.6.1.1.0/gromit.snmprec Creating simulation context 1.3.6.1.6.1.1.0/wallace at /tmp/recording/1.3.6.1.6.1.1.0/wallace.snmprec Creating simulation context 1.3.6.1.6.1.1.1/cheese at /tmp/recording/1.3.6.1.6.1.1.1/cheese.snmprec PCap statistics: packets snooped: 64 packets dropped: 24 packets dropped: by interface 0 SNMP statistics: empty packets: 0 OIDs seen: 19 UDP packets: 19 Response PDUs seen: 19 contexts seen: 3 SNMP exceptions: 0 SNMP errors: 0 snapshots taken: 0 agents seen: 2 unknown L2 protocol: 0 IP packets: 19 bad packets: 0 Here's one of data files produced: .. code-block:: bash $ cat /tmp/recording/1.3.6.1.6.1.1.0/gromit.snmprec 1.3.6.1.2.1.1.1.0|4|Linux jupiter 2.6.37.6-smp #2 SMP Fri May 17 22:03:50 CDT 2013 i686 1.3.6.1.2.1.1.2.0|6|1.3.6.1.4.1.8072.3.2.10 1.3.6.1.2.1.1.3.0|67|311441639 1.3.6.1.2.1.1.4.0|4|postmaster@jupiter 1.3.6.1.2.1.1.5.0|4|jupiter 1.3.6.1.2.1.1.6.0|4|Jupiter 1.3.6.1.2.1.1.8.0|67|1 You can now move data files into your Simulator's data directory and fire up simulation. The *pcap2dev.py* tool can also invoke :ref:`variation modules ` to feed recorded data through them. .. _snmpwalk-dump: Using snmpwalk reporting ------------------------ In some cases you may not be able to run :ref:`snmprec.py ` against a donor device. That can happen, for instance, if you can't setup *snmprec.py* on a system from where donor device is available or donor device is gone leaving you with just Net-SNMP's *snmpwalk* dumps someone have collected for you. Simulator provides limited support for snmpwalk-generated data files. Just save *snmpwalk* output into a file with *.snmpwalk* suffix and put it under the *--data-dir*. Once Simulator finds and indexes the *.snmpwalk* files, it will report them just as it does for its native *.snmprec* files. .. code-block:: bash $ snmpwalk -v2c -c public -ObentU localhost 1.3.6 > myagent.snmpwalk .. note:: Make sure you get *snmpwalk* producing plain OIDs and values! By default snmpwalk tries to beautify raw data from Agent with MIB information. As beautified data may not contain OIDs and numeric values, it could not be interpreted by the Simulator. Therefore always run *snmpwalk* with the "-ObentU" options. The *.snmpwalk* lines that can't be parsed by the Simulator will be skipped and details reported to stdout for your further consideration. In particular, current implementation does not cope well with multi-line strings sometimes produced by the *snmpwalk* tool. Alternatively, you can convert the *.snmpwalk* files into *.snmprec* ones by running them through the :ref:`datafile.py ` tool. .. _agent-pro-dump: Using Simple Agent Pro samples ------------------------------ Another possible format for taking and storing SNMP snapshots is SimpleSoft `Simple Agent Pro `_ data files. Although we have neither seen any documentation on its data files format nor ever owned or used Simple Agent Pro software, a sample data file `published on the Internet `_ reveals that SimpleAgentPro's file format is very similar to Net-SNMP's snmpwalk. It essentially looks like *snmpwalk* output with different field separators. .. note:: SNMP Simulator might not support certain features/dialects of SimpleAgentPro data files format so your mileage may vary. In case you store your SNMP snapshots archives in SimpleAgentPro's data files and wish to use them with this Simulator, just put your SimpleAgentPro-formatted SNMP snapshot information (excluding comments) into text files having *.sapwalk* suffix and let Simulator find and index them. Once completed, Simulator will report access information for them just as it does for its native *.snmprec* files. Alternatively, you can convert the *.sapwalk* files into *.snmprec* ones by running them through the :ref:`datafile.py ` tool. snmpsim-0.4.5/docs/source/quickstart.rst0000664006321400632140000000656613175435562020614 0ustar ietingofietingof Quick start =========== .. toctree:: :maxdepth: 2 Installation ------------ SNMP Simulator is written in Python and depends on other Python libraries. The easiest way to deploy SNMP Simulator is by downloading it from PyPI: .. code-block:: bash $ virtualenv venv $ source venv/bin/activate $ pip install snmpsim Run the simulator ----------------- Once installed, invoke *snmpsimd.py* daemon and point it to a directory containing simulation data: .. code-block:: bash $ snmpsimd.py --data-dir=./data --agent-udpv4-endpoint=127.0.0.1:1024 Test the setup -------------- Now you can query simulated agent(s) with Net-SNMP's command-line tools which are usually shipped along with your operating system: .. code-block:: bash $ snmpwalk -v2c -c public 127.0.0.1:1024 system SNMPv2-MIB::sysDescr.0 = STRING: Linux zeus 4.8.6.5-smp #2 SMP Sun Nov 13 14:58:11 CDT 2016 i686 SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10 DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (126714301) 14 days, 15:59:03.01 SNMPv2-MIB::sysContact.0 = STRING: SNMP Laboratories, info@snmplabs.com SNMPv2-MIB::sysName.0 = STRING: new system name SNMPv2-MIB::sysLocation.0 = STRING: San Francisco, California, United States SNMPv2-MIB::sysServices.0 = INTEGER: 72 SNMPv2-MIB::sysORLastChange.0 = Timeticks: (126714455) 14 days, 15:59:04.55 Simulation data for each simulated SNMP agent is stored in simple plain-text file. Each line in represents a single SNMP object in form of pipe-separated fields *OID|TYPE|VALUE*. .. code-block:: bash $ cat ./data/public.snmprec 1.3.6.1.2.1.1.1.0|4|Linux 2.6.25.5-smp SMP Tue Jun 19 14:58:11 CDT 2007 i686 1.3.6.1.2.1.1.2.0|6|1.3.6.1.4.1.8072.3.2.10 1.3.6.1.2.1.1.3.0|67|233425120 1.3.6.1.2.1.2.2.1.6.2|4x|00127962f940 1.3.6.1.2.1.4.22.1.3.2.192.21.54.7|64x|c3dafe61 ... Simulator uses the parameters (such as SNMP community name or SNMPv3 context or IP address) of SNMP query to choose .snmprec file to respond with. Simulate existing SNMP agent ---------------------------- Besides creating simulation data by hand, you can generate it from some existing SNMP agent. Here we use publicly available SNMP Simulator instance as a donor device: .. code-block:: bash $ snmprec.py --agent-udpv4-endpoint=demo.snmplabs.com --output-file=./data/public.snmprec SNMP version 2c, Community name: public Querying UDP/IPv4 agent at 195.218.195.228:161 Agent response timeout: 3.00 secs, retries: 3 Sending initial GETNEXT request for 1.3.6 (stop at ).... OIDs dumped: 182, elapsed: 11.97 sec, rate: 7.00 OIDs/sec, errors: 0 Simulate from MIB ----------------- Alternatively, you could build simulation data from a MIB file: .. code-block:: bash $ mib2dev.py --output-file=./data/public.snmprec --mib-module=IF-MIB # MIB module: IF-MIB, from the beginning till the end # Starting table IF-MIB::ifTable (1.3.6.1.2.1.2.2) # Synthesizing row #1 of table 1.3.6.1.2.1.2.2.1 ... # Finished table 1.3.6.1.2.1.2.2.1 (10 rows) # End of IF-MIB, 177 OID(s) dumped You can even sniff network traffic on the wire recovering SNMP messages there and building simulation data from it. Besides static files, SNMP simulator can be configured to call its plugin modules for simulation data. We ship plugins to interface SQL and noSQL databases, file-based key-value stores and other sources of information. snmpsim-0.4.5/docs/source/development.rst0000664006321400632140000000357113175435562020735 0ustar ietingofietingof Future features =============== We are thinking of further SNMP Simulator development in these particular areas: * Re-work data files indices implementation to allow unordered OIDs and better performance on GETNEXT/GETBULK operations. * Let variation modules configuring custom SNMPv1/v2c community names and SNMPv3 context names. That would be the alternative way to address simulation data. * Simulating SNMP table: while the latest Simulator release supports writable OIDs and SQL backend (which also allows for writable OIDs with potentially complex logic triggered by their access), we think a lightweight variation module readily implementing a RowStatus-driven SNMP table would also be handy. Users of that module would invoke it from their *.snmprec* file for an OID subtree serving their SNMP table. The module would accept basic configuration parameters such as: table columns OIDs and types, valid index ranges, default initialization parameters. * Allow rendering simulation data from a `template `_ based on user-supplied variables possibly taken from SNMP query, process and host contexts. * SNMP Notifications: current implementation can fully simulate SNMP Command Generator operations. It would be nice to be able to record SNMP Notifications coming from live SNMP Agents, store and replay them at configured rate and possibly modified (variated) values. * Implement REST API to *snmpsimd.py* to let user record and replay snapshots through a web browser or in-house automation scripts. * Composable devices: the idea is to be able to compose simulated device from specific MIBs the device implements. If you need one of these or some other feature - please open a `feature request `_ at GitHub or e-mail directly to *etingof@gmail.com* to discuss contractual work possibilities. snmpsim-0.4.5/docs/source/conf.py0000664006321400632140000001350413412164152017141 0ustar ietingofietingof#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # SNMP Simulator documentation build configuration file, created by # sphinx-quickstart on Mon Oct 23 17:36:06 2017. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ['sphinx.ext.viewcode'] # Add any paths that contain templates here, relative to this directory. templates_path = ['.templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The master toctree document. master_doc = 'contents' # General information about the project. project = 'SNMP Simulator' copyright = '2010-2019, Ilya Etingof' author = 'Ilya Etingof' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '0.4' # The full version, including alpha/beta/rc tags. release = '0.4' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path exclude_patterns = [] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'alabaster' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = { 'logo': 'logo.svg', 'description': '

Brewing free software for the greater good

', 'show_powered_by': False, 'github_user': 'etingof', 'github_repo': 'snmpsim', 'fixed_sidebar': True, } html_sidebars = { '**': [ 'about.html', 'navigation.html', 'relations.html', 'searchbox.html', 'donate.html', ] } # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. html_favicon = '.static/favicon.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['.static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # This is required for the alabaster theme # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars # html_sidebars = { # '**': [ # 'relations.html', # needs 'show_related': True theme option to display # 'searchbox.html', # ] # } # If true, links to the reST sources are added to the pages. html_show_sourcelink = False # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. html_show_sphinx = False # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. htmlhelp_basename = 'SNMPSimulatordoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'SNMPSimulator.tex', 'SNMP Simulator Documentation', 'Ilya Etingof', 'manual'), ] # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'snmpsimulator', 'SNMP Simulator Documentation', [author], 1) ] # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'SNMPSimulator', 'SNMP Simulator Documentation', author, 'SNMPSimulator', 'One line description of project.', 'Miscellaneous'), ] snmpsim-0.4.5/docs/source/changelog.rst0000664006321400632140000000006513175435562020335 0ustar ietingofietingof Changelog ========= .. include:: ../../CHANGES.txt snmpsim-0.4.5/requirements.txt0000664006321400632140000000002513345010600016661 0ustar ietingofietingofpysnmp>=4.4.3,<5.0.0 snmpsim-0.4.5/LICENSE.txt0000664006321400632140000000246613412164152015242 0ustar ietingofietingofCopyright (c) 2010-2019, Ilya Etingof All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. snmpsim-0.4.5/runtests.sh0000775006321400632140000000037313051053434015637 0ustar ietingofietingof#!/usr/bin/env bash set -e python scripts/snmprec.py --agent-udpv4-endpoint=demo.snmplabs.com # this fails with new pysnmp's TEXTUAL-CONVENTION parser # python scripts/mib2dev.py --mib-module=IF-MIB python scripts/mib2dev.py --mib-module=SNMPv2-MIB snmpsim-0.4.5/snmpsim.egg-info/0000775006321400632140000000000013412164240016565 5ustar ietingofietingofsnmpsim-0.4.5/snmpsim.egg-info/SOURCES.txt0000664006321400632140000000663113412164240020457 0ustar ietingofietingofCHANGES.txt LICENSE.txt MANIFEST.in README.md THANKS.txt TODO.txt devel-requirements.txt requirements.txt runtests.sh setup.cfg setup.py data/README.txt data/bgp.snmprec data/cisco_16_switch.snmprec data/hp_perf.snmprec data/hp_perf2.snmprec data/public.snmprec data/1.3.6.1.6.1.1.0/127.0.0.1.snmprec data/1.3.6.1.6.1.1.0/README-v2c.txt data/1.3.6.1.6.1.1.0/README-v3.txt data/foreignformats/README.txt data/foreignformats/linux.snmpwalk data/foreignformats/winxp1.snmpwalk data/foreignformats/winxp2.sapwalk data/mib2dev/host-resources-mib.snmprec data/mib2dev/ip-mib.snmprec data/mib2dev/tcp-mib.snmprec data/mib2dev/udp-mib.snmprec data/public/1.3.6.1.2.1.100.1.13.0.snmprec data/public/README-v2c.txt data/public/README-v3.txt data/public/1.3.6.1.2.1.100.1.2.0/README-v2c.txt data/public/1.3.6.1.2.1.100.1.2.0/README-v3.txt data/public/1.3.6.1.2.1.100.1.2.0/__1.snmprec data/public/1.3.6.1.6.1.1.0/127.0.0.1.snmprec data/public/1.3.6.1.6.1.1.0/README-v2c.txt data/public/1.3.6.1.6.1.1.0/README-v3.txt data/recorded/linksys-system.snmprec data/recorded/linux-full-walk.snmprec data/recorded/solaris-system.snmprec data/recorded/udp-endpoint-table-walk.snmprec data/recorded/winxp-full-walk.snmprec data/variation/README.txt data/variation/delay.snmprec data/variation/error.snmprec data/variation/multiplex.snmprec data/variation/notification.snmprec data/variation/sql.snmprec data/variation/subprocess.snmprec data/variation/virtualtable.snmprec data/variation/writecache.snmprec data/variation/multiplex/00000.snmprec data/variation/multiplex/00001.snmprec data/variation/multiplex/00002.snmprec data/variation/multiplex/00003.snmprec data/variation/multiplex/00004.snmprec data/variation/multiplex/00005.snmprec data/variation/multiplex/00006.snmprec data/variation/multiplex/00007.snmprec data/variation/multiplex/00008.snmprec data/variation/multiplex/00009.snmprec data/variation/multiplex/00010.snmprec data/variation/multiplex/README.txt docs/source/addressing-agents.rst docs/source/building-simulation-data.rst docs/source/changelog.rst docs/source/conf.py docs/source/contents.rst docs/source/development.rst docs/source/license.rst docs/source/managing-simulation-data.rst docs/source/public-snmp-agent-simulator.rst docs/source/quickstart.rst docs/source/recording-with-variation-modules.rst docs/source/simulating-agents.rst docs/source/simulation-with-variation-modules.rst docs/source/tips-and-tricks.rst docs/source/.static/logo.svg scripts/datafile.py scripts/mib2dev.py scripts/pcap2dev.py scripts/snmprec.py scripts/snmpsimd.py snmpsim/__init__.py snmpsim/confdir.py snmpsim/daemon.py snmpsim/error.py snmpsim/log.py snmpsim/mltsplit.py snmpsim.egg-info/PKG-INFO snmpsim.egg-info/SOURCES.txt snmpsim.egg-info/dependency_links.txt snmpsim.egg-info/not-zip-safe snmpsim.egg-info/requires.txt snmpsim.egg-info/top_level.txt snmpsim/grammar/__init__.py snmpsim/grammar/abstract.py snmpsim/grammar/dump.py snmpsim/grammar/mvc.py snmpsim/grammar/sap.py snmpsim/grammar/snmprec.py snmpsim/grammar/walk.py snmpsim/record/__init__.py snmpsim/record/abstract.py snmpsim/record/dump.py snmpsim/record/mvc.py snmpsim/record/sap.py snmpsim/record/snmprec.py snmpsim/record/walk.py snmpsim/record/search/__init__.py snmpsim/record/search/database.py snmpsim/record/search/file.py variation/delay.py variation/error.py variation/multiplex.py variation/notification.py variation/numeric.py variation/redis.py variation/sql.py variation/subprocess.py variation/writecache.pysnmpsim-0.4.5/snmpsim.egg-info/not-zip-safe0000664006321400632140000000000113075632035021022 0ustar ietingofietingof snmpsim-0.4.5/snmpsim.egg-info/top_level.txt0000664006321400632140000000001013412164237021314 0ustar ietingofietingofsnmpsim snmpsim-0.4.5/snmpsim.egg-info/PKG-INFO0000664006321400632140000000326113412164237017672 0ustar ietingofietingofMetadata-Version: 1.0 Name: snmpsim Version: 0.4.5 Summary: SNMP Agents simulator Home-page: https://github.com/etingof/snmpsim Author: Ilya Etingof Author-email: etingof@gmail.com License: BSD Description: SNMP Simulator is a tool that acts as multitude of SNMP Agents built into real physical devices, from SNMP Manager's point of view. Simulator builds and uses a database of physical devices' SNMP footprints to respond like their original counterparts do. Platform: any Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Education Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: Intended Audience :: Telecommunications Industry Classifier: License :: OSI Approved :: BSD License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.4 Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Topic :: Communications Classifier: Topic :: System :: Monitoring Classifier: Topic :: System :: Networking :: Monitoring snmpsim-0.4.5/snmpsim.egg-info/dependency_links.txt0000664006321400632140000000000113412164237022641 0ustar ietingofietingof snmpsim-0.4.5/snmpsim.egg-info/requires.txt0000664006321400632140000000002513412164237021170 0ustar ietingofietingofpysnmp>=4.4.3,<5.0.0 snmpsim-0.4.5/variation/0000775006321400632140000000000013412164240015401 5ustar ietingofietingofsnmpsim-0.4.5/variation/delay.py0000664006321400632140000001330213412164152017052 0ustar ietingofietingof# # This file is part of snmpsim software. # # Copyright (c) 2010-2019, Ilya Etingof # License: http://snmplabs.com/snmpsim/license.html # import time import random from snmpsim.grammar.snmprec import SnmprecGrammar from snmpsim.record.snmprec import SnmprecRecord from snmpsim.mltsplit import split from snmpsim import log from snmpsim import error def init(**context): random.seed() def variate(oid, tag, value, **context): if not context['nextFlag'] and not context['exactMatch']: return context['origOid'], tag, context['errorStatus'] if 'settings' not in recordContext: recordContext['settings'] = dict([split(x, '=') for x in split(value, ',')]) if 'hexvalue' in recordContext['settings']: recordContext['settings']['value'] = [int(recordContext['settings']['hexvalue'][x:x + 2], 16) for x in range(0, len(recordContext['settings']['hexvalue']), 2)] if 'wait' in recordContext['settings']: recordContext['settings']['wait'] = float(recordContext['settings']['wait']) else: recordContext['settings']['wait'] = 500.0 if 'deviation' in recordContext['settings']: recordContext['settings']['deviation'] = float(recordContext['settings']['deviation']) else: recordContext['settings']['deviation'] = 0.0 if 'vlist' in recordContext['settings']: vlist = {} recordContext['settings']['vlist'] = split(recordContext['settings']['vlist'], ':') while recordContext['settings']['vlist']: o, v, d = recordContext['settings']['vlist'][:3] recordContext['settings']['vlist'] = recordContext['settings']['vlist'][3:] d = int(d) typeTag, _ = SnmprecRecord.unpackTag(tag) v = SnmprecGrammar.tagMap[typeTag](v) if o not in vlist: vlist[o] = {} if o == 'eq': vlist[o][v] = d elif o in ('lt', 'gt'): vlist[o] = v, d else: log.msg('delay: bad vlist syntax: %s' % recordContext['settings']['vlist']) recordContext['settings']['vlist'] = vlist if 'tlist' in recordContext['settings']: tlist = {} recordContext['settings']['tlist'] = split(recordContext['settings']['tlist'], ':') while recordContext['settings']['tlist']: o, v, d = recordContext['settings']['tlist'][:3] recordContext['settings']['tlist'] = recordContext['settings']['tlist'][3:] v = int(v) d = int(d) if o not in tlist: tlist[o] = {} if o == 'eq': tlist[o][v] = d elif o in ('lt', 'gt'): tlist[o] = v, d else: log.msg('delay: bad tlist syntax: %s' % recordContext['settings']['tlist']) recordContext['settings']['tlist'] = tlist if context['setFlag'] and 'vlist' in recordContext['settings']: if ('eq' in recordContext['settings']['vlist'] and context['origValue'] in recordContext['settings']['vlist']['eq']): delay = recordContext['settings']['vlist']['eq'][context['origValue']] elif ('lt' in recordContext['settings']['vlist'] and context['origValue'] < recordContext['settings']['vlist']['lt'][0]): delay = recordContext['settings']['vlist']['lt'][1] elif ('gt' in recordContext['settings']['vlist'] and context['origValue'] > recordContext['settings']['vlist']['gt'][0]): delay = recordContext['settings']['vlist']['gt'][1] else: delay = recordContext['settings']['wait'] elif 'tlist' in recordContext['settings']: now = int(time.time()) if ('eq' in recordContext['settings']['tlist'] and now == recordContext['settings']['tlist']['eq']): delay = recordContext['settings']['tlist']['eq'][now] elif ('lt' in recordContext['settings']['tlist'] and now < recordContext['settings']['tlist']['lt'][0]): delay = recordContext['settings']['tlist']['lt'][1] elif ('gt' in recordContext['settings']['tlist'] and now > recordContext['settings']['tlist']['gt'][0]): delay = recordContext['settings']['tlist']['gt'][1] else: delay = recordContext['settings']['wait'] else: delay = recordContext['settings']['wait'] if recordContext['settings']['deviation']: delay += random.randrange( -recordContext['settings']['deviation'], recordContext['settings']['deviation'] ) if delay < 0: delay = 0 elif delay > 99999: log.msg('delay: dropping response for %s' % oid) raise error.NoDataNotification() log.msg('delay: waiting %d milliseconds for %s' % (delay, oid)) time.sleep(delay / 1000) # ms if context['setFlag'] or 'value' not in recordContext['settings']: return oid, tag, context['origValue'] else: return oid, tag, recordContext['settings']['value'] def record(oid, tag, value, **context): if context['stopFlag']: raise error.NoDataNotification() tag += ':delay' if 'hexvalue' in context: textValue = 'hexvalue=' + context['hexvalue'] else: textValue = 'value=' + value textValue += ',wait=%d' % int((time.time() - context['reqTime']) * 1000) # ms if 'options' in context: textValue += ',' + context['options'] return oid, tag, textValue def shutdown(**context): pass snmpsim-0.4.5/variation/error.py0000664006321400632140000001032213412164152017104 0ustar ietingofietingof# # This file is part of snmpsim software. # # Copyright (c) 2010-2019, Ilya Etingof # License: http://snmplabs.com/snmpsim/license.html # from snmpsim.grammar.snmprec import SnmprecGrammar from snmpsim.record.snmprec import SnmprecRecord from snmpsim import log from snmpsim.mltsplit import split from pysnmp.smi import error errorTypes = { 'generror': error.GenError, 'noaccess': error.NoAccessError, 'wrongtype': error.WrongTypeError, 'wrongvalue': error.WrongValueError, 'nocreation': error.NoCreationError, 'inconsistentvalue': error.InconsistentValueError, 'resourceunavailable': error.ResourceUnavailableError, 'commitfailed': error.CommitFailedError, 'undofailed': error.UndoFailedError, 'authorizationerror': error.AuthorizationError, 'notwritable': error.NotWritableError, 'inconsistentname': error.InconsistentNameError, 'nosuchobject': error.NoSuchObjectError, 'nosuchinstance': error.NoSuchInstanceError, 'endofmib': error.EndOfMibViewError } def init(**context): pass def variate(oid, tag, value, **context): if not context['nextFlag'] and not context['exactMatch']: return context['origOid'], tag, context['errorStatus'] if 'settings' not in recordContext: recordContext['settings'] = dict([split(x, '=') for x in split(value, ',')]) if 'hexvalue' in recordContext['settings']: recordContext['settings']['value'] = [int(recordContext['settings']['hexvalue'][x:x + 2], 16) for x in range(0, len(recordContext['settings']['hexvalue']), 2)] if 'status' in recordContext['settings']: recordContext['settings']['status'] = recordContext['settings']['status'].lower() if 'op' not in recordContext['settings']: recordContext['settings']['op'] = 'any' if 'vlist' in recordContext['settings']: vlist = {} recordContext['settings']['vlist'] = split(recordContext['settings']['vlist'], ':') while recordContext['settings']['vlist']: o, v, e = recordContext['settings']['vlist'][:3] recordContext['settings']['vlist'] = recordContext['settings']['vlist'][3:] typeTag, _ = SnmprecRecord.unpackTag(tag) v = SnmprecGrammar.tagMap[typeTag](v) if o not in vlist: vlist[o] = {} if o == 'eq': vlist[o][v] = e elif o in ('lt', 'gt'): vlist[o] = v, e else: log.msg('error: bad vlist syntax: %s' % recordContext['settings']['vlist']) recordContext['settings']['vlist'] = vlist e = None if context['setFlag']: if 'vlist' in recordContext['settings']: if ('eq' in recordContext['settings']['vlist'] and context['origValue'] in recordContext['settings']['vlist']['eq']): e = recordContext['settings']['vlist']['eq'][context['origValue']] elif ('lt' in recordContext['settings']['vlist'] and context['origValue'] < recordContext['settings']['vlist']['lt'][0]): e = recordContext['settings']['vlist']['lt'][1] elif ('gt' in recordContext['settings']['vlist'] and context['origValue'] > recordContext['settings']['vlist']['gt'][0]): e = recordContext['settings']['vlist']['gt'][1] elif recordContext['settings']['op'] in ('set', 'any'): if 'status' in recordContext['settings']: e = recordContext['settings']['status'] else: if recordContext['settings']['op'] in ('get', 'any'): if 'status' in recordContext['settings']: e = recordContext['settings']['status'] if e and e in errorTypes: log.msg('error: reporting %s for %s' % (e, oid)) raise errorTypes[e]( name=oid, idx=max(0, context['varsTotal'] - context['varsRemaining'] - 1) ) if context['setFlag']: recordContext['settings']['value'] = context['origValue'] return oid, tag, recordContext['settings'].get('value', context['errorStatus']) def shutdown(**context): pass snmpsim-0.4.5/variation/notification.py0000664006321400632140000002170113412164152020444 0ustar ietingofietingof# # This file is part of snmpsim software. # # Copyright (c) 2010-2019, Ilya Etingof # License: http://snmplabs.com/snmpsim/license.html # # Managed value variation module # Send SNMP Notification # from pysnmp.hlapi.asyncore import * from snmpsim.grammar.snmprec import SnmprecGrammar from snmpsim.record.snmprec import SnmprecRecord from snmpsim.mltsplit import split from snmpsim import error, log def init(**context): pass typeMap = { 's': OctetString, 'h': lambda x: OctetString(hexValue=x), 'i': Integer32, 'o': ObjectIdentifier, 'a': IpAddress, 'u': Unsigned32, 'g': Gauge32, 't': TimeTicks, 'b': Bits, 'I': Counter64 } def _cbFun(sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): oid, value = cbCtx if errorIndication or errorStatus: log.msg('notification: for %s=%r failed with errorIndication %s, errorStatus %s' % (oid, value, errorIndication, errorStatus)) def variate(oid, tag, value, **context): if 'snmpEngine' in context and context['snmpEngine']: snmpEngine = context['snmpEngine'] if snmpEngine not in moduleContext: moduleContext[snmpEngine] = {} if context['transportDomain'] not in moduleContext[snmpEngine]: # register this SNMP Engine to handle our transports' # receiver IDs (which we build by outbound and simulator # transportDomains concatenation) snmpEngine.registerTransportDispatcher( snmpEngine.transportDispatcher, UdpTransportTarget.transportDomain + context['transportDomain'] ) snmpEngine.registerTransportDispatcher( snmpEngine.transportDispatcher, Udp6TransportTarget.transportDomain + context['transportDomain'] ) moduleContext[snmpEngine][context['transportDomain']] = 1 else: raise error.SnmpsimError('variation module not given snmpEngine') if not context['nextFlag'] and not context['exactMatch']: return context['origOid'], tag, context['errorStatus'] if 'settings' not in recordContext: recordContext['settings'] = dict([split(x, '=') for x in split(value, ',')]) for k, v in (('op', 'set'), ('community', 'public'), ('authkey', None), ('authproto', 'md5'), ('privkey', None), ('privproto', 'des'), ('proto', 'udp'), ('port', '162'), ('ntftype', 'trap'), ('trapoid', '1.3.6.1.6.3.1.1.5.1')): recordContext['settings'].setdefault(k, v) if 'hexvalue' in recordContext['settings']: recordContext['settings']['value'] = [int(recordContext['settings']['hexvalue'][x:x + 2], 16) for x in range(0, len(recordContext['settings']['hexvalue']), 2)] if 'vlist' in recordContext['settings']: vlist = {} recordContext['settings']['vlist'] = split(recordContext['settings']['vlist'], ':') while recordContext['settings']['vlist']: o, v = recordContext['settings']['vlist'][:2] recordContext['settings']['vlist'] = recordContext['settings']['vlist'][2:] typeTag, _ = SnmprecRecord.unpackTag(tag) v = SnmprecGrammar.tagMap[typeTag](v) if o not in vlist: vlist[o] = set() if o == 'eq': vlist[o].add(v) elif o in ('lt', 'gt'): vlist[o] = v else: log.msg('notification: bad vlist syntax: %s' % recordContext['settings']['vlist']) recordContext['settings']['vlist'] = vlist args = recordContext['settings'] if context['setFlag'] and 'vlist' in args: if ('eq' in args['vlist'] and context['origValue'] in args['vlist']['eq']): pass elif ('lt' in args['vlist'] and context['origValue'] < args['vlist']['lt']): pass elif ('gt' in args['vlist'] and context['origValue'] > args['vlist']['gt']): pass else: return oid, tag, context['origValue'] if args['op'] not in ('get', 'set', 'any', '*'): log.msg('notification: unknown SNMP request type configured: %s' % args['op']) return context['origOid'], tag, context['errorStatus'] if (args['op'] == 'get' and not context['setFlag'] or args['op'] == 'set' and context['setFlag'] or args['op'] in ('any', '*')): if args['version'] in ('1', '2c'): authData = CommunityData(args['community'], mpModel=args['version'] == '2c' and 1 or 0) elif args['version'] == '3': if args['authproto'] == 'md5': authProtocol = usmHMACMD5AuthProtocol elif args['authproto'] == 'sha': authProtocol = usmHMACSHAAuthProtocol elif args['authproto'] == 'none': authProtocol = usmNoAuthProtocol else: log.msg('notification: unknown auth proto %s' % args['authproto']) return context['origOid'], tag, context['errorStatus'] if args['privproto'] == 'des': privProtocol = usmDESPrivProtocol elif args['privproto'] == 'aes': privProtocol = usmAesCfb128Protocol elif args['privproto'] == 'none': privProtocol = usmNoPrivProtocol else: log.msg('notification: unknown privacy proto %s' % args['privproto']) return context['origOid'], tag, context['errorStatus'] authData = UsmUserData(args['user'], args['authkey'], args['privkey'], authProtocol=authProtocol, privProtocol=privProtocol) else: log.msg('notification: unknown SNMP version %s' % args['version']) return context['origOid'], tag, context['errorStatus'] if 'host' not in args: log.msg('notification: target hostname not configured for OID %s' % (oid,)) return context['origOid'], tag, context['errorStatus'] if args['proto'] == 'udp': target = UdpTransportTarget((args['host'], int(args['port']))) elif args['proto'] == 'udp6': target = Udp6TransportTarget((args['host'], int(args['port']))) else: log.msg('notification: unknown transport %s' % args['proto']) return context['origOid'], tag, context['errorStatus'] localAddress = None if 'bindaddr' in args: localAddress = args['bindaddr'] else: if context['transportDomain'][:len(target.transportDomain)] == target.transportDomain: localAddress = snmpEngine.transportDispatcher.getTransport(context['transportDomain']).getLocalAddress()[0] else: log.msg('notification: incompatible network transport types used by CommandResponder vs NotificationOriginator') if 'bindaddr' in args: localAddress = args['bindaddr'] if localAddress: log.msg('notification: binding to local address %s' % localAddress) target.setLocalAddress((localAddress, 0)) # this will make target objects different based on their bind address target.transportDomain = target.transportDomain + context['transportDomain'] varBinds = [] if 'uptime' in args: varBinds.append( (ObjectIdentifier('1.3.6.1.2.1.1.3.0'), TimeTicks(args['uptime'])) ) if args['version'] == '1': if 'agentaddress' in args: varBinds.append( (ObjectIdentifier('1.3.6.1.6.3.18.1.3.0'), IpAddress(args['agentaddress'])) ) if 'enterprise' in args: varBinds.append( (ObjectIdentifier('1.3.6.1.6.3.1.1.4.3.0'), ObjectIdentifier(args['enterprise'])) ) if 'varbinds' in args: vbs = split(args['varbinds'], ':') while vbs: varBinds.append( (ObjectIdentifier(vbs[0]), typeMap[vbs[1]](vbs[2])) ) vbs = vbs[3:] sendNotification( snmpEngine, authData, target, ContextData(), args['ntftype'], NotificationType(ObjectIdentity(args['trapoid'])).addVarBinds(*varBinds), cbFun=_cbFun, cbCtx=(oid, value) ) log.msg('notification: sending Notification to %s with credentials %s' % (authData, target)) if context['setFlag'] or 'value' not in args: return oid, tag, context['origValue'] else: return oid, tag, args['value'] def shutdown(**context): pass snmpsim-0.4.5/variation/subprocess.py0000664006321400632140000000635213412164152020153 0ustar ietingofietingof# # This file is part of snmpsim software. # # Copyright (c) 2010-2019, Ilya Etingof # License: http://snmplabs.com/snmpsim/license.html # # Managed value variation module # Get/set managed value by invoking an external program # import sys import subprocess from pysnmp.proto import rfc1902 from snmpsim.mltsplit import split from snmpsim import log def init(**context): moduleContext['settings'] = {} if context['options']: moduleContext['settings'].update( dict([split(x, ':') for x in split(context['options'], ',')]) ) if 'shell' not in moduleContext['settings']: moduleContext['settings']['shell'] = sys.platform[:3] == 'win' else: moduleContext['settings']['shell'] = int(moduleContext['settings']['shell']) def variate(oid, tag, value, **context): # in --v2c-arch some of the items are not defined transportDomain = transportAddress = securityModel = securityName = \ securityLevel = contextName = '' if 'transportDomain' in context: transportDomain = rfc1902.ObjectName(context['transportDomain']).prettyPrint() if 'transportAddress' in context: transportAddress = ':'.join([str(x) for x in context['transportAddress']]) if 'securityModel' in context: securityModel = str(context['securityModel']) if 'securityName' in context: securityName = str(context['securityName']) if 'securityLevel' in context: securityLevel = str(context['securityLevel']) if 'contextName' in context: contextName = str(context['contextName']) args = [(x .replace('@TRANSPORTDOMAIN@', transportDomain) .replace('@TRANSPORTADDRESS@', transportAddress) .replace('@SECURITYMODEL@', securityModel) .replace('@SECURITYNAME@', securityName) .replace('@SECURITYLEVEL@', securityLevel) .replace('@CONTEXTNAME@', contextName) .replace('@DATAFILE@', context['dataFile']) .replace('@OID@', str(oid)) .replace('@TAG@', tag) .replace('@ORIGOID@', str(context['origOid'])) .replace('@ORIGTAG@', str(sum([x for x in context['origValue'].tagSet[0]]))) .replace('@ORIGVALUE@', str(context['origValue'])) .replace('@SETFLAG@', str(int(context['setFlag']))) .replace('@NEXTFLAG@', str(int(context['nextFlag']))) .replace('@SUBTREEFLAG@', str(int(context['subtreeFlag'])))) for x in split(value, ' ')] log.msg('subprocess: executing external process "%s"' % ' '.join(args)) call = (hasattr(subprocess, 'check_output') and subprocess.check_output or hasattr(subprocess, 'check_call') and subprocess.check_call or subprocess.call) if not hasattr(subprocess, 'check_output'): log.msg('subprocess: old Python, expect no output!') try: return oid, tag, call( args, shell=moduleContext['settings']['shell'] ) except (hasattr(subprocess, 'CalledProcessError') and subprocess.CalledProcessError or Exception): log.msg('subprocess: external program execution failed') return context['origOid'], tag, context['errorStatus'] def shutdown(**context): pass snmpsim-0.4.5/variation/multiplex.py0000664006321400632140000002233013412164152020000 0ustar ietingofietingof# # This file is part of snmpsim software. # # Copyright (c) 2010-2019, Ilya Etingof # License: http://snmplabs.com/snmpsim/license.html # # Managed value variation module: simulate a live Agent using # a series of snapshots. # import os import time import bisect from pyasn1.compat.octets import str2octs from pysnmp.proto import rfc1902 from snmpsim.record.snmprec import SnmprecRecord from snmpsim.record.search.file import searchRecordByOid, getRecord from snmpsim.record.search.database import RecordIndex from snmpsim import confdir from snmpsim.mltsplit import split from snmpsim import log from snmpsim import error def init(**context): if context['options']: for k, v in [split(x, ':') for x in split(context['options'], ',')]: if k == 'addon': if k in moduleContext: moduleContext[k].append(v) else: moduleContext[k] = [v] else: moduleContext[k] = v if context['mode'] == 'variating': moduleContext['booted'] = time.time() elif context['mode'] == 'recording': if 'dir' not in moduleContext: raise error.SnmpsimError('SNMP snapshots directory not specified') if not os.path.exists(moduleContext['dir']): log.msg('multiplex: creating %s...' % moduleContext['dir']) os.makedirs(moduleContext['dir']) if 'iterations' in moduleContext: moduleContext['iterations'] = max(0, int(moduleContext['iterations']) - 1) if 'period' in moduleContext: moduleContext['period'] = float(moduleContext['period']) else: moduleContext['period'] = 10.0 moduleContext['ready'] = True def variate(oid, tag, value, **context): if 'settings' not in recordContext: recordContext['settings'] = dict([split(x, '=') for x in split(value, ',')]) if 'dir' not in recordContext['settings']: log.msg('multiplex: snapshot directory not specified') return context['origOid'], tag, context['errorStatus'] recordContext['settings']['dir'] = recordContext['settings']['dir'].replace( '/', os.path.sep ) if recordContext['settings']['dir'][0] != os.path.sep: for x in confdir.data: d = os.path.join(x, recordContext['settings']['dir']) if os.path.exists(d): break else: log.msg('multiplex: directory %s not found' % recordContext['settings']['dir']) return context['origOid'], tag, context['errorStatus'] else: d = recordContext['settings']['dir'] recordContext['dirmap'] = dict( [(int(os.path.basename(x).split(os.path.extsep)[0]), os.path.join(d, x)) for x in os.listdir(d) if x[-7:] == 'snmprec'] ) recordContext['keys'] = list( recordContext['dirmap'].keys() ) recordContext['bounds'] = ( min(recordContext['keys']), max(recordContext['keys']) ) if 'period' in recordContext['settings']: recordContext['settings']['period'] = float(recordContext['settings']['period']) else: recordContext['settings']['period'] = 60.0 if 'wrap' in recordContext['settings']: recordContext['settings']['wrap'] = bool(recordContext['settings']['wrap']) else: recordContext['settings']['wrap'] = False if 'control' in recordContext['settings']: recordContext['settings']['control'] = rfc1902.ObjectName( recordContext['settings']['control'] ) log.msg('multiplex: using control OID %s for subtree %s, time-based multiplexing disabled' % (recordContext['settings']['control'], oid)) recordContext['ready'] = True if 'ready' not in recordContext: return context['origOid'], tag, context['errorStatus'] if oid not in moduleContext: moduleContext[oid] = {} if context['setFlag']: if 'control' in recordContext['settings'] and \ recordContext['settings']['control'] == context['origOid']: fileno = int(context['origValue']) if fileno >= len(recordContext['keys']): log.msg('multiplex: .snmprec file number %s over limit of %s' % (fileno, len(recordContext['keys']))) return context['origOid'], tag, context['errorStatus'] moduleContext[oid]['fileno'] = fileno log.msg('multiplex: switched to file #%s (%s)' % (recordContext['keys'][fileno], recordContext['dirmap'][recordContext['keys'][fileno]])) return context['origOid'], tag, context['origValue'] else: return context['origOid'], tag, context['errorStatus'] if 'control' in recordContext['settings']: if 'fileno' not in moduleContext[oid]: moduleContext[oid]['fileno'] = 0 if (not context['nextFlag'] and recordContext['settings']['control'] == context['origOid']): return context['origOid'], tag, rfc1902.Integer32(moduleContext[oid]['fileno']) else: timeslot = (time.time() - moduleContext['booted']) % ( recordContext['settings']['period'] * len(recordContext['dirmap'])) fileslot = int(timeslot / recordContext['settings']['period']) + recordContext['bounds'][0] fileno = bisect.bisect(recordContext['keys'], fileslot) - 1 if ('fileno' not in moduleContext[oid] or moduleContext[oid]['fileno'] < fileno or recordContext['settings']['wrap']): moduleContext[oid]['fileno'] = fileno datafile = recordContext['dirmap'][ recordContext['keys'][moduleContext[oid]['fileno']] ] if ('datafile' not in moduleContext[oid] or moduleContext[oid]['datafile'] != datafile): if 'datafileobj' in moduleContext[oid]: moduleContext[oid]['datafileobj'].close() moduleContext[oid]['datafileobj'] = RecordIndex( datafile, SnmprecRecord() ).create() moduleContext[oid]['datafile'] = datafile log.msg('multiplex: switching to data file %s for %s' % (datafile, context['origOid'])) text, db = moduleContext[oid]['datafileobj'].getHandles() textOid = str(rfc1902.OctetString('.'.join(['%s' % x for x in context['origOid']]))) try: line = moduleContext[oid]['datafileobj'].lookup(textOid) except KeyError: offset = searchRecordByOid(context['origOid'], text, SnmprecRecord()) exactMatch = False else: offset, subtreeFlag, prevOffset = line.split(str2octs(',')) exactMatch = True text.seek(int(offset)) line, _, _ = getRecord(text) # matched line if context['nextFlag']: if exactMatch: line, _, _ = getRecord(text) else: if not exactMatch: return context['origOid'], tag, context['errorStatus'] if not line: return context['origOid'], tag, context['errorStatus'] try: oid, value = SnmprecRecord().evaluate(line) except error.SnmpsimError: oid, value = context['origOid'], context['errorStatus'] return oid, tag, value def record(oid, tag, value, **context): if 'ready' not in moduleContext: raise error.SnmpsimError('module not initialized') if 'started' not in moduleContext: moduleContext['started'] = time.time() if context['stopFlag']: if 'file' in moduleContext: moduleContext['file'].close() del moduleContext['file'] else: moduleContext['filenum'] = 0 if 'iterations' in moduleContext and moduleContext['iterations']: log.msg('multiplex: %s iterations remaining' % moduleContext['iterations']) moduleContext['started'] = time.time() moduleContext['iterations'] -= 1 moduleContext['filenum'] += 1 wait = max(0, moduleContext['period'] - (time.time() - moduleContext['started'])) raise error.MoreDataNotification(period=wait) else: raise error.NoDataNotification() if 'file' not in moduleContext: if 'filenum' not in moduleContext: moduleContext['filenum'] = 0 snmprecfile = os.path.join(moduleContext['dir'], '%.5d%ssnmprec' % (moduleContext['filenum'], os.path.extsep)) moduleContext['file'] = open(snmprecfile, 'wb') log.msg('multiplex: writing into %s file...' % snmprecfile) moduleContext['file'].write( SnmprecRecord().format(context['origOid'], context['origValue']) ) if not context['total']: settings = { 'dir': moduleContext['dir'].replace(os.path.sep, '/') } if 'period' in moduleContext: settings['period'] = '%.2f' % float(moduleContext['period']) if 'addon' in moduleContext: settings.update( dict([split(x, '=') for x in moduleContext['addon']]) ) value = ','.join(['%s=%s' % (k, v) for k, v in settings.items()]) return str(context['startOID']), ':multiplex', value else: raise error.NoDataNotification() def shutdown(**context): pass snmpsim-0.4.5/variation/numeric.py0000664006321400632140000002137713412164152017431 0ustar ietingofietingof# # This file is part of snmpsim software. # # Copyright (c) 2010-2019, Ilya Etingof # License: http://snmplabs.com/snmpsim/license.html # # Managed value variation module # Simulate a numeric value # Valid values in module options are: # 2 - Integer # 65 - Counter32 # 66 - Gauge32 # 67 - TimeTicks # 70 - Counter64 import math import time import random from pysnmp.proto import rfc1902 from snmpsim.mltsplit import split from snmpsim import log from snmpsim import error tboot = time.time() def init(**context): if context['mode'] == 'variating': random.seed() if context['mode'] == 'recording': moduleContext['settings'] = {} if context['options']: for k, v in [split(x, ':') for x in split(context['options'], ',')]: if k == 'addon': if k in moduleContext['settings']: moduleContext['settings'][k].append(v) else: moduleContext['settings'][k] = [v] else: moduleContext['settings'][k] = v if 'iterations' in moduleContext['settings']: moduleContext['settings']['iterations'] = int(moduleContext['settings']['iterations']) if moduleContext['settings']['iterations']: moduleContext['settings']['iterations'] = 1 # no reason for more if 'period' in moduleContext['settings']: moduleContext['settings']['period'] = float(moduleContext['settings']['period']) else: moduleContext['settings']['period'] = 10.0 if 'taglist' not in moduleContext['settings']: moduleContext['settings']['taglist'] = '2-65-66-67-70' def variate(oid, tag, value, **context): if not context['nextFlag'] and not context['exactMatch']: return context['origOid'], tag, context['errorStatus'] if context['setFlag']: return context['origOid'], tag, context['errorStatus'] if 'settings' not in recordContext: recordContext['settings'] = dict([split(x, '=') for x in split(value, ',')]) for k in recordContext['settings']: if k != 'function': recordContext['settings'][k] = float(recordContext['settings'][k]) if 'min' not in recordContext['settings']: recordContext['settings']['min'] = 0 if 'max' not in recordContext['settings']: if tag == '70': recordContext['settings']['max'] = 0xffffffffffffffff else: recordContext['settings']['max'] = 0xffffffff if 'rate' not in recordContext['settings']: recordContext['settings']['rate'] = 1 if 'function' in recordContext['settings']: f = split(recordContext['settings']['function'], '%') recordContext['settings']['function'] = getattr(math, f[0]), f[1:] else: recordContext['settings']['function'] = lambda x: x, () vold, told = recordContext['settings'].get('initial', recordContext['settings']['min']), tboot if 'cumulative' in recordContext['settings']: if 'value' not in recordContext: recordContext['value'] = vold, told vold, told = recordContext['value'] tnow = time.time() if 'atime' in recordContext['settings']: t = tnow else: t = tnow - tboot f, args = recordContext['settings']['function'] _args = [] if args: for x in args: if x == '