SendPingAsync Timeouts on WSL
I want to send Ping
s at a high interval at some sites, so I've created a simple C# Console App to do so:
while (true)
{
var start = DateTimeOffset.Now.ToUnixTimeMilliseconds();
var pingTask = Task.Run(async () =>
{
try
{
var pinger = new System.Net.NetworkInformation.Ping();
var pingReply = await pinger.SendPingAsync("google.com", 250);
Console.WriteLine(pingReply.Status);
} catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
});
await Task.WhenAny(Task.Delay(50), pingTask);
Console.WriteLine($"total wait: {DateTimeOffset.Now.ToUnixTimeMilliseconds() - start}");
}
While running this directly on Windows, nearly all pingTask
s result in Success
. However, running this on WSL or Docker (using the default auto-generated Dockerfile
from Visual Studio) results something like the following:
total wait: 69
Success
Success
total wait: 23
Success
total wait: 22
Success
total wait: 24
Success
total wait: 14
Success
total wait: 20
Success
total wait: 20
Success
total wait: 19
Success
total wait: 23
Success
total wait: 18
total wait: 53
total wait: 44
total wait: 53
total wait: 50
total wait: 50
TimedOut
total wait: 53
TimedOut
total wait: 42
TimedOut
total wait: 51
TimedOut
total wait: 52
TimedOut
total wait: 50
TimedOut
total wait: 51
TimedOut
and all subsequent tasks are TimedOut
. This applies to both WSL1 and WSL2. This does not occur when running on Docker in an actual Linux machine. I haven't tried running this directly on a Linux box without Docker.
Note also that the ping google.com -i 0.05
command works fine in WSL1 and WSL2 (when running as root of course) so sending pings on WSL can work.
It looks like there is some queue build up of sockets and it prevents all subsequent ping requests from occurring, but I was wondering if anyone knows why this might be. Is there some setting I can tweak to fix this?
It turns out this was in fact being flood banned, but not by the server. My own router was detecting my pings as a PING OF DEATH ATTACK
and blocking them. After messing with wireshark a bit, it looks like the specific thing that is causing my router to detect .NET's SendPingAsync
in Linux as an attack, but not rapid pings from either a Windows setup or the ping
cli tool in Linux is due to differences in using the Identifier
and Sequence Number
parts of the ICMP header.
Identifier | Sequence Number | |
---|---|---|
Linux ping CLI |
Constant | Incrementing |
Windows ICMP system call | Constant | Incrementing |
.NET SendPingAsync in Linux |
Incrementing | Constant |
In particular, the autoincrementing of the Identifier
specifically is what my router thinks is problematic.
The reasons behind why .NET's SendPingAsync
implementations are like this way is that it seems to replicate Mono's implementation (See discussion here and the relevant source code parts.) I'm not sure why Mono was implemented in this manner.
According to the spec both are valid uses so I suppose my router is just being weird:
Identifier
If code = 0, an identifier to aid in matching echos and replies,
may be zero.
Sequence Number
If code = 0, a sequence number to aid in matching echos and
replies, may be zero.