How to get a list of connected clients from my DHCP server?

ryuusoultaker

Member


Messages: 28

I'm running a DHCP server on my FreeBSD PC and I want to get the list of connected client on my network but I don't know how. Can someone tell me the best way to do it?

Best Regards
Ryuu
 

plamaiziere

Active Member

Reaction score: 40
Messages: 184

ryuusoultaker said:
I'm running a DHCP server on my FreeBSD PC and I want to get the list of connected client on my network but I don't know how. Can someone tell me the best way to do it?
Ryuu
You will find the leases in /var/something (don't remember exactly) with their status.
regards
 

kpa

Beastie's Twin

Reaction score: 1,822
Messages: 6,318

Listing the leases is not a reliable way to find out connected machines. A machine with a valid lease in the DHCP server's database may be turned off before the lease expires. You would have to test if the machine is still alive by some other means, a plain ping(8) or maybe nmap(1)
 
OP
ryuusoultaker

ryuusoultaker

Member


Messages: 28

I checked the leases file at /var/db/dhcpd/dhcpd.lease but it only provide me the information about last leased IP. I need the list of leased IP that still online so I can see how much client that connected from my BSD machine if it possible..

plamaiziere said:
You will find the leases in /var/something (don't remember exactly) with their status.
regards
 

SirDice

Administrator
Staff member
Administrator
Moderator

Reaction score: 9,117
Messages: 33,671

ryuusoultaker said:
I checked the leases file at /var/db/dhcpd/dhcpd.lease but it only provide me the information about last leased IP. I need the list of leased IP that still online so I can see how much client that connected from my BSD machine if it possible..
Parse the entire file.
 

pboehmer

Active Member

Reaction score: 32
Messages: 144

I'm surprised that after all of these years, the isc-dhcp-server packages still do not have a built-in utility for this. There is a program called omshell that is part of the isc-dhcp-server package that gets installed. A quick glance at the man page indicates that it only modifies settings in a currently running dhcpd, but does provide a simple "list" function.

I'd imagine that it wouldn't be too trivial to write up a shell script to ping scan your DHCP pool, get the associated MAC of the responding systems, extracting the system name from the leases file with the IP and MAC information, and then generating a report. I have a feeling that this is one of those cases where admins either manually go through the leases file (like me) or wrote their own script and just keep it in their personal tool chest.
 

knarf

Member

Reaction score: 9
Messages: 89

Maybe # arp -a is your friend? # ndp -a for v6. arpwatch and ndpmon are also fine. All of this has nothing to do with DHCP, but maybe it's still what you're looking for?
 

pboehmer

Active Member

Reaction score: 32
Messages: 144

OK, I spent a couple of minutes and concocted this. This script works with the isc42-dhcp-server port, and should work with the other versions. YMMV on other DHCP server software. I extract the pool ranges (if you have multiple pools) from /usr/local/etc/dhcpd.conf and use fping (/usr/ports/net/fping) to list the active addresses. I use arp to get the MAC of the active IPs. From there, I just grep out the hostname from the last matching IP and MAC address in /var/db/dhcp/dhcpd.leases. Its not exactly streamline, but it seems to work.

Code:
#!/bin/tcsh 
## listleases.sh
## Displays a list of active DHCP leases
## NOTE: requires fping port to use

## Get pool(s) from /usr/local/etc/dhcpd.conf 
foreach POOL (`grep range /usr/local/etc/dhcpd.conf | awk '{print $2"_"$3}' | sed 's/;//g'`)
  set POOLSET = `echo $POOL | sed 's/_/ /g'`
  echo "DHCP Pool: $POOLSET"
	
  ## use fping to find active IPs in the dhcp pool
  foreach ENTRY (`fping -a -g $POOLSET`)
        set ENTRYARP = `arp $ENTRY | awk '{print $4}'`
	set ENTRYUID = `grep -C7 "lease $ENTRY" /var/db/dhcpd/dhcpd.leases | grep -C3 "$ENTRYARP" | grep hostname | tail -n 1`
	echo "$ENTRY | $ENTRYARP | $ENTRYUID"
  end
end
I hope someone finds this useful.
 

SirDice

Administrator
Staff member
Administrator
Moderator

Reaction score: 9,117
Messages: 33,671

If the DHCP client is behind a router arp(8) will not show the correct MAC address.
 
OP
ryuusoultaker

ryuusoultaker

Member


Messages: 28

SirDice said:
Parse the entire file.
Parse the entire file. I will try it first.. If I'm not mistaken, the BSD PC run as router it self, so it is the one that gives IP address into connected client.. So it is possible to list the connected client by arp command?


pboehmer said:
OK, I spent a couple of minutes and concocted this. This script works with the isc42-dhcp-server port, and should work with the other versions. YMMV on other DHCP server software. I extract the pool ranges (if you have multiple pools) from /usr/local/etc/dhcpd.conf and use fping (/usr/ports/net/fping) to list the active addresses. I use arp to get the MAC of the active IPs. From there, I just grep out the hostname from the last matching IP and MAC address in /var/db/dhcp/dhcpd.leases. Its not exactly streamline, but it seems to work.

Code:
#!/bin/tcsh 
## listleases.sh
## Displays a list of active DHCP leases
## NOTE: requires fping port to use

## Get pool(s) from /usr/local/etc/dhcpd.conf 
foreach POOL (`grep range /usr/local/etc/dhcpd.conf | awk '{print $2"_"$3}' | sed 's/;//g'`)
  set POOLSET = `echo $POOL | sed 's/_/ /g'`
  echo "DHCP Pool: $POOLSET"
	
  ## use fping to find active IPs in the dhcp pool
  foreach ENTRY (`fping -a -g $POOLSET`)
        set ENTRYARP = `arp $ENTRY | awk '{print $4}'`
	set ENTRYUID = `grep -C7 "lease $ENTRY" /var/db/dhcpd/dhcpd.leases | grep -C3 "$ENTRYARP" | grep hostname | tail -n 1`
	echo "$ENTRY | $ENTRYARP | $ENTRYUID"
  end
end
I hope someone finds this useful.
I'm not good at bash programming, so maybe I have to put my courage up first to try it :D but thank you for replying..
 

pboehmer

Active Member

Reaction score: 32
Messages: 144

Yes, SirDice brought up a good point that I didn't account for. The script will not work correctly if the IP pool addresses are routed. The script was written for listing devices that are local to the DHCP server, like you would find in a typical small office environment.

To get the MAC address of IPs in routed pools, I was thinking about adding the traceroute command of the device IP to determine number of hops. If hops is greater than 1, then perform a SNMP get/walk call on the second to last response of the traceroute output (which *should* be the closest router) to get the corresponding MAC (assuming at the very least that A, you have appropriate access to the router, and B, that it responds to ICMP traffic). Way too many other variables to even make this viable.

Another idea (provided by a coworker) is to scrap verifying by MAC address and use the dhcpd.leases lease stop time entry and comparing it to local time. If the local time is earlier than the lease stop time, that would verify the entry.

Another take is a client/server reporting system, but probably still not viable when you consider smartphones and other non-PC devices.

Any other ideas?
 

MacGyver

Member

Reaction score: 5
Messages: 21

Code:
#!/usr/bin/perl

$now = time();
use Time::Local;

open(LEASE, "/var/db/dhcpd/dhcpd.leases");
foreach $line (<LEASE>) {
        chomp($line);
        $data = 1 if $line =~ /^lease /;
        $data = 0 if $line =~ /^}/;

        if ($data) {
                if ($line =~ /^lease/) {
                        $ip = (split(" ", $line))[1];
                } elsif ($line =~ /^  starts/) {
                        ($date, $time) = (split(" ", $line))[2,3];
                        ($y, $m, $d) = split("/", $date);
                        ($H, $M, $S) = split(":", $time);
                        $start = timelocal($S,$M,$H,$d,$m,$y);
                } elsif ($line =~ /^  ends/) {
                        ($date, $time) = (split(" ", $line))[2,3];
                        ($y, $m, $d) = split("/", $date);
                        ($H, $M, $S) = split(":", $time);
                        $stop = timelocal($S,$M,$H,$d,$m,$y);
                } elsif ($line =~ /^  hardware ethernet/) {
                        $mac = (split(" ", $line))[2];
                        $mac =~ s/;//;
                } elsif ($line =~ /^  client-hostname/) {
                        $client = (split(/\"/, $line))[1];
                }
        } else {
                print localtime($start) . "\t" . localtime($stop) . "\t$ip\t$mac\t$client\n" if $stop >= $now;
                $ip = ""; $start = ""; $stop = ""; $mac = ""; $client = "";
        }
}
close(LEASE);
 

HappMacDonald

New Member

Reaction score: 1
Messages: 2

Patch for MacGyver's handy script

Time::Local appears to want months in 0..11 numerical format (0 being January, 11 being December) while the numerical time format used in dhcpd.leases (and virtually everywhere else in the world) starts months with 1 for January, skipping zero entirely.

So I recommend patching the two lines in MacGyver's script using timelocal() to use this invocation, instead:

Code:
timelocal($S,$M-1,$H,$d,$m,$y)
Otherwise, thanks for the script, sir! :D
 

HappMacDonald

New Member

Reaction score: 1
Messages: 2

Sorry, actually got my $Minutes and $months confused in that first patch suggestion. D:

Code:
timelocal($S,$M,$H,$d,$m-1,$y)
 
Top