#!/usr/bin/perl
my $path_to_leasefile = "/var/state/dhcp/dhcpd.leases";
use strict;
use Net::Ping;
#To convert the UTC times to seconds since the epoch
use Time::Local;
#To format the output time
use POSIX ("strftime");
use Term::ANSIColor;
use Getopt::Long (":config", "bundling");
use Term::ANSIColor (":constants");
$Term::ANSIColor::AUTORESET = 1;
my ($showmac,$showatm,$showip,$showexpired,$help);
GetOptions('mac|m' => \$showmac,'atm|a' => \$showatm,'ip|i=s' => \$showip,'expired|x' => \$showexpired,'help|h'=>\$help);
if ($help) { die(&usage()); }
my @list;
open (INFILE,$path_to_leasefile);
my %hash;
my ($count,$expired_lease);
$expired_lease=0;
while (<INFILE>) {
if ($_ =~ /lease (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/i) {
my $ip = $1;
my $hostname = undef;
my $remoteid = undef;
my $macaddr = undef;
my $lease_start = undef;
my $lease_end = undef;
# Go until you see a } which is the end of record char
while ($_ !~ /}/) {
$_ = <INFILE>;
if ($_ =~ /starts/) {
$lease_start = &leasegm_to_epoch($_);
}
elsif ($_ =~ /ends/) {
$lease_end = &leasegm_to_epoch($_);
}
elsif ($_ =~ /client-hostname \"(.*)\"/ ) {
$hostname = $1;
}
elsif ($_ =~ /option agent\.remote-id (.*);/ ) {
$remoteid = $1;
}
elsif ($_ =~ /hardware ethernet (.*);/ ) {
$macaddr = $1;
}
}
my $expired = &lease_expired($lease_end);
#If we're not searching for ONE IP and the lease isn't expired add it to the hash
if (!$showip && !$expired) {
# Put it in the hash no matter what, if showip isn't set because it will overwrite
$hash{$ip}={"hostname"=>$hostname,"remoteid"=>$remoteid,"mac"=>$macaddr,"lease_end"=>$lease_end};
}
elsif ($showip && $ip =~ /$showip/ && !$expired) {
# Only populate the hash if it matches the passed in request
$hash{$ip}={"hostname"=>$hostname,"remoteid"=>$remoteid,"mac"=>$macaddr,"lease_end"=>$lease_end};
}
elsif ($expired) {
#if ($showexpired) {
# my $ctime = strftime("%m-%d-%Y %I:%M%p",localtime($lease_end));
# print "Expired: $ip\t($ctime)\n";
#}
$expired_lease++;
}
$count++;
}
}
close INFILE;
if ($showip) {
print "Showing IPs that match \"$showip\"\n";
}
@list = sort(keys %hash);
my $total = scalar(@list) + 1;
my $maxlen;
#get the length of the longest IP
for my $ip(@list) {
if ($maxlen < length($ip)) { $maxlen = length($ip); }
}
my $output;
#$output .= "Content-Type: text/html\n\n";
#$output .= "Checking $total ($count dupes) leases for validity\n";
print "Checking $total leases ($expired_lease expired) for validity\n";
my $ping = Net::Ping->new("icmp");
my $count=0;
foreach my $ip (@list) {
my $result = $ping->ping($ip,1);
if ($result) {
$result = GREEN "Alive";
$count++;
}
else { $result = RED "Dead"; }
# Get the hostname part
my $hostname;
$hostname = $hash{$ip}->{'hostname'} or $hostname = BOLD BLUE "*blank*";
my $lease_end;
if ($showexpired) {
if (strftime("%Y",localtime($hash{$ip}->{lease_end})) > 2020) {
$lease_end = "Never";
$lease_end = padtext($lease_end,20);
}
else {
$lease_end = strftime("%m-%d-%Y %I:%M%p",localtime($hash{$ip}->{lease_end}));
$lease_end = padtext($lease_end,20);
}
}
else { $lease_end = ""; }
# Get the agentid
my $remoteid;
$remoteid = $hash{$ip}->{'remoteid'} or $remoteid = "none";
my $mac;
if ($showmac) { $mac = $hash{$ip}->{'mac'} or $mac = ""; }
my $atm;
if ($showatm) { $atm = $hash{$ip}->{'remoteid'} or $atm = ""; }
if ($showatm) { $atm = &getoption82($atm); }
$ip = padtext($ip,$maxlen + 2);
$mac = padtext($mac,19);
$result = padtext($result,16);
$atm = padtext($atm,5);
$hostname = padtext("($hostname)",20);
my $outline = "$ip$result$mac$atm$lease_end$hostname\n";
print $outline;
}
my $percent;
if (!$total == 0) {
$percent = sprintf("%2.f%%", ($count/$total) * 100);
}
else {
$percent = "100%";
}
print "$count active leases ($percent)\n";
#$output .= "$count active leases ($percent)\n";
print $output;
sub getoption82 () {
my $data = shift;
if (!$data) { return -1; }
my @list = split(":",$data);
my $vpi = hex($list[9]);
my $vci = (hex($list[10]) * 16) + hex($list[11]);
return "$vpi-$vci";
}
sub padtext() {
my $str = shift;
my $len = shift;
if (!$str || !$len) { return $str; }
$str = sprintf("%-${len}s",$str);
return $str;
}
sub leasegm_to_epoch() {
my ($sec,$min,$hours,$mday,$mon,$year);
if (my @list = $_[0] =~ /(\w+)\s+(\d+)\s+(\d{4})\/(\d{1,2})\/(\d{1,2})\s+(\d{1,2}):(\d{1,2}):(\d{1,2})/) {
$sec = $list[7];
$min = $list[6];
$hours = $list[5];
$mday = $list[4];
$mon = $list[3] - 1;
$year = $list[2] - 1900;
}
elsif (my @list = $_[0] =~ /ends never/) {
$sec = 1;
$min = 1;
$hours = 1;
$mday = 1;
$mon = 1;
$year = 132;
}
else { die("Whoa that aint good!\n"); }
#print "$sec,$min,$hours,$mday,$mon,$year\n";
my $time_string = timegm($sec,$min,$hours,$mday,$mon,$year);
return $time_string;
}
sub lease_expired() {
my $lease_time = shift;
if (!$lease_time) { return undef; }
my $time_now = time();
if ($lease_time < $time_now) {
return 1;
}
else {
return 0;
}
}
sub usage() {
my $output .= "$0
-x --expired show lease expiration times
-m --mac show lease MAC address
-a --atm show lease ATM (Option 82) information
-i --IP=1.2.3.4 filter for ip 1.2.3.4 (regexp)
";
}
syntax highlighted by Code2HTML, v. 0.9