4

I want to join an IPv6 multicast group (in this example: "ff15::2a") via C# code.

What Worked

The following Python implementation works perfectly:

import socket
import struct

with socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) as s:
    # Build the request bytes (multicast address + interface [0])
    address_bytes = socket.inet_pton(socket.AF_INET6, "ff15::2a")
    interface_id = struct.pack("@I", 0)

    s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, address_bytes + interface_id)

And sends the following packet:

wireshark screenshot of the correct packet

What Didn't Work

The following C# implementation sends the wrong packet:

using System;
using System.Net.Sockets;

Socket socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);

//Build the request bytes (multicast address + interface [0])
byte[] addressBytes = IPAddress.Parse("ff15::2a").GetAddressBytes();
byte[] optionValue = new byte[addressBytes.Length + sizeof(int)];
Buffer.BlockCopy(addressBytes, 0, optionValue, 0, addressBytes.Length);

socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, optionValue);

Notice - changed to EXCLUDE!

wireshark screenshot of the wrong packet

Remarks

  • SocketOptionName.DropMembership sends the opposite packet too, but I can't use it as a workaround because it throws an exception if I'm not a member of the group already
  • C# works fine with IPv4 multicast, but not IPv6
  • I tested C# in .NET 6, .NET Core 3.1 and .NET Framework (Mono)
  • This alternative implementation has the same issue:
using System;
using System.Net.Sockets;

Socket socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);

IPAddress address = IPAddress.Parse("ff15::2a");
socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption(address));
Bip901
  • 590
  • 6
  • 22
  • That's really weird. I can tell you one thing: this basically feeds all the way through to `setsockopt` and the option you are passing is equal to `IPV6_ADD_MEMBERSHIP` so it should just work – Charlieface Sep 09 '22 at 14:19
  • What is this suppose to do : "address_bytes + interface_id" ? – jdweng Sep 09 '22 at 15:27
  • @Charlieface You are looking at IPv4. For IPv6 it's [ipv6_mreq](https://learn.microsoft.com/en-us/windows/win32/api/ws2ipdef/ns-ws2ipdef-ipv6_mreq). – Bip901 Sep 09 '22 at 16:50
  • Righto. Is this on the same machine as Python, have you tried updating drivers? – Charlieface Sep 09 '22 at 16:54
  • I can replicate this issue on my Windows 10 PC and on my Android 12 phone (Xamarin), so I'm guessing the problem is somewhere above the OS level. Edit: I've added a remark. – Bip901 Sep 09 '22 at 16:56
  • 1
    I would recommend trying the same on .NET 5, and see if it's a regression introduced via .NET 6. – Haney Sep 09 '22 at 17:09
  • What happens if you try the newer `MCAST_JOIN_GROUP` option along with a [`GROUP_REQ`](https://learn.microsoft.com/en-us/windows/win32/api/ws2ipdef/ns-ws2ipdef-group_req) struct? Essentially the same except with the two members flipped – Charlieface Sep 10 '22 at 20:58
  • @Haney Tried it now with .NET Core 3.1 LTS - same result. – Bip901 Sep 17 '22 at 13:50

0 Answers0