From 4ab6659d930b639641feb03ea4abfb630d269fdb Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Thu, 8 Mar 2018 09:20:53 +0100 Subject: [PATCH] Fix "failed to bind socket: Cannot assign requested address" on linux with ipv6 disabled Bug: https://bugs.freedesktop.org/show_bug.cgi?id=61922 --- dbus/dbus-sysdeps-unix.c | 70 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 4 deletions(-) diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c index ff814256..4f68aae7 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -1326,6 +1326,48 @@ _dbus_listen_systemd_sockets (DBusSocket **fds, } /** + * @returns #FALSE if no ipv6 support has been found + */ +static dbus_bool_t +_dbus_has_ipv6 (void) +{ + static DBusAtomic cached_result = { -1 }; + struct addrinfo hints; + struct addrinfo *ai = 0; + DBusSocket temp = DBUS_SOCKET_INIT; + dbus_bool_t has_ipv6 = TRUE; + + if(_dbus_atomic_get (&cached_result) != -1) + return TRUE; + + _DBUS_ZERO (hints); + + hints.ai_family = AF_INET6; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + if (getaddrinfo("::1", NULL, &hints, &ai) != 0 || !ai) + has_ipv6 = FALSE; + + if (has_ipv6 && (temp.fd = socket (AF_INET6, SOCK_STREAM, 0)) == EINVAL) + has_ipv6 = FALSE; + + int s; + if (has_ipv6 && (s = bind (temp.fd, ai->ai_addr, ai->ai_addrlen)) == -1) + has_ipv6 = FALSE; + + if (!_dbus_socket_is_valid (temp)) + close (temp.fd); + if (ai) + freeaddrinfo (ai); + + /* Atomic version of "cached_result = has_ipv6" */ + if (has_ipv6) + _dbus_atomic_inc (&cached_result); + return has_ipv6; +} + +/** * Creates a socket and connects to a socket at the given host * and port. The connection fd is returned, and is set up as * nonblocking. @@ -1365,11 +1407,21 @@ _dbus_connect_tcp_socket_with_nonce (const char *host, _DBUS_ZERO (hints); if (!family) - hints.ai_family = AF_UNSPEC; + hints.ai_family = _dbus_has_ipv6 () ? AF_UNSPEC : AF_INET; else if (!strcmp(family, "ipv4")) hints.ai_family = AF_INET; else if (!strcmp(family, "ipv6")) - hints.ai_family = AF_INET6; + { + if (_dbus_has_ipv6 ()) + hints.ai_family = AF_INET6; + else + { + dbus_set_error (error, + DBUS_ERROR_INVALID_ARGS, + "No ipv6 support available", ""); + return _dbus_socket_get_invalid (); + } + } else { dbus_set_error (error, @@ -1484,11 +1536,21 @@ _dbus_listen_tcp_socket (const char *host, _DBUS_ZERO (hints); if (!family) - hints.ai_family = AF_UNSPEC; + hints.ai_family = _dbus_has_ipv6 () ? AF_UNSPEC : AF_INET; else if (!strcmp(family, "ipv4")) hints.ai_family = AF_INET; else if (!strcmp(family, "ipv6")) - hints.ai_family = AF_INET6; + { + if (_dbus_has_ipv6 ()) + hints.ai_family = AF_INET6; + else + { + dbus_set_error (error, + DBUS_ERROR_INVALID_ARGS, + "No ipv6 support available"); + return -1; + } + } else { dbus_set_error (error, -- 2.12.3