support for fragmentation Ping option on Unix#34435
Conversation
src/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs
Outdated
Show resolved
Hide resolved
src/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs
Outdated
Show resolved
Hide resolved
| int resultLength = ReadLink(pingBinary, buffer, 4000); | ||
|
|
||
| // If pingBinary is not link resultLength will be -1 | ||
| if (resultLength > 0 && resultLength < 4000) |
There was a problem hiding this comment.
Where is this 4000 number coming from? It's used multiple times, so it'd be good to put it in a named constant, but I'm unclear as to its origin. Is it guaranteed to be big enough? Is it larger than is actually needed? Do we need to try again with ReadLink if the buffer size was insufficient?
There was a problem hiding this comment.
My memory failed me. I was thinking about MAXPATHLEN but that is only 1024 on Linux. That should be sufficient for any case. And probably bigger than we need as well. It is always possible that some system or particular installation would do something weird with ping and we may fail. When ping is part of os and it is link to something else, it would normally live in /[usr/]/[local]/[s]bin If it is not, it is probably not busybox.
Also note, that the code does not (and cannot) detect hard links. It will detect normal scenarios like Alpine and it may fail to detect corner cases.
src/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs
Outdated
Show resolved
Hide resolved
src/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs
Outdated
Show resolved
Hide resolved
src/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs
Outdated
Show resolved
Hide resolved
| sb.Append(" -D "); | ||
| } | ||
| } | ||
| else if (!s_isBusybox.Value) // busybox implementation does not support fragmentation option. |
There was a problem hiding this comment.
Are there possibly other things beyond the "busybox" implementation that don't support this? What happens if we come across such an implementation... this will cause all pings to fail by default, right? Is there any risk there?
There was a problem hiding this comment.
Yes, there is some risk. I added test with primary intent to catch such case. (ping loopback with this on/off) We should hit this path only if the option was specified e.g. simple p = new Ping() ; p.Send() will not hit this. Also the privileged path with RAW socket will not hit this.
The risk is contained to set of specific conditions.
Also for example on Alpine, one can choose to install full ping, it just is not the default. So if we come across distribution with some unusual implementation we can revisit the detection or mitigation.
There was a problem hiding this comment.
We should hit this path only if the option was specified
Won't we hit it if any option was specified, not just this one? Maybe that's what you meant.
There was a problem hiding this comment.
Yes. The PingOptions only has Ttl and DontFragment. So it is simple ping with no (default) options or options.
|
Thanks, @wfurt. Generally looks good, but some issues to be addressed. |
… ping_frag_9350
|
OSX failed in DNS tests. Unrelated to this. @dotnet-bot test OSX x64 Debug Build |
|
@dotnet-bot test OSX x64 Debug Build |
stephentoub
left a comment
There was a problem hiding this comment.
It still makes me nervous that we might be using options that aren't supported. We should continue to think about other options, e.g. whether we could detect that a failure is due to a bad option and then retry without the option and remember that for future usage, or re-investigate alternatives to shelling out to the command-line when not elevated, etc. Thanks.
| return true; | ||
| } | ||
|
|
||
| return false; |
There was a problem hiding this comment.
Nit: this can just be:
return linkedNamed != null && linkedName.EndsWith("busybox", StringComparison.Ordinal);| { | ||
| string linkedName = Interop.Sys.ReadLink(pingBinary); | ||
|
|
||
| // If pingBinary is not link linkedName will be null |
| if (s_isBSD) | ||
| { | ||
| // The bit is off by default on OSX & FreeBSD | ||
| if (fragmentOption == PingFragmentOptions.Dont) { |
There was a problem hiding this comment.
Nit: move brace to next line
|
I understand @stephentoub. That was one reason why I did not do it together with Ttl. There at least two other approaches we can take. We can spawn one ping to loopback and see if that works with that option. We can check for rapid failure when used first time (or parse output on non-zero return code) and try it again without it. |
* add support for fragmentation Ping option on Unix * add missing project file * small adjustments * fix typo * feedback from review * remove no longer needed import * remove changes to HttpCookieProtocolTests pulled in by mistake Commit migrated from dotnet/corefx@8fea941
fixes #9350 [Ping] Unix - System.Net.Ping ignores PingOptions
This is similar to #30324 with caveat that Busybox ping used on Alpine by default does not support options for fragmentation. When such condition is detected, option will be silently ignored as it is right now. One option on Alpine is to install "normal" ping via package manager. It should always work when using RAW socket implementation.
This change also adds new tests to verify integration on Unix. If we pass option ping implementation does not like (like I found with Busybox) this show blow up.
I also added on test to external server to actually test Ttl processing. I found one case where virtualization sets TTL back to 64 when NATing outbound packets and test fails. We can disable that test if this become problematic in future. It works fine in Azure and on my physical machines.