如何检测本地网络中的特定设备?

lx0bsm1f  于 2021-07-11  发布在  Java
关注(0)|答案(2)|浏览(860)

我正在构建一个物联网解决方案,我将有多个设备连接到我的本地网络,我想连接到控制我的解决方案的集线器。
一旦我连接了一个新设备,我想把它和集线器连接起来,并给它一个名称来识别它。我想实现自动检测(所以我不知道)´不必手动输入ip地址)。例如,当chromecast出现在网络中时,我可以在手机的流媒体应用程序中看到它。所以我想做一些类似的事情来连接集线器和设备。
到目前为止,我的想法是有两种方法:
集线器扫描网络中的新设备(定期或当我说有新设备存在时)。
一旦连接,这些设备就会扫描网络以找到集线器。
这些方法中有哪一种更倾向于另一种吗?为什么?
做扫描时,无论我选择哪个方向,最有效的扫描方法是什么?我正在使用java实现一个应用程序,到目前为止,我得到的是:

int timeout = 100;
for (int i = 1; i < 255; i++)
{
    String host = subnet + "." + i;

    if (InetAddress.getByName(host).isReachable(timeout))
    {
        String hostname = InetAddress.getByName(host).getHostName();
        String canonicalHostName = InetAddress.getByName(host).getCanonicalHostName();
        System.out.println(host + " is reachable. Hostname: " + hostname + ", CanonicalHostName: " + canonicalHostName);
    }
}

我在这里看到的是,返回的主机名对于我网络中的大多数内容来说只是ip地址,而不是我在路由器中看到的主机名。我想我可以使用主机名作为一个识别器来检测特定的设备并了解它们在哪里-但是这个小poc似乎不起作用。那么我怎样才能很好地识别这些设备呢?
有没有java(或javascript)和esp8266的库/解决方案可以做到这一点(感觉像是一个常见的问题,如果实施“智能家居”设备)。

v2g6jxz6

v2g6jxz61#

我们发现局域网上的设备没有单一的方法。
设备通常不是扫描网络,而是使用多播或广播协议来宣布它们的存在,或者它们在(通常是外部的)预先配置的服务器上会合。
一些设备使用基于dns协议的MDN,它们通过多播数据包来在网络上公布它们的存在。苹果在其产品中使用MDN。它在android上的支持很差,需要在windows上安装额外的软件。MDN名称通常位于 .local 域名。
一些设备使用upnp和ssdp-belkin的wemo产品线来实现这一点。upnp和ssdp是基于xml和soap的过于复杂的协议,对于内存和处理能力有限的设备(如esp8266和esp32)来说,这是一个糟糕的选择。
有些设备只是使用自己的协议。俳句的“大屁股粉丝”系列就是这样做的——他们用一种国产的协议来广播udp数据包,这种协议至少一开始容易受到各种问题的攻击。除非你真的知道自己在做什么,否则我不建议你走这条路。其他已建立的协议已经有机会解决这些漏洞。除非您在协议设计方面有经验,否则您更有可能重新发现其他协议所遇到的问题,而不是一个漂亮闪亮的新可发现性协议。
这类设备要么定期广播或多播一个宣布自己的数据包,要么你称之为“集线器”的东西会广播或多播一个请求,而这些设备会响应这个请求。
并不是所有的设备都提供了一个接口来直接控制它们所连接的局域网。有些只是与远程服务器会合。在本例中,您通过请求服务器枚举它们来发现它们,并通过该服务器控制它们。谷歌的nest产品就是这样工作的——初始配置是通过蓝牙完成的;之后,应用程序通过远程服务器与设备通信。
以这种方式集合的设备通常预先配置有集合服务器的名称,但是在网络配置期间,它们也可能配置有服务器的名称(通常应用程序与它们通信以共享wifi凭据;它还可以共享关于集合服务器的信息)。
我们通常不会扫描ip地址块中的名称或主动探测新设备,除非我们正在调试网络或进行某种安全扫描。
您描述的扫描ip地址块的过程有问题且不可靠。它工作的唯一原因是一些路由器从设备的dhcp请求中获取设备的名称(或者路由器可能被配置为知道设备的名称)。路由器还为网络上的设备处理dns,通常通过将它们转发到isp的dns服务器或网络所有者配置它使用的dns服务器。它截获它知道其名称的设备的dns请求,并自己回复它们,而不是将它们转发到外部dns服务器。
您还必须了解网络配置才能正确执行此操作。网络只有24小时吗?如果是22号怎么办?还是16岁?如果网络配置为a/8,是否准备扫描2^24个ip地址?
虽然路由器可能会截获对名称和返回地址的请求,但它不一定会截获对地址和返回名称的请求。
扫描也会产生不必要的网络流量。虽然你的一个“枢纽”扫描可能看起来不多,如果你有多个扫描仪从不同的制造商运行它的规模不好。
如果你的“集线器”绕过路由器的dns请求,那么它也将无法解析路由器提供的名称。
也不是所有的路由器都这么做。它不是互联网体系结构的一部分,它是一些路由器提供的一种便利功能。你不能指望它能工作。
您还可以尝试对网络进行活动扫描,尝试与网络上的每个ip地址进行通信。我们这样做是为了进行网络调试,但是不断地运行它来检测新设备将是一种与网络交互的敌对方式。
网络基础设施设备-交换机和路由器-当然维护网络上所有活动设备的列表。您可以使用snmp(简单网络管理协议)访问这些列表,但是很少有用户交换机和路由器支持snmp。允许你的网络基础设施访问一个随机的软件是一个网络安全的噩梦。
最好的选择是一个简单的多播/广播协议,如mdns。不要扫描、宣布或请求。它响应迅速,不会给网络带来负担,不依赖于路由器的特性,也不会让网络管理员讨厌你。

wnrlj8wa

wnrlj8wa2#

很久以前,我实现了一个类似的解决方案来发现连接到网络的客户机。我的策略是利用dhcp配置。
如果您的设备必须从您控制的linux/unix dhcp服务器请求ip地址,您可以将其配置为在设备与网络连接或断开连接时通知您。
我们使用的是linux dhcp服务器,在dhcpd.conf中有一节是关于事件的。基本上,它说当dhcp为客户机提交一个特定的ip地址租约时,它会引发一个事件,当这种情况发生时,它可以运行一个您可以为该事件定义的侦听器。在侦听器中,我们可以要求dhcp执行一个命令,例如将客户机信息(例如mac地址)及其ip地址租约写入一个命名管道,而java应用程序可能只是从这个队列中读取(有关详细信息,请参见dhcp评估)。当客户端释放ip租约或租约到期时,可以运行类似的事件。
下面是一个例子

subnet 192.168.1.0 netmask 255.255.255.0 {
    option routers  192.168.1.2;

    on commit {
        set clip = binary-to-ascii(10, 8, ".", leased-address);
        set clhw = binary-to-ascii(16, 8, ":", substring(hardware, 1, 6));
        execute("/usr/local/sbin/dhcpevent", "commit", clip, clhw, host-decl-name);
    }
    ...

如果你能控制你的dhcp配置有这么多你可以从中提取。

相关问题