【问题标题】:Trying to discover iOS devices on my network using python script尝试使用 python 脚本在我的网络上发现 iOS 设备
【发布时间】:2013-05-04 14:44:01
【问题描述】:

尝试使用 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 将开放)。还有什么想法吗?

【问题讨论】:

  • 首先,您确实安装了 Windows 版 Bonjour,对吧?
  • 是的。想我已经明白了。累了其他几个命令之类的。 python browse_and_resolve.py _airplay._tcp 并发现了我的苹果电视
  • 同时,Bonjour 的重点是发现服务,而不是设备。如果你发现了一个设备,你会怎么做?答案应该告诉你计划使用什么服务,它告诉你要浏览什么服务。例如,如果你想ssh 到你局域网上任何越狱的 iPhone,请浏览 _ssh._tcp
  • 最后,PyBonjour 的文档就是您链接到的那个页面,因为它只是围绕 Apple 的 Bonjour 或它的一个端口的一堆薄包装。因此,请阅读 Apple 的 overviewguidereference
  • 这是我最初的观点。据我所知,(未越狱的)iPhone 不会宣传任何服务,除非您正在运行使用 Bonjour 的应用程序。

标签: python ios bonjour


【解决方案1】:

使用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 设备关键字(请参阅this example)。它是人类可读的。请注意,您需要以管理员身份运行所有这些才能使其正常工作(Windows:runas,其他:sudo)。

【讨论】:

  • 我很确定您需要 scan 每个 IP,然后 nm[ip] 才能工作。当然,您必须扫描正确的端口以猜测主机名,这……我不确定您可以从哪些端口获得 iPhone 会打开。
  • @abarnert 你是对的,我在脑海中写下了这个。更新回复
  • 解决了第一个问题。并且关于-O 的额外内容很好(但您可能希望将--osscan-guess--fuzzy 添加到-O 行)。但是,iPhone 是否有 22-443 范围内的开放端口?如果没有,nmap 就没有什么可继续的了(也许时机除外)。 (此外,您提供的示例和它链接的文档都没有显示要查找 iOS 的关键字……但您可以通过在 iPhone 上运行它并查看字符串来解决这个问题;手动解析并不难。)
  • nmap 获取端口 62078 = iphone-sync
  • 另一个选项我曾想过在我拥有的 linux 机器上使用 DNS 服务器,或者只是使用我当前正在运行的 pfSense 防火墙运行 syslog 服务器。
【解决方案2】:

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

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

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

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

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

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


至于是否有任何方法来检测iOS设备……嗯,至少有两种可能。我不知道它们是否会起作用,但是……

首先,即使 iOS 设备没有为您做任何广告,我认为它正在浏览可以做广告的服务。它还怎么发现有一个 Apple TV 可以连接到 AirTunes,有一个局域网上的 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,了解从 Wireshark 神秘的单行描述中不明显的格式的详细信息。)

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

【讨论】:

  • 谢谢,只是试图检测一个人何时在家或不在家,使用那里的 iPhone。然后我会在我的服务器上运行基于此的脚本。早上会好好看看所有选项。
  • 是的,一直这么想,最后还是会看到的。
  • 不能越狱,运行最新的操作系统。
【解决方案3】:

所以我已经研究同一个问题大约一年了。我很快就让它在我的 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

如果您直接将代码复制到自己的脚本中,代码可能无法正常工作,因为缺少一些我没有复制的部分,以尝试保持简单易读,但希望上面的代码能给每个人一个感觉关于我做事的方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-18
    • 1970-01-01
    • 2015-10-04
    相关资源
    最近更新 更多