#!/usr/bin/perl use strict 'subs'; # 0.50 - Written by Douglas Rand # 0.60 - Modified by Patrick Ryan 12-1-1999 ## Line "foreach $i (ip2int($begin) .. ip2int($end)) {" replaced by ## "for ($i = ip2int($begin), $j = ip2int($end); $i < $j; $i++) {" # 0.70 - Modified by Leif Sawyer 12-10-1999 ## patches to ignore scopes with no active leases ## patches to automatically format for HTML based on environment # 0.80 - Modified by Simon Barnes 1/19/2000 ## patches to allow single-host ranges # 0.82 - Some cleanups, Leif Sawyer 3/10/2000 $Version = "0.82"; require "timelocal.pl"; require "newgetopt.pl"; use Time::ParseDate; &NGetOpt("detail:s"); print "getopt\n" if defined($opt_detail); @WDays = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"); @MNames = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); $PathLeases = "/var/dhcpd/dhcpd.leases"; $PathConfig = "/etc/dhcpd/dhcpd.conf"; my(%IP); my($DEBUG) = 0; $IPPat = "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"; $date=`/bin/date`; chop $date; my($HTML); $HTML = (defined($ENV{"REQUEST_METHOD"}) && $ENV{"REQUEST_METHOD"} ne "")?1:0; print "Content-type: text/plain\n\n" if $HTML; print "DHCP Lease stats for $date\n"; open(CONFIG, "<$PathConfig") || die "Canot open $PathConfig: $!\n"; open(LEASES, "<$PathLeases") || die "Cannot open $PathLeases: $!\n"; my($subnet,$netmask); while() { chop; # print "$_\n" if $DEBUG; if(/^\s*subnet\s+($IPPat)\s+netmask\s+($IPPat)/) { print "subnet = $1, netmask = $2\n" if $DEBUG; $subnet = $1; $netmask = $2; $network{$subnet} = 1; } if (/^\s*range\s+/) { if(/^\s*range\s+($IPPat)\s+($IPPat)\s*;\s*$/) { $begin = $1, $end = $2; } elsif (/^\s*range\s+($IPPat)\s*;\s*$/) { $begin = $1, $end = $1; } else { die "range found, but can't parse range data:\n$_\n$!"; } for ($i = ip2int($begin), $j = ip2int($end); $i <= $j; $i++) { #print "i=$i, int2ip->" . int2ip($i) . ", subnet=$subnet\n" if $DEBUG; $range{int2ip($i)} = $subnet; $IP{$subnet}{$i} = 1; } } } while() { $ip = $1 if /^lease (\d+\.\d+\.\d+\.\d+) \{$/; $start{$ip} = $1 if /^\tstarts \d (\d+\/\d+\/\d+ \d+:\d+:\d+);$/; $end{$ip} = $1 if ((/^\tends \d (\d+\/\d+\/\d+ \d+:\d+:\d+);$/) || (/^\tends (never);$/)); $hwtype{$ip} = $1, $hwaddress{$ip} = $2 if /^\thardware (ethernet|token-ring) ([0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+);/; $abandoned{$ip} = 1 if /^\tabandoned;$/; $hostname{$ip} = $1 if/^\tclient-hostname \"(.*)\";$/; } $time = time(); print "IP Address Status Lease Begin Lease End HW Address\n" if defined($opt_detail); foreach $ip (sort ipsort keys %range) { $net = $range{$ip}; $Total{$net}++; if($start{$ip}) { $startSecs = parsedate("$start{$ip} GMT"); if ($end{$ip} != "never") { $endSecs = parsedate("$end{$ip} GMT"); $end = &mktime($endSecs); } else { $endSecs = "never"; $end = "never"; } $start = &mktime($startSecs); if(($endSecs >= $time) || ($endSecs eq "never")) { $status = "Active"; $Active{$net}++ unless $abandoned{$ip}; } else { $status = "Expired"; $Expired{$net}++ unless $abandoned{$ip}; $Available{$net}++ unless $abandoned{$ip}; } } else { $start = ""; $end = ""; $status = "Unused"; $Unused{$net}++; $Available{$net}++ unless $abandoned{$ip}; } if($abandoned{$ip}) { $status = "Abandoned"; $Abandoned{$net}++; } printf("%-15s %-9s %19s %19s %17s\n", $ip, $status, $start, $end, $hwaddress{$ip}) if defined($opt_detail); } if(!defined($opt_detail)) { print "Network Active Available Abandoned Total\n"; foreach $net (sort ipsort keys %network) { print "net = $net, Active = $Active{$net}, total = $Total{$net}\n" if $DEBUG; printf("%-15s %4d/%3.0f%% %4d/%3.0f%% %4d/%3.0f%% %4d\n", $net, $Active{$net}, ($Total{$net}>0?($Active{$net} / $Total{$net}):0) * 100.0, $Available{$net}, ($Total{$net}>0?($Available{$net} / $Total{$net}):0) * 100.0, $Abandoned{$net}, ($Total{$net}>0?($Abandoned{$net} / $Total{$net}):0) * 100.0, $Total{$net}) if ($Active{$net} > 0); } } print "\n"; sub mktime { my($secs) = shift; my($time, $year, $month, $day, $hour, $minute, $seconds, $wday); ($second, $minute, $hour, $day, $month, $year, $wday) = localtime($secs); $time = sprintf("%s %s %2d %2d:%02d:%02d", $WDays[$wday], $MNames[$month], $day, $hour, $minute, $second); return($time); } sub ip2int { my($ip) = shift; my($number) = 0; $number = $1 * 256 * 256 * 256 + $2 * 256 * 256 + $3 * 256 + $4 if $ip =~ /^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/; return $number; } sub int2ip { my($number) = shift; my($ip); $ip = ($number & 0xff000000) / (256 * 256 * 256); $ip .= "." . ($number & 0x00ff0000) / (256 * 256); $ip .= "." . ($number & 0x0000ff00) / (256); $ip .= "." . ($number & 0x000000ff); return $ip; } sub ipsort { my(%A, %B); $A[0] = $1, $A[1] = $2, $A[2] = $3, $A[3] = $4 if $a =~ /^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/; $B[0] = $1, $B[1] = $2, $B[2] = $3, $B[3] = $4 if $b =~ /^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/; return $A[0] <=> $B[0] if $A[0] != $B[0]; return $A[1] <=> $B[1] if $A[1] != $B[1]; return $A[2] <=> $B[2] if $A[2] != $B[2]; return $A[3] <=> $B[3]; }