Category: Utilities
Author/Contact Info seanbo
sean@chienbizarre.com
Description: This is used to munge through a DHCP lease file to determine information about corrupt records, expired leases, do a comparison on laptops vs. desktops (which here is determined by a 2 hour long lease is a laptop), by subnet.
#!/usr/bin/perl -w
#*******************************************************
# Programmer:   Sean L. Ryle
# Program:      dhcpleases.pl (ls dhcp leases)
# Date:         03.19.2001
# Purpose:      To search for and sort the DHCP lease
#               file.
# Modification Log
# Ini   Date            Notes
# ---   ----------      --------------------
# SLR   03.19.2001      Creation of this script
# SLR   03.21.2001      added Date::Manip usage
# SLR   04.20.2001      added Getopt::Std usage
#
#*******************************************************

use Date::Manip;
use Getopt::Std;

#lease file, will need to be modified when put
#in production to reflect the correct path
$LEASE_FILE = "dhcp.leases";

#get command line args
getopts('adlthsu', \%opts);

#if help is requested, print help & go no further
if($opts{'h'})
{
   print_help();
   exit 0;
}

$ip_re   = qr(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3});  # Matches an IP #
$date_re = qr(\d\d\d\d/\d\d/\d\d \d\d:\d\d:\d\d);   # Matches a date a
+nd time
$Hbyte_re= qr([\da-f][\da-f]);                      # Matches two hex 
+digits
$mac_re  = qr((?:$Hbyte_re:){5}$Hbyte_re);          # Matches a MAC ad
+dress

$regex = qr(
  ^ lease              \s ($ip_re) \s {\n          # Match 'lease' &  
+save IP
\s* starts             \s \d \s ($date_re);\n      # Match and save st
+art date
\s* ends               \s \d \s ($date_re);\n      # Match and save en
+d date
(?:\s* (abandoned);\n)?                            # Match abandoned
(?:\s* hardware\sethernet \s ($mac_re);\n)?        # Match and save 1s
+t MAC
(?:\s* uid                \s (\d\d:$mac_re);\n)?   # Match and save ui
+d
(?:\s* client-hostname    \s "([^"]+)";\n)?        # Match and save na
+me
}$)x;

#open the file for reading
open(LF, $LEASE_FILE) || die "Error: $!\n$LEASE_FILE could not be open
+ed.\n";
local $/ = "}\n";
while($record = <LF>) {
    #print "$record\n";     #used for debugging
    unless(($ip, $start, $end, $abd, $mac, $uid, $name) = $record =~ m
+/$regex/)
    {
        #save the bad record in case retrieeval is requested
        $bad{$.} = $record;
        next;
    }

    if(defined($abd))
    {
       $aban{$ip} = $record;

    } else
    {
      $d=&DateCalc($start,$end);

      if($d eq "+0:0:0:0:2:0:0")
      {
         $laptop{$ip} = $record;
      } else {

         $desktop{$ip} = $record;
      }

    }

}


#close the file
close(LF);

    #process command like args
       foreach my $parm(keys(%opts)) {

          if($opts{'a'}) {

             sort_ips(\%aban);

          }elsif($opts{'d'}) {

             sort_ips(\%desktop);

          }elsif($opts{'l'}) {

             sort_ips(\%laptop);

          }elsif($opts{'t'}) {

             print_abd_records();

          }elsif($opts{'s'}) {

             lease_summary();

          }elsif($opts{'u'}) {

             print_bad_records();

          }elsif($opts{'h'}) {

            print_help();

          }else{

            print_help();
          }
       }

exit;

sub print_info()
{
    print "IP:\t$ip\n";
    print "Start:\t$start\n";
    print "End:\t$end\n";
    print "MAC1:\t$mac\n";
    print "UID:\t$uid\n";
    print "Name:\t$name\n";
    print "Aban:\t$abd\n";
    print "---------------\n";
}

sub print_bad_records()
{
    print "Bad Record Detail\n";
    print "-----------------\n";

    foreach my $element(keys(%bad))
    {
        print "Record #$element:\n$bad{$element}";
    }

    print "\n";
}

sub print_abd_records()
{
    print "Abandonded Record Detail\n";
    print "------------------------\n";

    foreach my $element(keys(%aban))
    {
        print "IP Address: $element\n$aban{$element}";
    }

    print "\n";
}

sub lease_summary()
{
    print "DHCP Lease Summary\n";
    print "------------------\n";
    print "Unparsable:\t".keys(%bad)."\n";
    print "Abandonded:\t".keys(%aban)."\n";
    print "Desktop:\t".keys(%desktop)."\n";
    print "Laptop:\t\t".keys(%laptop)."\n";
    print "\n";
}

sub sort_ips()
{
    my %counts;
    my $hash_ref = shift;

    print "Subnet\t\tCount\n";

    foreach my $ip(keys(%$hash_ref)) {
       my $subnet = pack 'C3', split /\./, $ip;
       $counts{$subnet}++;
    }

    foreach my $subnet(sort keys(%counts)) {
       print join '.', unpack 'C3', $subnet;
       print ":\t$counts{$subnet}";
       print "\n";
    }

    print "\n";
}

sub print_help()
{
    print "lsdl [-a][-d][-l][-t][-h][-s][-u]\n";
    print "-a\tDisplay a summary of abandonded leases sorted by subnet
+.\n";
    print "-d\tDisplay a summary of deesktop leases sorted by subnet.\
+n";
    print "-l\tDisplay a summary of laptop leases sorted by subnet.\n"
+;
    print "-t\tDisplay a detail of abandonded leases sorted by subnet.
+\n";
    print "-h\tDisplay this help.\n";
    print "-s\tDisplay a summary of the entire lease file.\n";
    print "-u\tDisplay a detail of unreadable records from the lease f
+ile.\n";
}

# here is a sample file

__END__
lease 10.178.72.57 {
        starts 1 2001/03/19 18:47:27;
        ends 0 2001/03/25 18:47:27;
        hardware ethernet 00:00:d0:c0:75:5e;
        uid 01:00:00:d0:c0:75:5e;
        client-hostname "SUUUUD01";
}
lease 10.178.72.51 {
        starts 1 2001/03/19 18:47:25;
        ends 0 2001/03/25 18:47:25;
        hardware ethernet 00:00:d0:c0:75:70;
        uid 01:00:00:d0:c0:75:70;
        client-hostname "SVVVVD01";
}
lease 10.178.72.45 {
        starts 1 2001/03/19 23:47:24;
        ends 0 2001/03/20 01:47:24;
        hardware ethernet 00:00:d0:c0:75:1f;
        uid 01:00:00:d0:c0:75:1f;
        client-hostname "SWWWWD01";
}
lease 10.178.72.45 {
        ends 0 2001/03/25 18:47:24;
        hardware ethernet 00:00:d0:c0:75:1f;
        uid 01:00:00:d0:c0:75:1f;
        client-hostname "SXXXXD01";
}
lease 10.4.120.102 {
        starts 2 1999/08/17 22:48:42;
        ends 2 2038/01/19 03:14:07;
        abandoned;
        client-hostname "PreinstalledCom";
}
lease 10.4.120.103 {
        starts 2 1999/08/17 22:48:42;
        ends 2 2038/01/19 03:14:07;
        abandoned;
        client-hostname "PreinstalledCom";
}
lease 10.4.120.104 {
        starts 2 1999/08/17 22:48:42;
        ends 2 2038/01/19 03:14:07;
        abandoned;
        client-hostname "PreinstalledCom";
}