在Python中查找多播UDP消息的发送方的MAC地址?

时间:2009-11-12 13:42:03

标签: python sockets udp multicast mac-address

我有一些代码通过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 个答案:

答案 0 :(得分:7)

通常,您无法获取mac地址。您可能在LAN上使用ARP成功,但在Internet上则不可能。

考虑您收到的数据包具有发件人NATting路由器的IP地址的情况。数据包可能已经遍历了任意数量的中间机器,每个中间机器也具有mac地址。谁应该支持你所追求的那种查询?对于沿途的所有机器,发件人的mac地址完全没用,为什么还要支持那种查找呢?

而且,顺便说一下,changing the mac address在很多网卡上都是微不足道的,所以将它用作某种独特的ID并不是一个明智的想法。

答案 1 :(得分:1)

您需要的协议是ARP。查看此question/answer了解详情

答案 2 :(得分:1)

我不确定是否可以获取发件人的MAC地址,因为MAC地址是链路级地址,而不是IP等网络级地址。当包含UDP消息的数据包从发送方路由到接收方时,MAC地址将在网络中的每一跳发生变化。

答案 3 :(得分:0)

我不知道如何在python中做到这一点,但有可能获得MAC地址。例如,通过使用tcpdump,我将所有数据包放入文件:

sudo tcpdump -i enp0s31f6 -w file_name port 6665

然后在python中用:

读取它
       packetlist = rdpcap("./file_name")
       for pkt in packetlist:  
       print pkt.src, pkt.load

你可以看到mac地址

编辑: 我找到了一种方法: 在函数嗅探的帮助下用scapy嗅探所有软件包,然后过滤软件包以获得你需要的东西。在那里你可以使用mac地址 例如,来自我的项目:

sniff(prn=self._pkt_callback, store=0)

def _pkt_callback(self, pkt):
    if not self.sniffer_on:
         return
    if Ether not in pkt or pkt[Ether].type != 0x800:
        return
    if pkt[IP].proto != 17: # 17 means UDP package
        return
    if pkt[UDP].dport != 6665:
        return

    print pkt.src, pkt.load    #src is mac address

答案 4 :(得分:0)

为此,您需要捕获原始以太网帧,而不仅仅是 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 等上)调查 Berkeley Packet Filter 让内核为您做这件事。后者的 CPU 效率更高,但实施起来却相当麻烦。
  • 建议使用 ARP 或类似方法的答案可能会满足您的需求,但也可能不会。他们会告诉你你的操作系统在 IP 地址和 MAC 之间有什么关联;这对第 2 层协议、多播、广播等或在响应 ARP 请求时撒谎都无济于事。