Home

Awesome

OIDrage

A lightweight SNMPv2c server for testing purposes. Sends mimic responses of test data based on any snmpwalk output. Designed to scale.

OIDrage Logo

About OIDrage

A lightweight SNMPv2c setup to mimic an entire MIB tree of datapoints. Can be easily spawned over and over to replicate thousands of live machines. Use as a standalone python script, or deploy as a container.

Project page at GitHub

dockerhub using oidrage:latest

This software is designed to be raw, quick, and not feature-bloated. It can mimic existing snmp mibs for load testing and metrics-gathering-platforms evaluation.
For example, a real cacti installation or a cli snmp transaction against multiple auto-discoverable targets.

No library dependencies. It is stand-alone and requires Python 3.3+ for IP address module support. The usual PySNMP libraries is not required, in fact, there is no requirements.txt. This is built from scratch to assemble packets from bytecode.

The input file is a valid snmpwalk output (numerical).
Either provide your own mimic.txt using "snmpwalk -v2c -c public -On 127.0.0.1 .1 > mimic.txt", or just use the default provided.

By default, any community string will work. Alternatively, one can be set and will be required.

<a href="https://www.buymeacoffee.com/pbest"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=pbest&button_colour=40DCA5&font_colour=ffffff&font_family=Cookie&outline_colour=000000&coffee_colour=FFDD00" /></a>

How to Run

A number of ways to use and scale.

  1. Python

Download the source code and run manually from the command line, any OS:

python3 ./OIDrage.py --help
  1. DockerHub

Call the oidrage:latest image to use the latest docker image at DockerHub:

docker run --name OIDrageTEST --env COMMUNITY=private -p 5005:161 oidrage:latest  

Options

By default, no options are required, optional configurations are as below.

OIDrage can be configured via the command line (priority), or by environment variables.

Command Line

For complete features, run "python3 OIDrage.py -h"

usage: OIDrage.py [-h] [-f INPUTFILE] [-i IPADDRESS] [-p PORT] [-d DELAY]
                  [-c COMMUNITY] [-D DEBUG]

OIDrage SNMPd Mimic Server by Patrick Scott Best

optional arguments:
  -h, --help            show this help message and exit
  -f INPUTFILE, --inputfile INPUTFILE
                        Input file. [mimic.txt]
  -i IPADDRESS, --ipaddress IPADDRESS
                        IP Address. [127.0.0.1]
  -p PORT, --port PORT  UDP port number to bind to. [161]
  -d DELAY, --delay DELAY
                        Response delay, in milliseconds. [0]
  -c COMMUNITY, --community COMMUNITY
                        Require a specific community string from client. [*]
  -D DEBUG, --debug DEBUG
                        Debug

Environment Variables

Makes this suitable for containerisation.

Implementation

Create a mimic tree using an snmpwalk or use the included default (a linux system) Python script can run on a singular host, default binding to 127.0.0.1 on standard port 161. Values returned are static. A python script designed to make use of raw UDP port message and answer .

Updates

Future

Contributing

I would love you to contribute to OIDrage, pull requests are welcome!

Besides feature coding, I could also use a hand with our SNMPwalk collection.

We are always happy to see examples of SNMPwalk outputs from various devices:

Notes

Web Resources

OID Types found in RFC 1902

Curses upon you, ITU-T X.690 ANS.1 (Abstract Syntax Notation 1) BER (Basic Encoding Rules) at ITU

Python Argparse Tutorial by Sam Starkman's Medium and Toward Data Science Argparse syntax python docs Argparse tutorial python docs

Getbulk explanations at net-snmp and web-nms

Setting Environment variables in vscode with a great stackoverflow response VS Code python environments overview visual studio VS Code suppress certain PEP8 warnings stackoverflow response

Best description of OPAQUE Float values stackoverflow response

Encoding Notes

SNMP message encoding requires the use of maths in 3 circumstances

Understanding the OID node values encoding took a lot of investigation.
OIDs are variable-length and there is a flag and mathematical formula used to calculate them as the OID OBJECT_NAME is examined.

Not only are the OID nodes themselves encoded with variable length, but the placeholders/positions in the bytes response for "bytes to follow" (eg, bytes length) also need to be accomodated with the same encoding scheme.

I've also discovered that OID values that are Integer32 have some kind of unique calculation performed. 0xFF is -1 in decimal. 0x0400 is 1024decimal. 0x01 is 1 decimal.

Opaque type OID values are typically IEEE 754 32-bit floats. It was really hard to find a standalone example of conversion.

OID implementation

Great breakdowns and images of actual byte sequences. https://www.ranecommercial.com/legacy/note161.html

https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-object-identifier?redirectedfrom=MSDN

More on Variable Length Quantity (ASN.1 encoding) https://stackoverflow.com/questions/5929050/how-does-asn-1-encode-an-object-identifier

There's a myriad of ways to calculate, but my first real clue was found in the wireshark codebase Found in https://github.com/wireshark/wireshark/blob/master/epan/oids.c#L1115

	if (subid <= 0x0000007F) {
		bytelen += 1;
	} else if (subid <= 0x00003FFF ) {
		bytelen += 2;
	} else if (subid <= 0x001FFFFF ) {
		bytelen += 3;
	} else if (subid <= 0x0FFFFFFF ) {
		bytelen += 4;
	} else {
		bytelen += 5;
	}
}
	switch(len) {
		default: *bytes_p=NULL; return 0;
		case 5: *(b++) = ((subid & 0xF0000000) >> 28) | 0x80;
		/* FALL THROUGH */
		case 4: *(b++) = ((subid & 0x0FE00000) >> 21) | 0x80;
		/* FALL THROUGH */
		case 3: *(b++) = ((subid & 0x001FC000) >> 14) | 0x80;
		/* FALL THROUGH */
		case 2: *(b++) = ((subid & 0x00003F80) >> 7)  | 0x80;
		/* FALL THROUGH */
		case 1: *(b++) =   subid & 0x0000007F ; break;