diff options
author | Pavel Šimerda <pavlix@pavlix.net> | 2016-08-12 19:37:17 +0200 |
---|---|---|
committer | Pavel Šimerda <pavlix@pavlix.net> | 2016-08-23 12:11:38 +0200 |
commit | d141cb6e4ee3388f0508afa0f6368aaa1236778c (patch) | |
tree | 5a3d1841b0366424cfa348ac8bbe9e9cc7ae16a4 | |
parent | 393e1835fc3d7e13554e7fe9d9ab3ddbce7cab99 (diff) | |
download | iputils-d141cb6e4ee3388f0508afa0f6368aaa1236778c.tar.gz |
ping: work with older kernels that don't support ping sockets
Fixes #54, related #32.
-rw-r--r-- | ping.c | 75 |
1 files changed, 64 insertions, 11 deletions
@@ -55,6 +55,7 @@ #include "ping.h" +#include <assert.h> #include <netinet/ip.h> #include <netinet/ip_icmp.h> #ifndef WITHOUT_IFADDRS @@ -110,27 +111,79 @@ static int pmtudisc = -1; static void create_socket(socket_st *sock, int family, int socktype, int protocol, int requisite) { + int do_fallback = 0; + errno = 0; - sock->fd = socket(family, socktype, protocol); + assert(sock->fd == -1); + assert(socktype == SOCK_DGRAM || socktype == SOCK_RAW); + + /* Attempt to create a ping socket if requested. Attempt to create a raw + * socket otherwise or as a fallback. Well known errno values follow. + * + * 1) EACCES + * + * Kernel returns EACCES for all ping socket creation attempts when the + * user isn't allowed to use ping socket. A range of group ids is + * configured using the `net.ipv4.ping_group_range` sysctl. Fallback + * to raw socket is necessary. + * + * Kernel returns EACCES for all raw socket creation attempts when the + * proces doesn't have the `CAP_NET_RAW` capability. + * + * 2) EAFNOSUPPORT + * + * Kernel returns EAFNOSUPPORT for IPv6 ping or raw socket creation + * attempts when run with IPv6 support disabled (e.g. via `ipv6.disable=1` + * kernel command-line option. + * + * https://github.com/iputils/iputils/issues/32 + * + * OpenVZ 2.6.32-042stab113.11 and possibly other older kernels return + * EAFNOSUPPORT for all IPv4 ping socket creation attempts due to lack + * of support in the kernel. Fallback to raw socket is necessary. + * + * https://github.com/iputils/iputils/issues/54 + * + * 3) EPROTONOSUPPORT + * + * OpenVZ 2.6.32-042stab113.11 and possibly other older kernels return + * EPROTONOSUPPORT for all IPv6 ping socket creation attempts due to lack + * of support in the kernel. Fallback to raw socket is necessary. + * + * https://github.com/iputils/iputils/issues/54 + * + */ + if (socktype == SOCK_DGRAM) + sock->fd = socket(family, socktype, protocol); + + /* Kernel doesn't support ping sockets. */ + if (sock->fd == -1 && errno == EAFNOSUPPORT && family == AF_INET) + do_fallback = 1; + if (sock->fd == -1 && errno == EPROTONOSUPPORT && family == AF_INET6) + do_fallback = 1; - /* Attempt creating a raw socket when ping socket failed */ - if (sock->fd == -1 && errno != EAFNOSUPPORT && socktype == SOCK_DGRAM) { - if (options & F_VERBOSE) + /* User is not allowed to use ping sockets. */ + if (sock->fd == -1 && errno == EACCES) + do_fallback = 1; + + if (socktype == SOCK_RAW || do_fallback) { + if (options & F_VERBOSE && do_fallback) fprintf(stderr, "ping: socket: %s, attempting raw socket...\n", strerror(errno)); - create_socket(sock, family, SOCK_RAW, protocol, requisite); - return; + socktype = SOCK_RAW; + sock->fd = socket(family, SOCK_RAW, protocol); } if (sock->fd == -1) { - if (requisite || errno != EAFNOSUPPORT || options & F_VERBOSE) + /* Report error related to disabled IPv6 only when IPv6 also failed or in + * verbose mode. Report other errors always. + */ + if ((errno == EAFNOSUPPORT && socktype == AF_INET6) || options & F_VERBOSE || requisite) fprintf(stderr, "ping: socket: %s\n", strerror(errno)); if (requisite) exit(2); - return; - } - - sock->socktype = socktype; + } else + sock->socktype = socktype; } static void set_socket_option(socket_st *sock, int level, int optname, const void *optval, socklen_t optlen) |