#!/usr/bin/perl

##################################################################
# MRTG 2.8.9  -- Config file creator
##################################################################
# Created by Jon Rifkin <j.rifkin@uconn.edu>
# this converts the Index and IP interface targets from a config
# file to Physical Address targets.
#################################################################
#
# Distributed under the GNU copyleft

#
# Two ways to use this script
#
#   1 - Convert existing config files
#     Usage:   cfgmaker_phys old.cfg > new.cfg

#   2 - Create new files with hard address
#     Usage:   cfgmaker public@127.0.20.1 | cfgmaker_phys > 127.0.20.1.cfg
#
# NOTE:  While this conversion will make mrtg query the interfaces according to their
#        Physical Address (also known as "Hard Address" or "MAC Address"), instead
#        of the interface Index, it will not change the output file names in the
#        "WorkDir".  These file are typically named for the Index - at least they
#        are the by script 'cfgmaker'.
#
#        An interface which changes its Index will maintain its Physical Address.
#        But the file names (.html, .log files) might reflect the old Index value.
#        This is OK, it will not change any functionality in MRTG, but it might
#        cause confusion if you mistake the file names for the interface Index.
#    JR Oct 21, 1999

use SNMP_Session "0.71";
use BER "0.66";
use SNMP_util "0.71";

while (<>) {

	#  Not a target statement, print this line and read next
	if ( ! /^\s*target\s*\[([^\]]+)\]\s*:(.*)$/i ) {
		print $_;
		next;
	}

	#  If target includes ! then pass
	if (/!/) {
		print $_;
		next;
	}

	#  If target includes oid of form 1.2.16.2.... then pass
	if (/\d+\.\d+\.\d+:/) {
		print $_;
		next;
		}

	#  Print current target as comment
	print "### $_";

	#  Break down target statement
	$tname = $1;
	($var,$router) = ($2 =~ /\s*([^:]+):(.*)$/);
	$var =~ s/^\s+//;
	$var =~ s/\s+$//;

	#  Convert form   2:public@1.2.3.4  
        #             to !xx-xx-xx-xx-xx-xx:public@1.2.3.4
	if ($var =~ /^(\d+)$/) {
		$phys = &getphysaddress($router,$1);
		#  Test for null physical address (it happens sometimes)
		if ($phys eq "") {
			print STDERR "ERROR at target line: $_";
			print STDERR "   No Physical Address associated with interface \"$1\", not converting.\n";
			print $_;
			next;
			}
		print "Target[$tname]: !$phys:$router\n";
		next;
		}

	#  Convert form   /5.6.7.8:public@1.2.3.4  
        #             to !xx-xx-xx-xx-xx-xx:public@1.2.3.4
	if ($var =~ /^\/(\d+\.\d+\.\d+\.\d+)$/) {
		($intf) = &snmpget ($router, "ipAdEntIfIndex.$1");
		$phys   = &getphysaddress($router,$intf);
		#  Test for null physical address (it happens sometimes)
		if ($phys eq "") {
			print STDERR "ERROR at target line: $_";
			print STDERR "   No Physical Address associated with interface IP \"/$1\", not converting.\n";
			print $_;
			next;
			}
		print "Target[$tname]: !$phys:$router\n";
		next;
		}


	#  Convert form  InErrors.3&OutErrors.3:public@1.2.3.4
	#            or  InErrors/5.6.7.8&InErrors/5.6.7.8:public@1.2.3.4
	#            to  InErrors!xx-xx-xx-xx-xx-xx&OutErrors!xx-xx-xx-xx-xx-xx:public@1.2.3.4
	#
	@var = split (/&/, $var);
	@newvar = ();
	for $v (@var) {
		#  Interface notation
		if ($v =~ /^([^.\/]+)\.(.*)$/) {
			$vname = $1;
			$intf  = $2;
		}
		#  IP notation, get interface from IP
		elsif ($v =~ m!^([^/]+)\/(.*)$!) {
			$vname = $1;
			($intf) = &snmpget ($router, "ipAdEntIfIndex.$2");
		}
		#  unrecongnized
		else {
			print "#  cfgconvert  cannot recognize following target\n";
			print $_;
			last;
		}

		#  Get physaddress from interface
		$phys = &getphysaddress($router, $intf);


		#  Test for null physical address (it happens sometimes)
		if ($phys eq "") {
			print STDERR "ERROR at target line: $_";
			print STDERR "   No Physical Address associated with target \"$v\", not converting\n";
			push @newvar, $v;
			next;
			}

		#  Add this variable (with phys address) to pair
		push @newvar, "$1!$phys";
	}
	print "Target[$tname]: ", join("&",@newvar), ":$router\n";
}

	

sub getphysaddress {
	my ($router,$intf) = @_;
	my ($b, $bin, @bin, @phys);
	($bin) = &snmpget ($router, "ifPhysAddress.$intf");
	@bin = split (//, $bin);
	@phys = ();
	for $b (split (//,$bin)) {
		push @phys, unpack("H*", $b);
	}
	$phys = join "-", @phys;
}
