#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#38247 | Alexander Nozdrin | 11 Jun |