Comando para listar endereços dhcp atribuídos

20

Existe um comando que posso usar para perguntar ao servidor dhcpd quais endereços foram atribuídos?

    
por pylover 21.09.2013 / 20:19

6 respostas

21

Não, você só pode obter esse servidor de informações do servidor DHCP. Essas informações estão contidas no arquivo .lease do servidor DHCP: /var/lib/dhcpd/dhcpd.leases , se você estiver usando o servidor DHCP do ISC.

Exemplo

$ 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 "
$ 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 "%pre%1%pre%03w31i";
}
...
...
1%pre%03w31i"; } ... ...
    
por 21.09.2013 / 20:26
18

isc-dhcpd versão do pacote 4.3.1 tem este comando para listar as concessões:

dhcp-lease-list --lease PATH_TO_LEASE_FILE

Este é um script de script perl simples que também suporta versões DHCP mais antigas. Você pode ver uma cópia no código-fonte do Debian ou na distribuição oficial de DHCP (em contrib/ ) também.

A saída é bonita:

$ 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-

É mais bonito se você baixar o arquivo oui.txt como sugerido, mas a saída pode ficar confusa a menos que você aplique o seguinte patch:

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

Este patch foi enviado como ISC-Bugs # 41288 e aguarda revisão.

    
por 05.12.2015 / 12:13
8
O comando

egrep pode ser usado para obter uma saída:

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

Saída:

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;
}
    
por 21.09.2013 / 20:47
3

A maioria das respostas acima é parcial. E para ser honesto, não há solução simples. 1) Você pode analisar o arquivo de banco de dados dhcpd.leases e obter informações sobre concessões ativas, mas você não obterá informações sobre quaisquer endereços FIXED (atribuídos por uma linha como:

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

E isso também não está realmente dando nenhuma informação sobre quando foi a última vez que um dhcp ack foi enviado para a máquina.

2) por outro lado, você pode analisar o arquivo dhcpd.log para procurar linhas ack (elas se parecem com isso):

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

Mas o que você realmente deve fazer é fazer ambos. Primeiro, analise o arquivo de log e, em seguida, atualize o arquivo com informações obtidas do arquivo dhcpd.leases com o banco de dados para informações ausentes, como a concessão de início de término etc.

Agora: Eu joguei cerca de 2 dias úteis completos até criar uma solução que cria uma tabela HTML com TODAS as concessões ativas, FIXED e dinâmicas. Aqui está o código que você pode colocar na pasta cgi-bin ou em qualquer lugar.

#!/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

Por favor, note que: 1) o script acima precisa de uma ligeira modificação antes de executar em seu ambiente, você tem que modificar os locais dos arquivos, e um regex dependendo do seu formato de arquivo de log. Veja o comentário no script. 2) o script acima não está verificando se o IP não é repetido na tabela ACK, se duas máquinas diferentes obtiveram o mesmo endereço nos últimos dias. Isso é por design (o que eu pessoalmente precisava ver cada endereço mac que estava presente na minha rede durante os últimos dias) - você pode modificá-lo facilmente, há uma seção pronta para isso no código, basta adicionar uma condição.

Espero que você goste.

    
por 13.03.2017 / 14:42
1

O formato dos arquivos de concessões foi alterado ou, pelo menos, é diferente ao usar dhcpcd5 . Para ver a concessão que você tem em wlan0 para a rede WiFi MyNetwork , você teria que olhar para este arquivo (ou algo parecido): /var/lib/dhcpcd5/dhcpcd-wlan0-MyNetwork.lease .

Esse arquivo é um arquivo binário. (Por quê? Eu não sei. Talvez para salvar alguns preciosos ciclos de CPU na análise? Blech.) Para visualizá-lo, use o dhcpcd --dumplease , que analisa o binário de STDIN e gera uma versão legível:

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

Por outro lado, se você quiser apenas ver qual a concessão atual atribuída a wlan0 , basta fazer:

dhcpcd --dumplease wlan0
    
por 22.07.2018 / 08:18
1

Eu realmente escrevi algo no bash para tentar entender isso. Ele grava todos os endereços IP no mesmo arquivo de nome, então se outro aparecer novamente, ele sobrescreverá o arquivo anterior, portanto, não haverá duplicatas. Ele também usará oui.txt para encontrar o fabricante do endereço MAC em questão.

Veja se você pode usá-lo.

#!/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
    
por 31.08.2018 / 23:02

Tags