*** From dhcp-server -- To unsubscribe, see the end of this message. ***

Gary Mills writes:
> At times, it would be quite useful to view portions of the database
> that the DHCP server keeps in memory.  For example, it would be very
> helpful sometimes to determine the ethernet address associated with
> a particular IP address.  Has anyone done this with the ISC DHCP
> server?  Parsing both the dhcpd.conf and dhcpd.leases file should
> yield the same result, but it would be quite a complicated process,
> and duplicates what the server already does.

Run this and you'll get a report of what IP's are leased to whom, and
also you'll get a breakdown by subnet.  We run it hourly with the
output mailed to the assistant network guru.

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#       showleases
#       IP.pm
#
echo x - showleases
sed 's/^X//' >showleases << 'END-of-showleases'
X#!/usr/local/bin/perl
X
Xuse IP;
X
X#location of the lease file
X$CONF_FILENAME = shift @ARGV;
X$LEASE_FILENAME = shift @ARGV;
X
X$now = `date -u '+%Y/%m/%d %H:%M:%S'`;
Xchop $now;
X
X# print "[$now]\n";
X
Xsub print_text_header {
X  print "DHCP leases at $now\n";
X  print "All times are UTC\n";
X  print "Start                 End                   ip_addr          mac_addr\n";
X  print 
"----------------------------------------------------------------------------\n";
X}
X
Xopen(CONF_FILE, "<$CONF_FILENAME") || die "Can't read $CONF_FILENAME";
Xwhile(<CONF_FILE>) {
X  chop;
X LINE:
X  {
X    /subnet\s*(\S+)\s*netmask\s*(\S+)/ && do {
X      $subnet_addr = $1;
X      $netmask = $2;
X      zeroize(\$subnet_addr);
X      zeroize(\$netmask);
X      $subnets{$subnet_addr} = $netmask;
X      $netmasks{$netmask} = 1;
X      last LINE;
X    }
X  }
X}
Xclose CONF_FILE;
X
X# print join("\n", sort(keys %netmasks)), "\n";
X# exit 0;
X
X
Xopen(LEASEFILE, "<$LEASE_FILENAME") || die "can't read $LEASE_FILENAME";
Xwhile(<LEASEFILE>) {
X  chop;
X LINE:
X  {
X    /^lease (.*) {/ && do {
X      $ip_addr = $1;
X      &zeroize(\$ip_addr);
X      last LINE;
X    };
X    /starts (\d+) (.*) (.*);/ && do {
X      ($n, $date, $time) = ($1, $2, $3);
X      $start = "$date $time";
X      $began = $start lt $now;
X      # print "$began = $start < $now\n";
X      last LINE;
X    };
X    /ends (\d+) (.*) (.*);/ && do {
X      ($n, $date, $time) = ($1, $2, $3);
X      $end = "$date $time";
X      $over = $end lt $now;
X      last LINE;
X    };
X    /hardware ethernet (.*);/ && do {
X      $mac = $1;
X      last LINE;
X    };
X    /}/ && do {
X      next LINE if defined $leases{$ip_addr};
X    MASK:
X      foreach $mask ( sort keys %netmasks ) {
X       $probe = &mask($ip_addr, $mask);
X       # print "PROBE $ip_addr/$mask $probe\n";
X       if($subnets{$probe} eq $mask) {
X         # print "SUBNET $probe\n";
X         $subnet = $probe;
X         last MASK;
X       }
X      }
X      $line = "$start   $end   $ip_addr  $mac\n";
X      # $line = "($subnet)   $ip_addr  $mac\n";
X      # print "\nLINE $line";
X      $leases{$ip_addr} = $line;
X      if ($began && ! $over) {
X       # print "ACTIVE\n";
X       push(@list, $line);
X       $active_leases{$ip_addr} = $line
X         if !defined $active_leases{$ip_addr};
X       $total_leases++;
X       # print "Incrementing $subnet (was $found_leases{$subnet})\n";
X       $found_leases{$subnet}++;
X      }
X      last LINE;
X    };
X  }
X}
X
X&print_text_header;
Xforeach $lease ( @leases{sort keys %active_leases} ) {
X  $i++;
X  # printf "%3d $lease", $i;
X  print $lease;
X}
X# print join('', @leases{sort keys %active_leases});
X
Xprint "\n\n";
Xprint "Total leases: $total_leases\n";
Xprint "Subnet Number          Active Leases\n";
Xprint "------------------------------------\n";
X
Xforeach $subnet ( sort keys %subnets ) {
X  printf("%15s %8s\n", $subnet, $found_leases{$subnet});
X}
END-of-showleases
echo x - IP.pm
sed 's/^X//' >IP.pm << 'END-of-IP.pm'
X#!/usr/local/bin/perl
X
X=pod
X=head1 IP.pm - IP address arithmetic for Hostmaster
X
XAn IP address in canonical form is a string of the following form:
X
X  NNN.NNN.NNN.NNN
X
XAn IP address in colloquial (common) form is a regular IP address with
Xno leading zeroes in the octets.
X
XThe functions in this module:
X
X=head2 mask($addr, $netmask)
X
XReturns the address masked by the mask.
X
X=head2 dezero(\$scalar_ref)
X
XExpects a reference to an address in canonical
Xform, and turns the address into colloquial form.
X
X=head2 zeroize(\$scalar_ref)
X
XExpects a reference to an address in common form, and turns the address into
Xcanonical form.
X
X=head2 complement($canonical_addr)
X
XExpects a canonical-form address, and returns its bitwise complement.
X
X=head2 incr_addr($addr)
X
XExpects a canonical address; returns the next address on that network
X(i.e. the address plus 1).  Does no bounds checking to be sure you're
Xnot crossing over a subnet boundary.
X
X=head2 broadcastify($addr, $netmask)
X
XReturns the broadcast address for the subnet that $addr is a member
Xof, by complementing netmask and then bitwise-or'ing it in with the
Xaddress.
X
X=cut
X
X# while (<>) {
X#   ($ip, $mask) = split(' ', $_);
X#   print "MASKED ", mask($ip, $mask), "\n";
X#   &dezero(\$ip);
X#   print "DEZERO ", $ip, "\n";
X#   &zeroize(\$ip);
X#   print "REZERO ", $ip, "\n";
X# }
X
Xsub mask {
X  my($ip, $mask) = @_;
X  my @ip_bytes;
X  my @mask_bytes;
X  my @answer_bytes;
X
X  use integer;
X
X  &dezero(\$ip);
X  &dezero(\$mask);
X  @ip_bytes = split('\.', $ip);
X  @mask_bytes = split('\.', $mask);
X  # print "IP   ", join('/', @ip_bytes), "\n";
X  # print "MASK ", join('/', @mask_bytes), "\n";
X
X  while(@ip_bytes) {
X    use integer;
X    $ans = int($ip_bytes[0]) & int($mask_bytes[0]);
X    # print "$ip_bytes[0] & $mask_bytes[0] = $ans\n";
X    push(@answer_bytes, $ans);
X    shift @ip_bytes;
X    shift @mask_bytes;
X  }
X  return sprintf("%03d.%03d.%03d.%03d",
X                $answer_bytes[0],
X                $answer_bytes[1],
X                $answer_bytes[2],
X                $answer_bytes[3]);
X}
X
Xsub dezero {
X  my ($ip) = @_;
X  $$ip =~ s/\.000/.0/g;                # convert .000 to .0 in address
X  $$ip =~ s/\.0+([1-9])/.$1/g; # convert .024 to .24 in address
X}
X
Xsub zeroize {
X  my ($ip) =  @_;
X  my ($o1, $o2, $o3, $o4);
X
X  ($o1, $o2, $o3, $o4) = split('\.', $$ip);
X  $$ip = sprintf("%03d.%03d.%03d.%03d",
X                $o1, $o2, $o3, $o4);
X}
X
Xsub complement {
X  my($ip) = @_;
X  my @ip_bytes;
X  my @answer_bytes;
X
X  use integer;
X
X  &dezero(\$ip);
X  @ip_bytes = split('\.', $ip);
X  while(@ip_bytes) {
X    use integer;
X    $ans = abs(255 - $ip_bytes[0]);
X    # print "$ip_bytes[0] & $mask_bytes[0] = $ans\n";
X    push(@answer_bytes, $ans);
X    shift @ip_bytes;
X  }
X  return sprintf("%03d.%03d.%03d.%03d",
X                $answer_bytes[0],
X                $answer_bytes[1],
X                $answer_bytes[2],
X                $answer_bytes[3]);
X}
X
X
X
Xsub incr_addr {
X  my ($ip) = @_;
X  my ($o1, $o2, $o3, $o4);
X
X  &dezero(\$ip);
X  ($o1, $o2, $o3, $o4) = split('\.', $ip);
X  $o4++;
X  if ($o4 > 255) {
X    $o4=0;
X    $o3++;
X    if ($o3 > 255) {
X      $o3=0;
X      $o2++;
X      if ($o2 > 255) {
X       $o2=0;
X       $o1++;
X      }
X    }
X  }
X  return sprintf("%03d.%03d.%03d.%03d",
X                $o1, $o2, $o3, $o4);
X  
X}
X
Xsub broadcastify {
X  my($ip, $netmask) = @_;
X
X  my @ip_bytes;
X  my @mask_bytes;
X  my @answer_bytes;
X
X  use integer;
X
X  &dezero(\$ip);
X  &dezero(\$netmask);
X  @ip_bytes = split('\.', $ip);
X  @mask_bytes = split('\.', $netmask);
X  # print "IP   ", join('/', @ip_bytes), "\n";
X  # print "MASK ", join('/', @mask_bytes), "\n";
X
X  while(@ip_bytes) {
X    use integer;
X    $ans = int($ip_bytes[0]) | (256 + ~ int($mask_bytes[0]));
X    # print "$ip_bytes[0] & $mask_bytes[0] = $ans\n";
X    push(@answer_bytes, $ans);
X    shift @ip_bytes;
X    shift @mask_bytes;
X  }
X  return sprintf("%03d.%03d.%03d.%03d",
X                $answer_bytes[0],
X                $answer_bytes[1],
X                $answer_bytes[2],
X                $answer_bytes[3]);
X}
X
X
X1;
END-of-IP.pm
exit



------------------------------------------------------------------------------
To unsubscribe from this list, please visit http://www.fugue.com/dhcp/lists
If you are without web access, or if you are having trouble with the web page,
please send mail to [EMAIL PROTECTED]   Please try to use the web
page first - it will take a long time for your request to be processed by hand.
------------------------------------------------------------------------------

Reply via email to