标题问题答案:
/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
View Code
把状态为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
View Code
控制器方法源代码如下:


@app.route("/wirelessClientList")
def dhcpClientPage():
# 获取DHCP客户端列表方法
deviceList = clearDhcpClientFreeAndToList(getDhcpClientMap())
print deviceList
return render_template('dhcpclient.html', dlist=deviceList)
View Code
页面中遍历(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 %}
View Code
















