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



## ryuusoultaker (Jul 7, 2012)

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 (Jul 7, 2012)

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 (Jul 7, 2012)

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)


----------



## ryuusoultaker (Jul 8, 2012)

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 (Jul 9, 2012)

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 (Jul 9, 2012)

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 (Jul 10, 2012)

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 (Jul 10, 2012)

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.


```
#!/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 (Jul 10, 2012)

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


----------



## ryuusoultaker (Jul 10, 2012)

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.
> 
> 
> ```
> ...



I'm not good at bash programming, so maybe I have to put my courage up first to try it  but thank you for replying..


----------



## pboehmer (Jul 10, 2012)

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 (Jul 10, 2012)

```
#!/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 (Jun 13, 2013)

*Patch for MacGyver's handy script*

Time::Local appears to want months in 0..11 numerical format (0 being _J_anuary, 11 being _D_ecember) 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:


```
timelocal($S,$M-1,$H,$d,$m,$y)
```

Otherwise, thanks for the script, sir!


----------



## HappMacDonald (Jun 13, 2013)

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


```
timelocal($S,$M,$H,$d,$m-1,$y)
```


----------

