From 139a81576e3f8cb4c3b59be315e16f4274ffb2e7 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Sat, 31 Jan 2015 13:34:26 +0100 Subject: [PATCH] Fix dbus-daemon startup on Windows in case no family is specified and ipv6 is disabled Not specifing a socket family on a tcp listen address on Windows let dbus-daemon uses AF_UNPEC family, which results into a fatal error on trying to listen on ipv6, regardless if ipv6 is enabled or not. To avoid this issue dbus-daemon now checks at startup once if ipv6 is supported and avoids to listen on ipv6 if not present. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=61922 --- dbus/dbus-sysdeps-win.c | 128 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 96 insertions(+), 32 deletions(-) diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c index 9b93db72..4a456ec4 100644 --- a/dbus/dbus-sysdeps-win.c +++ b/dbus/dbus-sysdeps-win.c @@ -139,50 +139,79 @@ load_ex_ip_helper_procedures(void) * get pid from localhost tcp connection using peer_port * This function is available on WinXP >= SP3 * @param peer_port peers tcp port + * @param family adress family - AF_INET or AF_INET6 * @return process id or 0 if connection has not been found */ static dbus_pid_t -get_pid_from_extended_tcp_table(int peer_port) +get_pid_from_extended_tcp_table (int peer_port, int family) { dbus_pid_t result; DWORD errorCode, size = 0, i; - MIB_TCPTABLE_OWNER_PID *tcp_table; if ((errorCode = - GetExtendedTcpTable (NULL, &size, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0)) == ERROR_INSUFFICIENT_BUFFER) + GetExtendedTcpTable (NULL, &size, TRUE, family, TCP_TABLE_OWNER_PID_ALL, 0)) != ERROR_INSUFFICIENT_BUFFER) { - tcp_table = (MIB_TCPTABLE_OWNER_PID *) dbus_malloc (size); + _dbus_win_warn_win_error ("unexpected error returned from GetExtendedTcpTable", errorCode); + return 0; + } + + if (family == AF_INET6) + { + MIB_TCP6TABLE_OWNER_PID *tcp_table; + tcp_table = (MIB_TCP6TABLE_OWNER_PID *) dbus_malloc (size); if (tcp_table == NULL) { _dbus_verbose ("Error allocating memory\n"); return 0; } + + if ((errorCode = GetExtendedTcpTable (tcp_table, &size, TRUE, family, TCP_TABLE_OWNER_PID_ALL, 0)) != NO_ERROR) + { + _dbus_verbose ("Error fetching tcp table %d\n", (int)errorCode); + dbus_free (tcp_table); + return 0; + } + + result = 0; + for (i = 0; i < tcp_table->dwNumEntries; i++) + { + dbus_bool_t is_localhost; + MIB_TCP6ROW_OWNER_PID *p = &tcp_table->table[i]; + int local_port = ntohs (p->dwLocalPort); + is_localhost = (memcmp(p->ucLocalAddr, in6addr_loopback.s6_addr, 16) == 0); + if (p->dwState == MIB_TCP_STATE_ESTAB && is_localhost && local_port == peer_port) + result = p->dwOwningPid; + } + dbus_free (tcp_table); } else { - _dbus_win_warn_win_error ("unexpected error returned from GetExtendedTcpTable", errorCode); - return 0; - } + MIB_TCPTABLE_OWNER_PID *tcp_table; + tcp_table = (MIB_TCPTABLE_OWNER_PID *) dbus_malloc (size); + if (tcp_table == NULL) + { + _dbus_verbose ("Error allocating memory\n"); + return 0; + } + if ((errorCode = GetExtendedTcpTable (tcp_table, &size, TRUE, family, TCP_TABLE_OWNER_PID_ALL, 0)) != NO_ERROR) + { + _dbus_verbose ("Error fetching tcp table %d\n", (int)errorCode); + dbus_free (tcp_table); + return 0; + } - if ((errorCode = GetExtendedTcpTable (tcp_table, &size, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0)) != NO_ERROR) - { - _dbus_verbose ("Error fetching tcp table %d\n", (int)errorCode); + result = 0; + for (i = 0; i < tcp_table->dwNumEntries; i++) + { + MIB_TCPROW_OWNER_PID *p = &tcp_table->table[i]; + int local_address = ntohl (p->dwLocalAddr); + int local_port = ntohs (p->dwLocalPort); + if (p->dwState == MIB_TCP_STATE_ESTAB + && local_address == INADDR_LOOPBACK && local_port == peer_port) + result = p->dwOwningPid; + } dbus_free (tcp_table); - return 0; } - - result = 0; - for (i = 0; i < tcp_table->dwNumEntries; i++) - { - MIB_TCPROW_OWNER_PID *p = &tcp_table->table[i]; - int local_address = ntohl (p->dwLocalAddr); - int local_port = ntohs (p->dwLocalPort); - if (p->dwState == MIB_TCP_STATE_ESTAB - && local_address == INADDR_LOOPBACK && local_port == peer_port) - result = p->dwOwningPid; - } - - dbus_free (tcp_table); _dbus_verbose ("got pid %lu\n", result); return result; } @@ -260,14 +289,9 @@ _dbus_get_peer_pid_from_tcp_handle (int handle) } else if (addr.ss_family == AF_INET6) { - _dbus_verbose ("FIXME [61922]: IPV6 support not working on windows\n"); - return 0; - /* struct sockaddr_in6 *s = (struct sockaddr_in6 * )&addr; peer_port = ntohs (s->sin6_port); is_localhost = (memcmp(s->sin6_addr.s6_addr, in6addr_loopback.s6_addr, 16) == 0); - _dbus_verbose ("IPV6 %08x %08x\n", s->sin6_addr.s6_addr, in6addr_loopback.s6_addr); - */ } else { @@ -290,7 +314,7 @@ _dbus_get_peer_pid_from_tcp_handle (int handle) _dbus_verbose ("trying to get peer's pid\n"); - result = get_pid_from_extended_tcp_table (peer_port); + result = get_pid_from_extended_tcp_table (peer_port, addr.ss_family); if (result > 0) return result; result = get_pid_from_tcp_ex_table (peer_port); @@ -663,6 +687,46 @@ _dbus_connect_named_pipe (const char *path, #endif /** + * @returns #FALSE if no ipv6 support has been found + */ +static dbus_bool_t +_dbus_has_ipv6 (void) +{ + static long cached_result = -1; + struct addrinfo hints; + struct addrinfo *ai = 0; + DBusSocket temp = DBUS_SOCKET_INIT; + dbus_bool_t has_ipv6; + + if(cached_result != -1) + return cached_result; + + _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.sock = socket (AF_INET6, SOCK_STREAM, 0)) == INVALID_SOCKET) + has_ipv6 = FALSE; + + if (has_ipv6 && bind (temp.sock, ai->ai_addr, ai->ai_addrlen) == SOCKET_ERROR) + has_ipv6 = FALSE; + + if (!_dbus_socket_is_valid (temp)) + closesocket (temp.sock); + if (ai) + freeaddrinfo (ai); + + /* Atomic version of "cached_result = has_ipv6" */ + InterlockedExchange (&cached_result, has_ipv6); + return has_ipv6; +} + +/** * @returns #FALSE if no memory */ dbus_bool_t @@ -1522,7 +1586,7 @@ _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")) @@ -1673,7 +1737,7 @@ _dbus_listen_tcp_socket (const char *host, _DBUS_ZERO (hints); if (!family) - hints.ai_family = AF_INET; + 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")) -- 2.12.3