FreeBSD: ReceiveMessageFromAsync returns IPPacketInformation.Interface == 0 for IPv4 limited broadcast
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
### 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:
```text
0.0.0.0:68 -> 255.255.255.255:67
```
.NET 10 reports:
```text
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:
```text
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:
```csharp
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:
```text
0.0.0.0:68 -> 255.255.255.255:67
```
The .NET application reports:
```text
Destination : 255.255.255.255
Interface index : 0
```
while the receiving interface is:
```text
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:
```text
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:
```text
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:
```text
0
```
while `PacketInformation.Address` correctly contains:
```text
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
```text
.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.
Contributor guide
Research direction
Reproduce the issue with Socket.ReceiveMessageFromAsync on FreeBSD using the console application and compare its IPPacketInformation.Interface value with native recvmsg() using IP_RECVDSTADDR and IP_RECVIF. Trace the FreeBSD socket implementation responsible for translating control messages into IPPacketInformation. Done means the limited-broadcast packet reports the receiving interface index, such as 2 for igc1, while existing destination-address behavior remains correct.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- networking, operating-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100