Raddle SNMP Agent Emulator

The Net::Raddle::SNMPAgent package provides complete control over the data returned by an SNMP agent. This is useful when building emulated networks for testing network management packages or teaching people to use them.

In its simplest form, Raddle will replay static data captured from a real SNMP agent (e.g. using the snmpwalk command).

More advanced usage includes adding interfaces and entries in various tables, to build up a complex emulated device.

Prerequisites

Raddle requires net-snmp version 5.0.8 or later, built with the Perl module enabled. If using 5.0.8, a patch must be applied to the source code first.

The Perl modules Digest::MD5 and Carp are also required.

Example

To emulate a router called r1 using an snmpwalk output file in /usr/local/etc/snmp-emulator/r1.snmp, put this in /usr/local/etc/snmp-emulator/r1.pl:

        use Net::Raddle::SNMPAgent;
        my $agent = Net::Raddle::SNMPAgent->new() or die "Could not initialise Raddle";
        $agent->ParseDataFile( '/usr/local/etc/snmp-emulator/r1.snmp', 0 );

This is the config file /usr/local/etc/snmp-emulator/r1.conf:

        # Listen on port 9501
        agentaddress    udp:localhost:9501,tcp:localhost:9501
        # Access control
        com2sec notConfigUser  default       public
        group   notConfigGroup v1            notConfigUser
        group   notConfigGroup v2c           notConfigUser
        view    iso included .iso
        access  notConfigGroup "" any noauth exact iso none none
        # Emulator script
        perl do "/usr/local/etc/snmp-emulator/r1.pl"

It is wise to test the emulator script before trying to run it with snmpd, as the daemon seems to hide certain types of error report. Do something like this:

        perl -w /usr/local/etc/snmp-emulator/r1.pl

Start snmpd like this:

        snmpd -C -I vacm_vars -c /usr/local/etc/snmp-emulator/r1.conf

SNMPD will now respond on localhost:9501 using data from the r1.snmp file.

Generating data files

Use snmpwalk or snmpbulkwalk:

       snmpwalk -v 1 -c <community> -OneU <device>

It is OK to miss the 'n' option from -O if you prefer to use symbolic names

Error Handling

Parameter errors and other serious problems are signalled using confess from the Carp module. This in turn calls die

Setup Procedures

Net::Raddle::SNMPAgent->new(params)
Initialises the SNMP emulation and links it to the main SNMP agent.

params is a key-value list, which can specify:

        debugging => 0,         # higher number for more debugging
        subagent => 0,          # Should this be an AgentX subagent?

If $subagent is true, register as an AgentX subagent. If $subagent is false (e.g. zero), run as part of the main agent process.

e.g.:

        my $agent = Net::Raddle::SNMPAgent->new( debugging => 1 );

$agent->AgentXMainLoop()
If running as an AgentX subagent, this procedure must be called after all other setup is complete. AgentXMainLoop only returns if the process receives an INT or QUIT signal.

$agent->ParseDataFile($filename,$CompatKludges)
Read in SNMP OID = Value pairs from a file. Use this to load boiler-plate MIB items.

If $CompatKludges is true, tries to parse output from earlier versions of Net-SNMP and UCD-SNMP. This is not completely successful, as the output formats are ambiguous. It is strongly suggested that $CompatKludges should be zero.

$agent->version
Returns the version number of the Net::Raddle::SNMPAgent module

Utility Procedures

NOTE these are not exported by default. You should either import them explicitly with:

        use Net::Raddle::SNMPAgent qw(IPToMAC Netmask CanonicalOID);

or you should refer to them using the package name, e.g.:

        my $mask = Net::Raddle::SNMPAgent::Netmask(27);
CanonicalOID($oid)
Returns canonical text string form of an OID. e.g.:
        my $oidstr = CanonicalOID( 'IF-MIB::ifNumber.0' );

Canonical OIDs have the form: '.1.3.6.1.2.1.1.3.0'

Returns undef if the OID cannot be processed.

IPToMAC($prefix,$IP)
Invent a likely MAC address from an IP address and a 2-octet prefix. e.g.:
        my $MACaddr = IPToMac( '00:30', '10.3.76.45' );

This allows the ARP tables of different devices to be set up with consistent data without having to hand-configure the mappings.

Netmask($length)
Convert netmask length to dotted-quad form, e.g.:
        my $mask = Netmask(24);
        # $mask is now '255.255.255.0'

Procedures acting on individual MIB items

$agent->TieMIBItem($canonicaloid,$type,$classname,$classparam)
Ties a MIB item to a class, creating the item if necessary. The MIB item to be tied is specified as a canonical OID and an SNMP data type. e.g.:
        $agent->TieMIBItem( CanonicalOID('SNMPv2-MIB::sysUpTime.0'), ASN_TIMETICKS,
                "TicksSince", Mktime( 2002, 9, 24, 3, 59, 14) );

Available data types are:

        ASN_OBJECT_ID   An OID - must be in canonical form.
        ASN_OCTET_STR   Octet string. Can be text or binary.
        ASN_INTEGER     32-bit integer.
        ASN_TIMETICKS   Time ticks (units of 0.01s)
        ASN_GAUGE       32-bit non-wrapping integer.
        ASN_IPADDRESS   An IP address in the form 10.3.27.200
        ASN_COUNTER     32-bit counter.
        ASN_COUNTER64   64-bit counter (not yet working properly).

$agent->SetMIBValue($canonicaloid,$type,$initialvalue)
Sets the value of a MIB item, creating the item if it does not already exist. e.g.:
        SetMIBValue( '.1.3.6.1.2.1.1.5.0', ASN_OCTET_STR, 'router.example.org' )

$agent->GetMIBValue($canonicaloid,$type,$initialvalue)
Gets the value of a MIB item.

Returns a hash of the form:

        { type => DATATYPE, value => VALUE }

Returns undef if the item is not defined.

already exist. e.g.:

        my %mibitem = $agent->GetMIBValue( '.1.3.6.1.2.1.1.5.0' );

Procedures working on higher-level objects

$agent->AddIF($datahash)
Add an interface, with data as specified in $datahash e.g.:
        $IFIndex = $agent->AddIF( { ifType => 'csmacd', ifSpeed => 10000000 } );

The complete list of values that can be specified is the ifTable:

        ifIndex                 InterfaceIndex,
        ifDescr                 DisplayString,
        ifType                  IANAifType,
        ifMtu                   Integer32,
        ifSpeed                 Gauge32,
        ifPhysAddress           PhysAddress,
        ifAdminStatus           INTEGER,
        ifOperStatus            INTEGER,
        ifLastChange            TimeTicks,
        ifInOctets              Counter32,
        ifInUcastPkts           Counter32,
        ifInNUcastPkts          Counter32,  -- deprecated
        ifInDiscards            Counter32,
        ifInErrors              Counter32,
        ifInUnknownProtos       Counter32,
        ifOutOctets             Counter32,
        ifOutUcastPkts          Counter32,
        ifOutNUcastPkts         Counter32,  -- deprecated
        ifOutDiscards           Counter32,
        ifOutErrors             Counter32,
        ifOutQLen               Gauge32,    -- deprecated
        ifSpecific              OBJECT IDENTIFIER -- deprecated

These items from ifXTable may also be specified:

        ifName                  DisplayString,
        ifInMulticastPkts       Counter32,
        ifInBroadcastPkts       Counter32,
        ifOutMulticastPkts      Counter32,
        ifOutBroadcastPkts      Counter32,
        ifAlias                 DisplayString,

Any value that is not supplied will be defaulted.

Include 'WithDeprecatedItems => 1' in $datahash if you want to return data for the items marked as deprecated.

$agent->AddIpAddrEntry($datahash)
Add an IpAddrEntry - this is what binds IP addresses to interfaces

e.g.:

        $agent->AddIpAddrEntry( {
                ipAdEntAddr => '10.0.0.177',
                ipAdEntIfIndex => 2,
                ipAdEntNetMask => '255.255.255.0',
                ipAdEntBcastAddr => 1,
                ipAdEntReasmMaxSize => 8192,
        } );

ipAdEntAddr and ipAdEntIfIndex MUST be specified. Other values default as shown above if not specified.

$agent->AddIpNetToMediaEntry($datahash)
Add an IpNetToMediaEntry - this is what binds IP addresses to MAC addresses (the ARP table). e.g.:
        $agent->AddIpNetToMediaEntry( {
                ipNetToMediaIfIndex => 3,
                ipNetToMediaPhysAddress => '0:30:b6:36:14:d4',
                ipNetToMediaNetAddress => '10.0.0.177',
                ipNetToMediaType => 4,
        } );

The first three MUST be specified. ipNetToMediaType defaults to type static(4) if not specified Possible values are:

       other(1),        -- none of the following
       invalid(2),      -- an invalidated mapping
       dynamic(3),      -- obtained by dynamic means (e.g. ARP)
       static(4)        -- static (configuration or hardware)

$agent->AddIpRouteEntry($datahash)
Add an entry to the routing table e.g.:
        $agent->AddIpRouteEntry ({
                ipRouteDest => '10.1.3.0',
                ipRouteIfIndex => 2,
                ipRouteMetric1 => -1,                   *
                ipRouteMetric2 => -1,                   *
                ipRouteMetric3 => -1,                   *
                ipRouteMetric4 => -1,                   *
                ipRouteNextHop => '10.0.2.34',
                ipRouteType => 4,                       *
                ipRouteProto => 2,                      *
                ipRouteAge => 0,                        *
                ipRouteMask => '255.255.255.0',
                ipRouteMetric5 => -1,                   *
                ipRouteInfo => '.0.0',                  *
        });

Items marked '*' above can be omitted, and will default to the values shown.


Examples

For detailed code examples, see the examples directory in the Raddle distribution.


Distribution

Raddle is distributed from SourceForge: http://raddle.sourceforge.net/


Author

Andrew Findlay <andrew.findlay@skills-1st.co.uk>