Skip to content

Instantly share code, notes, and snippets.

@mattpascoe
Last active September 17, 2018 16:30
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save mattpascoe/4348991 to your computer and use it in GitHub Desktop.
Save mattpascoe/4348991 to your computer and use it in GitHub Desktop.
Perl script to parse ISC DHCP lease file and display basic info. I dont recall if I wrote this or if I found it on the interwebs somewhere!?!?.. a quick goog search did not find it but hey its useful so have at it.
#!/usr/bin/perl
#
# Update the path to your lease file below
use strict;
use File::Copy;
#use DateTime;
#always parse a copy not the live file
#my $leasefile = '/var/lib/dhcpd/dhcpd.leases';
my $leasefile = '/var/lib/dhcp/db/dhcpd.leases';
my $tempfile = '/tmp/dhcpd.leases';
copy($leasefile,$tempfile) or die "Copy failed: $!";
#my $LocalTZ = DateTime::TimeZone->new( name => 'local' );
my $LocalTZ = '';
open LEASES, "< $tempfile" or die $!;
my @lines = <LEASES>;
close LEASES;
#Get the state of each server
my $readit;
my $line;
#valid failover states
#unknown-state, partner-down, normal, communications-interrupted, resolution-interrupted, potential-conflict, recover, recover-done, shutdown, paused, and startup
# seems like I want the last failover statement
my $my_state="cant determine";
my $my_state_time="cant determine";
my $peer_state="cant determine";
my $peer_state_time="cant determine";
my $failover = 0;
foreach $line (@lines){
if ($line=~/failover peer .*? state {/){
$readit = 1;
$failover = 1;
}
if ($readit){
if ($line=~/my\sstate\s(.*?)\sat\s\d\s(.*?)\;/){
$my_state = $1;
$my_state_time = $2;
}
if ($line=~/partner\sstate\s(.*?)\sat\s\d\s(.*?)\;/){
$peer_state = $1;
$peer_state_time = $2;
}
}
if ($readit && $line=~/^}/){
$readit = 0;
}
}
if ($failover){
$my_state_time = localize($my_state_time);
my ($mdate, $mtime) = split (/T/,$my_state_time);
$peer_state_time = localize($peer_state_time);
my ($pdate, $ptime) = split (/T/,$peer_state_time);
print "My state is $my_state at $mtime on $mdate\nPartner state is $peer_state at $ptime on $pdate\n";
}else{
print "This appears to be a stand alone server\n"
}
#Get the leases and their states
my @lease_states;
my $active = 0;
my $lease = 0;
my $ip;
my $mac=' ';
my $end_date_time;
my $start_date_time;
my $start_time;
my $start_date;
my $name;
my $state;
foreach $line (@lines){
if ($line=~/lease\s(\d+\.\d+\.\d+\.\d+)/){
$ip=$1;
$readit = 1;
$lease++;
$name="";
}
if ($readit && $line=~/starts\s\d\s(\d+\/\d+\/\d+\s\d+:\d+:\d+)\;/){
$start_date_time =$1;
}
if ($readit && $line=~/ends\s\d\s(\d+\/\d+\/\d+\s\d+:\d+:\d+)\;/){
$end_date_time =$1;
#print $start_date_time;
# $start_date_time = localize($start_date_time);
# ($start_date, $start_time) = split (/T/,$start_date_time);
}
if ($readit && $line =~/hardware\sethernet\s(.*?)\;/){
$mac=$1;
}
if ($readit && $line =~/client-hostname\s"(.*?)"\;/){
$name=$1;
}
if ($readit){
if ($line=~/^\s+binding\sstate\s(.*?)\;/){
$state = $1;
if ($state eq 'active'){
$active++;
}
}
}
if ($readit && $line=~/^}/){
push (@lease_states,"$ip\t$start_date_time\t$end_date_time\t$mac\t$state\t\t$name\n");
$readit = 0;
}
}
@lease_states=sort (@lease_states);
my $header=("IP\t\tSTART TIME\t\tEND TIME\t\tMAC\t\t\tSTATE\t\tHOSTNAME\n");
print $header;
print @lease_states;
print "Total leases: $lease\n";
print "Total active leases: $active\n";
sub localize{
# in format 2010/06/01 22:10:01
my $datetime=shift;
my ($date, $time) = split (/ /,$datetime);
my ($hr, $min, $sec) = split (/:/,$time);
my ($yr, $mo, $day)= split (/\//,$date);
#my $dt = DateTime->new(
# year => $yr,
# month => $mo,
# day => $day,
# hour => $hr,
# minute => $min,
# second => $sec,
# time_zone =>'UTC' );
# $dt->set_time_zone($LocalTZ);
# return $dt->datetime;
return $datetime;
# use this to split the out
# ($date, $time) = split (/T/,$dt->datetime);
}
@awfki
Copy link

awfki commented Apr 29, 2014

Love it, and it saved me having to write my own, but I'd suggest adding $name=""; below line 87 to reset the name for leases where it wasn't set. I have a lot of those.

Thanks

@mattpascoe
Copy link
Author

Good call.. I've updated the gist.

@merentitis
Copy link

Nice and useful script! I get many duplicates:
192.168.2.122 2014/11/19 09:11:02 2014/11/19 09:41:02 58:a2:b5:d5:1b:bc active android-92aca921526b52f0
192.168.2.122 2014/11/19 09:25:27 2014/11/19 09:55:27 58:a2:b5:d5:1b:bc active android-92aca921526b52f0

@mpsharrad
Copy link

Thanks for the script - in a similar vein to the first post by awfki I had to add in $mac=""; below line 87 to reset the mac address otherwise it looked like one mac address was using all of the spare ip addresses.

@ypid
Copy link

ypid commented Jul 6, 2016

@mattpascoe Script works as advertised. Thanks for that! Are you aware of the Text::DHCPLeases module?

@merentitis You have a LG Electronics device. Interesting 😉 To preserve your privacy you should always use a random MAC address based on MAC addresses reserved for documentation as defined by RFC7042. Example: 00:00:5E:00:53:23. You can be targeted using your MAC address as selector!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment