1
votes

I want to have an IPv6 UDP socket that can receive broadcast/multicast messages from any local interface using Link-Local addresses.

In Linux it is enough to bind it to in6addr_any, but in Windows you will not receive any multicast until you join a multicast group using setsockopt() + IPV6_JOIN_GROUP. The problem that an interface index must be provided during this option. But this is inconvenient. Is there a way to receive multicast from any interface in Windows?

UPD: I use destination address ff02::1 (All Nodes Address)

1
"I want to have an IPv6 UDP socket that can receive broadcast/multicast messages..." IPv6 doesn't have broadcast.Ron Maupin
I have no idea if if_index 0 has a special meaning, but it might be worth a try... Otherwise you'll have to loop over the available interfaces...Sander Steffann

1 Answers

0
votes

For IPv4, the index of the network interface is the IP address; for IPv6 the index of the network interface is returned by the method socket.getaddrinfo.

The code below shows how to listen to multicast on all network interfaces:

from socket import AF_INET6, AF_INET
import socket
import struct

# Bugfix for Python 3.6 for Windows ... missing IPPROTO_IPV6 constant
if not hasattr(socket, 'IPPROTO_IPV6'):
    socket.IPPROTO_IPV6 = 41

multicast_address = {
    AF_INET: ["224.0.1.187"],
    AF_INET6: ["FF00::FD"]
}
multicast_port = 5683

addr_info = socket.getaddrinfo('', None)  # get all ip
for addr in addr_info:
    family = addr[0]
    local_address = addr[4][0]

    sock = socket.socket(family, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind((local_address, multicast_port))
    if family == AF_INET:
        for multicast_group in multicast_address[family]:
            sock.setsockopt(
                socket.IPPROTO_IP,
                socket.IP_ADD_MEMBERSHIP,
                socket.inet_aton(multicast_group) + socket.inet_aton(local_address)
            )
    elif family == AF_INET6:
        for multicast_group in multicast_address[family]:
            ipv6mr_interface = struct.pack('i', addr[4][3])
            ipv6_mreq = socket.inet_pton(socket.AF_INET6, multicast_group) + ipv6mr_interface
            sock.setsockopt(
                socket.IPPROTO_IPV6,
                socket.IPV6_JOIN_GROUP,
                ipv6_mreq
            )
# _transport, _protocol = await loop.create_datagram_endpoint(
#     lambda: protocol_factory(), sock=sock)