Commande pour répertorier les adresses DHCP attribuées

21

Existe-t-il une commande que je peux utiliser pour demander au serveur dhcpd quelles adresses ont été attribuées?

pylover
la source

Réponses:

21

Non, vous ne pouvez obtenir ces informations côté serveur qu'à partir du serveur DHCP. Ces informations sont contenues dans le fichier .lease du serveur DHCP:, /var/lib/dhcpd/dhcpd.leasessi vous utilisez le serveur DHCP d'ISC.

Exemple

$ more /var/lib/dhcpd/dhcpd.leases
# All times in this file are in UTC (GMT), not your local timezone.   This is
# not a bug, so please don't ask about it.   There is no portable way to
# store leases in the local timezone, so please don't request this as a
# feature.   If this is inconvenient or confusing to you, we sincerely
# apologize.   Seriously, though - don't ask.
# The format of this file is documented in the dhcpd.leases(5) manual page.
# This lease file was written by isc-dhcp-V3.0.5-RedHat

lease 192.168.1.100 {
  starts 4 2011/09/22 20:27:28;
  ends 1 2011/09/26 20:27:28;
  tstp 1 2011/09/26 20:27:28;
  binding state free;
  hardware ethernet 00:1b:77:93:a1:69;
  uid "\001\000\033w\223\241i";
}
...
...
slm
la source
3
Sur ubuntu, le chemin est /var/lib/dhcp/dhcpd.leases(ie non dà la fin du premier dhcp...)
Alexis Wilke
20

isc-dhcpdla version du package 4.3.1a cette commande pour lister les baux:

dhcp-lease-list --lease PATH_TO_LEASE_FILE

Il s'agit d'un simple script de script perl qui prend également en charge les anciennes versions de DHCP. Vous pouvez en voir une copie dans le code source Debian ou dans la distribution DHCP officielle (en contrib/) également.

La sortie est jolie:

$ perl contrib/dhcp-lease-list.pl --lease /var/db/dhcpd/dhcpd.leases
To get manufacturer names please download http://standards.ieee.org/regauth/oui/oui.txt to /usr/local/etc/oui.txt
MAC                IP              hostname       valid until         manufacturer
===============================================================================================
90:27:e4:f9:9d:d7  192.168.0.182   iMac-de-mac    2015-12-12 01:37:06 -NA-
d8:a2:5e:94:40:81  192.168.0.178   foo-2          2015-12-12 01:04:56 -NA-
e8:9a:8f:6e:0f:60  192.168.0.127   angela         2015-12-11 23:55:32 -NA-
ec:55:f9:c5:f2:55  192.168.0.179   angela         2015-12-11 23:54:56 -NA-
f0:4f:7c:3f:9e:dc  192.168.0.183   kindle-1234567 2015-12-11 23:54:31 -NA-
f4:ec:38:e2:f9:67  192.168.0.185   -NA-           2015-12-11 23:55:40 -NA-
f8:d1:11:b7:5a:62  192.168.0.184   -NA-           2015-12-11 23:57:34 -NA-

C'est plus joli si vous téléchargez le oui.txtfichier comme suggéré, mais la sortie peut être tronquée à moins que vous n'appliquiez le patch suivant:

--- dhcp-lease-list.pl.orig     2015-12-12 12:30:00.000000000 -0500
+++ dhcp-lease-list.pl  2015-12-12 12:54:31.000000000 -0500
@@ -41,7 +41,7 @@
     if (defined $oui) {
        $manu = join('-', ($_[0] =~ /^(..):(..):(..):/));
        $manu = `grep -i '$manu' $oui | cut -f3`;
-       chomp($manu);
+       $manu =~ s/^\s+|\s+$//g;
     }

     return $manu;
@@ -142,7 +142,7 @@
     }
     foreach (@leases) {
        if ($opt_format eq 'human') {
-          printf("%-19s%-16s%-15s%-20s%-20s\n",
+          printf("%-19s%-16s%-14.14s %-20s%-20s\n",
                  $_->{'mac'},       # MAC
                  $_->{'ip'},        # IP address
                  $_->{'hostname'},  # hostname

Ce correctif a été soumis en amont sous le numéro ISC-Bugs # 41288 et attend sa révision.

Hojat Modaresi
la source
8

La commande egrep peut être utilisée pour obtenir une sortie:

egrep "lease|hostname|hardware|\}" /var/lib/dhcpd/dhcpd.leases

Production:

lease 192.168.11.10 {
  hardware ethernet 20:6a:8a:55:19:0a;
  client-hostname "Maryam-PC";
}
lease 192.168.11.7 {
  hardware ethernet 00:16:ea:51:d3:12;
  client-hostname "parsoon";
}
lease 192.168.11.3 {
  hardware ethernet 00:17:c4:3f:84:e3;
  client-hostname "zahra-ubuntu";
}
lease 192.168.11.5 {
  hardware ethernet 58:b0:35:f1:31:2f;
}
pylover
la source
4

La plupart des réponses ci-dessus sont partielles. Et pour être honnête, il n'y a pas de solution simple. 1) Vous pouvez analyser le fichier de base de données dhcpd.leases et obtenir des informations sur les baux actifs, mais vous n'obtiendrez pas d'informations sur les adresses FIXES (attribuées par une ligne comme:

host switch1      { hardware ethernet a1:b2:c3:d7:2f:bc ; fixed-address switch1.mydomain.com; }

Et cela ne donne pas non plus vraiment d'informations sur la dernière fois qu'un accusé de réception DHCP a été envoyé à la machine.

2) d'autre part, vous pouvez analyser le fichier dhcpd.log pour rechercher des lignes d'ack (elles ressemblent à ceci):

2017-03-12T08:44:52.421114+01:00, Linuxx, info, dhcpd: DHCPREQUEST for 10.0.0.63 from 68:ab:35:59:9c:a1 via 10.0.0.1 
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

Mais ce que vous devez vraiment faire, c'est de faire les deux. Analysez d'abord le fichier journal, puis mettez à jour le fichier avec les informations obtenues à partir du fichier dhcpd.leases avec la base de données pour les informations manquantes telles que le début du bail, etc.

Maintenant: j'ai joué environ 2 jours ouvrables complets jusqu'à ce que j'aie créé une solution qui crée un tableau HTML avec TOUS les baux actifs, à la fois FIXE et dynamique. Voici le code que vous pouvez placer dans votre dossier cgi-bin ou n'importe où.

#!/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
#
# written by Marcin Gosiewski, BV Grupa s.c. Poland <[email protected]>
# based on portions of code by Jason Antman <[email protected]> 
#
# 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
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" );
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=(); 
foreach my $logfilename (@logfilenames)
{
  open LOGFILE, '<', $logfilename;
  chomp(@loglines = <LOGFILE>);
  #printf "LINES1: " . scalar @loglines . " in " .$logfilename . "\n";
  push(@lines, @loglines);
  close(LOGFILE);
}
@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/(^.{10})T(.{8}).+,\ dhcpd: DHCPACK on (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) to ((?:[0-9a-f]{2}[:-]){5}[0-9a-f]{2}.*) via (.+)/;
  $line =~m/(^.{10})T(.{8}).+,\ dhcpd: DHCPACK on (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) to ((?:[0-9a-f]{2}[:-]){5}[0-9a-f]{2}) (.*)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{"$mac"}->{'ip'} = "$ip";
  $data{"$mac"}->{'status'} = "$status";
  $data{"$mac"}->{'interface'} = "$interface";
  $data{"$mac"}->{'adate'} = "$adate";
  $data{"$mac"}->{'atime'} = "$atime";
  $data{"$mac"}->{'sdate'} = "$sdate";
  $data{"$mac"}->{'stime'} = "$stime";
  $data{"$mac"}->{'edate'} = "$edate";
  $data{"$mac"}->{'etime'} = "$etime";
  $data{"$mac"}->{'mac'} = "$mac";
  $data{"$mac"}->{'hostname'} = "$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 (<LEASEDB>) 
{
  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{"$mac"}->{'mac'}))
          {
            #record does not exist, fill up default data
            $data{"$mac"}->{'mac'} = "$mac";
            $data{"$mac"}->{'interface'} = "$interface";
            $data{"$mac"}->{'ip'} = "$ip";
            $data{"$mac"}->{'hostname'} = "$hostname";
          }
          # record exists, let's check if we should update
          $data{"$mac"}->{'status'} = "$status";
          $data{"$mac"}->{'sdate'} = "$sdate";
          $data{"$mac"}->{'stime'} = "$stime";
          $data{"$mac"}->{'edate'} = "$edate";
          $data{"$mac"}->{'etime'} = "$etime";
          $data{"$mac"}->{'hostname'} = "$hostname";
          #we do NOT update ACK time because we do not have it
          #do NOT uncomment below
          #$data{"$mac"}->{'adate'} = "$adate";
          #$data{"$mac"}->{'atime'} = "$atime";

        }
    }
  }
}
close(LEASEDB);

#######################################################################
# sort data
#######################################################################

#we sort by IP but you can sort by anything.
my @sorted = sort { ($data{$a}{'ip'}) cmp ($data{$b}{'ip'}) } %data;

#######################################################################
# Print out everything to the HTML table
#######################################################################

my $hostnamelong="";

printf "Content-type: text/html\n\n";
printf "<html><head><title>Aktywne dzierzawy DHCP</title></head>\n";
printf "<style> table, th, td { border: 1px solid lightgray; border-collapse: collapse; padding: 3px; } ";
printf "tr:nth-child(even) { background-color: #dddddd; } ";
printf "</style>\n";
printf "<body>\n";
printf "<table border='1' cellpadding='6'>\n";
printf "<tr><th>IP</th><th>Status</th><th>Interface</th><th>Lease time</th><th>ACK time</th><th>Mac</th><th>Host</th></tr>\n";
foreach my $key (@sorted) {
    if($data{$key}{'mac'} 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{$key}{'hostname'};
    #
    # version with reverse dns lookup: 
    # BEGIN
    $dnsname = gethostbyaddr(inet_aton($data{$key}{'ip'}), AF_INET);
    if($data{$key}{'hostname'} ne "")
    {
      $hostnamelong = $data{$key}{'hostname'} . " | " . $dnsname;
    }
    else
    {
      $hostnamelong = $dnsname;
    }
    $dnsname = "";
    # END

    printf "<tr>";
    printf "<td>" . $data{$key}{'ip'} ."</td>";
    printf "<td>" . $data{$key}{'status'} ."</td>";
    printf "<td>" . $data{$key}{'interface'} ."</td>";
    printf "<td>" . $data{$key}{'sdate'} . " " . $data{$key}{'stime'} ." - ";
    printf $data{$key}{'edate'} . " " . $data{$key}{'etime'} ."</td>";
    printf "<td>" . $data{$key}{'adate'} . " " . $data{$key}{'atime'} . "</td>";
    printf "<td>" . $data{$key}{'mac'} ."</td>";
    printf "<td>" . $hostnamelong ."</td>";
    printf "</tr>\n";
}

printf "</table>\n";
printf "</body></html>\n";

# END of programm

Veuillez noter que: 1) le script ci-dessus doit être légèrement modifié avant d'être exécuté dans VOTRE environnement, vous devez modifier l'emplacement des fichiers et une expression régulière en fonction du format de votre fichier journal. Voir le commentaire dans le script. 2) le script ci-dessus ne vérifie pas si l'IP n'est pas répétée dans la table ACK, si 2 machines différentes ont obtenu la même adresse au cours des derniers jours. C'est par conception (ce dont j'avais personnellement besoin pour voir chaque adresse mac qui était présente dans mon réseau au cours des derniers jours) - vous pouvez facilement la modifier, il y a une section prête pour cela dans le code, ajoutez simplement une condition.

J'espère que vous aimez.

damago1
la source
1

Le format des fichiers de baux a changé, ou du moins il est différent lors de l'utilisation dhcpcd5. Pour voir le bail que vous avez sur wlan0le réseau WiFi MyNetwork, il vous faudrait regarder ce fichier (ou quelque chose comme ça): /var/lib/dhcpcd5/dhcpcd-wlan0-MyNetwork.lease.

Ce fichier est un fichier binaire. (Pourquoi? Je ne sais pas. Peut-être pour économiser de précieux cycles CPU en l'analysant? Blech.) Pour le voir, utilisez le dhcpcd --dumplease, qui analyse le binaire de STDIN et génère une version lisible par l'homme:

cat /var/lib/dhcpcd5/dhcpcd-wlan0-MyNetwork.lease | dhcpcd --dumplease

D'un autre côté, si vous voulez simplement voir à quoi correspond le bail actuel wlan0, vous pouvez simplement faire:

dhcpcd --dumplease wlan0
Shalom Craimer
la source
1

J'ai en fait écrit quelque chose en bash pour essayer d'obtenir cela. Il écrit chaque adresse IP dans le même fichier de nom, donc si une autre apparaît à nouveau, il écrasera le fichier précédent, il n'y aura donc pas de doublons. Il utilisera également oui.txt pour trouver le fabricant de l'adresse MAC en question.

Voyez si vous pouvez l'utiliser.

#!/bin/bash

pid=$$

while read i
do
        echo $i | egrep -qi '^lease|hardware|starts|ends|hostname' || continue
        if [[ $i =~ [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} ]]; then
                ip=$(echo $i | awk '{print $2}')
                printf "IP Address: " > /root/$ip.$pid
                echo $ip >> /root/$ip.$pid
        elif [[ $i =~ starts ]]; then
                printf "\tLease start: " >> /root/$ip.$pid
                echo $i | awk '{print $3,$4}' | tr -d ';' >> /root/$ip.$pid
        elif [[ $i =~ ends ]]; then
                printf "\tLease ends: " >> /root/$ip.$pid
                echo $i | awk '{print $3,$4}' | tr -d ';' >> /root/$ip.$pid
        elif [[ $i =~ ethernet ]]; then
                mac=$(echo -n $i | awk '{print $3}' | tr -d ';')
                oui=$(echo -n $mac | tr ':' '-' | cut -c1-8)

                printf "\tMAC Address: " >> /root/$ip.$pid
                echo $mac >> /root/$ip.$pid
                printf "\tManufacturer: " >> /root/$ip.$pid
                grep -i $oui /usr/share/hwdata/oui.txt | awk '{print $3,$4,$5,$6}' >> /root/$ip.$pid
                printf "\n" >> /root/$ip.$pid
        elif [[ $i =~ hostname ]]; then
                printf "\tHostname: " >> /root/$ip.$pid
                echo $i | awk '{print $2}' | tr -d ';' >> /root/$ip.$pid
        fi

done < /var/lib/dhcpd/dhcpd.leases

cat /root/*.$pid
echo "Total leased: $(ls -l /root/*.$pid | wc -l)"
rm -rf /root/*.$pid
Marko Todoric
la source