มีคำสั่งที่ฉันสามารถใช้เพื่อถามเซิร์ฟเวอร์ dhcpd ที่อยู่ที่ได้รับมอบหมาย?
มีคำสั่งที่ฉันสามารถใช้เพื่อถามเซิร์ฟเวอร์ dhcpd ที่อยู่ที่ได้รับมอบหมาย?
คำตอบ:
ไม่ได้คุณจะได้รับข้อมูลด้านเซิร์ฟเวอร์นี้จากเซิร์ฟเวอร์ DHCP เท่านั้น ข้อมูลนี้มีอยู่ในไฟล์. Please ของเซิร์ฟเวอร์ DHCP: /var/lib/dhcpd/dhcpd.leases
หากคุณใช้เซิร์ฟเวอร์ DHCP ของ 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
รุ่นแพคเกจ4.3.1
มีคำสั่งนี้เพื่อแสดงรายการสัญญาเช่า:
dhcp-lease-list --lease PATH_TO_LEASE_FILE
นี่เป็นสคริปต์สคริปต์แบบง่ายที่สนับสนุน DHCP รุ่นเก่ากว่า คุณสามารถดูสำเนาในซอร์สโค้ด Debianหรือในการแจกจ่าย DHCP อย่างเป็นทางการ (ในcontrib/
) เช่นกัน
ผลลัพธ์ค่อนข้างดี:
$ 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-
มันสวยกว่านี้ถ้าคุณดาวน์โหลดoui.txt
ไฟล์ตามที่แนะนำ แต่เอาท์พุทสามารถอ่านไม่ออกเว้นแต่คุณจะใช้โปรแกรมแก้ไขต่อไปนี้:
--- 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
ชุดข้อมูลแก้ไขนี้ได้รับการส่งอัปสตรีมเป็น ISC-Bugs # 41288 และรอการตรวจสอบ
สามารถใช้คำสั่ง egrep เพื่อรับเอาต์พุต:
egrep "lease|hostname|hardware|\}" /var/lib/dhcpd/dhcpd.leases
เอาท์พุท:
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;
}
คำตอบส่วนใหญ่ข้างต้นเป็นบางส่วน และตามจริงแล้วไม่มีวิธีแก้ปัญหาง่ายๆ 1) คุณสามารถแยกวิเคราะห์ไฟล์ฐานข้อมูล dhcpd.leases และรับข้อมูลเกี่ยวกับสัญญาเช่าที่ใช้งานอยู่ แต่คุณจะไม่ได้รับข้อมูลเกี่ยวกับที่อยู่ที่ถูกแก้ไขใด ๆ (มอบหมายโดยสายเช่น:
host switch1 { hardware ethernet a1:b2:c3:d7:2f:bc ; fixed-address switch1.mydomain.com; }
และนี่ก็ไม่ได้ให้ข้อมูลใด ๆ กับเมื่อครั้งล่าสุดที่มีการส่ง dhcp ack ไปยังเครื่อง
2) ในอีกทางหนึ่งคุณสามารถแยกไฟล์ dhcpd.log เพื่อค้นหาบรรทัด ack (พวกเขามีลักษณะเช่นนี้):
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
แต่สิ่งที่คุณควรทำจริงๆคือทำทั้งสองอย่าง ขั้นแรกให้แยกไฟล์บันทึกแล้วอัปเดตไฟล์ด้วยข้อมูลที่ได้รับจากไฟล์ dhcpd.leases พร้อมฐานข้อมูลสำหรับข้อมูลที่ขาดหายไปเช่นการเช่าเริ่มต้นเป็นต้น
ตอนนี้: ฉันได้เล่นเต็มวันประมาณ 2 วันทำการจนกว่าฉันจะได้สร้างโซลูชันที่สร้างตาราง HTML ที่มีสัญญาเช่าทั้งหมดที่ใช้งานอยู่ทั้งแบบคงที่และแบบไดนามิก นี่คือรหัสที่คุณสามารถวางไว้ในโฟลเดอร์ cgi-bin หรือที่ใดก็ได้
#!/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
โปรดทราบว่า: 1) สคริปต์ด้านบนต้องการการแก้ไขเล็กน้อยก่อนที่จะทำงานในสภาพแวดล้อมของคุณคุณต้องแก้ไขตำแหน่งไฟล์และหนึ่ง regex ขึ้นอยู่กับรูปแบบไฟล์บันทึกของคุณ ดูความคิดเห็นในสคริปต์ 2) สคริปต์ข้างต้นไม่ได้ตรวจสอบว่า IP ไม่ซ้ำในตาราง ACK หรือไม่หาก 2 เครื่องที่แตกต่างกันมีที่อยู่เดียวกันภายในวันที่ผ่านมา นี่คือการออกแบบ (สิ่งที่ฉันต้องการเห็น mac แต่ละตัวซึ่งอยู่ในเครือข่ายของฉันในช่วงวันที่ผ่านมา) - คุณสามารถแก้ไขได้อย่างง่ายดายมีส่วนที่พร้อมสำหรับโค้ดนี้เพียงเพิ่มเงื่อนไขเดียว
หวังว่าคุณจะชอบมัน.
dhcpcd5
รูปแบบของไฟล์สัญญาเช่ามีการเปลี่ยนแปลงหรืออย่างน้อยก็จะแตกต่างกันเมื่อใช้ หากต้องการดูสัญญาเช่าที่คุณมีในwlan0
เครือข่ายไร้สายMyNetwork
ที่คุณจะต้องมองไปที่ภาพนี้ /var/lib/dhcpcd5/dhcpcd-wlan0-MyNetwork.lease
(หรือสิ่งที่ชอบ):
ไฟล์นั้นเป็นไฟล์ไบนารี (เพราะอะไรฉันไม่ทราบอาจช่วยซีพียูที่ล้ำค่าในการแยกวิเคราะห์หรือไม่ Blech.) หากต้องการดูให้ใช้ตัวdhcpcd --dumplease
แยกวิเคราะห์ไบนารีจาก STDIN และส่งออกเวอร์ชันที่มนุษย์อ่านได้:
cat /var/lib/dhcpcd5/dhcpcd-wlan0-MyNetwork.lease | dhcpcd --dumplease
ในทางกลับกันหากคุณต้องการดูว่าสัญญาเช่าปัจจุบันที่กำหนดไว้wlan0
คืออะไรคุณสามารถทำได้ดังนี้
dhcpcd --dumplease wlan0
ฉันเขียนอะไรบางอย่างในทุบตีเพื่อลองสิ่งนี้ มันจะเขียนที่อยู่ IP ทุกไฟล์ไปยังชื่อไฟล์เดียวกันดังนั้นหากอีกอันหนึ่งปรากฏขึ้นอีกครั้งมันจะเขียนทับไฟล์ก่อนหน้าดังนั้นจะไม่มีการซ้ำซ้อน นอกจากนี้ยังจะใช้ oui.txt เพื่อค้นหาผู้ผลิตที่อยู่ MAC ที่เป็นปัญหา
ดูว่าคุณสามารถใช้มัน
#!/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
(เช่นไม่มีd
ที่ส่วนท้ายของคนแรกdhcp
... )