https://bugs.winehq.org/show_bug.cgi?id=8332
Damjan Jovanovic damjan.jov@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |damjan.jov@gmail.com, | |gabrielopcode@gmail.com
--- Comment #31 from Damjan Jovanovic damjan.jov@gmail.com --- 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:
1. 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.
2. 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---