7

尝试使用 pybonjour 但不确定它是否是我需要的。https://code.google.com/p/pybonjour/

我希望能够自动发现出现在我的网络上的 iOS 设备,稍后将基于此运行脚本,但首先我只想在我的 wifi 网络上出现/消失时立即发现 iOS 设备。

那么问题来了,我该怎么做呢?在安装了 python27 和 pybonjour 包的 Windows 机器上运行,这两个示例从 pybonjour 页面工作,但是我运行什么命令来使用网络中包含的脚本发现 iOS 设备?还是只有在我运行此脚本的电脑上运行的发现服务!

如果我走错了方向,请告诉我,我似乎找不到这个包上的文档!

python browse_and_resolve.py xxxxxx

谢谢马特。

更新...

这篇文章和浏览器对查找我需要搜索的服务很有帮助,http ://marknelson.us/2011/10/25/dns-service-discovery-on-windows/。

例子; (这发现了我的苹果电视,不在家里的自动取款机,所以无法检查 iphone 的名称!我假设是 iphone!

python browse_and_resolve.py _appletv._tcp

此外,如果您有 Windows 实用程序 dns-sd.exe,它将搜索网络上所有可用的服务。我用它来找到我正在寻找的东西。

dns-sd -B _services._dns-sd._udp

更新...

“Bonjour 以两种方式使用: - 发布服务 - 检测(浏览)可用服务”。

对于我想做的事情,我认为它不会起作用,因为 ipad/iPhone 不会宣传服务,除非我正在运行一个宣传服务的应用程序(或者越狱我的 iPhone/ipad,然后 ssh 将打开) . 还有什么想法吗?

4

3 回答 3

4

您尝试做的事情(a)可能无法完成,并且(b)如果可以的话,可能不会有太大用处。

Bonjour 的重点是发现服务,而不是设备。当然,每项服务都是由某些设备提供的,因此您可以间接地发现带有它的设备……但只能通过发现他们正在宣传的服务。

据我所知,(Apple TV 除外)不宣传任何服务,除非您运行的应用程序使用 Bonjour 在其他机器上查找相同的应用程序。(越狱设备除外,经常宣传SSH、AFP等)

有几种方法可以间接获取网络上任何人所宣传的所有服务的列表。最简单的可能是使用Bonjour Browser for Windows。(我从未真正使用过它,但我使用过的原始 Mac 工具和 Java 端口建议 Windows 用户使用此 Windows 端口。)启动它,你会得到一个服务列表,并且您可以单击每个以获取详细信息。

因此,您可以验证您的 iPhone 和 iPad 没有宣传任何服务,这将表明无法通过 Bonjour 检测到它们。

同时,即使您确实找到了设备,您打算做什么?大概你想以某种方式与设备通信,对吧?无论您尝试与之通信的服务是什么……只需浏览该服务,然后在适当的情况下过滤到 iOS 设备。这比浏览 iOS 设备然后过滤到那些拥有您想要的服务的设备要容易得多。


至于有没有办法检测iOS设备……嗯,至少有两种可能。我不知道它们是否会起作用,但是……</p>

首先,即使 iOS 设备没有为你做任何广告,我认为它正在浏览可以做广告的服务。它还怎么发现 AirTunes 有一个 Apple TV,局域网上有一个 iTunes 可以与之同步,等等?

因此,使用 Bonjour 浏览器来获取您运行 iTunes 的桌面、Apple TV 等正在做广告的所有服务的列表。然后关闭桌面上的所有服务,使用 PyBonjour 来宣传任何看似相关的服务(如果需要,使用 netcat 在您宣传的端口上放置琐碎的侦听器)。然后打开你的 iPhone,看看它是否连接到其中任何一个。您可能希望让它运行一段时间,或者关闭 WiFi 再重新打开。(我猜,尽管有 Apple 的建议,但它并不会持续浏览大多数服务,而是每隔一段时间和/或每次网络状态发生变化时检查一次。毕竟,Apple 的建议是针对前台交互应用程序,不是后台服务。)

不幸的是,即使您可以找到所有 iOS 设备都可以连接的服务,您也可能无法仅通过连接来区分 iOS 设备和其他设备。例如,我很确定任何运行 iTunes 的 Mac 或 Windows 机器都会访问你的假 AirTunes 服务,任何 Mac 都会访问你的 AirPrint,等等。那么,您如何将其与 iPhone 击中它区分开来呢?您可能需要实际提供足够的协议才能从中获取信息。这对于 Apple 的未记录协议来说尤其困难。

但希望你会走运,并且会有所有 iOS 设备想要与之交谈的东西,而没有其他东西想要与之交谈。iTunes Sync 似乎是显而易见的可能性。

或者,他们必须广播一些内容,否则它们将无法正常工作。如果没有广播,您将无法访问 WiFi 网络。大多数家庭 WiFi 网络都使用 DHCP,这意味着它们也必须广播 DHCP 发现(和请求)。您可以在这些消息中检测到某种启发式签名。如果不出意外,启用 DDNS 应该会导致设备发送其主机名,并且您可以据此猜测(例如,除非您更改默认值,hostname.lower().endswith('iphone'))。

最简单的方法可能是将您的桌面设置为家庭网络的主要接入点。我相信这就像在控制面板中的某处打开 Internet 连接共享一样简单。(设置为 DHCP 中继代理的开销比作为一个完整的路由器要少得多,但我不知道你是如何开始在 Windows 上这样做的。)然后你可以捕获 DHCP 广播(或者,如果失败了, 802.11 广播。(有关从 Wireshark 神秘的单行描述中不明显的格式的详细信息,请参阅RFC 2131。 )

您可以更进一步,观察每个主机在连接到 Internet 后建立的 Internet 连接。任何定期检查 App Store、iOS 升级服务器等的设备……好吧,除非有越狱开发团队的人住在你家,那可能是 iPhone,对吧?缺点是其中一些检查可能是非常周期性的,并且在 iPhone 连接到您的网络 6 小时后检测它并不是很令人兴奋。

于 2013-05-10T18:27:51.813 回答
3

使用python-nmap而不是 Bonjour。或者您可以使用pyzeroconf(Bonjour 是 zeroconf 的实现),但它有点过时(但应该仍然可以使用)。

python-nmap 可能是最简单的,假设您想查找主机名中包含“iPhone”或“iPad”的所有连接设备(只是一个简单的概念):

import nmap

...

def notify_me(ip, hostname):
  print("I found an iOS device! IP Address: %s, Hostname: %s" % (ip, hostname))

iOS_device_list = ['iPhone', 'iPad']
iOS_devices_on_net = {}
nm = nmap.PortScanner()

# scan ip range
for i in range(2, 50, 1):
  ip = "192.168.1." + str(i)
  # specify ports to scan
  nm.scan(ip, '62078') # Matt mentioned that it picks up iphone-sync on this port
  hostname = nm[ip].hostname()
  for device in iOS_device_list:
    if device.lower() in hostname.lower():
      iOS_devices_on_net.update({ip:hostname})
      notify_me(ip, hostname)

# show all iOS devices in ip range
print iOS_devices_on_net

这种方法的局限性在于它依赖于个人没有更改他们的主机名,该主机名最初包括他们的姓名和设备名称。它还假设在 iOS 设备上有一个端口正在侦听,该端口将返回一个主机名(可能不是这种情况)。您可以osscan通过使用 python-nmap 库将其作为命令运行来使用首选。这显然是一种更好的方法。我上面的概念只是如何使用它的一个简单示例。

从命令行使用 nmap(我相信 python-nmap 有nm.commandline()方法)是最简单的:

nmap -O -v ip

也尝试添加--osscan-guess; --fuzzy以获得最佳效果。例子:

nmap -O -v --osscan-guess ip

然后只需在输出中搜索 iOS 设备关键字(请参阅此示例)。它是人类可读的。请注意,您需要以管理员身份运行所有这些才能使其正常工作(Windows:,runas其他:)sudo

于 2013-05-10T16:16:41.730 回答
0

所以我已经在同一个问题上工作了大约一年。我很快就让它在我的 mac 上运行,但在我的 PC 上运行时遇到了很多麻烦。我尝试了许多不同的方法。我有一个家庭自动化系统,当我或我的伴侣在家时(即我们的 iPhone 可以在家庭 WiFi 上检测到),它会打开暖气和热水(通过 arduino 和 RF 模块)。最后,我使用“nslookup”来查找 iPhone 的 IP 地址(以防 IP 地址因为它们是动态的而发生变化(但它们实际上从未在我的路由器上这样做))和“nmap”来检测 iPhone 是否开启网络。如果 iPhone 处于深度睡眠状态,'nmap' 并不总是能找到手机,所以在它说手机在家之前,我已经让它检查了 10 次。下面是我在 python 中的家庭自动化代码的一部分。我用过线程。

# Dictionary to store variables to reuse on program restart
v = {
    'boilerControlCH' : 'HIH', # 'scheduled' or 'HIH' (Honey I'm Home)
    'boilerControlHW' : 'scheduled',
    'thermostatSetPoint' : 20.8,
    'thermostatVariance' : 0.1,
    'morningTime' : datetime(1970,1,1,6,0,0),
    'nightTime' : datetime(1970,1,1,23,0,0),
    'someOneHome' : False,
    'guest' : False,
    'minimumTemperatureOO' : False,
    'minimumTemperature' : 4.0,
    'iPhoneMark' : {'iPhoneHostname' : 'marks-iphone', 'home' : False},
    'iPhoneJessica' : {'iPhoneHostname' :'jessicaesiphone', 'home' : False}
    }

# Check if anyone at home
def occupancyStatus(person, Bol = False):
    with lockOccupancyStatus:
        someOneHome = False

        if 'iPhone' in person:
            v[person]['home'] = Bol
        elif 'retest' in person:
            pass
        else:
            v[person] = Bol

        if v['guest'] == True:
            someOneHome = True

        for key in v:
            if 'iPhone' in key:
                if v[key]['home'] == True:
                    someOneHome = True

        v['someOneHome'] = someOneHome
        variablesToFile()
    return

和主要代码

# iPhone home status threading code
class nmapClass(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        global exitCounter

        nmapThread()
        msg.log('Exited nmapThread')    
        waitEvent.set()
        waitEventAdjustable.set()
        serialDataWaiting.set()
        exitCounter += 1


def nmapThread():
    iPhone = {}
    maxCounts = 10
    for phone in v:
        if 'iPhone' in phone:
            iPhone[phone] = {}
            iPhone[phone]['hostname'] = v[phone]['iPhoneHostname']
            iPhone[phone]['count'] = maxCounts
    #msg.log(iPhone)

    while exitFlag[0] == 0:
        for phone in iPhone:
            if iPhone[phone]['count'] > 0:
                phoneFound = False
                IPAddress = '0.0.0.0'

                # Find iPhones IP address using its hostname
                commandNsloolup = 'nslookup %s' %iPhone[phone]['hostname']
                childNslookup = pexpect.popen_spawn.PopenSpawn(commandNsloolup, timeout = None)
                output = childNslookup.readline()
                while '\r\n' in output:
                    #msg.log(output)
                    if 'Name:' in output:
                        output = childNslookup.readline()
                        if 'Address:' in output:
                            tempStr = output
                            startPoint = tempStr.find('192')
                            tempStr = tempStr[startPoint:]
                            IPAddress = tempStr.replace('\r\n', '')
                            #msg.log(IPAddress)
                    output = childNslookup.readline()


                if IPAddress == '0.0.0.0':
                    pass
                    #msg.error('Error finding IP address for %s' %iPhone[phone]['hostname'], GFI(CF()).lineno)
                else:
                    #commandNmap = 'nmap -PR -sn %s' %IPAddress
                    #commandNmap = 'nmap -p 62078 -Pn %s' %IPAddress # -p specifies ports to try and access, -Pn removes pinging
                    commandNmap = 'nmap -p 62078 --max-rate 100 %s' %IPAddress
                    childNmap = pexpect.popen_spawn.PopenSpawn(commandNmap, timeout = None)
                    output = childNmap.readline()
                    while '\r\n' in output:
                        if 'Host is up' in output:
                            phoneFound = True
                            break
                        output = childNmap.readline()
                    #if phoneFound:
                    #   break


                if phoneFound:              
                    iPhone[phone]['count'] = 0

                    if v[phone]['home'] == False:
                        msg.log('%s\'s iPhone has returned home' %phone)
                        occupancyStatus(phone, True)
                        waitEventAdjustable.set()
                    #else:
                        #msg.log('%s\'s iPhone still at home' %phone)
                else:
                    iPhone[phone]['count'] -= 1

                    if v[phone]['home'] == True and iPhone[phone]['count'] == 0:
                        msg.log('%s\'s iPhone has left home' %phone)
                        occupancyStatus(phone, False)
                        waitEventAdjustable.set()
                    #else:
                        #msg.log('%s\'s iPhone still away from home' %phone)

            elif iPhone[phone]['count'] < 0:
                msg.error('Error with count variable in iPhone dictionary', GFI(CF()).lineno)


        longWait = True
        for phone in iPhone:
            if iPhone[phone]['count'] > 0:
                longWait = False
                #msg.log('%s: %s' %(phone, iPhone[phone]['count']))

        if longWait:
            #msg.log('wait long')               
            # 600 = run every 10 minutes
            waitEvent.wait(timeout=600)
            for phone in iPhone:
                iPhone[phone]['count'] = maxCounts
        else:
            #msg.log('wait short')
            waitEvent.wait(timeout=60)  

    return

如果您将代码直接复制到自己的脚本中,则代码可能无法正常工作,因为缺少一些我没有复制的部分,以尝试保持简单易读,但希望上面的代码能让每个人都了解我是如何做到的做了事情。

于 2019-09-22T12:41:08.740 回答