运行截图如下:
代码
直接贴代码了,里面有很详细的注释:
# -*- coding: utf-8 -*-
import os
import re
import socket
# 获取指定IP地址的MAC地址
def getMac(target_IP):
# 初始化 用正则表达式're'编译出匹配MAC地址的正则表达式对象
patt_mac = re.compile('([a-f0-9]{2}[-:]){5}[a-f0-9]{2}', re.I)
# ping
os.popen('ping -n 1 -w 500 {} > nul'.format(target_IP))
# 然后使用'arp'命令获取该IP地址对应的MAC地址 返回一个类文件对象 可以通过 read 方法获取命令的输出结果
arp_file = os.popen('arp -a {}'.format(target_IP))
# 使用正则表达式'self.patt_mac'在输出结果中查找符合 MAC 地址格式的字符串 并返回找到的第一个匹配项 即 IP 对应的 MAC 地址
mac_addr = patt_mac.search(arp_file.read())
# 根据正则表达式对象匹配MAC地址 如果匹配到了就返回MAC地址 否则返回None
if mac_addr:
mac_addr = mac_addr.group()
return mac_addr
else:
return '00-00-00-00-00-00'
# 获取与本机在同一局域网下的设备 IP与MAC的映射
if __name__ == '__main__':
'''
# 返回默认网卡对应的IP地址
ip_addr = socket.gethostbyname(socket.gethostname())
'''
# 创建一个UDP套接字
socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 连接到一个公共ip地址
socket.connect(('www.baidu.com', 80))
# 获取本地套接字的地址信息 这个地址信息就是本机在局域网中的IP地址
ip_addr = socket.getsockname()[0]
# 关闭套接字
socket.close()
print("当前本机局域网ip地址为:" + ip_addr + '\n')
# 获取网关
idx = 0
cnt = 0
for i in ip_addr:
idx = idx + 1
if (i == '.'):
cnt = cnt + 1
if (cnt == 3):
break
gate_way = ip_addr[0:idx]
# 循环发送arp请求及获取对应ip的mac地址
for i in range(0, 255):
target_IP = gate_way + str(i)
if (target_IP != ip_addr):
target_Mac = getMac(target_IP)
if (target_Mac == "00-00-00-00-00-00"):
print("{:>15}".format(target_IP) + ":\t\tTimeout!")
else:
print("{:>15}".format(target_IP) + ":\t\t" + target_Mac)
胡说八道
0x01
细心的你可能发现了,我注释掉了这么一句代码:
# 返回默认网卡对应的IP地址
ip_addr = socket.gethostbyname(socket.gethostname())
这是我刚开始用来获取本机 ip 的方法,先通过 socket.gethostname() 获取本机的主机名,然后通过 socket.gethostbyname() 将主机名转换为 ip 地址。
经过在多个不同的局域网下测试发现,如果你有装有虚拟机或者有多个网卡的话,可能会返回与你期望的 IP 地址不一致的结果,我这有时候就会返回虚拟机的虚拟网卡的 ip…
所以换成了创建套接字去访问公共地址的方法。
修正:
后面发现使用套接字的方法也有 bug,如果 ip 和 网关 的网络号不同时,跑出来的全是 Timeout(还没理解 遇到了就记录一下
方法总比困难多,我们可以通过执行 ‘route print’ 命令获取 默认路由 0.0.0.0
的网关:
route print
然后 像上面提取MAC地址那样提取出来用就好。
0x02
另外,这样似乎并不能保证当前能查到 MAC 地址的设备一定接入了局域网,因为可能这只是你的 arp缓存,而不是刚刚更新的。目前只想到这么两种解决方法:
1.在运行程序前,清下 arp 缓存。以管理员身份运行 powershell,执行:
arp -d *
2.使用 Python 的 Scapy 库(它可以用于构造和解析网络数据包)发送 ICMP Echo Request 报文,并解析 ICMP Echo Reply 报文中的源 MAC 地址。
(下一篇博客再实现…