Bug #45017 Failure to connect if hostname maps to multiple addresses
Submitted: 21 May 23:16 Modified: 10 Aug 2:00
Reporter: Davi Arnaut
Status: Closed
Category:C API Severity:S1 (Critical)
Version:4.1, 5.0, 5,1, 6.0 bzr OS:Linux (Ubuntu 9.04)
Assigned to: Davi Arnaut Target Version:5.1+
Triage: Triaged: D2 (Serious)

[21 May 23:16] Davi Arnaut
Description:
The problem is that the C API connect function (mysql_real_connect) only attempts to
connect to the first IP address returned for a hostname. This can be a problem if a
hostname maps to multiple IP address and the server is not bound to the first one that is
returned.

This poses a nasty problem on systems where localhost is mapped to ::1 and 127.0.0.1. It
leads to test failures on Ubuntu 9.04 since the server binds to 127.0.0.1 and attempts to
connect to localhost will fail as ::1 is returned first.

How to repeat:
On a host where localhost is mapped to multiple addresses (ie: Ubuntu 9.04 server), start
the server on 127.0.0.1 and try to connect to localhost using the mysql command line
client.

Suggested fix:
Attempt to connect to each address a hostname is mapped to.

=== modified file 'sql-common/client.c'
--- sql-common/client.c	2009-05-20 17:39:02 +0000
+++ sql-common/client.c	2009-05-21 21:12:55 +0000
@@ -1938,6 +1938,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
   char		*end,*host_info;
   ulong		pkt_length;
   NET		*net= &mysql->net;
+  my_socket     sock;
 #ifdef MYSQL_SERVER
   thr_alarm_t   alarmed;
   ALARM		alarm_buff;
@@ -2180,10 +2181,9 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
     }
 
     /* We only look at the first item (something to think about changing in the future)
*/
-    t_res= res_lst; 
+    for (t_res= res_lst; t_res; t_res= t_res->ai_next)
     {
-      my_socket sock= socket(t_res->ai_family, t_res->ai_socktype,
-                             t_res->ai_protocol);
+      sock= socket(t_res->ai_family, t_res->ai_socktype, t_res->ai_protocol);
       if (sock == SOCKET_ERROR)
       {
         set_mysql_extended_error(mysql, CR_IPSOCK_ERROR, unknown_sqlstate,
@@ -2192,28 +2192,33 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
         goto error;
       }
 
-      net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
-      if (! net->vio )
-      {
-        DBUG_PRINT("error",("Unknow protocol %d ", mysql->options.protocol));
-        set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
-        closesocket(sock);
-        freeaddrinfo(res_lst);
-        goto error;
-      }
+      if (!my_connect(sock, t_res->ai_addr, t_res->ai_addrlen,
+                      mysql->options.connect_timeout))
+        break;
 
-      if (my_connect(sock, t_res->ai_addr, t_res->ai_addrlen,
-                     mysql->options.connect_timeout))
-      {
-        DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno,
-                            host));
-        set_mysql_extended_error(mysql, CR_CONN_HOST_ERROR, unknown_sqlstate,
-                                 ER(CR_CONN_HOST_ERROR), host, socket_errno);
-        vio_delete(net->vio);
-        net->vio= 0;
-        freeaddrinfo(res_lst);
-        goto error;
-      }
+      closesocket(sock);
+    }
+
+    if (!t_res)
+    {
+      DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno,
+                          host));
+      set_mysql_extended_error(mysql, CR_CONN_HOST_ERROR, unknown_sqlstate,
+                                ER(CR_CONN_HOST_ERROR), host, socket_errno);
+      vio_delete(net->vio);
+      net->vio= 0;
+      freeaddrinfo(res_lst);
+      goto error;
+    }
+
+    net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
+    if (! net->vio )
+    {
+      DBUG_PRINT("error",("Unknow protocol %d ", mysql->options.protocol));
+      set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
+      closesocket(sock);
+      freeaddrinfo(res_lst);
+      goto error;
     }
 
     freeaddrinfo(res_lst);
[21 May 23:28] Davi Arnaut
Patch is just a scratch, not meant to be used as-is.
[22 May 9:43] Sveta Smirnova
Thank you for the report.

Verified as described using MySQL command line client (mysql).
[26 May 2:27] Miguel Solorzano
Bug: http://bugs.mysql.com/bug.php?id=45047 has been marked as duplicate of this one.
[5 Jun 19:42] Alexandr Khotskov
quick
On Solaris whis bug present too
[24 Jul 16:13] Konstantin Osipov
This bug is affecting me. Please fix!
[27 Jul 12:08] Luigi Grilli
I have the same bug on a Windows Server 2008 tested on 2 different servers.
On the server is running a mysql server instance on localhost.

If I try to connect to "localhost" with mysql_real_connect, i get the error:
Error: can't connect to MySQL server on 'localhost' (10061)

If I try to connect to "127.0.0.1" with mysql_real_connect, all works smoothly.

I'm using mysql-connector-c-noinstall-6.0.1-win32 of the mysql connector library.

As further info, if I ping localhost the hostname is translated into the ::1: ipv6
address, NOT 127.0.0.1 ipv4 address.

Using mysql client everything is fine with both localhost and 127.0.0.1.
[31 Jul 2:29] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/79729

3051 Davi Arnaut	2009-07-30
      Bug#45017: Failure to connect if hostname maps to multiple addresses
      
      The problem is that the C API function mysql_real_connect
      only attempts to connect to the first IP address returned
      for a hostname. This can be a problem if a hostname maps
      to multiple IP address and the server is not bound to the
      first one that is returned.
      
      The solution is to augment mysql_real_connect so that it
      attempts to connect to all IPv4 addresses that a domain
      name maps to. The function goes over the list of address
      until a successful connection is established.
      
      No test case is provided as its not possible to test this
      automatically with the current testing infrastructure.
     @ sql-common/client.c
        The client will try to connect to each IPv4 address from
        the list of addresses that hostname maps to until a successful
        connection is established or there are no more address.
[31 Jul 2:46] Jim Winstead
IPv6 support will need to be added when merging to 5.4, at least. I'm not sure it is
important to add the check to skip IPv6 addresses in 5.1, either.
[1 Aug 16:58] Davi Arnaut
> IPv6 support will need to be added when merging to 5.4, at least.

Yes, sure.

> I'm not sure it is important to add the check to skip IPv6 addresses in 5.1, either.

It's better than attempting to connect to a IPv6 address via IPv4. The bytes of the IPv6
address will be interpreted as a IPv4 address and might end up somewhere else. Not
critical, but a bit nasty.
[3 Aug 22:43] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/79962

3507 Davi Arnaut	2009-08-03
      Bug#45017: Failure to connect if hostname maps to multiple addresses
      
      The problem is that the C API function mysql_real_connect
      only attempts to connect to the first IP address returned
      for a hostname. This can be a problem if a hostname maps
      to multiple IP address and the server is not bound to the
      first one that is returned.
      
      The solution is to augment mysql_real_connect so that it
      attempts to connect to all IPv4/6 addresses that a domain
      name maps to. The function goes over the list of address
      until a successful connection is established.
      
      No test case is provided as its not possible to test this
      automatically with the current testing infrastructure.
     @ sql-common/client.c
        The client will try to connect to each address from the
        list of addresses that hostname maps to until a successful
        connection is established or there are no more address.
[4 Aug 14:55] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/80013

3512 Davi Arnaut	2009-08-04 [merge]
      Bug#45017: Failure to connect if hostname maps to multiple addresses
      
      The problem is that the C API function mysql_real_connect
      only attempts to connect to the first IP address returned
      for a hostname. This can be a problem if a hostname maps
      to multiple IP address and the server is not bound to the
      first one that is returned.
      
      The solution is to augment mysql_real_connect so that it
      attempts to connect to all IPv4/6 addresses that a domain
      name maps to. The function goes over the list of address
      until a successful connection is established.
      
      No test case is provided as its not possible to test this
      automatically with the current testing infrastructure.
     @ sql-common/client.c
        The client will try to connect to each address from the
        list of addresses that hostname maps to until a successful
        connection is established or there are no more address.
[4 Aug 14:57] Davi Arnaut
Queued to 5.1-bugteam and mysql-pe.
[4 Aug 21:51] Bugs System
Pushed into 5.4.4-alpha (revid:alik@sun.com-20090804194615-h40sa098mx4z49qg) (version
source revid:davi.arnaut@sun.com-20090804125339-bsxnlamxyfsnjws3) (merge vers:
5.4.4-alpha) (pib:11)
[4 Aug 22:45] Bugs System
Pushed into 5.1.38 (revid:davi.arnaut@sun.com-20090804204317-ggodqkik7de6nfpz) (version
source revid:davi.arnaut@sun.com-20090804204317-ggodqkik7de6nfpz) (merge vers: 5.1.38)
(pib:11)
[10 Aug 2:00] Paul DuBois
Noted in 5.1.38, 5.4.4 changelogs.

The mysql_real_connect() C API function only attempted to connect to
the first IP address returned for a hostname. This could be a problem
if a hostname mapped to multiple IP address and the server was not
bound to the first one returned. Now mysql_real_connect() attempts to 
connect to all IPv4/6 addresses that a domain name maps to.
[13 Aug 0:25] Paul DuBois
Noted in 5.4.2 changelog because next 5.4 version will be 5.4.2 and not 5.4.4.
[15 Aug 3:42] Paul DuBois
Ignore previous comment about 5.4.2.
[29 Sep 12:22] chandra sekar
Hi. I am new to Fedora and Mysql . While installing Mysql in Fedora hv mistakenly given
the ip as "127.0.0.1" . Now i want to change the ip . Pls guide where and how to do it .
Thanks .
[1 Oct 7:59] Bugs System
Pushed into 5.1.39-ndb-6.3.28 (revid:jonas@mysql.com-20091001055605-ap2kiaarr7p40mmv)
(version source revid:jonas@mysql.com-20091001055605-ap2kiaarr7p40mmv) (merge vers:
5.1.39-ndb-6.3.28) (pib:11)
[1 Oct 9:25] Bugs System
Pushed into 5.1.39-ndb-7.0.9 (revid:jonas@mysql.com-20091001072547-kv17uu06hfjhgjay)
(version source revid:jonas@mysql.com-20091001071652-irejtnumzbpsbgk2) (merge vers:
5.1.39-ndb-7.0.9) (pib:11)
[1 Oct 15:25] Bugs System
Pushed into 5.1.39-ndb-7.1.0 (revid:jonas@mysql.com-20091001123013-g9ob2tsyctpw6zs0)
(version source revid:jonas@mysql.com-20091001123013-g9ob2tsyctpw6zs0) (merge vers:
5.1.39-ndb-7.1.0) (pib:11)
[5 Oct 12:50] Bugs System
Pushed into 5.1.39-ndb-6.2.19 (revid:jonas@mysql.com-20091005103850-dwij2dojwpvf5hi6)
(version source revid:jonas@mysql.com-20090930185117-bhud4ek1y0hsj1nv) (merge vers:
5.1.39-ndb-6.2.19) (pib:11)
[6 Nov 2:16] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/89540

3196 Frazer Clement	2009-11-06
      Bug47757 MySQL Cluster : port bug#45017 to 7.0 (ipv6)
      modified:
        sql-common/client.c