List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:June 11 2009 7:07am
Subject:bzr commit into mysql-5.4 branch (alik:2798) Bug#38247
View as plain text  
#At file:///mnt/raid/alik/MySQL/bzr/bug38247/azalea-bf-bug38247.2/ based on revid:alik@stripped

 2798 Alexander Nozdrin	2009-06-11
      Fix one symptom of Bug#38247 (Server does not resolve connecting ip's).
      
      This patch fixes the main complaint of Bug#38247, which is the server
      does not resolve host names.
      
      Technically, this patch fixes two problems:
      
        - a second getnameinfo() call is needed to retrieve actual host name,
          not an IP address as a string.
      
        - normalize_ip_address() has been introduced in order to be able
          to compare IPv4 and IPv6 addresses.

    modified:
      mysql-test/r/connect.result
      mysql-test/t/connect.test
      sql/hostname.cc
=== modified file 'mysql-test/r/connect.result'
--- a/mysql-test/r/connect.result	2009-03-06 20:33:52 +0000
+++ b/mysql-test/r/connect.result	2009-06-11 07:06:55 +0000
@@ -224,3 +224,14 @@ SET GLOBAL event_scheduler = OFF;
 # ------------------------------------------------------------------
 # -- End of 5.1 tests
 # ------------------------------------------------------------------
+
+# -- Bug#38247: Server does not resolve connecting ip's.
+
+GRANT ALL PRIVILEGES ON *.* TO u1@quad;
+GRANT ALL PRIVILEGES ON *.* TO u2@stripped;
+SELECT 1;
+DROP USER u1@quad;
+DROP USER u2@stripped;
+
+# -- End of Bug#38247.
+

=== modified file 'mysql-test/t/connect.test'
--- a/mysql-test/t/connect.test	2009-03-06 14:56:17 +0000
+++ b/mysql-test/t/connect.test	2009-06-11 07:06:55 +0000
@@ -296,6 +296,58 @@ SET GLOBAL event_scheduler = OFF;
 --echo # -- End of 5.1 tests
 --echo # ------------------------------------------------------------------
 
+###########################################################################
+
+--echo
+--echo # -- Bug#38247: Server does not resolve connecting ip's.
+--echo
+
+let $hostname_file= $MYSQLTEST_VARDIR/tmp/bug38247.include;
+
+perl;
+use Sys::Hostname;
+use Socket;
+
+my $hostname= hostname();
+my $ip_address= inet_ntoa(scalar gethostbyname($hostname));
+
+my $file= $ENV{'MYSQLTEST_VARDIR'} . '/tmp/bug38247.include';
+
+open FH, "> $file";
+print FH "let \$hostname= $hostname;";
+print FH "let \$ip_address= $ip_address;";
+close FH; 
+EOF
+
+source $hostname_file;
+remove_file $hostname_file;
+
+eval GRANT ALL PRIVILEGES ON *.* TO u1@$hostname;
+eval GRANT ALL PRIVILEGES ON *.* TO u2@$ip_address;
+
+--connect(con1,$hostname,u1,,test,,)
+--disable_result_log
+SELECT 1;
+--enable_result_log
+--disconnect con1
+
+#
+# This is disabled due to another symptom of Bug#38247.
+#
+# --connect(con2,$ip_address,u2,,test,,)
+# --disable_result_log
+# SELECT 1;
+# --enable_result_log
+# --disconnect con2
+
+--connection default
+eval DROP USER u1@$hostname;
+eval DROP USER u2@$ip_address;
+
+--echo
+--echo # -- End of Bug#38247.
+--echo
+
 # Wait till all disconnects are completed
 --source include/wait_until_count_sessions.inc
 

=== modified file 'sql/hostname.cc'
--- a/sql/hostname.cc	2009-01-27 02:08:48 +0000
+++ b/sql/hostname.cc	2009-06-11 07:06:55 +0000
@@ -40,6 +40,64 @@ extern "C" {					// Because of SCO 3.2V4
 }
 #endif
 
+/*************************************************************************
+ *** The functions below are defined in the ws2ipdef.h header file.
+ *** However, they are enabled only starting from WindowsXP. MySQL is
+ *** supported starting from Windows 2000, that's why we need to have them
+ *** defined manually here.
+**************************************************************************/
+#if defined(__WIN__) && defined(_WIN32_WINNT) && _WIN32_WINNT <= 0x0500
+
+WS2TCPIP_INLINE
+BOOLEAN
+IN6_IS_ADDR_LOOPBACK(CONST IN6_ADDR *a)
+{
+    /*
+      We can't use the in6addr_loopback variable, since that would
+      require existing callers to link with a specific library.
+    */
+
+    return (BOOLEAN)((a->s6_words[0] == 0) &&
+                     (a->s6_words[1] == 0) &&
+                     (a->s6_words[2] == 0) &&
+                     (a->s6_words[3] == 0) &&
+                     (a->s6_words[4] == 0) &&
+                     (a->s6_words[5] == 0) &&
+                     (a->s6_words[6] == 0) &&
+                     (a->s6_words[7] == 0x0100));
+}
+
+WS2TCPIP_INLINE
+BOOLEAN
+IN6_IS_ADDR_V4MAPPED(CONST IN6_ADDR *a)
+{
+    return (BOOLEAN)((a->s6_words[0] == 0) &&
+                     (a->s6_words[1] == 0) &&
+                     (a->s6_words[2] == 0) &&
+                     (a->s6_words[3] == 0) &&
+                     (a->s6_words[4] == 0) &&
+                     (a->s6_words[5] == 0xffff));
+}
+
+WS2TCPIP_INLINE
+BOOLEAN
+IN6_IS_ADDR_V4COMPAT(CONST IN6_ADDR *a)
+{
+    return (BOOLEAN)((a->s6_words[0] == 0) &&
+                     (a->s6_words[1] == 0) &&
+                     (a->s6_words[2] == 0) &&
+                     (a->s6_words[3] == 0) &&
+                     (a->s6_words[4] == 0) &&
+                     (a->s6_words[5] == 0) &&
+                     !((a->s6_words[6] == 0) &&
+                       (a->s6_addr[14] == 0) &&
+                       ((a->s6_addr[15] == 0) || (a->s6_addr[15] == 1))));
+}
+
+#endif
+
+/************************************************************************/
+
 class host_entry :public hash_filo_element
 {
 public:
@@ -134,8 +192,80 @@ void reset_host_errors(struct sockaddr_s
 }
 
 
+/**
+  Normalize the IP address of a client.
+
+  When IPv4 and IPv6 are both used in the network stack,
+  or in the network path between a client and a server,
+  a client can have different apparent IP addresses,
+  based on the exact route taken.
+  This function normalize the client IP representation,
+  so it's suitable to use as a key for searches.
+  Transformations are implemented as follows:
+  - IPv4 a.b.c.d --> IPv6 mapped IPv4 ::ffff:a.b.c.d
+  - IPv6 compat IPv4 ::a.b.c.d --> IPv6 mapped IPv4 ::ffff:a.b.c.d
+  - IPv6 --> IPv6
+
+  @param [in]   in_address         IP address to be normalized
+  @param [out]  normalized_address Normalized IP address
+
+  @note According to RFC3493 the only specified member of the in6_addr
+  structure is s6_addr.
+*/
+static void normalize_ip_address(struct sockaddr *in_address,
+                                 struct in6_addr *normalized_address)
+{
+  uint32 *out_s6_addr32= (uint32 *) normalized_address->s6_addr;
+
+  switch (in_address->sa_family){
+  case AF_INET:
+  {
+    struct in_addr *inp_addr4= & ((struct sockaddr_in*)in_address)->sin_addr;
+
+    out_s6_addr32[0]= 0;
+    out_s6_addr32[1]= 0;
+    out_s6_addr32[2]= htonl(0xffff);
+    out_s6_addr32[3]= inp_addr4->s_addr; /* in net byte order */
+
+    DBUG_ASSERT(IN6_IS_ADDR_V4MAPPED(normalized_address));
+    break;
+  }
+
+  case AF_INET6:
+  {
+    struct in6_addr *inp_addr6= & ((struct sockaddr_in6*)in_address)->sin6_addr;
+    uint32 *inp_s6_addr32= (uint32 *) inp_addr6->s6_addr;
+
+    if (IN6_IS_ADDR_V4COMPAT(inp_addr6))
+    {
+      out_s6_addr32[0]= 0;
+      out_s6_addr32[1]= 0;
+      out_s6_addr32[2]= htonl(0xffff);
+      out_s6_addr32[3]= inp_s6_addr32[3]; /* in net byte order */
+      DBUG_ASSERT(IN6_IS_ADDR_V4MAPPED(normalized_address));
+    }
+    else
+    {
+      /* All in net byte order */
+      out_s6_addr32[0]= inp_s6_addr32[0];
+      out_s6_addr32[1]= inp_s6_addr32[1];
+      out_s6_addr32[2]= inp_s6_addr32[2];
+      out_s6_addr32[3]= inp_s6_addr32[3];
+    }
+
+    break;
+  }
+
+  default:
+    DBUG_ASSERT(FALSE);
+    break;
+  }
+}
+
+
 char *ip_to_hostname(struct sockaddr_storage *in, int addrLen, uint *errors)
 {
+  struct in6_addr in_normalized;
   char *name;
 
   struct addrinfo hints,*res_lst,*t_res;
@@ -146,7 +276,12 @@ char *ip_to_hostname(struct sockaddr_sto
   DBUG_ENTER("ip_to_hostname");
   *errors=0;
 
-  /* Historical comparison for 127.0.0.1 */
+  /*
+    Historical comparison for 127.0.0.1.
+
+    Call getnameinfo() with NI_NUMERICHOST, which means, it will return IP
+    address as a string.
+  */
   gxi_error= getnameinfo((struct sockaddr *)in, addrLen,
                          hostname_buff, NI_MAXHOST,
                          NULL, 0, NI_NUMERICHOST);
@@ -155,7 +290,7 @@ char *ip_to_hostname(struct sockaddr_sto
     DBUG_PRINT("error",("getnameinfo returned %d", gxi_error));
     DBUG_RETURN(0);
   }
-  DBUG_PRINT("info",("resolved: %s", hostname_buff));
+  DBUG_PRINT("info",("Client IP address: %s", hostname_buff));
 
   /* The next three compares are to solve historical solutions with localhost */
   if (!memcmp(hostname_buff, "127.0.0.1", sizeof("127.0.0.1")))
@@ -190,6 +325,18 @@ char *ip_to_hostname(struct sockaddr_sto
     pthread_mutex_unlock(&hostname_cache->lock);
   }
 
+  /* Resolve host name. */
+
+  gxi_error= getnameinfo((struct sockaddr *)in, addrLen,
+                         hostname_buff, NI_MAXHOST,
+                         NULL, 0, 0);
+  if (gxi_error)
+  {
+    DBUG_PRINT("error",("getnameinfo returned %d", gxi_error));
+    DBUG_RETURN(0);
+  }
+  DBUG_PRINT("info",("Client host name: %s", hostname_buff));
+
   if (!(name= my_strdup(hostname_buff, MYF(0))))
   {
     DBUG_PRINT("error",("out of memory"));
@@ -240,10 +387,16 @@ char *ip_to_hostname(struct sockaddr_sto
   }
 
   /* Check that 'getaddrinfo' returned the used ip */
+
+  normalize_ip_address((struct sockaddr *) in, &in_normalized);
+
   for (t_res= res_lst; t_res; t_res=t_res->ai_next)
   {
-    if (!memcmp(&(t_res->ai_addr), in,
-                sizeof(struct sockaddr_storage) ) )
+    struct in6_addr t_res_normalized;
+    normalize_ip_address(t_res->ai_addr, &t_res_normalized);
+
+    if (!memcmp(&in_normalized, &t_res_normalized,
+                sizeof (in6_addr)))
     {
       add_hostname(in, name);
       freeaddrinfo(res_lst);


Attachment: [text/bzr-bundle] bzr/alik@sun.com-20090611070655-argxn85dxlhwhbin.bundle
Thread
bzr commit into mysql-5.4 branch (alik:2798) Bug#38247Alexander Nozdrin11 Jun