Check my DHCP lease?
Is there a way to show my current (client) DHCP lease? Or even better — retrieve all options/infos sent with DHCPACK ?
@heemayl this file is empty in my case (Ubuntu 15.10), maybe because NetworkManager is acquiring dhcp lease (?)
@heemayl was correct for the directory. On Debian Stretch I found infos in «/var/lib/dhcp/dhclient.eth0.leases»
9 Answers 9
I’m not aware of a way to query this information on the client. If you are on the server you can see information on the client leases in /var/lib/dhcp/dhclient.leases . From the client the only way i know is:
sudo grep dhclient /var/log/syslog
Which should give you something like:
May 20 18:34:38 [machine_name] dhclient: DHCPREQUEST on eth0 to [DHCP_SERVER_IP] port 67 May 20 18:34:38 [machine_name] dhclient: DHCPACK from [DHCP_SERVER_IP] May 20 18:34:38 [machine_name] dhclient: bound to [client_dhcp_ip] -- renewal in 1517 seconds.
depending on your distro, it should be located in /var/lib/dhcp under dhclient..leases or /var/lib/dhclient.leases . you can also specify the path of your dhclient.leases file by passing -lf when starting dhclient.
With NetworkManager use nmcli to query the DHCP status for your active connection (assuming one) with
nmcli -f ipv4.method con show "`nmcli -t -f NAME connection `"
For full DHCP information use -f DHCP4 . Adjust for ipv6 as necessary.
This prints the DHCP information for the currently active connection: nmcli -f DHCP4 con show «$(nmcli -g NAME con show —active)»
I used dhcpdump when I was testing DHCP. It will dump both sides of the DHCP transaction. If you leave it running it will log the options passed.
You may want to restart your DHCP client to see the initial negotiation. The renewal request should contain all the running configuration.
There is one other aspect to this answer to consider to show your DHCP lease time and other DHCP information in the offer. If using Linux systemd-networkd, none of the options above work as they relate to network manager (the Linux solutions at least)
There is a similar question with answer explaining this at How do I check DHCP lease time in systemd-networkd?
Depending on the OS; Enabling debug isn’t always necessary.
systemd-networkd should store the lease info under /run/systemd/netif/leases/
i.e.
cat /run/systemd/netif/leases/2
Check Which Lease.
If you thought this couldn’t get anymore confused, you’d be wrong 😉
I found this question unpicking my own DHCP issues on Ubuntu 22.04 Desktop edition, where I discovered that I actually had TWO leases!:
sudo cat /var/lib/dhcp/dhclient.leases sudo cat /var/lib/NetworkManager/internal-d6b936ad-d73f-4898-a826-edbb61d6155a-eth0.lease
So which is the one being used.
(2) DHCP Clients:
Unlike Ubuntu’s LTS server flavour, their Desktop edition winds-in NetworkManager into the networking gears.
Determine Default DHCP Client
So, there’s (2) DHCP clients in this case, but which of these are actually being used?
In Ubuntu Networking, there is a layer of abstraction called netplan which sets the default networking gears in the directive renderer .
A review of /etc/netplan/01-network-manager-all.yaml reveals that NetworkManager is controlling our networking, NOT systemd-networkd.
A review of NetworkManager’s logging:
journalctl -u NetworkManager.service | grep DHCP
reveals that NetworkManager is using its’ own DHCP client:
NetworkManager[5117]: [1655970837.0088] dhcp-init: Using DHCP client 'internal'.
Thus, of our (2) leases, the one being used by the system is:
/var/lib/NetworkManager/internal-d6b936ad-d73f-4898-a826-edbb61d6155a-eth0.lease
Note the keyword in that log message is «using«: even if a gazillion DHCP clients are shown in the logging as enabled , only the one specified as «using» is the active DHCP client.
Wow, this was a tangle; hope this saves others going down the same deep, dark rabbit hole.
How to monitor DHCP leased ip address
I have Ubuntu server 12.10 as DRBL and CloneZilla. How can I find out how many IP addresses have been assigned to the clients. How do I control/monitor the DHCP daemon service(stop/start/status)?
5 Answers 5
To monitor Dhcp leases just type in terminal :
gedit /var/lib/dhcp/dhcpd.leases
Is gedit really the best way to peek into that file? First, it requires a desktop environment, which is usually not present on a server installation. Second: launching an editor suggests this file could be modified, but I’m pretty sure that editing it can cause nothing but trouble.
All the answers above are partial. And to be honest there is no simple solution. 1) You can parse the dhcpd.leases database file and get information on active leases, but
- you will not get information on any FIXED addresses (assigned by a line like:
2) on the other hand you can parse the dhcpd.log file to search for ack lines (they look like this):
2017-03-12T08:44:52.421174+01:00, Linuxx, info, dhcpd: DHCPACK on 10.0.0.63 to 68:ab:35:59:9c:a1 via 10.0.0.1
Which is giving you information on DHCPD requests and replies but there is no information about actual leases (time, status).
What you should really do is to do BOTH. First parse the log file, and then update the file with information obtained from dhcpd.leases file with database for missing information like lease start-end etc.
Now: I have played circa 2 full workdays till I have created a solution which creates a HTML table with ALL active leases, both FIXED and dynamic. Here is the code that you can place in your cgi-bin folder or wherever.
#!/usr/bin/perl ##################################################################################### # list dhcpd active leases # - both "fixed" addresses which are normally not placed into leases database # - and dynamically given leases which are present in leases DB # working for isc-dhcpd-server service but should also work for other compatible # dhcpd servers. # produces HTML or CSV list of leases # in shell can pipe to lynx: # ./dhcp-leases.pl | lynx -stdin # # written by Marcin Gosiewski, BV Grupa s.c. Poland http://www.bvsystemy.pl/ # based on portions of code by Jason Antman # # to make it work change the $logfilename and $leasedbname below and modify # the regexp in second part of code (see below) to match your log lines format # also you can optionally turn off reverse dns lookup (see below) which speeds up the process # of table creation and is useless unless you have reverse dns populated for # your fixed or dynamic leases # # CHANGELOG: # 2017-03-13: initial version # 2019-08-15: extended for @logprog by Jim Klimov use Socket; use strict; use warnings; no warnings 'uninitialized'; # adjust this to match your files location: both log file and leases # database. We use 2 last log files from logrotate, but you can add as many as you want my @logfilenames = ( "/var/log/LOCALAPP.dhcpd.log.1", "/var/log/LOCALAPP.dhcpd.log" ); # Alternately, on systems without explicit log (e.g. with systemd journals), use empty array of files: ### my @logfilenames = ( ); # if empty, use output from logprog below my @logprog = qw ( sudo journalctl --no-pager -lu dhcpd ); # Delegate rights for logprog as root, e.g. # echo 'www-data ALL=(root) NOPASSWD:/usr/bin/journalctl --no-pager -lu dhcpd' > /etc/sudoers.d/www-journalctl my $leasedbname = "/var/lib/dhcp/dhcpd.leases"; my %data = (); # optional, can be modified to produce local time use Time::Local; use POSIX 'strftime'; my $now = time(); # local variables, lease information stored here my $ip=""; my $status=""; my $interface=""; my $sdate=""; # beginning of lease my $stime=""; my $edate=""; # end of lease my $etime=""; my $adate=""; # last update (ACK) sent to requesting server my $atime=""; my $mac=""; my $hostname=""; my $dnsname=""; # reverse dns lookup for host ####################################################################### # first gather data from logfile for all ACK actions ####################################################################### # collect all lines from log files into memory. my @lines = (); my @loglines=(); if (scalar @logfilenames > 0) < foreach my $logfilename (@logfilenames) < open LOGFILE, '); #printf "LINES1: " . scalar @loglines . " in " .$logfilename . "\n"; push(@lines, @loglines); close(LOGFILE); > > else < open LOGPROG, '-|', join (' ', @logprog) or die "Could not pipe from logprog"; chomp(@loglines = ); #printf "LINES1: " . scalar @loglines . " in " .$logfilename . "\n"; push(@lines, @loglines); close(LOGPROG); > @loglines=(); #printf "TOTAL LINES: " . scalar @lines . "\n"; foreach my $line (@lines) < if ( $line !~ m/dhcpd[^:]*: DHCPACK/) < next;>#printf "LINE: $line\n"; ############################### # Modify the following line to make regexp capture 6 groups from log line: # 1 - date # 2 - time # 3 - ip # 4 - mac # 5 - hostname if available # 6 - interface #$line =~ m/(^.)T(.).+,\ dhcpd: DHCPACK on (\d\.\d\.\d\.\d) to ((?:[0-9a-f][:-])[0-9a-f].*) via (.+)/; $line =~ m/(^.)T(.).+,\ dhcpd: DHCPACK on (\d\.\d\.\d\.\d) to ((?:[0-9a-f][:-])[0-9a-f]) (.*)via (.+)/; #$line =~ m/^(.) (.)\ .+,?\ dhcpd[^:]*: DHCPACK on (\d\.\d\.\d\.\d) to ((?:[0-9a-f][:-])[0-9a-f]) (.*)via (.+)/; # process the input $adate="$1"; $atime="$2"; $ip="$3"; $mac="$4"; $hostname="$5"; $interface="$6"; #add some 'known' facts: $status="ACK"; $sdate=""; #"FOREVER"; $stime=""; $edate=""; $etime=""; #create/update record for this mac_addr #you can add extra check here if the IP address is not duplicated within #ack history and choose only the newer one. $data-> = "$ip"; $data-> = "$status"; $data-> = "$interface"; $data-> = "$adate"; $data-> = "$atime"; $data-> = "$sdate"; $data-> = "$stime"; $data-> = "$edate"; $data-> = "$etime"; $data-> = "$mac"; if (length($hostname) > 0) < $hostname =~ s/^\ *\(*//; $hostname =~ s/\)*\ *$//; >$data-> = "$hostname"; > #close(LOGFILE); ####################################################################### # gather data from lease database for dynamic addresses # update the records (for existing) or add new records ####################################################################### my $isdata = 0; my $type = ""; #this information is not present in leases database so we just set #it to default values $interface="dhcpd"; $status="ACTIVE"; $adate="-"; $atime=""; open LEASEDB, $leasedbname or die $!; foreach my $line () < chomp($line); $isdata = 1 if $line =~ /^lease /; $isdata = 0 if $line =~ /^>/; if ($isdata) < if ($line =~ /^lease/) < $ip = (split(" ", $line))[1]; >elsif ($line =~ /^ starts/) < ($sdate, $stime) = (split(" ", $line))[2,3]; $sdate =~ s/\//-/g; $stime =~ s/;//; >elsif ($line =~ /^ ends/) < ($type, $edate, $etime) = (split(" ", $line))[1,2,3]; if($type eq "never;") < $edate="forever"; $etime=" "; >else < $edate =~ s/\//-/g; $etime =~ s/;//; >> elsif ($line =~ /^ hardware ethernet/) < $mac = (split(" ", $line))[2]; $mac =~ s/;//; >elsif ($line =~ /^ client-hostname/) < $hostname = (split(/\"/, $line))[1]; >elsif($mac ne "") < #we have parsed the whole record, no more matching entries #data is collected to variables. now push the record. #now let's decide if we are updating the record or creating #new record # check against lease date, do not add expired leases # convert lease end time to local time/date and compare with $now my $y=0; my $m=0; my $d=0; my $H=0; my $M=0; my $S=0; my $edatetime = $now; ($y, $m, $d) = split("-", $edate); ($H, $M, $S) = split(":", $etime); $edatetime = timelocal($S,$M,$H,$d,$m-1,$y); if($edatetime >= $now) < # now check if record exists if(!defined($data->)) < #record does not exist, fill up default data $data-> = "$mac"; $data-> = "$interface"; $data-> = "$ip"; $data-> = "$hostname"; > # record exists, let's check if we should update $data-> = "$status"; $data-> = "$sdate"; $data-> = "$stime"; $data-> = "$edate"; $data-> = "$etime"; $data-> = "$hostname"; #we do NOT update ACK time because we do not have it #do NOT uncomment below #$data-> = "$adate"; #$data-> = "$atime"; > > > > close(LEASEDB); ####################################################################### # sort data ####################################################################### #we sort by IP but you can sort by anything. my @sorted = sort < ($data) cmp ($data) > %data; ####################################################################### # Print out everything to the HTML table ####################################################################### my $hostnamelong=""; printf "Content-type: text/html\n\n"; printf "\n"; printf " \n"; printf "\n"; printf "\n"; printf "IP Status Interface Lease time ACK time Mac Host \n"; foreach my $key (@sorted) < if($data eq "") < next ; ># BEGIN reverse dns lookup # can optionally turn off reverse dns lookup (comment out below lines) which speeds up the process # of table creation and is useless unless you have reverse dns populated for # your fixed or dynamic leases uncomment single line below instead: # # version without reverse dns lookup: # $hostnamelong = $data; # # version with reverse dns lookup: # BEGIN $dnsname = gethostbyaddr(inet_aton($data), AF_INET); if($data ne "") < $hostnamelong = $data . " | " . $dnsname; > else < $hostnamelong = $dnsname; >$dnsname = ""; # END printf ""; printf "" . $data ." "; printf "" . $data ." "; printf "" . $data ." "; printf "" . $data . " " . $data ." - "; printf $data . " " . $data ." "; printf "" . $data . " " . $data . " "; printf "" . $data ." "; printf "" . $hostnamelong ." "; printf " \n"; > printf "
\n"; printf "\n"; # END of programm
1) the above script needs slight modification before running in YOUR environment, you have to modify the files locations, and one regex depending on your log file format. See comment in script.
2) the above script is not checking whether the IP is not repeated in ACK table, if 2 different machines got the same address within last days. This is by design (what I personally needed to see each mac address which was present in my network during last days) — you can easily modify it, there is a ready section for this in code, just add one condition.