由于我的网络为上网设备和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在三层互通。

发表评论