1 |
#!/usr/bin/perl |
2 |
|
3 |
my $path_to_leasefile = "/var/lib/dhcp/dhcpd.leases"; |
4 |
my $ping_ttl = .3; |
5 |
my $date_format = "%m-%d-%Y %I:%M%p"; |
6 |
|
7 |
use strict; |
8 |
use Net::Ping; |
9 |
#To convert the UTC times to seconds since the epoch |
10 |
use Time::Local; |
11 |
#To format the output time |
12 |
use POSIX ("strftime"); |
13 |
use Term::ANSIColor; |
14 |
use Getopt::Long; |
15 |
#use Getopt::Long (":config", "bundling"); |
16 |
use Term::ANSIColor (":constants"); |
17 |
$Term::ANSIColor::AUTORESET = 1; |
18 |
|
19 |
#Populate all the command line variables |
20 |
my ($showmac,$showatm,$showip,$showexpired,$help,$color); |
21 |
GetOptions('mac|m' => \$showmac,'atm|a' => \$showatm,'ip|i=s' => \$showip,'expired|x' => \$showexpired,'help|h'=>\$help,'color|c'=>\$color); |
22 |
|
23 |
$ENV{'REQUEST_METHOD'}; |
24 |
|
25 |
#Display the usage if they pass in --help or -h |
26 |
if ($help) { die(&usage()); } |
27 |
|
28 |
my @list; |
29 |
my %hash; |
30 |
my ($count,$expired_lease); |
31 |
|
32 |
#Open the lease file to begin parsing it |
33 |
open (INFILE,$path_to_leasefile); |
34 |
|
35 |
#print "$< - $>\n"; |
36 |
|
37 |
$expired_lease=0; |
38 |
while (<INFILE>) { |
39 |
if ($_ =~ /lease (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/i) { |
40 |
|
41 |
my $ip = $1; |
42 |
my $hostname = undef; |
43 |
my $remoteid = undef; |
44 |
my $macaddr = undef; |
45 |
my $lease_start = undef; |
46 |
my $lease_end = undef; |
47 |
# Go until you see a } which is the end of record char |
48 |
while ($_ !~ /^}$/) { |
49 |
$_ = <INFILE>; |
50 |
if ($_ =~ /starts/) { |
51 |
$lease_start = &leasegm_to_epoch($_); |
52 |
} |
53 |
elsif ($_ =~ /ends/) { |
54 |
$lease_end = &leasegm_to_epoch($_); |
55 |
} |
56 |
elsif ($_ =~ /client-hostname \"(.*)\"/ ) { |
57 |
$hostname = $1; |
58 |
} |
59 |
elsif ($_ =~ /option agent\.remote-id (.*);/ ) { |
60 |
$remoteid = $1; |
61 |
} |
62 |
elsif ($_ =~ /hardware ethernet (.*);/ ) { |
63 |
$macaddr = $1; |
64 |
} |
65 |
} |
66 |
|
67 |
my $expired = &lease_expired($lease_end); |
68 |
|
69 |
#If we're not searching for ONE IP and the lease isn't expired add it to the hash |
70 |
if (!$showip && !$expired) { |
71 |
# Put it in the hash no matter what, if showip isn't set because it will overwrite |
72 |
$hash{$ip}={"hostname"=>$hostname,"remoteid"=>$remoteid,"mac"=>$macaddr,"lease_end"=>$lease_end}; |
73 |
} |
74 |
elsif ($showip && $ip =~ /$showip/ && !$expired) { |
75 |
# Only populate the hash if it matches the passed in request |
76 |
$hash{$ip}={"hostname"=>$hostname,"remoteid"=>$remoteid,"mac"=>$macaddr,"lease_end"=>$lease_end}; |
77 |
} |
78 |
elsif ($expired) { |
79 |
#if ($showexpired) { |
80 |
# my $ctime = strftime("%m-%d-%Y %I:%M%p",localtime($lease_end)); |
81 |
# print "Expired: $ip\t($ctime)\n"; |
82 |
#} |
83 |
$expired_lease++; |
84 |
} |
85 |
|
86 |
$count++; |
87 |
} |
88 |
} |
89 |
|
90 |
close INFILE; |
91 |
|
92 |
if ($showip) { |
93 |
print "Showing IPs that match \"$showip\"\n"; |
94 |
} |
95 |
|
96 |
@list = sort(keys %hash); |
97 |
my $total = scalar(@list) + 1; |
98 |
|
99 |
my $maxlen; |
100 |
#get the length of the longest IP |
101 |
for my $ip(@list) { |
102 |
if ($maxlen < length($ip)) { $maxlen = length($ip); } |
103 |
} |
104 |
|
105 |
my $output; |
106 |
#$output .= "Content-Type: text/html\n\n"; |
107 |
#$output .= "Checking $total ($count dupes) leases for validity\n"; |
108 |
print "Checking $total leases ($expired_lease expired) for validity\n"; |
109 |
|
110 |
my $ping = Net::Ping->new("icmp"); |
111 |
my $count=0; |
112 |
|
113 |
foreach my $ip (@list) { |
114 |
my $result = $ping->ping($ip,$ping_ttl); |
115 |
if ($result) { |
116 |
$result = "Alive"; |
117 |
if ($color) { $result = GREEN $result; } |
118 |
$count++; |
119 |
} |
120 |
else { |
121 |
$result = "Dead"; |
122 |
if ($color) { $result = RED $result; } |
123 |
} |
124 |
|
125 |
# Get the hostname part |
126 |
my $hostname; |
127 |
$hostname = $hash{$ip}->{'hostname'}; |
128 |
if (!$hostname) { |
129 |
$hostname = "*blank*"; |
130 |
if ($color) { $hostname = BOLD BLUE $hostname; } |
131 |
} |
132 |
|
133 |
my $lease_end; |
134 |
#If we're showing when the leases expire |
135 |
if ($showexpired) { |
136 |
#If the year is great than 2020 (my way of representing "never") than it's a |
137 |
#lease that doesn't expire |
138 |
if (strftime("%Y",localtime($hash{$ip}->{lease_end})) > 2020) { |
139 |
$lease_end = "Never"; |
140 |
if ($color) { $lease_end = BOLD WHITE $lease_end; } |
141 |
$lease_end = &padtext($lease_end,length($lease_end)+2); |
142 |
} |
143 |
#Show the date in the date format |
144 |
else { |
145 |
$lease_end = strftime($date_format,localtime($hash{$ip}->{lease_end})); |
146 |
$lease_end = padtext($lease_end,length($lease_end)+2); |
147 |
} |
148 |
} |
149 |
else { $lease_end = ""; } |
150 |
|
151 |
# Get the agentid |
152 |
my $remoteid; |
153 |
$remoteid = $hash{$ip}->{'remoteid'} or $remoteid = "none"; |
154 |
|
155 |
my $mac; |
156 |
if ($showmac) { $mac = $hash{$ip}->{'mac'} or $mac = ""; } |
157 |
my $atm; |
158 |
if ($showatm) { $atm = $hash{$ip}->{'remoteid'} or $atm = ""; } |
159 |
if ($showatm) { $atm = &getoption82($atm); } |
160 |
|
161 |
$ip = padtext($ip,$maxlen + 2); |
162 |
$mac = padtext($mac,19); |
163 |
|
164 |
if (!$color) { $result = padtext($result,7); } |
165 |
else { $result = padtext($result,16); } |
166 |
|
167 |
$atm = padtext($atm,5); |
168 |
$hostname = padtext("($hostname)",20); |
169 |
|
170 |
my $outline = "$ip$result$mac$atm$lease_end$hostname\n"; |
171 |
print $outline; |
172 |
} |
173 |
|
174 |
my $percent; |
175 |
if (!$total == 0) { |
176 |
$percent = sprintf("%2.f%%", ($count/$total) * 100); |
177 |
} |
178 |
else { |
179 |
$percent = "100%"; |
180 |
} |
181 |
print "$count active leases ($percent)\n"; |
182 |
#$output .= "$count active leases ($percent)\n"; |
183 |
print $output; |
184 |
|
185 |
sub getoption82 () { |
186 |
my $data = shift; |
187 |
if (!$data) { return -1; } |
188 |
|
189 |
my @list = split(":",$data); |
190 |
my $vpi = hex($list[9]); |
191 |
my $vci = (hex($list[10]) * 16) + hex($list[11]); |
192 |
return "$vpi-$vci"; |
193 |
} |
194 |
|
195 |
sub padtext() { |
196 |
my $str = shift; |
197 |
my $len = shift; |
198 |
if (!$str || !$len) { return $str; } |
199 |
|
200 |
$str = sprintf("%-${len}s",$str); |
201 |
return $str; |
202 |
} |
203 |
|
204 |
sub leasegm_to_epoch() { |
205 |
my ($sec,$min,$hours,$mday,$mon,$year); |
206 |
|
207 |
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})/) { |
208 |
$sec = $list[7]; |
209 |
$min = $list[6]; |
210 |
$hours = $list[5]; |
211 |
$mday = $list[4]; |
212 |
$mon = $list[3] - 1; |
213 |
$year = $list[2] - 1900; |
214 |
} |
215 |
elsif (my @list = $_[0] =~ /ends never/) { |
216 |
$sec = 1; |
217 |
$min = 1; |
218 |
$hours = 1; |
219 |
$mday = 1; |
220 |
$mon = 1; |
221 |
$year = 132; |
222 |
} |
223 |
else { die("Whoa that aint good!\n"); } |
224 |
|
225 |
#print "$sec,$min,$hours,$mday,$mon,$year\n"; |
226 |
my $time_string = timegm($sec,$min,$hours,$mday,$mon,$year); |
227 |
|
228 |
return $time_string; |
229 |
} |
230 |
|
231 |
# Check to see if the lease has expired |
232 |
sub lease_expired() { |
233 |
my $lease_time = shift; |
234 |
#Make sure a lease time is passed in |
235 |
if (!$lease_time) { return undef; } |
236 |
|
237 |
my $time_now = time(); |
238 |
|
239 |
#If the lease is before right now, then the lease is still good |
240 |
if ($lease_time < $time_now) { return 1; } |
241 |
#Otherwise it has expired |
242 |
else { return 0; } |
243 |
} |
244 |
|
245 |
sub usage() { |
246 |
my $output .= "$0 |
247 |
-x --expired show lease expiration times |
248 |
-m --mac show lease MAC address |
249 |
-a --atm show lease ATM (Option 82) information |
250 |
-i --IP=1.2.3.4 filter for ip 1.2.3.4 (regexp) |
251 |
-c --color show output in color for readability |
252 |
"; |
253 |
} |