List:Commits« Previous MessageNext Message »
From:Davi Arnaut Date:July 31 2009 12:28am
Subject:bzr commit into mysql-5.1-bugteam branch (davi:3051) Bug#45017
View as plain text  
# At a local mysql-5.1-bugteam repository of davi

 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.

    modified:
      sql-common/client.c
=== modified file 'sql-common/client.c'
--- a/sql-common/client.c	2009-06-10 14:05:07 +0000
+++ b/sql-common/client.c	2009-07-31 00:28:43 +0000
@@ -2027,6 +2027,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
       (!mysql->options.protocol ||
        mysql->options.protocol == MYSQL_PROTOCOL_TCP))
   {
+    int status= -1;
     unix_socket=0;				/* This is not used */
     if (!port)
       port=mysql_port;
@@ -2052,6 +2053,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
     net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
     bzero((char*) &sock_addr,sizeof(sock_addr));
     sock_addr.sin_family = AF_INET;
+    sock_addr.sin_port = (ushort) htons((ushort) port);
 
     /*
       The server name may be a host name or IP address
@@ -2060,28 +2062,46 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
     if ((int) (ip_addr = inet_addr(host)) != (int) INADDR_NONE)
     {
       memcpy_fixed(&sock_addr.sin_addr,&ip_addr,sizeof(ip_addr));
+      status= my_connect(sock, (struct sockaddr *) &sock_addr,
+                         sizeof(sock_addr), mysql->options.connect_timeout);
     }
     else
     {
-      int tmp_errno;
+      int i, tmp_errno;
       struct hostent tmp_hostent,*hp;
       char buff2[GETHOSTBYNAME_BUFF_SIZE];
       hp = my_gethostbyname_r(host,&tmp_hostent,buff2,sizeof(buff2),
 			      &tmp_errno);
-      if (!hp)
+
+      /*
+        Don't attempt to connect to non IPv4 addresses as the client could
+        end up sending information to a unknown server. For example, a IPv6
+        address might be returned from gethostbyname depending on options
+        set via the RES_OPTIONS environment variable.
+      */
+      if (!hp || (hp->h_addrtype != AF_INET))
       {
 	my_gethostbyname_r_free();
         set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate,
                                  ER(CR_UNKNOWN_HOST), host, tmp_errno);
 	goto error;
       }
-      memcpy(&sock_addr.sin_addr, hp->h_addr,
-             min(sizeof(sock_addr.sin_addr), (size_t) hp->h_length));
+
+      for (i= 0; status && hp->h_addr_list[i]; i++)
+      {
+        IF_DBUG(char ipaddr[18];)
+        memcpy(&sock_addr.sin_addr, hp->h_addr_list[i],
+               min(sizeof(sock_addr.sin_addr), (size_t) hp->h_length));
+        DBUG_PRINT("info",("Trying %s...",
+                          (my_inet_ntoa(sock_addr.sin_addr, ipaddr), ipaddr)));
+        status= my_connect(sock, (struct sockaddr *) &sock_addr,
+                           sizeof(sock_addr), mysql->options.connect_timeout);
+      }
+
       my_gethostbyname_r_free();
     }
-    sock_addr.sin_port = (ushort) htons((ushort) port);
-    if (my_connect(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
-		   mysql->options.connect_timeout))
+
+    if (status)
     {
       DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno,
 			  host));


Attachment: [text/bzr-bundle] bzr/davi.arnaut@sun.com-20090731002843-y62x3n5qox2hq9zk.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (davi:3051) Bug#45017Davi Arnaut31 Jul