diff --git a/plugin/x/src/io/xpl_listener_tcp.cc b/plugin/x/src/io/xpl_listener_tcp.cc index 84e09081e8e..bb9e75f9fcc 100644 --- a/plugin/x/src/io/xpl_listener_tcp.cc +++ b/plugin/x/src/io/xpl_listener_tcp.cc @@ -27,6 +27,7 @@ #include #ifndef _WIN32 +#include #include #endif @@ -223,9 +224,21 @@ class Tcp_creator { bool is_ipv6_avaiable() { std::shared_ptr socket(m_factory.create_socket( KEY_socket_x_diagnostics, AF_INET6, SOCK_STREAM, 0)); - const bool has_ipv6 = INVALID_SOCKET != socket->get_socket_fd(); + if (INVALID_SOCKET == socket->get_socket_fd()) return false; - return has_ipv6; + /* + Additionally verify the IPv6 stack is functional by binding + to ::1. When IPv6 is disabled via sysctl, the kernel module + stays loaded so socket() succeeds, but ::1 is not assigned + and bind() fails with EADDRNOTAVAIL. + */ + struct sockaddr_in6 sa; + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = 0; + inet_pton(AF_INET6, "::1", &sa.sin6_addr); + + return socket->bind((struct sockaddr *)&sa, sizeof(sa)) == 0; } struct addrinfo *resolve_addr_info(const std::string &address, diff --git a/sql/conn_handler/socket_connection.cc b/sql/conn_handler/socket_connection.cc index c99609e4e1e..b189a6e0983 100644 --- a/sql/conn_handler/socket_connection.cc +++ b/sql/conn_handler/socket_connection.cc @@ -37,6 +37,9 @@ #ifdef HAVE_NETINET_IN_H #include #endif +#ifndef _WIN32 +#include +#endif #include #include #include @@ -412,8 +415,23 @@ class TCP_socket { */ const MYSQL_SOCKET s = mysql_socket_socket(0, AF_INET6, SOCK_STREAM, 0); - ipv6_available = mysql_socket_getfd(s) != INVALID_SOCKET; - if (ipv6_available) mysql_socket_close(s); + if (mysql_socket_getfd(s) != INVALID_SOCKET) { + /* + Additionally verify the IPv6 stack is functional by binding + to ::1. When IPv6 is disabled via sysctl, the kernel module + stays loaded so socket() succeeds, but ::1 is not assigned + and bind() fails with EADDRNOTAVAIL. + */ + struct sockaddr_in6 sa; + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = 0; + inet_pton(AF_INET6, "::1", &sa.sin6_addr); + ipv6_available = + (bind(mysql_socket_getfd(s), (struct sockaddr *)&sa, + sizeof(sa)) == 0); + mysql_socket_close(s); + } } if (ipv6_available && DBUG_EVALUATE_IF("sim_ipv6_unavailable", false, true)) {