2

我正在运行带有有线网络接口的 Linux 设备。此接口的另一端插入另一个网络感知设备,该设备配置为使用一些静态 IP 地址和一些网络掩码。因此,我们有一个非常简单的网络,仅由两台设备和一根电缆组成,甚至没有在它们之间切换,什么都没有。

任务是开始与另一台设备通话,我们需要

  1. 用 ifconfig 之类的把网络挂起来。
  2. 获取 IP 地址并启动我的程序,该程序使用此 IP 地址与设备一起工作。

我知道我可以进行广播 ping 并获取电缆另一端设备的 IP 地址。这对我有用。但是要激活网络并进行广播 ping,我需要知道网络地址和网络掩码。我当前的 bash 脚本看起来像

ifconfig 192.168.100.1 netmask 255.255.255.0 up
ping -b 192.168.100.255

设备做出响应。不幸的是,其中一些设备可能被错误地配置为不可预测的网络和网络掩码。任何人都可以提出如何自动检索网络设置(netbase,网络掩码)的想法吗?即使是部分解决方案也会感激不尽。如果有帮助,可以在我这边编译和安装一个自定义 C 工具。

4

2 回答 2

3

对于第一部分,只要您能以某种方式限制范围,您就可以使用 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 请求。

  1. 从倒数第二个子网开始N=29
  2. X从这个由主机 IP 和子网掩码组成的子网中选择一个 IP N。确保选择的 IP 不是主机的 IP,也不是网络/广播。还要确保这个 IP 不是由主机 IP 和掩码形成的子网的一部分N+1
  3. 使用源 Ping 另一台主机X(您不在乎它是否应答,只需发送请求即可)
  4. 如果您看到 ARP 请求X,则减N一。回到 2
  5. 如果您没有看到 的 ARP 请求XN+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 
于 2012-12-31T16:43:58.017 回答
-1

你所要求的是不可能的。

最初,您有一个没有 IP 地址的接口。因此,您发送的任何数据包都不知道将回复发送到哪里(ICMP 或 ARP 请求因此不起作用)。

由于发件人不知道如何到达此接口,您可以在该接口上侦听任何广播 ARP 请求(使用 tcpdump、wireshark 等)。这将向您显示网络中正在解析哪些 IP 地址,但确实如此不给你网络掩码(以及网络地址)。此外,它不仅为您提供直接连接的邻居的 IP 地址,它还将为您提供在此广播域内发出的所有ARP 请求(因此您可能会看到许多 IP 地址)。

现在,至于确定设备正在使用的网络掩码,在使用 CIDR 时是不可能的(前缀可能在 /16 和 /32 之间的任何位置,并且无法确切知道邻居设备正在使用哪一个.)

话虽如此,您可能想查看链接本地 IPv4 地址。在 Linux 上有一个名为 AVAHI 的程序,而在 Windows 上则称为 APIPA。两者都实现了 RFC 3927:https ://www.rfc-editor.org/rfc/rfc3927

链路本地地址只能用于与同一物理或逻辑链路上的设备通信,因此如果您确实希望此设备位于同一子网上,则必须手动配置接口。

于 2012-12-31T21:46:09.783 回答