#!/usr/bin/perl

use Net::SNMP;
use Socket;

# Some arrays
#
@ccmHistoryEventCommandSource=("","commandLine","snmp");
@ccmHistoryEventConfigSource=("","erase","commandSource","running","startup","local","networkTftp","networkRcp","networkFtp","networkScp");
@ccmHistoryEventConfigDestination=("","erase","commandSource","running","startup","local","networkTftp","networkRcp","networkFtp","networkScp");
@ccCopyProtocol=("","tftp","ftp","rcp");
@ccCopySourceFileType=("","networkFile","","startupConfig","runningConfig");
@ccCopyDestFileType=("","networkFile","","startupConfig","runningConfig");
@ccCopyState=("","waiting","running","successful","failed");
@ccCopyServerAddress=("0.0.0.0");
@ccCopyFileName=("");
@ccCopyEntryRowStatus=("","active","notInService","notReady","createAndGo","createAndWait","destroy");

%OIDsToObjects=(
 "1.3.6.1.4.1.9.9.43.1.1.6.1.3"=>\@ccmHistoryEventCommandSource,
 "1.3.6.1.4.1.9.9.43.1.1.6.1.4"=>\@ccmHistoryEventConfigSource,
 "1.3.6.1.4.1.9.9.43.1.1.6.1.5"=>\@ccmHistoryEventConfigDestination,
 "1.3.6.1.4.1.9.9.96.1.1.1.1.2"=>\@ccCopyProtocol,
 "1.3.6.1.4.1.9.9.96.1.1.1.1.3"=>\@ccCopySourceFileType,
 "1.3.6.1.4.1.9.9.96.1.1.1.1.4"=>\@ccCopyDestFileType,
 "1.3.6.1.4.1.9.9.96.1.1.1.1.5"=>\@ccCopyServerAddress,
 "1.3.6.1.4.1.9.9.96.1.1.1.1.6"=>\@ccCopyFileName,
 "1.3.6.1.4.1.9.9.96.1.1.1.1.10"=>\@ccCopyState,
 "1.3.6.1.4.1.9.9.96.1.1.1.1.14"=>\@ccCopyEntryRowStatus
);


# Log-file. Because this script is called by SNMPTrap 
# Daemon we couldn't see its output. The only way is 
# to log activity to a file
#
open(LOG,">>/var/log/snmptrapd.log");
$i=0;

#Some default values
#
$strHost="0.0.0.0";
$strOID="1.3.6.1";

# Reading information of SNMPTrap Daemon which is
# substituted to STDIN Environment of this script
#
while (<STDIN>)
 {
  chomp;
  $strLine=$_;

# For debug use
#
#  printf(LOG, "%s\n", $strLine);

  # The first line of STDIN contains IP address of
  # the device that generated Trap
  #
  if($i==1)
   {
    $strLine=~/.*\[(.*)\].*/;
    $strHost=$1;
   }

  # If Trap is "Cisco Config" we catch it and
  # perform som actions on logging and backing
  # up configs
  #
  if($strLine =~ /enterprises\.9\.9\.43\.2\.0\.1/)
   {
    $strOID="1.3.6.1.4.1.9.9.43.2.0.1";
   }
  if($strOID =~ /1\.3\.6\.1\.4\.1\.9\.9\.43\.2\.0\.1/)
   {
    # Three values are sent in this Trap:
    # - "how"    - "from"    - "where"
    #
    if($strLine =~ /enterprises\.9\.9\.43\.1\.1\.6\.1\.3\.\d+ (\d+)/) 
     {
      $strVia=$OIDsToObjects{"1.3.6.1.4.1.9.9.43.1.1.6.1.3"}[$1];
     }
    if($strLine =~ /enterprises\.9\.9\.43\.1\.1\.6\.1\.4\.\d+ (\d+)/) 
     {
      $strSrc=$OIDsToObjects{"1.3.6.1.4.1.9.9.43.1.1.6.1.4"}[$1];
     }
    if($strLine =~ /enterprises\.9\.9\.43\.1\.1\.6\.1\.5\.\d+ (\d+)/) 
     {
      $strDst=$OIDsToObjects{"1.3.6.1.4.1.9.9.43.1.1.6.1.5"}[$1];
     }
   }
  $i++;
 }


# If we have situation when User on Cisco has
# done "copy run start"
#
if($strOID =~ /1\.3\.6\.1\.4\.1\.9\.9\.43\.2\.0\.1/ && $strVia =~ /commandLine/ && $strSrc =~ /running/ && $strDst =~ /startup/)
 {
  # Getting current Date and Time (timestamp)
  #
  $strDateTime=`date "+%Y.%m.%d %H:%M:%S"`;
  $strDateTime=~s/^(.*)\s*/$1/;

  # Getting Hostname, "Firstname" of Hostname - for SYSLOG search for
  # "%SYS-5-CONFIG_I: Configured from console by ...",
  # to exact identification of these lines and "burned device",
  # and also Hostname without "united-networks.ru".
  #
  $strHostname = gethostbyaddr(inet_aton($strHost), AF_INET);
  $strDeviceName = $1 if($strHostname =~ /^(.*)\.united-networks\.ru$/);
  $strHostname=~/^(.*?)\./;
  $strShortHostname=$1;

  # Rearrange domains to form filename for configuration: 
  # sr-2821.medvedkovo.msk -> msk.medvedkovo.sr-2821
  # 
  @HostDomains = split(/\./,$strHostname);
  $strBackupPath1="";
  for($i=0;$i<=$#HostDomains;$i++)
   {
    if($HostDomains[$i] =~ /united-networks/) { last; }
    $strBackupPath1=$HostDomains[$i].".".$strBackupPath1;
   }
  # Three paths:
  #  ./                       - relative to /var/tftp - to tell
  #                             Cisco where save config on TFTP
  #  /var/tftp/               - local absolute path 
  #  /backup/network_hardware - persistent storage
  # 
  $strBackupPath1=~s/(.*)\.$/$1/;
  $strBackupPath2="/backup/network_hardware/".$strBackupPath1;
  $strBackupPath3="/var/tftp/".$strBackupPath1;

  # Commands to Cisco to back up its config on TFTP via Net::SNMP
  #
  $OID_ccCopyProtocol="1.3.6.1.4.1.9.9.96.1.1.1.1.2.9";
  $OID_ccCopySourceFileType="1.3.6.1.4.1.9.9.96.1.1.1.1.3.9";
  $OID_ccCopyDestFileType="1.3.6.1.4.1.9.9.96.1.1.1.1.4.9";
  $OID_ccCopyServerAddress="1.3.6.1.4.1.9.9.96.1.1.1.1.5.9";
  $OID_ccCopyFileName="1.3.6.1.4.1.9.9.96.1.1.1.1.6.9";
  $OID_ccCopyState="1.3.6.1.4.1.9.9.96.1.1.1.1.10.9";
  $OID_ccCopyEntryRowStatus="1.3.6.1.4.1.9.9.96.1.1.1.1.14.9";

  # There are two cases where requests come from: from LAN
  # and VPN. TFTPD goes crazy if request went to improper IP
  # So we need to take in account direction and use nearest IP
  #
  $strTFTPAddress="172.16.0.1";
  $strTFTPAddress="172.31.0.1" if($strHost!~/^172\.16\.0\./);

  # Actually doing config backup
  #
  ($session, $error) = Net::SNMP->session(-hostname => $strHost,-community => "MyWrItEcOmMuNiTy",);
  $res=$session->set_request(-varbindlist => [ $OID_ccCopyEntryRowStatus, INTEGER,      "6" ],);
  $res=$session->set_request(-varbindlist => [ $OID_ccCopyProtocol,       INTEGER,      "1" ],);
  $res=$session->set_request(-varbindlist => [ $OID_ccCopySourceFileType, INTEGER,      "4" ],);
  $res=$session->set_request(-varbindlist => [ $OID_ccCopyDestFileType,   INTEGER,      "1" ],);
  $res=$session->set_request(-varbindlist => [ $OID_ccCopyServerAddress,  IPADDRESS,    $strTFTPAddress ],);
  $res=$session->set_request(-varbindlist => [ $OID_ccCopyFileName,       OCTET_STRING, $strBackupPath1 ],);
  $res=$session->set_request(-varbindlist => [ $OID_ccCopyEntryRowStatus, INTEGER,      "1" ],);

  # Wait for 100 seconds or until ccCopyStatus is not equal "successful"
  #
  $TimeStop=time+100;
  while(1)
   {
    $res=$session->get_request(-varbindlist => [ $OID_ccCopyState],);
    last if(time>$TimeStop || $res->{$OID_ccCopyState}==3);
   }
  $res=$session->set_request(-varbindlist => [ $OID_ccCopyEntryRowStatus, INTEGER,      "1" ],);


  # If we have previously backed up config and current config
  # successfully stored in /var/tftp/... - so, compare
  # them for differences by DIFF Utility
  #
  if( -e "$strBackupPath3" && -e $strBackupPath2)
   {
    $strDiff=`diff -C 5 $strBackupPath2 /var/tftp/$strBackupPath1 | sed 's/^\\(.*\\)\$/               \\1/'`;
   }
  if($strDiff =~ /^$/)
   {
    $strDiff="There is no changes encountered!";
   }
  else
   {
    $strDiff="\n".$strDiff;
   }

  # Rotating previous backups to form history of 10 backups
  # in past
  #
  for($i=9,$j=8;$i>0;$i--,$j--)
   { 
    if(-e "$strBackupPath2.$j.gz") { `mv $strBackupPath2.$j.gz $strBackupPath2.$i.gz`; }
   }
  # Last backup is processed separately
  #
  if(-e $strBackupPath2)
   { 
    `mv $strBackupPath2 $strBackupPath2.0`;
    `gzip $strBackupPath2.0`;
   }
  
  # Copy newly backed up config to its permanent location
  #
  `mv $strBackupPath3 $strBackupPath2`;


  # Scanning SYSLOG-file /var/log/network_hardware.log 
  # in backward order for "Configured from console.."
  # with Short Hostname containing.
  #
  # NOTICE: for Linux use "tac" instead "tail -r"
  #
  $strRes=`tail -r /var/log/network_hardware.log | egrep "$strHost|$strShortHostname" | grep -m 1 "Configured from console"`;
  $strChanger="Unknown (0.0.0.0)";
  if($strRes =~ /Configured from console by (.*) on .* \((.*)\)/)
   {
    $strChanger="$1 ($2)";
   }
  else
   {
    # This is for situation if log recently rotated -
    # look at archived log file
    #
    $strRes=`gunzip -c /var/log/network_hardware.log.1 | tail -r | grep $strHost | grep -m 1 "Configured from console"`;
    if($strRes =~ /Configured from console by (.*) on .* \((.*)\)/)
     {
      $strChanger="$1 ($2)";
     }
   }
 
  # Logging all gathered information
  #
  printf(LOG "\n*** Trap OID: '%s' ***\n",$strOID);
  printf(LOG "  Date/time:   %s\n",$strDateTime);
  printf(LOG "  Device IP:   %s\n",$strHost);
  printf(LOG "  Hostname:    %s (%s)\n",$strHostname,$strShortHostname);
  printf(LOG "  Description: Configuration changed via '%s' from '%s' to '%s'\n",$strVia,$strSrc,$strDst);
  printf(LOG "  Changer:     %s\n",$strChanger);
  printf(LOG "  Changes:     %s\n",$strDiff);

  # Snding the same information via e-mail to NOC
  #
  open (SENDMAIL, "|/usr/sbin/sendmail -t");
  printf(SENDMAIL "From: Check Config <check_config\@united-networks.ru>\n");
  printf(SENDMAIL "To: Charlie Root <root\@runoguy.ru>\n");
  printf(SENDMAIL "Reply-To: Charlie Root <root\@united-networks.ru>\n");
  printf(SENDMAIL "Subject: Device \"%s\" (%s) is changed by %s\n\n",uc($strDeviceName),$strHost,uc($strChanger));
  printf(SENDMAIL "  Date/time:   %s\n",$strDateTime);
  printf(SENDMAIL "  Device IP:   %s\n",$strHost);
  printf(SENDMAIL "  Hostname:    %s (%s)\n",$strHostname,$strShortHostname);
  printf(SENDMAIL "  Description: Configuration changed via '%s' from '%s' to '%s'\n",$strVia,$strSrc,$strDst);
  printf(SENDMAIL "  Changer:     %s\n",$strChanger);
  printf(SENDMAIL "  Changes:     %s\n",$strDiff);
  close(SENDMAIL);

 }
close(LOG);
trap_handler.txt · Last modified: 2016/01/31 11:14 (external edit)
 
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki