runtime: UdpClient inconsistent behaviour between Windows and Linux.

Description

When binding a UdpClient to some specific IPEndPoint, it acts differently on Windows and Linux;
On Windows, the client receives both broadcast and unicast messages.
On Linux, the client only receives unicast messages.

Reproduction Steps

Create two dlls; one for a Windows machine and one for a Linux machine.
Replace the values of thisDeviceIp, otherDeviceIp and broadcastIp with ones appropriate for the devices.
Both devices should be able to communicate with one another and share broadcast IP.

static void Main(string[] args)
{
   string thisDeviceIp = "10.0.0.1"; // 10.0.0.1 is a Windows host.
   string otherDeviceIp = "10.0.0.2"; // 10.0.0.2 is a Linux host.
   string broadcastIp = "10.0.0.255";
   string interfaceName = "eno1" // Name of network interface with IP "thisDeviceIp" on the Linux host

    UdpClient udpClient = new()
    {
        EnableBroadcast = true
    };
    if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
    {
        // Attempt to set the socket option "SO_BINDTODEVICE" on Linux.
        udpClient.Client.SetRawSocketOption(1, 25, Encoding.UTF8.GetBytes(interfaceName));
    }
    client.Client.Bind(new IPEndPoint(IPAddress.Parse(thisDeviceIp), 0xA000));

    IPEndPoint unicastAdddress = new(IPAddress.Parse(otherDeviceIp), 0xA000);
    IPEndPoint broadcastAddress = new(IPAddress.Parse(broadcastIp), 0xA000);
    _ = Task.Factory.StartNew(() => Listener(udpClient));

   // Sender logic
    while (true)
    {
        ConsoleKeyInfo f = Console.ReadKey(true);
        if (f.Modifiers.HasFlag(ConsoleModifiers.Control) && f.Key == ConsoleKey.C)
        {
            return;
        }

        if (f.Key == ConsoleKey.A)
        {
            udpClient.Send(Encoding.UTF8.GetBytes("data"), unicastAdddress);
        }
        else if (f.Key == ConsoleKey.B)
        {
            udpClient.Send(Encoding.UTF8.GetBytes("data"), broadcastAddress);
        }
    }
}

static void Listener(UdpClient udpClient)
{
    int messages = 0;
    IPEndPoint? remoteHost = null;

    // Receiver logic.
    while (true)
    {
        udpClient.Receive(ref remoteHost);
        if (remoteHost != null)
        {
            Console.WriteLine($"Received message from {remoteHost} ({messages++})");
        }
    }
}

Expected behavior

Pressing A on one device should show up as Received message from {ip} on the other host (unicast).
Pressing B on one device should show up as Received message from {ip} on both hosts (broadcast).

Actual behavior

Pressing A on one device correctly displays a message in the other.
Pressing B, however, only shows messages on the Windows host.

Regression?

No response

Known Workarounds

Bind to IPAddress.Any instead of a specific IP.
Not preferable, since both computers may have multiple network adapters with different IP addresses and using IPAdress.Any seems to pick semi-randomly.

Configuration

.NET version: Microsoft.NETCore.App 6.0.13 OS:

  • Windows host: Windows 10 x64
  • Linux host: Ubuntu 22.04.1 LTS (GNU/Linux 5.19.0-32-generic x86_64)

This issue does not seem to be specific to the specified Linux version, as this has also been tested with ubuntu 18.04 and 20.04.

Other information

No response

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 1
  • Comments: 19 (11 by maintainers)

Most upvoted comments

Thanks @tmds for chiming in!

Yep, my question has been answered and we’ve found a decent alternative.