gRPC: Avoid AF_INET6 sockets when the ::1 loopback address doesn't exist.

On Linux with disable_ipv6=1, we can create sockets bound to [::]:port, yet
connecting to that address triggers an Unreachable error.  Since IPv6 is
useless on such machines, it's cleaner to turn it off than expose users to a
half-broken state.
	Change on 2014/12/17 by pmarks <pmarks@google.com>
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=82387437
pull/1/merge
pmarks 10 years ago committed by Michael Lumish
parent 40260c4d5b
commit b74550655a
  1. 1
      Makefile
  2. 1
      build.json
  3. 37
      src/core/iomgr/socket_utils_common_posix.c
  4. 10
      src/core/iomgr/socket_utils_posix.h
  5. 2
      test/core/echo/echo_test.c
  6. 1
      test/core/end2end/dualstack_socket_test.c
  7. 41
      test/core/util/ipv6.h
  8. 60
      test/core/util/ipv6_posix.c
  9. 2
      vsprojects/vs2013/grpc_test_util.vcxproj

@ -1013,7 +1013,6 @@ LIBGRPC_TEST_UTIL_SRC = \
test/core/statistics/census_log_tests.c \
test/core/transport/transport_end2end_tests.c \
test/core/util/grpc_profiler.c \
test/core/util/ipv6_posix.c \
test/core/util/parse_hexstring.c \
test/core/util/port_posix.c \
test/core/util/slice_splitter.c \

@ -289,7 +289,6 @@
"test/core/statistics/census_log_tests.c",
"test/core/transport/transport_end2end_tests.c",
"test/core/util/grpc_profiler.c",
"test/core/util/ipv6_posix.c",
"test/core/util/parse_hexstring.c",
"test/core/util/port_posix.c",
"test/core/util/slice_splitter.c",

@ -50,6 +50,7 @@
#include <grpc/support/string.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/sync.h>
/* set a socket to non blocking mode */
int grpc_set_socket_nonblocking(int fd, int non_blocking) {
@ -111,6 +112,34 @@ int grpc_set_socket_low_latency(int fd, int low_latency) {
newval == val;
}
static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT;
static int g_ipv6_loopback_available;
static void probe_ipv6_once() {
int fd = socket(AF_INET6, SOCK_STREAM, 0);
g_ipv6_loopback_available = 0;
if (fd < 0) {
gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed.");
} else {
struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
g_ipv6_loopback_available = 1;
} else {
gpr_log(GPR_INFO,
"Disabling AF_INET6 sockets because ::1 is not available.");
}
close(fd);
}
}
int grpc_ipv6_loopback_available() {
gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once);
return g_ipv6_loopback_available;
}
/* This should be 0 in production, but it may be enabled for testing or
debugging purposes, to simulate an environment where IPv6 sockets can't
also speak IPv4. */
@ -132,7 +161,13 @@ int grpc_create_dualstack_socket(const struct sockaddr *addr, int type,
int protocol, grpc_dualstack_mode *dsmode) {
int family = addr->sa_family;
if (family == AF_INET6) {
int fd = socket(family, type, protocol);
int fd;
if (grpc_ipv6_loopback_available()) {
fd = socket(family, type, protocol);
} else {
fd = -1;
errno = EAFNOSUPPORT;
}
/* Check if we've got a valid dualstack socket. */
if (fd >= 0 && set_socket_dualstack(fd)) {
*dsmode = GRPC_DSMODE_DUALSTACK;

@ -53,6 +53,16 @@ int grpc_set_socket_reuse_addr(int fd, int reuse);
/* disable nagle */
int grpc_set_socket_low_latency(int fd, int low_latency);
/* Returns true if this system can create AF_INET6 sockets bound to ::1.
The value is probed once, and cached for the life of the process.
This is more restrictive than checking for socket(AF_INET6) to succeed,
because Linux with "net.ipv6.conf.all.disable_ipv6 = 1" is able to create
and bind IPv6 sockets, but cannot connect to a getsockname() of [::]:port
without a valid loopback interface. Rather than expose this half-broken
state to library users, we turn off IPv6 sockets. */
int grpc_ipv6_loopback_available();
/* An enum to keep track of IPv4/IPv6 socket modes.
Currently, this information is only used when a socket is first created, but

@ -40,11 +40,11 @@
#include <sys/types.h>
#include <sys/wait.h>
#include "src/core/iomgr/socket_utils_posix.h"
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#include "test/core/util/ipv6.h"
#include "test/core/util/port.h"
int test_client(const char *root, const char *host, int port) {

@ -37,7 +37,6 @@
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
#include "test/core/end2end/cq_verifier.h"
#include "test/core/util/ipv6.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"

@ -1,41 +0,0 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __GRPC_TEST_UTIL_IPV6_H__
#define __GRPC_TEST_UTIL_IPV6_H__
/* Returns true if we're able to create an AF_INET6 socket bound to ::1 on an
arbitrary port. */
int grpc_ipv6_loopback_available();
#endif /* __GRPC_TEST_UTIL_IPV6_H__ */

@ -1,60 +0,0 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_SOCKET
#include "test/core/util/ipv6.h"
#include <netinet/in.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
int grpc_ipv6_loopback_available() {
int ok = 0;
int fd = socket(AF_INET6, SOCK_STREAM, 0);
if (fd >= 0) {
struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
ok = 1;
}
close(fd);
}
return ok;
}
#endif /* GPR_POSIX_SOCKET */

@ -89,8 +89,6 @@
</ClCompile>
<ClCompile Include="..\..\test\core\util\grpc_profiler.c">
</ClCompile>
<ClCompile Include="..\..\test\core\util\ipv6_posix.c">
</ClCompile>
<ClCompile Include="..\..\test\core\util\parse_hexstring.c">
</ClCompile>
<ClCompile Include="..\..\test\core\util\port_posix.c">

Loading…
Cancel
Save