標題問題答案:
/var/lib/dhcp/dhcpd.leases,這個文件記錄了所有isc-dhcp-server分配的IP地址信息
dhcpd.leases文件詳解:
# 推薦用 $ man dhcpd.leases 指令 查看詳細含義
lease 192.168.8.24 {
starts 3 2016/05/18 10:48:59; # 分配地址的時間
ends 3 2016/05/18 10:58:59; # 租約到期時間
tstp 3 2016/05/18 10:58:59; # 租約到期時間
cltt 3 2016/05/18 10:49:04; # 客戶端最后訪問時間
binding state free; # 租約綁定狀態 狀態分別是 free 和 active
hardware ethernet 30:3a:64:50:2d:32; # 客戶端mac地址
uid "\0010:dP-2"; # 客戶端識別id
set vendor-class-identifier = "MSFT 5.0";
}
lease 192.168.8.25 {
starts 2 2016/06/14 04:23:16;
ends 2 2016/06/14 04:33:16;
cltt 2 2016/06/14 04:23:16;
binding state free;
next binding state free;
rewind binding state free;
hardware ethernet c0:ee:fb:25:82:92;
client-hostname "android-50efd8d429a1278b"; # 客戶端主機名
}
lease 192.168.8.25 {
starts 2 2016/06/14 04:28:08;
ends 2 2016/06/14 04:38:08;
cltt 2 2016/06/14 04:28:08;
binding state active;
next binding state free;
rewind binding state free;
hardware ethernet c0:ee:fb:25:82:92;
client-hostname "android-50efd8d429a1278b";
}
你若對如何找這類文件感興趣,可以接着往下看v
軟件:isc-dhcp-server(以下簡稱IDS), python flask, hostapd
平台:debian8 for arm(raspberry pi 樹莓派)
硬件:EP-N8508GS USB無線網卡(以下簡稱為無線網卡),樹莓派2B(以下簡稱PI)
目的:
學習LINUX,制作一個基於網頁端管理的無線路由器(本文主要講怎么找DHCP的客戶端列表)。
選修課大作業,非常感謝萬老師開這門課,讓我學到了很多linux的知識。
主要思路:
PI以任意方式通過有線網卡連接外網;
PI通過無線網卡作為Wireless Access Point,用到軟件hostapd;
PI安裝isc-dhcp-server作為DHCP服務器分配IPV4地址;
PI配置IP table使通過AP連接可以訪問外網;
配置網頁大部分已經完成,只是做功能補充,添加查看DHCP客戶端列表功能。
分析:
DHCP由isc-dhcp-server控制,linux不自帶DHCP服務器,所以猜測,DHCP的客戶端都是由IDS記錄的。
第一種情況,所有的記錄文件直接以文本文件的形式保存,文件命名是isc-dhcp-*,這種方法我們讀取查找起來最簡單;
第二種情況,文本文件記錄,存放在*/isc-dhcp/*,讀取起來和上一種情況類似;
第三種情況,用了sqlite存儲信息,被保存成*.db文件,這是讀取起來最麻煩的;
第四種情況,DHCP客戶端信息放在內存中,其他程序無法讀取,如果是這樣的,那就基本無解了,但是想到世面上的路由器都有查看DHCP客戶端的功能,IDS這個軟件應該會把這信息記錄到本地文件吧。
無論是什么情況,首先得把存儲信息的文件找出來,執行以下查找文件的指令:
$ sudo find / -name 'isc-dhcp*' -type f
查找結果:
pi@raspberrypi:~ $ sudo find / -name 'isc-dhcp*' -type f /var/lib/dpkg/info/isc-dhcp-client.conffiles /var/lib/dpkg/info/isc-dhcp-client.postrm /var/lib/dpkg/info/isc-dhcp-server.postrm /var/lib/dpkg/info/isc-dhcp-server.conffiles /var/lib/dpkg/info/isc-dhcp-server.prerm /var/lib/dpkg/info/isc-dhcp-server.list /var/lib/dpkg/info/isc-dhcp-server.config /var/lib/dpkg/info/isc-dhcp-client.md5sums /var/lib/dpkg/info/isc-dhcp-server.templates /var/lib/dpkg/info/isc-dhcp-server.postinst /var/lib/dpkg/info/isc-dhcp-common.list /var/lib/dpkg/info/isc-dhcp-client.list /var/lib/dpkg/info/isc-dhcp-server.md5sums /var/lib/dpkg/info/isc-dhcp-client.postinst /var/lib/dpkg/info/isc-dhcp-client.preinst /var/lib/dpkg/info/isc-dhcp-common.md5sums /run/systemd/generator.late/isc-dhcp-server.service
看到’isc-dhcp-client.list’這個文件,欣喜若狂,莫非就這么被我找到了,查看了一下結果…
pi@raspberrypi:/var/lib/dpkg/info $ cat isc-dhcp-client.list /. /var /var/lib /var/lib/dhcp /sbin /sbin/dhclient-script /sbin/dhclient /etc /etc/dhcp /etc/dhcp/dhclient.conf /etc/dhcp/dhclient-exit-hooks.d /etc/dhcp/dhclient-exit-hooks.d/debug /etc/dhcp/dhclient-exit-hooks.d/rfc3442-classless-routes /etc/dhcp/dhclient-enter-hooks.d /etc/dhcp/dhclient-enter-hooks.d/debug /usr /usr/share /usr/share/doc /usr/share/doc/isc-dhcp-client /usr/share/doc/isc-dhcp-client/copyright /usr/share/doc/isc-dhcp-client/changelog.Debian.gz /usr/share/doc/isc-dhcp-client/NEWS.Debian.gz /usr/share/man /usr/share/man/man5 /usr/share/man/man5/dhclient.conf.5.gz /usr/share/man/man5/dhclient.leases.5.gz /usr/share/man/man8 /usr/share/man/man8/dhclient-script.8.gz /usr/share/man/man8/dhclient.8.gz
繼續,當查看到isc-dhcp-client.postrm這個文件時,漸漸開始明朗了起來,紅色的語句,應該就是初始化dhcp服務時,需要刪除的文件,那么就是本次dhcp服務的記錄文件,接下來就是查看這些文件。
pi@raspberrypi:/var/lib/dpkg/info $ cat isc-dhcp-client.postrm #!/bin/sh -e # # if [ "$1" = "purge" ]; then # Remove lease database rm -f /var/lib/dhcp/dhclient*.leases rm -f /var/lib/dhcp/dhclient*.lease # Try to remove directory if [ -d /var/lib/dhcp ]; then rmdir --ignore-fail-on-non-empty /var/lib/dhcp/ fi rmdir --ignore-fail-on-non-empty /etc/dhcp fi
轉到 /var/lib/dhcp/ 可以看到有這樣一個文件,翻譯過來是dh客戶端.租約,猜想應該就是這個文件了:
pi@raspberrypi:/var/lib/dhcp $ ls -la dhclient*.leases -rw-r--r-- 1 root root 0 Mar 18 08:08 dhclient.leases pi@raspberrypi:/var/lib/dhcp $ cat dhclient.leases pi@raspberrypi:/var/lib/dhcp $
查看了一下 空歡喜,什么都沒有,
那就看看這個路徑還有些什么文件:
pi@raspberrypi:/var/lib/dhcp $ ls -la total 20 drwxr-xr-x 2 root root 4096 Jun 14 16:16 . drwxr-xr-x 47 root root 4096 May 18 10:32 .. -rw-r--r-- 1 root root 0 Mar 18 08:08 dhclient.leases -rw-r--r-- 1 root root 5535 Jun 14 16:50 dhcpd.leases -rw-r--r-- 1 root root 3015 Jun 14 16:16 dhcpd.leases~
文件數量不多,逐個查看,dhcpd.leases這個文件,沒錯就是他 運氣不錯,記錄了DHCP客戶端的連接日志:
pi@raspberrypi:/var/lib/dhcp $ cat dhcpd.leases # The format of this file is documented in the dhcpd.leases(5) manual page. # This lease file was written by isc-dhcp-4.3.1 lease 192.168.8.22 { starts 1 2016/06/14 16:55:13; ends 2 2016/06/14 17:05:13; cltt 2 2016/06/14 16:55:13; binding state active; next binding state free; rewind binding state free; hardware ethernet 0c:1d:af:e3:ab:e0; client-hostname "android-33afb4dbee873a4b"; }
# The format of this file is documented in the dhcpd.leases(5) manual page.
第一句注釋說,這個格式在dhcpd.leases(5)的用戶手冊,用戶手冊中記錄了每個項的詳細含義
$ man dhcpd.leases
這是我們需要用到的內容
lease 192.168.8.22 { starts 1 2016/06/14 16:55:13; # 租約開始時間 ends 2 2016/06/14 17:05:13; # 租約結束時間 cltt 2 2016/06/14 16:55:13; # 客戶端最后訪問時間 binding state active; # 綁定狀態 next binding state free; rewind binding state free; hardware ethernet 0c:1d:af:e3:ab:e0; # 客戶端mac地址 client-hostname "android-33afb4dbee873a4b"; # 客戶端主機名 }
接下來就是在python中寫獲取這些內容的方法,源代碼如下:

def getDhcpClientMap(): dhcp_client_filepath = "/var/lib/dhcp/dhcpd.leases" #dhcp_client_filepath = "dhcpd.leases" # 打開文件 dhcp_client_file = open(dhcp_client_filepath) # 創建list用於存放 dhcpClientList = {} rline = dhcp_client_file.readline() while(rline): # 檢查地址位置 pos192 = rline.find('192.168') if(pos192 >= 0): # 如果找到 創建對象 posdkh = rline.find('{') rIpAddr = rline[pos192:posdkh - 1] rstartTime = '' rendTime = '' rBindState = '' rMacAddr = '' rHostName = '' # 查找其他內容 while(True): rline = dhcp_client_file.readline() if(rline.find('}') >= 0): break; if(rline.find('starts') >= 0): rstartTime = rline[rline.find('starts') + 9:].replace(';\n', '') continue; if(rline.find('ends') >= 0): rendTime = rline[rline.find('ends') + 7:].replace(';\n', '') continue; if(rline.find(' binding state') >= 0): rBindState = rline[rline.find(' binding state') + 15:].replace(';\n', '').replace(' ', '') continue; if(rline.find('hardware ethernet') >= 0): rMacAddr = rline[rline.find('hardware ethernet') + 17:].replace(';\n', '').replace(' ', '') continue; if(rline.find('client-hostname') >= 0): rHostName = rline[rline.find('client-hostname') + 15:].replace(';\n', '').replace(' ', '').replace('"', '') continue; dxbDhcpClient = {} dxbDhcpClient['ipAddr'] = rIpAddr dxbDhcpClient['satrtTime'] = rstartTime dxbDhcpClient['endTime'] = rendTime dxbDhcpClient['bindState'] = rBindState dxbDhcpClient['macAddr'] = rMacAddr dxbDhcpClient['hostName'] = rHostName # 添加到存放的list dhcpClientList[rMacAddr] = dxbDhcpClient # 接着下一個循環 rline = dhcp_client_file.readline() return dhcpClientList
把狀態為active 的設備放入到一個list中,供前端顯示:

# 清除非連接狀態的客戶端 def clearDhcpClientFreeAndToList(dhcpClientMap): for tk in dhcpClientMap.keys(): if(dhcpClientMap[tk]["bindState"] == 'free'): dhcpClientMap.pop(tk) changeList = [] for tk in dhcpClientMap.keys(): changeList.append(dhcpClientMap[tk]) return changeList
控制器方法源代碼如下:

@app.route("/wirelessClientList") def dhcpClientPage(): # 獲取DHCP客戶端列表方法 deviceList = clearDhcpClientFreeAndToList(getDhcpClientMap()) print deviceList return render_template('dhcpclient.html', dlist=deviceList)
頁面中遍歷(for endfor)獲取到的客戶端代碼如下:

{% for dev in dlist %} <tr> <td>{{dev.hostName}}</td> <td>{{dev.ipAddr}}</td> <td>{{dev.macAddr}}</td> <td>{{dev.satrtTime}}</td> <td>{{dev.endTime}}</td> </tr> {% endfor %}