[Bug 8332] Applications and games using ICMP ping request report 'no connection to internet' (Wine 32-bit/64-bit preloader requires CAP_NET_RAW to create raw sockets)

WineHQ Bugzilla wine-bugs at winehq.org
Sun Jun 13 18:24:04 CDT 2021


https://bugs.winehq.org/show_bug.cgi?id=8332

Damjan Jovanovic <damjan.jov at gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |damjan.jov at gmail.com,
                   |                            |gabrielopcode at gmail.com

--- Comment #31 from Damjan Jovanovic <damjan.jov at 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 at 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 at gmail.com>
    Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---snip---

-- 
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.


More information about the wine-bugs mailing list