对于第一部分,只要您能以某种方式限制范围,您就可以使用 nmap,根据您的评论,这已经应该为您提供所需的主机:
sudo nmap -PR -sn 192.168.0-255.0-255 -e <interface-to-test>
这会根据 ARP 进行发现,如果成功,则在之后进行额外的 ICMP ping 以获取活动性。这个在没有活动本地主机的范围和 4 个活动主机的范围内花了我大约一秒钟的时间。因此,您甚至可以将其扩展到更大的范围,但不是完整的 IPv4 地址空间,除非您有一两天时间。在这种情况下,我只需连接wireshark 或tcpdump 并等待一个免费的ARP。
编辑:为此,您必须使用要测试的子网中的 IP 配置“源计算机”。我以为它会在离开子网或未配置 ip 时使用 ARP 的 DAD 模式,但它什么也不做。我在为下面的算法编写的脚本中添加了一个更通用的版本,但它比简单地使用 nmap 来获得这个结果要慢一些。
检测配置的网络掩码有点棘手。但我认为这个程序会起作用,主要思想是主机将向其子网中的主机发送一个 ARP 请求,而对于不在其子网中的主机,它的 default-gw 没有任何内容或 ARP 请求。
- 从倒数第二个子网开始
N=29
。
X
从这个由主机 IP 和子网掩码组成的子网中选择一个 IP N
。确保选择的 IP 不是主机的 IP,也不是网络/广播。还要确保这个 IP 不是由主机 IP 和掩码形成的子网的一部分N+1
。
- 使用源 Ping 另一台主机
X
(您不在乎它是否应答,只需发送请求即可)
- 如果您看到 ARP 请求
X
,则减N
一。回到 2
- 如果您没有看到 的 ARP 请求
X
,N+1
则搜索子网。
一个缺陷可能是过于雄心勃勃的网络堆栈实现可能会从传入的 ICMP 请求中学习 MAC,但我个人不知道有任何以这种方式工作的终端设备堆栈。
我不知道是否有工具可以为您执行此操作,但使用 ping、tcpdump 和子网计算器手动操作应该很容易;)。或者,如果您觉得有一些黑客行为,那么使用scapy实现这一点可能并没有太多工作
我自己编写了一个完整的 python scapy 脚本,它应该可以工作,我在我的家庭网络上的 linksys homegw、另一台 linux 机器和一个 android 设备上对其进行了测试:
from __future__ import print_function, absolute_import, unicode_literals
from scapy.base_classes import Net
from scapy.config import conf
from scapy.layers.inet import Ether, ARP, ICMP, IP
from scapy.sendrecv import srp, debug
import scapy.route
iface = b'eth0'
subnet_to_test = b'192.168.1.0/24'
#or:
subnet_to_test = b'192.168.1.*'
#IP/MAC discovery
pkt = Ether(dst=b'ff:ff:ff:ff:ff:ff') / ARP(psrc=b'0.0.0.0', pdst=subnet_to_test, hwdst=b'ff:ff:ff:ff:ff:ff')
responses = srp(pkt, timeout=1, retry=0, verbose=0, iface=iface)
for r in responses[0]:
found = r[1].getfieldval('psrc')
foundmac = r[1].getfieldval('hwsrc')
n = 29
conf.debug_match = 1
while n > -1:
net = Net("{}/{}".format(found, n))
my_src = net.choice()
while my_src in Net("{}/{}".format(found, n + 1)):
my_src = net.choice()
pkt = Ether(dst=foundmac) / IP(dst=found, src=my_src) / ICMP(type=8)
resp = srp(pkt, timeout=1, retry=0, verbose=0, iface=iface, filter=b'ether dst FF:FF:FF:FF:FF:FF and arp')
received = [x for x in debug.recv if x.haslayer(ARP) and x.getfieldval('pdst') == my_src]
received.extend(x[1] for x in resp[0] if x[1].haslayer(ARP) and x[1].getfieldval('pdst') == my_src)
if len(received) == 0:
print("Found host: {}/{} on mac {}".format(found, n + 1, foundmac))
break
n -= 1