Bug #45017 Failure to connect if hostname maps to multiple addresses
Submitted: 21 May 2009 21:16 Modified: 10 Aug 2009 0:00
Reporter: Davi Arnaut (OCA) Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: C API (client library) Severity:S1 (Critical)
Version:4.1, 5.0, 5,1, 6.0 bzr OS:Linux (Ubuntu 9.04)
Assigned to: Davi Arnaut CPU Architecture:Any

[21 May 2009 21: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 2009 21:28] Davi Arnaut
Patch is just a scratch, not meant to be used as-is.
[22 May 2009 7:43] Sveta Smirnova
Thank you for the report.

Verified as described using MySQL command line client (mysql).
[26 May 2009 0:27] MySQL Verification Team
Bug: http://bugs.mysql.com/bug.php?id=45047 has been marked as duplicate of this one.
[5 Jun 2009 17:42] Alexandr Khotskov
quick
On Solaris whis bug present too
[24 Jul 2009 14:13] Konstantin Osipov
This bug is affecting me. Please fix!
[27 Jul 2009 10: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 2009 0: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 2009 0: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 2009 14: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 2009 20: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 2009 12: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 2009 12:57] Davi Arnaut
Queued to 5.1-bugteam and mysql-pe.
[4 Aug 2009 19: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 2009 20: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 2009 0: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.
[15 Aug 2009 1:42] Paul Dubois
Ignore previous comment about 5.4.2.
[29 Sep 2009 10: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 2009 5: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 2009 7: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 2009 13: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 2009 10: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 2009 1: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
[11 Mar 2010 18:03] Paul Dubois
Noted in 5.5.3 changelog.