Snmpd

From RARForge
Jump to navigation Jump to search

Ubuntu/Debian[edit]

<source> sudo apt-get install snmpd snmp libsnmp15 libsnmp-perl libsnmp-info-perl libsnmp-base libnet-snmp-perl snmp-mibs-downloader libparse-debian-packages-perl </source>

/etc/snmp/snmpd.conf

<source>

agentAddress  udp:161
rocommunity <secret>
rouser   authOnlyUser
sysLocation    ChangeME - Sitting on the Dock of the Bay
sysContact     You <me@example.org>
sysServices    72
proc  mountd
proc  ntalkd    4
proc  sendmail 10 1
disk       /     10000
disk       /var  5%
includeAllDisks  10%
load   12 10 5
trapsink     localhost public
iquerySecName   internalUser       
rouser          internalUser
defaultMonitors          yes
linkUpDownNotifications  yes
extend    test1   /bin/echo  Hello, world!
extend-sh test2   echo Hello, world! ; echo Hi there ; exit 35
## this will allow you list the sw installed. Script required below
perl do   "/etc/snmp/hrswinstalled.pl";
master          agentx

</source>

  • list software installed script required
/etc/snmp/hrswinstalled.pl

<source lang=perl>

  1. !/usr/bin/perl
  1. This is a rather quick (?) and dirty (!) script to implement the hrSWInstalled
  2. MIB on Debian and other dpkg based Linux distributions.
  3. If you have improvements, please send to rmk@bistromath.org


  1. Configuration
  1. maximum allowed cache age (in seconds)
  2. the agent will check the mtime on $statusfile if it hasn't checked in this long

$maxCacheAge = 10;

  1. location of dpkg files

my $statusfile = "/var/lib/dpkg/status"; my $infodir = "/var/lib/dpkg/info";

  1. 0 - quiet, 1 - basic debugging, 2 - trace debugging

$debug = 0;

my $regat = '1.3.6.1.2.1.25.6'; my $hrSWInstalledLastChange = $regat . ".1"; my $hrSWInstalledLastUpdateTime = $regat . ".2"; my $hrSWInstalledEntry = $regat . ".3.1"; my $hrSWInstalledIndex = $hrSWInstalledEntry . ".1"; my $hrSWInstalledName = $hrSWInstalledEntry . ".2"; my $hrSWInstalledID = $hrSWInstalledEntry . ".3"; my $hrSWInstalledType = $hrSWInstalledEntry . ".4"; my $hrSWInstalledDate = $hrSWInstalledEntry . ".5";

use Net::SNMP qw(oid_lex_sort); use YAML; use IO::File; use Parse::Debian::Packages; use Data::Dumper; use NetSNMP::OID (':all'); use NetSNMP::agent (':all'); use NetSNMP::ASN (':all'); use SNMP;

my $inittime = time(); my $lastCacheCheck; my $cacheAge = 0; my %oidtable; my @oidkeys; my %nextOIDMap;

BEGIN {

  print STDERR "loading Debian hrSWInstalled MIB extension \n";

}

populateCaches();

  1. if we're not embedded, this will get auto-set below to 1

$subagent = 0;

  1. where we are going to hook onto

my $regoid = new NetSNMP::OID($regat); print STDERR "registering at ", $regoid, "\n" if ($debug);

  1. If we're not running embedded within the agent, then try to start
  2. our own subagent instead.

if ( !$agent ) {

  $agent = new NetSNMP::agent(
      'Name'   => 'hrswinstalled',
      'AgentX' => 1
  );    # make us a subagent
  $subagent = 1;
  print STDERR "started us as a subagent ($agent)\n";

}

  1. we register ourselves with the master agent we're embedded in. The
  2. global $agent variable is how we do this:

$agent->register( 'myname', $regoid, \&hrSWInstalledHandler );

if ($subagent) {

  # We need to perform a loop here waiting for snmp requests.  We
  # aren't doing anything else here, but we could.
  $SIG{'INT'}  = \&shutDown;
  $SIG{'QUIT'} = \&shutDown;
  $running     = 1;
  while ($running) {
      $agent->agent_check_and_process(1);    # 1 = block
      print STDERR "main loop\n" if ( $debug > 2 );
  }
  $agent->shutdown();

}

  1. the actual SNMP handler

sub hrSWInstalledHandler {

  my ( $handler, $registration_info, $request_info, $requests ) = @_;
  my $request;
  #check package cache time
  populateCaches() if statusCacheUpdated($statusfile);
  print STDERR "processing a request of type "
    . $request_info->getMode() . "\n"
    if $debug > 1;
  for ( $request = $requests ; $request ; $request = $request->next() ) {
      my $oid = $request->getOID();
      print STDERR "  processing request of $oid\n" if $debug > 1;
      if ( $request_info->getMode() == MODE_GET ) {
          my $numericOid = SNMP::translateObj($oid);
          $numericOid =~ s/^\.//;
          $request->setOID($numericOid);
          $request->setValue( $oidtable{$numericOid}{type},
              $oidtable{$numericOid}{val} );
      }
      elsif ( $request_info->getMode() == MODE_GETNEXT ) {
          print STDERR "requested oid $oid\n" if $debug > 1;
          for my $oidentry (
              $nextOIDMap{$oid} ? ( $nextOIDMap{$oid}, @oidkeys ) : @oidkeys )
          {
              if ( $oid < $oidtable{$oidentry}{oid} ) {
                  print STDERR "returned $oidentry" if $debug > 1;
                  $request->setOID($oidentry);
                  $request->setValue( $oidtable{$oidentry}{type},
                      $oidtable{$oidentry}{val} );
                  last;
              }
          }
      }
  }
  print STDERR "  finished processing\n" if $debug > 1;

}

  1. optimised oid map

sub nextOIDMap {

  my ( $oidtable, $oidkeys ) = @_;
  my %nextmap;
  my %oididx;
  my $idx = 0;
  print STDERR "Generating OID cache...\n" if $debug;
  #generate hash mapping OIDs in @{$oidkeys} array to the index of that key
  #within the array, for performance reasons
  for my $oidkey ( @{$oidkeys} ) {
      $oididx{$oidkey} = $idx;
  }
  for my $oid ( keys %{$oidtable} ) {
      my $index = $oididx{$oid};
      $nextmap{ $oidtable{$oid}{oid} } = $oidkeys->[ $index + 1 ];
  }
  print STDERR "\t...done.\n" if $debug;
  return %nextmap;

}

  1. check if package status has changed

sub statusCacheUpdated {

  my ($statusfile) = @_;
  #allow for max cache age
  return 0 if time() <= $lastCacheCheck + $maxCacheAge;
  $lastCacheCheck = time();
  print STDERR "dpkg cache expired\n"
    if $debug && ( stat($statusfile) )[9] > $cacheAge;
  return ( stat($statusfile) )[9] > $cacheAge ? 1 : 0;

}

  1. enumerate package status

sub enumPkgs {

  my ( $statusfile, $infodir ) = @_;
  my $index = 1;
  my %packages;
  my %oidtable;
  print STDERR "Enumerating installed packages...\n" if $debug;
  #remember our cache age
  $cacheAge = time();
  my $fh = IO::File->new($statusfile);
  my $parser = Parse::Debian::Packages->new($fh);
  while ( my %package = $parser->next ) {
      next unless $package{Status} =~ /(?<!not-)installed/;
      $packages{ $package{Package} } = \%package;
  }
  close $fh;
  for my $name ( sort keys %packages ) {
      my $oid;
      #hrSWInstalledIndex
      $oid = $hrSWInstalledIndex . "." . $index;
      $oidtable{$oid}{oid} =
        new NetSNMP::OID( $hrSWInstalledIndex . "." . "$index" );
      $oidtable{$oid}{type} = ASN_INTEGER;
      $oidtable{$oid}{val} = $index;
      #hrSWInstalledName
      $oid = $hrSWInstalledName . "." . $index;
      $oidtable{$oid}{oid} =
        new NetSNMP::OID( $hrSWInstalledName . "." . "$index" );
      $oidtable{$oid}{type} = ASN_OCTET_STR;
      $oidtable{$oid}{val} =
        "$name $packages{$name}{Version}/$packages{$name}{Architecture} ("
        . ( $packages{$name}{Description} || "No description" ) . ")";
      #hrSWInstalledDate
      $oid = $hrSWInstalledDate . "." . $index;
      $oidtable{$oid}{oid} =
        new NetSNMP::OID( $hrSWInstalledDate . "." . "$index" );
      $oidtable{$oid}{type} = ASN_OCTET_STR;
      my $mtime = ( stat( "$infodir" . "/" . $name . ".list" ) )[9];
      $oidtable{$oid}{val} = snmpDateStamp($mtime);
      #hrSWInstalledID
      $oid = $hrSWInstalledID . "." . $index;
      $oidtable{$oid}{oid} =
        new NetSNMP::OID( $hrSWInstalledID . "." . "$index" );
      $oidtable{$oid}{type} = ASN_OBJECT_ID;
      $oidtable{$oid}{val} = "0.0";
      #hrSWInstalledType
      $oid = $hrSWInstalledType . "." . $index;
      $oidtable{$oid}{oid} =
        new NetSNMP::OID( $hrSWInstalledType . "." . "$index" );
      $oidtable{$oid}{type} = ASN_INTEGER;
      if (   $packages{$name}{Priority} eq "required"
          || $packages{$name}{Section} eq "base" )
      {
          #OS package
          $oidtable{$oid}{val} = 2;
      }
      else {
          #application
          $oidtable{$oid}{val} = 4;
      }
      #increment index
      $index++;
  }
  #hrSWInstalledLastChange
  $oid = $hrSWInstalledLastChange . "." . $index;
  $oidtable{$oid}{oid} =
    new NetSNMP::OID( $hrSWInstalledLastChange . "." . "$index" );
  $oidtable{$oid}{type} = ASN_TIMETICKS;
  my $mtime = ( stat($statusfile) )[9];
  $oidtable{$oid}{val} = ( time() - $inittime ) * 100;
  #hrSWInstalledLastUpdateTime
  $oid = $hrSWInstalledLastUpdateTime . "." . $index;
  $oidtable{$oid}{oid} =
    new NetSNMP::OID( $hrSWInstalledLastUpdateTime . "." . "$index" );
  $oidtable{$oid}{type} = ASN_TIMETICKS;
  $oidtable{$oid}{val} = ( time() - $inittime ) * 100;
  print "\tdone. (" . scalar( keys %packages ) . " packages)\n" if $debug;
  return %oidtable;

}

  1. convert unix timestamp to snmp TimeAndDate

sub snmpDateStamp {

  my ($ts) = @_;
  my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
    gmtime($ts);
  return pack 'n C6 a C2', $year + 1900, $mon + 1, $mday, $hour, $min, $sec,
    0, '-', 0, 0;

}

sub populateCaches {

  %oidtable   = enumPkgs( $statusfile, $infodir );
  @oidkeys    = oid_lex_sort( keys %oidtable );
  %nextOIDMap = nextOIDMap( \%oidtable, \@oidkeys );

}

sub shutDown {

  $running = 0;
  print STDERR "shutting down\n" if ($debug);

} </source> <source> chmod +x /etc/snmp/hrswinstalled.pl </source>

  • verify it can run

<source> root@servrr:/etc/snmp# /etc/snmp/hrswinstalled.pl

loading Debian hrSWInstalled MIB extension 
started us as a subagent (NetSNMP::agent=HASH(0x42575f0))
## looks good - type ctrl-c to quit

</source>

<source> service snmpd restart

* Restarting network management services:              

</source>

<source> snmpwalk -v2c -c <secret> localhost iso.3.6.1.2.1.1.1.0 = STRING: "Linux onion 3.2.0-40-generic #64-Ubuntu SMP Mon Mar 25 21:22:10 UTC 2013 x86_64" iso.3.6.1.2.1.1.2.0 = OID: iso.3.6.1.4.1.8072.3.2.10 iso.3.6.1.2.1.1.3.0 = Timeticks: (3536) 0:00:35.36 iso.3.6.1.2.1.1.4.0 = STRING: "Me <me@example.org>" iso.3.6.1.2.1.1.5.0 = STRING: "server" iso.3.6.1.2.1.1.6.0 = STRING: "Sitting on the Dock of the Bay" iso.3.6.1.2.1.1.7.0 = INTEGER: 72 ..... </source>