#!/usr/bin/perl
# -*- mode: Perl -*-
##################################################################
# MRTG 2.7.2  -- Config file creator
##################################################################
# Created by Tobias Oetiker <oetiker@ee.ethz.ch>
# this produces a config file for one router, by bulling info
# off the router via snmp
#################################################################
#
# Distributed under the GNU copyleft

use BER "0.57";
use SNMP_Session "0.59";
use SNMP_util "0.57";

use Socket;
use strict;
use vars '$DEBUG';
my $DEBUG = 0;

my ($session, %ipaddr, %iphost);

sub main {

    snmpmapOID('ipAdEntAddr' => '1.3.6.1.2.1.4.20.1.1',
	       'ipAdEntIfIndex' => '1.3.6.1.2.1.4.20.1.2',
	       'sysObjectID' => '1.3.6.1.2.1.1.2.0',
	       'CiscolocIfDescr' => '1.3.6.1.4.1.9.2.2.1.1.28',
	       'ifAlias' => '1.3.6.1.2.1.31.1.1.1.18');

  my(%ifType_d)=('1'=>'Other',
		 '2'=>'regular1822',
		 '3'=>'hdh1822',
		 '4'=>'ddnX25',
		 '5'=>'rfc877x25',
		 '6'=>'ethernetCsmacd',
		 '7'=>'iso88023Csmacd',
		 '8'=>'iso88024TokenBus',
		 '9'=>'iso88025TokenRing',
		 '10'=>'iso88026Man',
		 '11'=>'starLan',
		 '12'=>'proteon10Mbit',
		 '13'=>'proteon80Mbit',
		 '14'=>'hyperchannel',
		 '15'=>'fddi',
		 '16'=>'lapb',
		 '17'=>'sdlc',
		 '18'=>'ds1',
		 '19'=>'e1',
		 '20'=>'basicISDN',
		 '21'=>'primaryISDN',
		 '22'=>'propPointToPointSerial',
		 '23'=>'ppp',
		 '24'=>'softwareLoopback',
		 '25'=>'eon',
		 '26'=>'ethernet-3Mbit',
		 '27'=>'nsip',
		 '28'=>'slip',
		 '29'=>'ultra',
		 '30'=>'ds3',
		 '31'=>'sip',
		 '32'=>'frame-relay',
		 '33'=>'rs232',
		 '34'=>'para',
		 '35'=>'arcnet',
		 '36'=>'arcnetPlus',
		 '37'=>'atm',
		 '38'=>'miox25',
		 '39'=>'sonet',
		 '40'=>'x25ple',
		 '41'=>'iso88022llc',
		 '42'=>'localTalk',
		 '43'=>'smdsDxi',
		 '44'=>'frameRelayService',
		 '45'=>'v35',
		 '46'=>'hssi',
		 '47'=>'hippi',
		 '48'=>'modem',
		 '49'=>'aal5',
		 '50'=>'sonetPath',
		 '51'=>'sonetVT',
		 '52'=>'smdsIcip',
		 '53'=>'propVirtual',
		 '54'=>'propMultiplexor',
		 '55'=>'100BaseVG',
                 #### New IF Types added 9/24/98 by Russ Carleton (roccor@livenetworking.com)
                 #### based on the IANA file updated at ftp://ftp.isi.edu/mib/ianaiftype.mib
                 '56'=>'Fibre Channel',
                 '57'=>'HIPPI Interface',
                 '58'=>'Obsolete for FrameRelay',
                 '59'=>'ATM Emulation of 802.3 LAN',
                 '60'=>'ATM Emulation of 802.5 LAN',
                 '61'=>'ATM Emulation of a Circuit',
                 '62'=>'FastEthernet (100BaseT)',
                 '63'=>'ISDN & X.25',
                 '64'=>'CCITT V.11/X.21',
                 '65'=>'CCITT V.36',
                 '66'=>'CCITT G703 at 64Kbps',
                 '67'=>'Obsolete G702 see DS1-MIB',
                 '68'=>'SNA QLLC',
                 '69'=>'Full Duplex Fast Ethernet (100BaseFX)',
                 '70'=>'Channel',
                 '71'=>'Radio Spread Spectrum (802.11)',
                 '72'=>'IBM System 360/370 OEMI Channel',
                 '73'=>'IBM Enterprise Systems Connection',
                 '74'=>'Data Link Switching',
                 '75'=>'ISDN S/T Interface',
                 '76'=>'ISDN U Interface',
                 '77'=>'Link Access Protocol D (LAPD)',
                 '78'=>'IP Switching Opjects',
                 '79'=>'Remote Source Route Bridging',
                 '80'=>'ATM Logical Port',
                 '81'=>'AT&T DS0 Point (64 Kbps)',
                 '82'=>'AT&T Group of DS0 on a single DS1',
                 '83'=>'BiSync Protocol (BSC)',
                 '84'=>'Asynchronous Protocol',
                 '85'=>'Combat Net Radio',
                 '86'=>'ISO 802.5r DTR',
                 '87'=>'Ext Pos Loc Report Sys',
                 '88'=>'Apple Talk Remote Access Protocol',
                 '89'=>'Proprietary Connectionless Protocol',
                 '90'=>'CCITT-ITU X.29 PAD Protocol',
                 '91'=>'CCITT-ITU X.3 PAD Facility',
                 '92'=>'MultiProtocol Connection over Frame/Relay',
                 '93'=>'CCITT-ITU X213',
                 '94'=>'Asymetric Digitial Subscriber Loop (ADSL)',
                 '95'=>'Rate-Adapt Digital Subscriber Loop (RDSL)',
                 '96'=>'Symetric Digitial Subscriber Loop (SDSL)',
                 '97'=>'Very High Speed Digitial Subscriber Loop (HDSL)',
                 '98'=>'ISO 802.5 CRFP',
                 '99'=>'Myricom Myrinet',
                 '100'=>'Voice recEive and transMit (voiceEM)',
                 '101'=>'Voice Foreign eXchange Office (voiceFXO)',
                 '102'=>'Voice Foreign eXchange Station (voiceFXS)',
                 '103'=>'Voice Encapulation',
                 '104'=>'Voice Over IP Encapulation',
                 '105'=>'ATM DXI',
                 '106'=>'ATM FUNI',
                 '107'=>'ATM IMA',
                 '108'=>'PPP Multilink Bundle',
                 '109'=>'IBM IP over CDLC',
                 '110'=>'IBM Common Link Access to Workstation',
                 '111'=>'IBM Stack to Stack',
                 '112'=>'IBM Virtual IP Address (VIPA)',
                 '113'=>'IBM Multi-Protocol Channel Support',
                 '114'=>'IBM IP over ATM',
                 '115'=>'ISO 802.5j Fiber Token Ring',
                 '116'=>'IBM Twinaxial Data Link Control (TDLC)',
                 '117'=>'Gigabit Ethernet',
                 '118'=>'Higher Data Link Control (HDLC)',
                 '119'=>'Link Access Protocol F (LAPF)',
                 '120'=>'CCITT V.37',
                 '121'=>'CCITT X.25 Multi-Link Protocol',
                 '122'=>'CCITT X.25 Hunt Group',
                 '123'=>'Transp HDLC',
                 '124'=>'Interleave Channel',
                 '125'=>'Fast Channel',
                 '126'=>'IP (for APPN HPR in IP Networks)',
                 '127'=>'CATV MAC Layer',
                 '128'=>'CATV Downstream Interface',
                 '129'=>'CATV Upstream Interface',
                 '130'=>'Avalon Parallel Processor',
                 '131'=>'Encapsulation Interface',
                 '132'=>'Coffee Pot',
                 '133'=>'Circuit Emulation Service',
                 '134'=>'ATM Sub Interface',
                 '135'=>'Layer 2 Virtual LAN using 802.1Q',
                 '136'=>'Layer 3 Virtual LAN using IP',
                 '137'=>'Layer 3 Virtual LAN using IPX',
                 '138'=>'IP Over Power Lines',
                 '139'=>'Multi-Media Mail over IP',
                 '140'=>'Dynamic synchronous Transfer Mode (DTM)',
                 '141'=>'Data Communications Network',
                 '142'=>'IP Forwarding Interface'
                 );

  my($vendor)=0;
  if ($ARGV[0] eq '--vendor') {
	$vendor = 1; shift @ARGV};

  my($community,$router) = ($1,$2) if $ARGV[0] =~ /(.*)\@(.*)/;
  die <<USAGE  unless $community && $router;

USAGE: cfgmaker [--vendor] 'community'\@'router'

use the --vendor option to try and wrestle some better information
from willing livingston and cisco routers ... (may not work)

EXAMPLE:  cfgmaker public\@ezwf7.ethz.ch >>mrtg.cfg


USAGE
  print "# Add a WorkDir: /some/path line to this file\n\n";

    $session = SNMP_Session->open ($router, $community, 161)
	|| die "Error opening SNMP session to $router";
  
  my($sysDescr,$sysContact,$sysName,$sysLocation,$ifNumber,$sysObjectID) =
    snmpget("$community\@$router",
	    'sysDescr','sysContact','sysName',	'sysLocation', 'ifNumber', 'sysObjectID');

   $sysDescr =~ s/\r\n?/
/g;  # Change returns to 
   my($cisco_router_sysid) = '1\.3\.6\.1\.4\.1\.9';
   my($livingston_router_sysid) = '1\.3\.6\.1\.4\.1\.307';
   my($ciscobox) = ($sysObjectID =~ /^$cisco_router_sysid/);
   my($portmaster) = ($sysObjectID =~ /^$livingston_router_sysid/);

    print <<ECHO;

WorkDir: /pkg/mon/www/mrtg/
Refresh: 300
Interval: 5
WriteExpires: yes 

#Global Modifications:
Unscaled[_]: ymwd
Options[_]: bits,growright
YLegend[_]: Bits Per Second
ShortLegend[_]: b/s
LegendI[_]:  Bits/s:
LegendO[_]:  Bits/s: 

#################################################################
#    Location: $sysLocation
#     Contact: $sysContact
# System Name: $sysName
#
# System Description including Software and Hardware Versions.
#
# $sysDescr
#################################################################
# Modified Mrtg cfgmaker Configuration file for SMNP Equipment
# Last edited - 1999, Mar 31th, revision 2.0
# Edited By   - mpburton (mpburton\@europa.com)
# Time        - 11:10 pm
# Created By  - Jlatimer (J.Latimer\@sussex.ac.uk)  
################################################################# 
#---------------------------------------------------------------  
ECHO

  $session->map_table ([[1,3,6,1,2,1,4,20,1,1],	# ipAdEntAddr
			[1,3,6,1,2,1,4,20,1,2]], # ipAdEntIf
		       sub ($@) {
			   my ($index, $ipadentaddr, $ipadentif) = @_;
			   grep (defined $_ && ($_=pretty_print $_),
				 ($ipadentif, $ipadentaddr));
			   $ipaddr{$ipadentif} = $ipadentaddr;
			   $iphost{$ipadentif} = 
			       gethostbyaddr(pack('C4',split(/\./,$ipaddr{$ipadentif})), AF_INET);
			   if (!defined $iphost{$ipadentif} || ($iphost{$ipadentif} eq '')){
			       $iphost{$ipadentif} = 'No hostname defined for IP address';
			   }
		       });

  print STDERR "Got Addresses\n" if $DEBUG;
  print STDERR "Got IfTable\n" if $DEBUG;

  my(%sifdesc,%siftype,%sifspeed,%sifadminstatus,%sifoperstatus,%sciscodescr,%sifrawdesc);

  ### May need the cisco IOS version number so we know which oid to use
  ###   to get the cisco description.
  ###
  ### - mjd 2/5/98 (Mike Diehn) (mdiehn@mindspring.net)
  ###
  my ($cisco_ver, $cisco_descr_oid, @ciscodescr);
  if ( $ciscobox ) {
    ($cisco_ver) = ($sysDescr =~ m/Version\s+([\d\.]+)\(\d/o);
    $cisco_descr_oid = ($cisco_ver ge "11.2") ? "ifAlias" : "CiscolocIfDescr";
  }

#mod by jon: create a hash table to map ifIndex integers to module/port names:
my $cat5500 = 0;
if ( $sysDescr =~ /WS-C55.*/i ) {
  $cat5500 = 1;
}

my (%iftomp, %iftovlan);
if ($cat5500) {

$session->map_table ([[1,3,6,1,4,1,9,5,1,4,1,1,11]],	#5500 port group

sub ($@) {
  my ($rowindex, $index) = @_;
  grep (defined $_ && ($_=pretty_print $_),
	($index));

#  $rowindex =~ s/\./\//g;
  $iftomp{$index} = $rowindex;
#  print "row:$rowindex; idx:$index";
#  print "\n\n";
});

#foreach my $key (sort(keys %iftomp)) {
#  print $key, '=', $iftomp{$key}, "\n";
#}

$session->map_table ([[1,3,6,1,4,1,9,5,1,9,3,1,3]],

sub ($@) {
  my ($rowindex, $vlan_no) = @_;
  grep (defined $_ && ($_=pretty_print $_),
        ($vlan_no));

  my $ifindex;
  foreach my $key (keys %iftomp) {
    if ($iftomp{$key} eq $rowindex) {
      $ifindex = $key;
    }
  }
  $iftovlan{$ifindex} = $vlan_no;

});

#foreach my $key (sort(keys %iftovlan)) {   
#  print $key, '=', $iftovlan{$key}, "\n";
#}
} #end if cat5500

$session->map_table ([[1,3,6,1,2,1,2,2,1,1], # ifIndex
		      [1,3,6,1,2,1,2,2,1,2], # ifDescr
		      [1,3,6,1,2,1,2,2,1,3], # ifType
		      [1,3,6,1,2,1,2,2,1,5], # ifSpeed
		      [1,3,6,1,2,1,2,2,1,7], # ifAdminStatus
		      [1,3,6,1,2,1,2,2,1,8]], # ifOperStatus
sub ($@) {
    my ($rowindex,$index,$ifdescr,$iftype,$ifspeed,$ifadminstatus,$ifoperstatus) = @_;
    grep (defined $_ && ($_=pretty_print $_),
	  ($index,$ifdescr,$iftype,$ifspeed,$ifadminstatus,$ifoperstatus));

  if ($cat5500) {
    my ($intname, $tmp_vlan_no) = split (' ',$ifdescr);
    if ( ($intname eq "sc0") || ($intname eq "sl0") ) {
      return;
    }
    if ($intname eq "VLAN") {
      if ($tmp_vlan_no >= 1000) {
        return;
      }
#The Catalyst software version 4.5 seems to return '0' as the ifSpeed for a
#VLAN.  We set it to 100Mb because we want to watch aggregate VLAN traffic.
      if ($ifspeed == 0) {
        $ifspeed = 100 * 10**6;
      }
    }
    my ($port_num, $vlan_desc);
    $port_num = $iftomp{$index};
    $port_num =~ s/\./\//g;
    if ($iftovlan{$index} != 1) {
      $vlan_desc = " Vlan $iftovlan{$index} ";
    }
    else {
      $vlan_desc = "Vlan $iftovlan{$index}";
    }
    if ($iftype != 53) {
      $sifdesc{$index} = "Port $port_num, $vlan_desc, $ifdescr";
    }
    else {
      $sifdesc{$index} = "  Aggregate Traffic: $ifdescr  ";
      $sifrawdesc{$index} = $ifdescr;
    }
  }
  else {
    $sifdesc{$index} = $ifdescr;
  }
    $siftype{$index} = $iftype;
    $sifspeed{$index} = $ifspeed;
    $sifadminstatus{$index} = $ifadminstatus;
    $sifoperstatus{$index} = $ifoperstatus;
    if ($portmaster && $vendor) {
      
      # We can only approximate speeds
      # 
      # so we think that ppp can do 76800 bit/s, and slip 38400.
      # (actualy, slip is a bit faster, but usualy users with newer modems
      # use ppp). Alternatively, you can set async speed to 115200 or
      # 230400 (the maximum speed supported by portmaster).
      # 
      # But if the interface is ptpW (sync), max speed is 128000
      # change it to your needs. On various Portmasters there are
      # various numbers of sync interfaces, so modify it.
      # 
      #  The most commonly used PM-2ER has only one sync.
      # 
      #  Paul Makeev (mac@redline.ru)
      # 

      if ($siftype{$index} eq '23') {
              if ($sifdesc{$index} eq 'ptpW1') {
                      $sifspeed{$index} = 128000;
              } else {
                      $sifspeed{$index} = 76800;
              }
      } elsif ($siftype{$index} eq '28') {
              $sifspeed{$index} = 38400;
      } elsif ($siftype{$index} eq '6') {
              $sifspeed{$index} = 10000000;
      }
    }

    ### Move this section south so we know what type of
    ###  circuit we're looking at before we retrieve
    ###  the cisco interface alias.
    ###
    ### This whole cicso thing should be re-written, but since
    ###   this script doesn't need to run quickly...
    ###
    ###  - mjd 2/5/98
    ###
    # Get the user configurable interface description entered in the config 
    # if it's a cisco-box
    #
    if ($ciscobox && $vendor) {

	my ($enoid, @descr);

	$enoid = $cisco_descr_oid . "." . $index;

	if ( $cisco_ver ge "11.2" or $siftype{$index} != '32' ) {

	  ### This is either not a frame-relay sub-interface or
	  ###  this router is running IOS 11.2+ and interface
	  ###  type won't matter. In either of these cases, it's
	  ###  ok to try getting the ifAlias or ciscoLocIfDesc.
	  ###
	  @descr = snmpget("$community\@$router", $enoid);

	} else {

	  ### This is a frame-relay sub-interface *and* the router
	  ###  is running an IOS older than 11.2. Therefore, we can
	  ###  get neither ifAlias nor ciscoLocIfDesc. Do something
	  ###  useful.
	  ###
	  @descr = ("Cisco PVCs descriptions require IOS 11.2+.");

	} # end if else

	### Put whatever I got into the array we'll use later to append the result
	###   of this operation onto the results from the ifDescr fetch.
	###
	push @ciscodescr, shift @descr;

    } # end if ($cisco_box && $vendor)

    # especially since cisco does not return a if
    # descr for each interface it has ...
    ## JB 2/8/97 - sometimes IOS inserts E1 controllers in the standard-MIB
    ## interface table, but not in the local interface table. This puts the
    ## local interface description table out-of-sync. the following 
    ## modification skips over E1 cards as interfaces.
    #
    ### I suspect that the mod I made above, to use the ifAlias
    ###   oid if possible, may cause problems here. If it seems
    ###   that your descriptions are out of sync, try commenting
    ###   out the "if ( condition )" and it's closing right brace
    ###   so that the "shift @ciscodescr" get executed for *all*
    ###   iterations of this loop.
    ###
    ### - mjd 2/5/95
    ###
    if ($ciscobox && $siftype{$index} != 18) {
          $sciscodescr{$index} = "<BR>" . (shift @ciscodescr) if @ciscodescr;
    }
});
  my $index;
  foreach $index ( sort { $a <=> $b } keys %sifdesc) {
    my $c;
    my $speed = int($sifspeed{$index} / 8); # bits to byte
    my $speed_str=&fmi($speed);
    my $name="$iphost{$index}";
    $name = "$router.$index" if not $name or $name =~ /\s/;

  if (($sifadminstatus{$index} != 1)
# this check added by Josh - don't query E1-stack controllers
      || ($siftype{$index} == 18)
	|| ($siftype{$index} == 24)
	|| ($speed == 0 ) 
	|| ($speed > 400 * 10**6)  #speeds of 400 MByte/s are not realistic
	|| ($sifoperstatus{$index} == 3)) {
    print <<ECHO;
########
######## This Interface is one of the following
######## - administratively not UP
######## - it is in test mode
######## - it is a softwareLoopback interface
######## - has a unrealistic speed setting
######## It is commented out for this reason.
########
ECHO
  $c="# ";
  }else {
    $c = '';
  }
    
  print <<ECHO;
${c}
ECHO

if ( ($cat5500) && ($siftype{$index} == 53) ) {
#  print "\n\nhere!! desc:$sifrawdesc{$index}\n\n";
  my $agg_vlan_no = $sifrawdesc{$index};
  $agg_vlan_no =~ s/\D//g;
  my $ctr = 0;
  foreach my $key (sort(keys %iftovlan)) {
#	print "key:$key;agg:$agg_vlan_no;index:$index\n\n\n\n";
    if ($iftovlan{$key} == $agg_vlan_no) {
#      print "\n\na hit!!\n\n";
      if ($ctr == 0) {
	print "${c}Target[$name]: $key:$community\@$router";
      }
      else {
	print " + $key:$community\@$router";
      }
      $ctr++;
    }
  }
}
else {
  print "${c}Target[$name]: $index:$community\@$router";
}

print <<ECHO;
${c}
${c}Directory[$name]:$sysName
${c}MaxBytes[$name]: $speed
${c}Title[$name]: $sysName ($iphost{$index}): $sifdesc{$index}
${c}PageTop[$name]: 
Traffic Analysis for $sifdesc{$index}
${c} $sciscodescr{$index}
${c} 
${c}    System: $sysName in $sysLocation
${c}    Maintainer: $sysContact
${c}    Interface: $sifdesc{$index} ($index)
${c}    IP: $iphost{$index} ($ipaddr{$index})
${c}    Max Speed:
${c}        $speed_str ($ifType_d{$siftype{$index}})
${c}  
${c}
#---------------------------------------------------------------
ECHO
  }
}
  
main;
exit(0);

sub fmi {
  my($number) = $_[0];
  my(@short);
  @short = ("Bytes/s","kBytes/s","MBytes/s","GBytes/s");
  my $digits=length("".$number);
  my $divm=0;
  while ($digits-$divm*3 > 4) { $divm++; }
  my $divnum = $number/10**($divm*3);
  return sprintf("%1.1f %s",$divnum,$short[$divm]);
}

