Skip to content

FreeBSD: ReceiveMessageFromAsync returns IPPacketInformation.Interface == 0 for IPv4 limited broadcast #132360

Description

@setsor

Description

On FreeBSD, Socket.ReceiveMessageFromAsync() returns IPPacketInformation.Interface == 0 when receiving an IPv4 limited broadcast packet, although the FreeBSD kernel provides the correct receiving interface through native recvmsg() / IP_RECVIF.

The issue was initially observed while debugging DHCPv4 traffic, but it was reproduced independently of the DHCP application.

For a packet received as:

0.0.0.0:68 -> 255.255.255.255:67

.NET 10 reports:

Remote endpoint : 0.0.0.0:68
Bytes           : 300
Destination     : 255.255.255.255
Interface index : 0

The packet was actually received on interface igc1, whose interface index is 2.

A native FreeBSD recvmsg() test using IP_RECVDSTADDR and IP_RECVIF reports:

destination : 255.255.255.255
ifindex     : 2
ifname      : igc1

Thus, the receiving-interface information is available from the FreeBSD kernel but is not reflected in SocketReceiveMessageFromResult.PacketInformation.Interface.

Reproduction Steps

Run the following .NET 10 console application on FreeBSD:

using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;

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

socket.SetSocketOption(
    SocketOptionLevel.Socket,
    SocketOptionName.ReuseAddress,
    true);

socket.EnableBroadcast = true;

socket.SetSocketOption(
    SocketOptionLevel.IP,
    SocketOptionName.PacketInformation,
    true);

socket.Bind(new IPEndPoint(IPAddress.Any, 67));

byte[] buffer = new byte[2048];
EndPoint remote = new IPEndPoint(IPAddress.Any, 0);

SocketReceiveMessageFromResult result =
    await socket.ReceiveMessageFromAsync(
        buffer,
        SocketFlags.None,
        remote);

Console.WriteLine($"Remote endpoint : {result.RemoteEndPoint}");
Console.WriteLine($"Bytes           : {result.ReceivedBytes}");
Console.WriteLine($"Destination     : {result.PacketInformation.Address}");
Console.WriteLine($"Interface index : {result.PacketInformation.Interface}");

foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
{
    IPv4InterfaceProperties? ipv4 =
        ni.GetIPProperties().GetIPv4Properties();

    if (ipv4 != null)
        Console.WriteLine($"{ni.Name}: interface index {ipv4.Index}");
}

Send an IPv4 limited broadcast packet to UDP port 67 on the same L2 network.

The issue was reproduced with a DHCPDISCOVER packet:

0.0.0.0:68 -> 255.255.255.255:67

The .NET application reports:

Destination     : 255.255.255.255
Interface index : 0

while the receiving interface is:

igc1: interface index 2

As a control test, a native FreeBSD UDP socket using recvmsg() with IP_RECVDSTADDR and IP_RECVIF receives the same type of limited-broadcast packet and reports:

destination : 255.255.255.255
ifindex     : 2
ifname      : igc1

Expected behavior

SocketReceiveMessageFromResult.PacketInformation.Interface should contain the index of the interface on which the IPv4 broadcast packet was received.

For this test, the expected value is:

2

corresponding to interface igc1, consistent with the interface information returned by native FreeBSD recvmsg() / IP_RECVIF.

Actual behavior

SocketReceiveMessageFromResult.PacketInformation.Interface is returned as:

0

while PacketInformation.Address correctly contains:

255.255.255.255

Native FreeBSD recvmsg() / IP_RECVIF reports interface index 2 (igc1) for the same type of packet.

Regression?

Unknown.

The behavior has been reproduced with .NET 10.0.10 on FreeBSD 15.1-RELEASE-p2. Earlier .NET runtime versions on FreeBSD have not been tested.

Known Workarounds

There is no reliable general application-level workaround when multiple interfaces may exist.

For an IPv4 limited broadcast, the destination address is 255.255.255.255, so the destination address itself cannot be used to determine the receiving interface.

In the original DHCP use case, a fallback can be implemented when only one unambiguous DHCP scope exists, but this does not solve the underlying loss of receiving-interface information and is not suitable for multi-interface systems.

Configuration

.NET SDK:
 Version:           10.0.110
 Commit:            f7d90799ce
 Workload version:  10.0.100-manifests.1641d827
 MSBuild version:   18.0.11+f7d90799c

Host:
 Version:           10.0.10
 Architecture:      x64
 Commit:            f7d90799ce

.NET runtimes installed:
 Microsoft.AspNetCore.App 10.0.10
 Microsoft.NETCore.App    10.0.10

Runtime Environment:
 OS Name:     FreeBSD
 OS Version:  15
 OS Platform: FreeBSD
 RID:         freebsd.15-x64

freebsd-version -ku:
 15.1-RELEASE-p2
 15.1-RELEASE-p2

uname -a:
 FreeBSD opnsense.home.arpa 15.1-RELEASE-p2 FreeBSD 15.1-RELEASE-p2 stable/26.7-n283714-dd064f22c895 SMP amd64

Other information

The discrepancy was isolated independently of the DHCP application that originally exposed it.

For the same type of IPv4 limited-broadcast traffic:

  • .NET Socket.ReceiveMessageFromAsync() reports interface index 0.
  • Native FreeBSD recvmsg() using IP_RECVIF reports interface index 2 (igc1).

The native test also confirms the destination address as 255.255.255.255.

This indicates that the FreeBSD kernel provides the receiving-interface information, but that information is not propagated into IPPacketInformation.Interface by the .NET socket implementation in this environment.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions