Có một lệnh tôi có thể sử dụng để hỏi máy chủ dhcpd địa chỉ nào đã được chỉ định không?
Có một lệnh tôi có thể sử dụng để hỏi máy chủ dhcpd địa chỉ nào đã được chỉ định không?
Câu trả lời:
Không, bạn chỉ có thể nhận được phía máy chủ thông tin này từ máy chủ DHCP. Thông tin này được chứa trong tệp .lease của máy chủ DHCP : /var/lib/dhcpd/dhcpd.leases
, nếu bạn đang sử dụng máy chủ DHCP của ISC.
$ 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";
}
...
...
isc-dhcpd
phiên bản gói 4.3.1
có lệnh này để liệt kê hợp đồng thuê:
dhcp-lease-list --lease PATH_TO_LEASE_FILE
Đây là một kịch bản lệnh perl đơn giản cũng hỗ trợ các bản phát hành DHCP cũ hơn. Bạn cũng có thể thấy một bản sao trong mã nguồn Debian hoặc trong bản phân phối DHCP chính thức (in contrib/
).
Đầu ra khá đẹp:
$ 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-
Sẽ đẹp hơn nếu bạn tải xuống oui.txt
tệp theo đề xuất, nhưng sau đó đầu ra có thể bị cắt xén trừ khi bạn áp dụng bản vá sau:
--- 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
Bản vá này đã được gửi ngược dòng dưới dạng ISC-Bugs # 41288 và đang chờ xem xét.
Lệnh egrep có thể được sử dụng để nhận đầu ra:
egrep "lease|hostname|hardware|\}" /var/lib/dhcpd/dhcpd.leases
Đầu ra:
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;
}
Hầu hết các câu trả lời ở trên là một phần. Và thành thật mà nói không có giải pháp đơn giản. 1) Bạn có thể phân tích tệp cơ sở dữ liệu dhcpd.lease và nhận thông tin về hợp đồng thuê hoạt động, nhưng bạn sẽ không nhận được thông tin về bất kỳ địa chỉ CỐ ĐỊNH nào (được chỉ định bởi một dòng như:
host switch1 { hardware ethernet a1:b2:c3:d7:2f:bc ; fixed-address switch1.mydomain.com; }
Và điều này cũng không thực sự cung cấp bất kỳ thông tin nào về lần cuối cùng một ack dhcp được gửi đến máy.
2) mặt khác, bạn có thể phân tích tệp dhcpd.log để tìm kiếm các dòng ack (chúng trông như thế này):
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
Nhưng những gì bạn thực sự nên làm là làm cả hai. Đầu tiên phân tích tệp nhật ký, sau đó cập nhật tệp với thông tin thu được từ tệp dhcpd.lease với cơ sở dữ liệu cho các thông tin bị thiếu như cho thuê bắt đầu, v.v.
Bây giờ: Tôi đã chơi khoảng 2 ngày làm việc cho đến khi tôi tạo ra một giải pháp tạo bảng HTML với TẤT CẢ các hợp đồng thuê hoạt động, cả CỐ ĐỊNH và động. Đây là mã mà bạn có thể đặt trong thư mục cgi-bin của bạn hoặc bất cứ nơi nà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 <marcin@gosiewski.pl>
# based on portions of code by Jason Antman <jason@jasonantman.com>
#
# 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
Xin lưu ý rằng: 1) tập lệnh trên cần sửa đổi một chút trước khi chạy trong môi trường CỦA BẠN, bạn phải sửa đổi vị trí tệp và một regex tùy thuộc vào định dạng tệp nhật ký của bạn. Xem bình luận trong kịch bản. 2) tập lệnh trên không kiểm tra xem IP có được lặp lại trong bảng ACK hay không, nếu 2 máy khác nhau có cùng địa chỉ trong những ngày qua. Đây là theo thiết kế (những gì cá nhân tôi cần để xem từng địa chỉ mac có trong mạng của tôi trong những ngày qua) - bạn có thể dễ dàng sửa đổi nó, có một phần sẵn sàng cho mã này, chỉ cần thêm một điều kiện.
Hy vọng bạn thích nó.
Định dạng của các tập tin cho thuê đã thay đổi, hoặc ít nhất là khác nhau khi sử dụng dhcpcd5
. Để xem hợp đồng thuê mà bạn có đối wlan0
với mạng WiFi MyNetwork
, bạn phải xem tệp này (hoặc một cái gì đó tương tự) : /var/lib/dhcpcd5/dhcpcd-wlan0-MyNetwork.lease
.
Tập tin đó là một tập tin nhị phân. (Tại sao? Tôi không biết. Có lẽ để lưu một số chu kỳ CPU quý giá trong việc phân tích cú pháp? Blech.) Để xem nó, hãy sử dụng dhcpcd --dumplease
, phân tích cú pháp nhị phân từ STDIN và đưa ra phiên bản có thể đọc được của con người:
cat /var/lib/dhcpcd5/dhcpcd-wlan0-MyNetwork.lease | dhcpcd --dumplease
Mặt khác, nếu bạn chỉ muốn xem hợp đồng thuê hiện tại được giao wlan0
là gì, bạn có thể chỉ cần làm:
dhcpcd --dumplease wlan0
Tôi thực sự đã viết một cái gì đó trong bash để cố gắng để có được điều này. Nó ghi mọi địa chỉ IP vào cùng một tệp tên, vì vậy nếu một địa chỉ khác xuất hiện lại, nó sẽ ghi đè lên tệp trước đó, do đó sẽ không có bất kỳ bản sao nào. Nó cũng sẽ sử dụng oui.txt để tìm nhà sản xuất địa chỉ MAC được đề cập.
Xem nếu bạn có thể sử dụng nó.
#!/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
/var/lib/dhcp/dhcpd.leases
(tức là khôngd
ở cuối phần đầu tiêndhcp
...)