I’m trying to send HTTP requests through specific network interfaces on my Raspberry Pi running .NET. I’ve written a C# program that creates an HttpClient bound to a specific interface. However, I’m encountering an issue where the client can only successfully connect through the interface that’s currently set as the default route, and will timeout otherwise.
Here’s a simplified version of my code:
public static HttpClient CreateBoundHttpClient(string interfaceName)
{
var @interface = NetworkInterface
.GetAllNetworkInterfaces()
.FirstOrDefault(i => i.Name == interfaceName);
if (@interface == null)
throw new ArgumentException($”Interface {interfaceName} not found.”);
var ipAddress = @interface
.GetIPProperties()
.UnicastAddresses
.FirstOrDefault(a => a.Address.AddressFamily == AddressFamily.InterNetwork)
?.Address;
if (ipAddress == null)
throw new InvalidOperationException($”No IPv4 address found for interface {interfaceName}.”);
var handler = new SocketsHttpHandler();
handler.ConnectCallback = async (context, cancellationToken) =>
{
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(ipAddress, 0));
try
{
await socket.ConnectAsync(context.DnsEndPoint, cancellationToken);
return new NetworkStream(socket, ownsSocket: true);
}
catch
{
socket.Dispose();
throw;
}
};
return new HttpClient(handler);
}
When I run my program, it attempts to make requests through both wlan0 and wlan1. Here are the results when wlan0 is the default route:
root@pi:~/Test $ ip route show default
default via 172.17.32.10 dev wlan0
root@pi:~/Test $ dotnet FreeWave.dll
wlan0 resp = OK
wlan1 = The request was canceled due to the configured HttpClient.Timeout of 10 seconds elapsing.
And when wlan1 is the default route:
root@pi:~/Test $ ip route show default
default via 172.17.32.10 dev wlan1
root@pi:~/Test $ dotnet FreeWave.dll
wlan0 = The request was canceled due to the configured HttpClient.Timeout of 10 seconds elapsing.
wlan1 resp = OK
Note that this does not seem to work either:
root@pi:~ $ ip route show default
default via 172.17.32.10 dev wlan0 proto dhcp src 172.17.34.168 metric 600
default via 172.17.32.10 dev wlan1 proto dhcp src 172.17.32.248 metric 601
Now, the interesting part is that curl works fine with both interfaces, regardless of which one is set as the default route:
curl –interface wlan0 https://api.ipify.org
curl –interface wlan1 https://api.ipify.org
Both of these curl commands succeed, even when the specified interface is not the default route.
I have attempted using a direct IP instead of a domain, thinking the issue could have been related to DNS resolution, but that did not seem to make a difference.
Note that this issue only seems to occur when both interfaces are connected to the same WiFi network.
My questions are:
Why does my C# code fail to connect through the non-default route interface, even though it successfully binds to it?
What might be causing this discrepancy between my C# code and curl?
How can I modify my code to achieve the same behavior as curl, allowing connections through any interface regardless of the default route?
Any insights or suggestions would be greatly appreciated!