3

i receive data from multicast for my UDP sniffer, but only in IPv4. My code looks like this,

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)

But i am receiving data only when i set IPv4 address, and i want also receive from IPv6 multicast address. I will be really grateful for any ideas and sorry for my english. ;-)

Sander Steffann
  • 9,509
  • 35
  • 40
  • my ideas was this: s = socket.socket(socket.AF_INET6, socket.SOCK_RAW, IP_PROTO_UDP) and s.setsockopt(socket.IPPROTO_IP, socket.IPV6_JOIN_GROUP, mreq) but i dont know, how to "pack" mreq or set it. – Pavel Sedlář Nov 07 '16 at 15:41

3 Answers3

4

this example gets a multicast on FF02::158 (IoTivity UDP CoAP) in Windows

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))

fuller answer https://stackoverflow.com/a/66943594/8625835

0

You need to use the sockopt IPV6_ADD_MEMBERSHIP, as the API between IPv6 and IPv4 is slightly different. This is a good example.

Hugh White
  • 468
  • 4
  • 7
  • Allright, thanks. And do you know how to set "mreq" like from code above i added? (mreq = struct.pack("4sl", socket.inet_aton('239.255.11.3'), socket.INADDR_ANY)) I dont know how to pack it. – Pavel Sedlář Nov 07 '16 at 16:52
  • ipv6_mreq is a 16-byte address, and an unsigned int interface index. Try mreq6 = struct.pack("16sI", socket.inet_pton( AF_INET6, 'your ip v6 group' ), 0 ) – Hugh White Nov 07 '16 at 17:12
  • And can iI use instead of 0 socket.INADDR_ANY? I got this part of code from some example of net and i don't quite get it, but i suppose when i used INADDR_ANY, i will listen on all ports. – Pavel Sedlář Nov 07 '16 at 17:22
0

This is what I'm doing in my code:

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))

This is for a DHCPv6 server, but you'll get the idea.

If you also want to get multicast packets transmitted by yourself you have to add:

mc_sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, 1)
Sander Steffann
  • 9,509
  • 35
  • 40