IPv6中使用RAW套接字进行UDP组播

3

我从多播接收数据,用于我的UDP嗅探器,但只能用IPv4。

我的代码看起来像这样:

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP)
except socket.error as msg:
    print('Socket could not be created. Error Code : ' + str(msg[0]) + ' Message ' + msg[1])
    sys.exit()

mreq = struct.pack("4sl", socket.inet_aton('239.255.11.3'), socket.INADDR_ANY)
# receive a packet

s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)

packet = s.recvfrom(65000)

我只能在设置IPv4地址时接收数据,但我也想从IPv6组播地址接收数据。非常感谢任何想法,对我的英语感到抱歉。;-)


我的想法是这样的:s = socket.socket(socket.AF_INET6, socket.SOCK_RAW, IP_PROTO_UDP)并且 s.setsockopt(socket.IPPROTO_IP, socket.IPV6_JOIN_GROUP, mreq)但是我不知道如何“打包”mreq或设置它。 - Pavel Sedlář
3个回答

4

这个例子在Windows上收到了一个针对FF02::158(IoTivity UDP CoAP)的组播。

import socket
import struct

address = ('', 5683)
interface_index = 0  # default

sock = socket.socket(family=socket.AF_INET6, type=socket.SOCK_DGRAM)
sock.bind(address)
for group in ['ff02::158']:  # multiple addresses can be specified
    sock.setsockopt(
        41,  # socket.IPPROTO_IPV6 = 41 - not found in windows 10, bug python
        socket.IPV6_JOIN_GROUP,
        struct.pack(
            '16si',
            socket.inet_pton(socket.AF_INET6, group),
            interface_index
        )
    )

while True:
    data, sender = sock.recvfrom(1500)
    while data[-1:] == '\0': data = data[:-1]  
    print(str(sender) + '  ' + repr(data))

完整的回答请参考https://dev59.com/O1DTa4cB1Zd3GeqPNOuK#66943594

0

你需要使用sockopt IPV6_ADD_MEMBERSHIP,因为IPv6和IPv4之间的API略有不同。这里有一个很好的例子。


好的,谢谢。你知道如何设置“mreq”吗?就像我上面添加的代码一样。(mreq = struct.pack("4sl", socket.inet_aton('239.255.11.3'), socket.INADDR_ANY)) 我不知道如何打包它。 - Pavel Sedlář
ipv6_mreq是一个16字节的地址和一个无符号整数接口索引。尝试mreq6 = struct.pack("16sI", socket.inet_pton(AF_INET6,'你的IPv6组'), 0)。 - Hugh White
我可以使用 socket.INADDR_ANY 替代 0 吗?我从网络上的某个示例代码中获取了这部分代码,但我不太明白它的意思。我猜当我使用 INADDR_ANY 时,我将会监听所有端口。 - Pavel Sedlář

0

这是我在我的代码中正在做的事情:

mc_address = ipaddress.IPv6Address('ff02::1:2')
listen_port = 547
interface_index = socket.if_nametoindex('eth0')

mc_sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
mc_sock.bind((str(mc_address), listen_port, 0, interface_index))
mc_sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP,
                   struct.pack('16sI', mc_address.packed, interface_index))

这是针对DHCPv6服务器的,但你可以理解这个想法。

如果你还想获取自己传输的多播数据包,你需要添加:

mc_sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, 1)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接