由于我的网络为上网设备和IoT设备划分了不同的VLAN, 提供AirPlay服务的电视在IoT设备的VLAN, 且手机在上网设备的VLAN, 而mDNS组播报文在默认情况下不会跨越VLAN转发, 因此, 我需要某种方法来让手机收到电视发出的mDNS组播报文。为此, 我尝试了avahi的mDNS Reflector。然而, 我又发现它会导致某些设备觉得自己的主机名有冲突, 于是, 我决定研究一种新方法。后来, 考虑到我实际上只需要让上网设备的VLAN收到电视的AirPlay服务发出的mDNS组播报文, 我决定先在IoT设备的VLAN下抓包获得相应的mDNS报文, 然后再手动在上网设备的VLAN中重放。具体方案记录如下:
一、抓包
如上所述, 先在IoT设备的VLAN下抓相应的mDNS组播包, 保存备用。
二、重放
然后, 我研制了一份脚本, 来定期通过ICMP Echo Request (俗称ping)检测电视是否开启, 若开启了, 则手动重放相应的mDNS组播包:
#!/usr/bin/env python3 import binascii import time from scapy.all import conf from scapy.layers.l2 import * from scapy.layers.inet import * from scapy.sendrecv import * conf.promisc = False conf.sniff_promisc = False payload = ''' 这里粘贴mDNS报文的有效载荷部分, 从UDP头结束之后开始, 格式为: 00 00 84 00 00 00 00 0e 00 00 00 05 01 31 01 31 03 31 31 31 03 31 31 31 07 69 6e 2d 61 64 64 72 ... '''.replace(' ', '').replace('\n', '') payload = binascii.a2b_hex(payload) SERVER_ADDR = '111.111.1.1' # 这里修改为服务器(电视)的IP地址 mdns = IP(src=SERVER_ADDR, dst='224.0.0.251', ttl=255) / UDP(sport=5353, dport=5353) / payload while True: echo = sr1(IP(dst=SERVER_ADDR) / ICMP(), timeout=1) if echo: send(mdns * 5, iface='eth0') # 这里修改为接入上网设备的VLAN的网络接口 time.sleep(10)
经测试, 非常好用!
请注意, 该脚本工作的前提是两个VLAN在三层互通。
发表评论