如何在Python中找到多播UDP消息发送者的MAC地址?
我有一些代码,它通过UDP组播来监听“公告”。我可以获取发送者的IP地址,但我真正需要的是发送者的MAC地址(因为IP地址是可以变化的)。
有没有简单的方法可以在Python中做到这一点?
这里有一段代码供参考,但可能并不需要。
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
# Allow multiple sockets to use the same PORT number
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Bind to the port that we know will receive multicast data
sock.bind((self.interface, MCAST_PORT))
# Tell API we are a multicast socket
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
# Tell API we want to add ourselves to a multicast group
# The address for the multicast group is the third param
status = sock.setsockopt(socket.IPPROTO_IP,
socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(MCAST_ADDR) + socket.inet_aton(self.interface));
data, addr = sock.recvfrom(1024)
...
5 个回答
1
我不太确定能不能获取发送者的MAC地址,因为MAC地址是链接层的地址,而不是像IP那样的网络层地址。每当数据包在网络中从发送者传送到接收者时,MAC地址都会在每个跳转点发生变化。
2
要做到这一点,你需要捕获原始的以太网帧,而不仅仅是UDP数据包。
import socket
ETH_P_ALL=3
sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_ALL))
sock.bind((interface_name, 0))
data = sock.recv(2000)
dmac = data[:6]
smac = data[6:12]
udp_offset = 14
ethertype = data[12:14]
if ethertype == [0x81, 0x00]: # 802.1Q VLAN-tagged
udp_offset += 4
udp_pkt = data[udp_offset:]
一些注意事项:
- 如果以太类型值是0x88a8,那就表示802.1ad QinQ或“堆叠VLAN”,需要正确处理才能找到UDP数据。
- 在大多数Linux系统上,你需要是
root
用户(或者拥有CAP_NET_RAW
权限)才能这样做。至于Windows上需要什么,估计也差不多。 - 实际上,这会像打开了水龙头一样,因为它会接收到所有的UDP数据包。你可以自己解析UDP头部,筛选出你感兴趣的数据包,或者在Linux/BSD等系统上使用伯克利数据包过滤器,让内核帮你处理。后者在CPU使用上更高效,但实现起来比较麻烦。
- 有些答案建议使用ARP或类似的方法,可能会满足你的需求,但也不一定能行。它们会告诉你操作系统是如何将IP地址和MAC地址关联起来的;但这对第二层协议、多播、广播等情况,或者如果有东西在对ARP请求做假响应时,就没什么帮助了。
7
一般来说,你是无法获取到MAC地址的。在局域网(LAN)中,可能通过ARP协议能成功获取,但在互联网上就不行了。
想象一下,你收到的数据包里包含的是发送者的NAT路由器的IP地址。这个数据包可能经过了很多中间的机器,每台机器都有自己的MAC地址。那么,谁来负责支持你想要的那种查找呢?对于沿途的所有机器来说,发送者的MAC地址根本没有用处,所以为什么要费心去支持这种查找呢?
顺便提一下,很多网络卡上更改MAC地址是很简单的事情,所以把它当作某种唯一的标识符并不是个明智的选择。