https://bugs.winehq.org/show_bug.cgi?id=8332
--- Comment #32 from Gabriel Ivăncescu gabrielopcode@gmail.com --- (In reply to Damjan Jovanovic from comment #31)
Falling back to calling the "ping" command line tool shouldn't ever be necessary on MacOS and Linux.
When creating a raw socket fails, Wine tries to fall back to using an unprivileged ICMP socket, which is a non-standard socket type present on MacOS and Linux:
---snip--- int sid=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP); if (sid < 0) { /* Some systems (e.g. Linux 3.0+ and Mac OS X) support non-privileged ICMP via SOCK_DGRAM type. */ sid=socket(AF_INET,SOCK_DGRAM,IPPROTO_ICMP); } ---snip---
Documentation: Linux: https://lwn.net/Articles/420800/ MacOS: http://www.manpagez.com/man/4/icmp/
On MacOS, I think that work fine.
Linux however is currently completely broken, and pinging always fail, because:
- This socket type does not return the IP header as expected from the
recvfrom() system call in the icmp_get_reply() function, causing the reply to be parsed incorrectly in that function. On Linux, the reply immediately begins with the ICMP header instead.
- Even when that is somewhat fixed (it's long and painful to fix fully), it
still breaks, because Linux overwrites the ICMP header field "icmp_id" with its own value, ie. this value is later overwritten by the kernel:
---snip--- icmp_header->icmp_id=id; ---snip---
causing this check in icmp_get_reply() to always fail:
---snip--- if ((icmp_header->icmp_id==id) && (icmp_header->icmp_seq==seq)) ---snip---
and the reply thus falsely never matches the request, so pinging still fails.
The "icmp_id" is overwritten by the socket's port number, which can be set through bind(). It cannot be queried by getsockname() which always returns port 0, even after bind(). However it seems best not to set it, let the kernel pick a free port, and then skip the icmp_id check above instead, as the kernel already filters replies by their icmp_id.
Fixing (2) is easy, but (1) really needs to use recvmsg() instead, with IP_RECVTTL, IP_RECVTOS, IP_RETOPTS, IP_RECVERR and other ancillary data, only on Linux and only for these unprivileged ICMP sockets. Then this alternative source of IP header data needs to be integrated into icmp_get_reply().
I don't know how Gabriel ever said that this works on Linux. Either he never tested, only tested pinging an invalid address, or Linux changed how unprivileged ICMP sockets work between then and now:
---snip--- commit e6d9aaeb67172dd0ba1e73f34c7f0cad36ed43ff Author: Gabriel Iv��ncescu gabrielopcode@gmail.com Date: Mon Aug 3 16:15:52 2020 +0300
iphlpapi: Update comment for SOCK_DGRAM since Linux also supports it
from 3.0.
Linux does require the user to be in the range specified by /proc/sys/net/ipv4/ping_group_range though, but otherwise works fine. Signed-off-by: Gabriel Iv��ncescu <gabrielopcode@gmail.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
---snip---
I don't remember the exact details, there was a game pinging multiple time every 5 seconds and it had a nasty stutter when that happened with the wine-staging patch, since it invoked external commands and was very slow.
I'm not that familiar with it, so I admit I haven't tested it at all other than creating the raw socket itself, but it did fix the slowdown; now that you mention it, though, it probably failed to ping.
Note that the commit you referenced doesn't actually do anything, it just changes a comment, which is true, because Linux does allow creating raw sockets with the aforementioned requirements specified. So the code was already broken. The "broken" functionality you mention was already there.