Previous section   Next section

Recipe 2.16 Generating a Server Host Table File

2.16.1 Problem

You want to build a detailed host file containing the IP addresses and interface names of all of your routers.

2.16.2 Solution

The Perl script in Example 2-4, host.pl, builds a detailed host table that includes all of the IP addresses on each router in a list of devices. The script is written in Perl and requires NET-SNMP to extract data from the router list. No arguments are expected or required.

Example 2-4. host.pl
#!/usr/local/bin/perl
#
#         host.pl -- a script to build a detailed host file from
#                    information gathered from a router list.
#
#Set behavior
$workingdir="/home/cisco/net";
$snmpro="ORARO";
#
$rtrlist="$workingdir/RTR_LIST";
$snmpwalk="/usr/local/bin/snmpwalk -v 1 -c $snmpro";
$snmpget="/usr/local/bin/snmpget -v 1 -c $snmpro";
open (RTR, "$rtrlist") || die "Can't open $rtrlist file";
open (RESULT, ">$workingdir/RESULT") || die "Can't open RESULT file";
while (<RTR>) {
   chomp($rtr="$_");
   @ifIndex=`$snmpwalk $rtr ipAdEntIfIndex`;
   @ipAddress=`$snmpwalk $rtr ipAdEntAddr`;
   $rtr1=`$snmpget $rtr .1.3.6.1.4.1.9.2.1.3.0`;
   chomp(($foo, $RTR) = split (/"/, $rtr1));
   $arraynum=0;
   for $ifnumber (@ifIndex) {
      chomp(($foo, $ifnum) = split(/= /, $ifnumber));
      $ifDescription=`$snmpget $rtr ifName.$ifnum`;
      chomp(($foo, $ipaddr) = split(/: /, $ipAddress[$arraynum]));
      chomp(($foo, $ifdes) = split(/= /, $ifDescription));
      $name="$RTR-$ifdes";
      #$name=~s/\//-/;
      if ( $ifdes eq "Lo0" ) { $name=$RTR };
      print RESULT "$ipaddr\t\t$name\n";
      $arraynum++;
   }
}
close(RTR);
close(RESULT);

2.16.3 Discussion

Most organizations manually build a host table for their management server(s), with a single IP entry per router, usually the loopback IP address. This script automatically builds a host file that contains all known IP addresses for each router.

Here is an example of the output from the host.pl script:

10.1.1.1                miami-Se0/0
10.2.2.2                miami
172.20.6.8              miami-Se0/2
172.22.1.4              miami-Fa1/0
172.25.1.8              miami-Et0/0
10.1.1.2                toronto-Se0/1
172.20.1.1              toronto-Se0/0.2
172.22.1.1              toronto-Fa0/1
172.25.1.5              toronto-Fa0/0.1
172.25.2.1              toronto-Se0/0.1
172.25.25.1             toronto
172.25.26.5             toronto-Lo1
10.1.99.55              detroit-BR0
172.25.3.7              detroit-Et0
172.25.25.6             detroit
172.20.1.2              boston-Se0.1
172.20.10.1             boston-Et0
172.20.100.1            boston

This output is in the format required for a Unix /etc/hosts file. The script extracts the IP address information via SNMP, then associates each address with the related router name and interface. The script also creates a primary host entry for each router using the address of the loopback0 interface, but with no interface information in the hostname. In this example, you can reach the router located in Boston with hostname boston rather than the less intuitive boston-Lo0.

Having a detailed host file is useful for many reasons. Sometimes the router will send a message to your server, either using SNMP or syslog, and use the IP address of the interface instead of a main loopback interface. Also, having a detailed host file makes the output of a traceroute command much easier to understand:

Freebsd% traceroute miami
traceroute to miami (10.2.2.2), 64 hops max, 52 byte packets
 1  detroit-Et0      (172.25.3.7)  2.263 ms  2.210 ms  2.178 ms
 2  toronto-Fa0/0.1  (172.25.1.5)  3.042 ms  3.060 ms  3.846 ms
 3  boston-Se0.1     (172.20.1.2)  8.234 ms  8.245 ms  8.145 ms
 4  miami-Se0/2      (172.20.6.8)  9.893 ms  9.893 ms  9.432 ms       
Freebsd%

This makes it much easier to decipher the path between the management station and the Miami router. Not only can we tell which routers lie along the path, but we can also clearly see which interfaces a packet sent along this path will use.

The script does not update the /etc/hosts file directly. You may need to manually import the script's output file into your system's /etc/hosts file. However, you can make this task easier by building a master file containing your normal host information and concatenating this master file together with the script output. This way you could even use the cron utility to automatically run this script and create a new up-to-date host file on a nightly basis.

Before the script will work, you must modify two variables. The $workingdir variable must be set to the directory that you will launch the script from. The $snmpro variable must be set to your SNMP read-only community string. The script assumes that you use the same read-only community string on all of your routers.

The script reads through a router list, and queries each device in sequence. It expects to find this list in a file called RTR_LIST in the working directory. The list can contain router names or IP addresses, with one entry per router, and one router per line. The script will extract the hostname directly from the router so you should also ensure that all of your routers are configured with unique hostnames. The results of the script are stored in a file called RESULT, contained in the working directory.

As a final note, we should mention that this script can generate hostnames that do not confirm to RFC 952, "DoD Internet Host Table Specification," which defines the official rules for hostnames. This is because the script can create hostnames with a forward slash (/) character in them, such as miami-Se0/2. This may cause problems for some applications, particularly if they use URL format addressing. For example, a query to http://miami-Se0/2 will clearly cause problems because the last character, "2", will be interpreted as a filename. However, most common applications such as ping and Telnet will accept this hostname without any complaints.

If you are a purist, or have applications that complain about these hostnames, we've included a line in the script that you can use to convert all of the slashes (/) to dashes (-). This line is currently commented out, but you can invoke it by simply removing the comment character (#) to change this line:

#$name=~s/\//-/;

to this:

$name=~s/\//-/;

2.16.4 See Also

RFC 952


  Previous section   Next section
Top