由于我的网络为上网设备和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组播包:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #!/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在三层互通。
发表评论