List:Commits« Previous MessageNext Message »
From:Kristofer Pettersson Date:August 25 2008 12:53pm
Subject:bzr commit into mysql-6.0 branch (kpettersson:2781) Bug#38247
View as plain text  
#At file:///home/thek/Development/cpp/mysqlbzr/mysql-6.0-bug38247/

 2781 Kristofer Pettersson	2008-08-25
      Bug#38247 Server does not resolve connecting ip's
      
      Server does not resolve the ip's of incoming connections.
      
      This patch provides a quick solution for this bug by striping the "::ffff:"
      prefix from a mapped IPv4.
modified:
  sql/hostname.cc
  vio/viosocket.c

per-file messages:
  sql/hostname.cc
    * Memcpy memory block size isn't sizeof(struct addrinfo) but sizeof(struct sockaddr_storage). This caused a crash.
    * Request getnameinfo with host name representation and not numeric representation.
    * Don't call freeaddrinfo if we failed to get a res_lst. (caused crash)
    * Make sure we project the character representation of an IPv4 address to the address space of IPv4 and not as a mapped IPv4.
  vio/viosocket.c
    * Transform mapped IPv4 to old IPv4 format.
=== modified file 'sql/hostname.cc'
--- a/sql/hostname.cc	2008-07-08 16:01:41 +0000
+++ b/sql/hostname.cc	2008-08-25 12:52:43 +0000
@@ -94,7 +94,7 @@ static void add_hostname(struct sockaddr
       if ((entry=(host_entry*) malloc(sizeof(host_entry)+length+1)))
       {
 	char *new_name;
-	memcpy_fixed(&entry->ip, in, sizeof(struct addrinfo));
+	memcpy_fixed(&entry->ip, in, sizeof(struct sockaddr_storage));
 	if (length)
 	  memcpy(new_name= (char *) (entry+1), name, length+1);
 	else
@@ -149,18 +149,21 @@ char *ip_to_hostname(struct sockaddr_sto
   DBUG_ENTER("ip_to_hostname");
   *errors=0;
 
-  /* Historical comparison for 127.0.0.1 */
-  gxi_error= getnameinfo((struct sockaddr *)in, addrLen,
-                         hostname_buff, NI_MAXHOST,
-                         NULL, 0, NI_NUMERICHOST);
-  if (gxi_error)
+  /*
+    Get host name in numeric form.
+  */
+  if ((gxi_error= getnameinfo((struct sockaddr *)in, addrLen,
+                             hostname_buff, NI_MAXHOST,
+                             NULL, 0, NI_NAMEREQD)))
   {
-    DBUG_PRINT("error",("getnameinfo returned %d", gxi_error));
-    DBUG_RETURN(0);
-  }
-  DBUG_PRINT("info",("resolved: %s", hostname_buff));
+      add_wrong_ip(in);
+      DBUG_RETURN(0);
+  };
 
-  /* The next three compares are to solve historical solutions with localhost */
+  /* 
+    The next three compares are to solve historical solutions with
+    localhost.
+  */
   if (!memcmp(hostname_buff, "127.0.0.1", sizeof("127.0.0.1")))
   {
     DBUG_RETURN((char *)my_localhost);
@@ -173,8 +176,17 @@ char *ip_to_hostname(struct sockaddr_sto
   {
     DBUG_RETURN((char *)my_localhost);
   }
+  
+  if (!(name= my_strdup(hostname_buff, MYF(0))))
+  {
+    DBUG_PRINT("error",("out of memory"));
+    DBUG_RETURN(0);
+  }
+  
+  DBUG_PRINT("info",("resolved: %s", hostname_buff));
 
   /* Check first if we have name in cache */
+  
   if (!(specialflag & SPECIAL_NO_HOST_CACHE))
   {
     pthread_mutex_lock(&hostname_cache->lock);
@@ -193,14 +205,10 @@ char *ip_to_hostname(struct sockaddr_sto
     pthread_mutex_unlock(&hostname_cache->lock);
   }
 
-  if (!(name= my_strdup(hostname_buff, MYF(0))))
-  {
-    DBUG_PRINT("error",("out of memory"));
-    DBUG_RETURN(0);
-  }
-
   /* Don't accept hostnames that starts with digits because they may be
-    false ip:s */
+    false ip:s. This can be used to exploit the current privilege system compare
+    function.
+  */
   if (my_isdigit(&my_charset_latin1, name[0]))
   {
     char *pos;
@@ -236,23 +244,62 @@ char *ip_to_hostname(struct sockaddr_sto
 #else
     if (gxi_error == EAI_NONAME )
 #endif
-      add_wrong_ip(in);
+    add_wrong_ip(in);
 
     my_free(name,MYF(0));
-    freeaddrinfo(res_lst);
     DBUG_RETURN(0);
   }
 
   /* Check that 'getaddrinfo' returned the used ip */
+  char str_tmp_addr_representation[INET6_ADDRSTRLEN];
+  if (in->ss_family == AF_INET6)
+  {
+    sockaddr_in6 *addr2= (sockaddr_in6 *)in;
+    if (!inet_ntop(AF_INET6, &(addr2->sin6_addr), str_tmp_addr_representation, INET6_ADDRSTRLEN))
+    {
+       /*
+         Address conversion failed. This should normally never happen.
+       */
+       my_free(name,MYF(0));
+       add_wrong_ip(in);
+       DBUG_RETURN(0);   
+    }
+    
+    /*
+      We expect the address to be a mapped IPv4 address with a prefix
+      of ::ffff: (7 characters long). Since the privilege system currently
+      expects regular IPv4 address we convert the representation IP here.
+    */
+    strmov(str_tmp_addr_representation, str_tmp_addr_representation+7); 
+    
+  }
+  else
+  {
+    sockaddr_in *addr2= (sockaddr_in *)in;
+    inet_ntop(AF_INET, &(addr2->sin_addr), str_tmp_addr_representation, INET_ADDRSTRLEN);
+  }
+  
   for (t_res= res_lst; t_res; t_res=t_res->ai_next)
   {
-    if (!memcmp(&(t_res->ai_addr), in,
-                sizeof(struct sockaddr_storage) ) )
+    char str_addr[INET6_ADDRSTRLEN];
+    if (t_res->ai_family == AF_INET)
+    {
+      sockaddr_in *addr= (sockaddr_in *)t_res->ai_addr;
+      inet_ntop(AF_INET,&addr->sin_addr, str_addr, INET_ADDRSTRLEN);
+    }
+    else
+    {
+      sockaddr_in6 *addr= (sockaddr_in6 *)t_res->ai_addr;
+      inet_ntop(AF_INET6,&addr->sin6_addr, str_addr, INET6_ADDRSTRLEN);
+    }
+    
+    if (!memcmp(str_addr,str_tmp_addr_representation,
+                strlen(str_addr)))
     {
       add_hostname(in, name);
       freeaddrinfo(res_lst);
       DBUG_RETURN(name);
-    }
+    }     
   }
   freeaddrinfo(res_lst);
   DBUG_PRINT("error",("Couldn't verify hostname with getaddrinfo"));

=== modified file 'vio/viosocket.c'
--- a/vio/viosocket.c	2008-05-14 13:33:43 +0000
+++ b/vio/viosocket.c	2008-08-25 12:52:43 +0000
@@ -350,7 +350,17 @@ my_bool vio_peer_addr(Vio *vio, char *bu
     */
     if (!memcmp(buf, "::ffff:127.0.0.1", sizeof("::ffff:127.0.0.1")))
       strmov(buf, "127.0.0.1");
+    /*
+      We currently only support IPv4 addresses in the privilege system. If the
+      current address is a mapped IPv6 address, we strip the leading
+      characters by matching the prefix "::ffff" 
+    */
+
+    if (buf[0] == ':' && buf[1] == ':' && buf[2] == 'f' && buf[3] == 'f' &&
+        buf[4] == 'f' && buf[5] == 'f')
+        strmov(buf,buf+7);
   }
+  
   DBUG_PRINT("exit", ("addr: %s", buf));
   DBUG_RETURN(0);
 }

Thread
bzr commit into mysql-6.0 branch (kpettersson:2781) Bug#38247Kristofer Pettersson25 Aug
  • Re: bzr commit into mysql-6.0 branch (kpettersson:2781) Bug#38247Marc Alff29 Aug