#At file:///home/frazer/bzr/mysql-5.1-telco-7.0/
2953 Frazer Clement 2009-08-11
Bug#46336 Backport IPv6 bug fixes to cluster-7.0
- Patch back of 'official' IPv6 fixes from mysql-azalea
e.g. fixes for bugs 45584, 43006 and 45606
- Minor modification to get_peername call to match
different Windows-specific code in mysql-5.1-telco-7.0
- Includes fix for Solaris getnameinfo() address length
issue.
modified:
CMakeLists.txt
configure.in
include/violite.h
mysql-test/t/skip_name_resolve.test
sql/hostname.cc
sql/mysql_priv.h
sql/sql_connect.cc
vio/viosocket.c
=== modified file 'CMakeLists.txt'
--- a/CMakeLists.txt 2009-05-27 15:21:45 +0000
+++ b/CMakeLists.txt 2009-08-11 15:56:39 +0000
@@ -34,6 +34,9 @@ CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/inclu
# Set standard options
ADD_DEFINITIONS(-DHAVE_YASSL)
+# Enable IPv6 handling code
+ADD_DEFINITIONS(-DHAVE_IPV6)
+
# Set debug options
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DFORCE_INIT_OF_VARS")
=== modified file 'configure.in'
--- a/configure.in 2009-08-05 14:37:58 +0000
+++ b/configure.in 2009-08-11 15:56:39 +0000
@@ -883,17 +883,35 @@ fi
AC_CHECK_HEADERS(netinet/in6.h)
-AC_CHECK_TYPES([struct in6_addr], [], [],
-[[#ifdef WIN32
-#include <winsock2.h>
-#else
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN6_H
-include <netinet/in6.h>
-#endif]])
+AC_CHECK_TYPES([struct sockaddr_in6, struct in6_addr],
+ [have_in6_types=yes],
+ [have_in6_types=no],
+ [[
+ #ifdef WIN32
+ #include <winsock2.h>
+ #else
+ #include <sys/types.h>
+ #include <netinet/in.h>
+ #include <sys/socket.h>
+ #endif
+
+ #ifdef HAVE_NETINET_IN6_H
+ #include <netinet/in6.h>
+ #endif
+ ]])
+
+AC_MSG_CHECKING([for IPv6 support])
+
+AC_ARG_ENABLE(ipv6,
+ AS_HELP_STRING([--disable-ipv6], [Disable support for IPv6 networking]),
+ [disable_ipv6=yes], [disable_ipv6=no])
+
+if test x"$disable_ipv6" = xyes -o x"$have_in6_types" = xno; then
+ AC_MSG_RESULT([no])
+else
+ AC_DEFINE([HAVE_IPV6], [1], [Define if IPv6 networking support is present])
+ AC_MSG_RESULT([yes])
+fi
#--------------------------------------------------------------------
# Check for TCP wrapper support
=== modified file 'include/violite.h'
--- a/include/violite.h 2009-05-27 15:21:45 +0000
+++ b/include/violite.h 2009-08-11 15:56:39 +0000
@@ -90,6 +90,14 @@ my_socket vio_fd(Vio*vio);
my_bool vio_peer_addr(Vio* vio, char *buf, uint16 *port, size_t buflen);
my_bool vio_poll_read(Vio *vio,uint timeout);
+my_bool vio_get_normalized_ip_string(const struct sockaddr *addr, int addr_length,
+ char *ip_string, size_t ip_string_size);
+
+int vio_getnameinfo(const struct sockaddr *sa,
+ char *hostname, size_t hostname_size,
+ char *port, size_t port_size,
+ int flags);
+
#ifdef HAVE_OPENSSL
#include <openssl/opensslv.h>
#if OPENSSL_VERSION_NUMBER < 0x0090700f
=== modified file 'mysql-test/t/skip_name_resolve.test'
--- a/mysql-test/t/skip_name_resolve.test 2009-03-10 15:54:24 +0000
+++ b/mysql-test/t/skip_name_resolve.test 2009-08-11 15:56:39 +0000
@@ -15,7 +15,7 @@ DROP USER mysqltest_1@'127.0.0.1/255.255
# Bug#13407 Remote connecting crashes server
# Server crashed when one used USER() function in connection for which
# was impossible to obtain peer hostname.
-connect (con1, 127.0.0.1, root, , test, $MASTER_MYPORT, );
+connect (con1, localhost, root, , test, $MASTER_MYPORT, );
--replace_column 1 #
SELECT USER();
# We are only interested in the fact that statement below doesn't
=== modified file 'sql/hostname.cc'
--- a/sql/hostname.cc 2009-08-05 17:56:06 +0000
+++ b/sql/hostname.cc 2009-08-11 15:56:39 +0000
@@ -43,197 +43,11 @@ extern "C" { // Because of SCO 3.2V4
}
#endif
-#ifdef __WIN__
-#define HAVE_STRUCT_IN6_ADDR
-#endif /* __WIN__ */
-
/*
- HOST_ENTRY_KEY_SIZE -- size of IP address string in the hash cache. The
- system constant NI_MAXHOST could be used here. However, it means at least
- 1024 bytes per IP, which seems to be quite big.
-
- Since IP address string is created by our function get_ip_string(), we
- can reduce the space. get_ip_string() returns a hexadecimal
- respresentation (1111:2222:...:8888) in case of IPv6 and the standard
- representation (111.222.333.444) in case of IPv4, which means 39 bytes at
- most. So, we need 40 bytes for storing IP address string including
- trailing zero.
-*/
-
-#define HOST_ENTRY_KEY_SIZE 40
-
-/************************************************************************/
-
-/*
- When this code was written there were issues with winsock in pusbuild,
- this constant is in this place for this reason.
-*/
-
-#ifdef EAI_NODATA
- const int MY_NONAME_ERR_CODE= EAI_NODATA;
-#else
- const int MY_NONAME_ERR_CODE= EAI_NONAME;
-#endif
-
-/************************************************************************/
-
-/**
- Get the string representation for IP address. IPv6 and IPv4 addresses are
- supported. The function is needed because getnameinfo() is known to be
- buggy in some circumstances. Actually, this is a basic replacement for
- getnameinfo() called with the NI_NUMERICHOST flag. Only the hostname part is
- dumped (the port part is omitted).
+ HOST_ENTRY_KEY_SIZE -- size of IP address string in the hash cache.
*/
-static void get_ip_string(const struct sockaddr *ip,
- char *ip_str, int ip_str_size)
-{
- switch (ip->sa_family) {
- case AF_INET:
- {
- struct in_addr *ip4= &((struct sockaddr_in *) ip)->sin_addr;
- uint32 ip4_int32= ntohl(ip4->s_addr);
- uint8 *ip4_int8= (uint8 *) &ip4_int32;
-
- int n= my_snprintf(ip_str, ip_str_size, "%d.%d.%d.%d",
- ip4_int8[0], ip4_int8[1], ip4_int8[2], ip4_int8[3]);
-
- DBUG_ASSERT(n < ip_str_size);
- (void)n; // Remove compiler warning
- break;
- }
-
-#ifdef HAVE_STRUCT_IN6_ADDR
- case AF_INET6:
- {
- struct in6_addr *ip6= &((struct sockaddr_in6 *) ip)->sin6_addr;
- uint16 *ip6_int16= (uint16 *) ip6->s6_addr;
-
- int n= my_snprintf(ip_str, ip_str_size,
- "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",
- ntohs(ip6_int16[0]), ntohs(ip6_int16[1]),
- ntohs(ip6_int16[2]), ntohs(ip6_int16[3]),
- ntohs(ip6_int16[4]), ntohs(ip6_int16[5]),
- ntohs(ip6_int16[6]), ntohs(ip6_int16[7]));
-
- DBUG_ASSERT(n < ip_str_size);
- (void)n; // Remove compiler warning
- break;
- }
-#endif /* HAVE_STRUCT_IN6_ADDR */
-
- default:
- DBUG_ASSERT(FALSE);
- }
-}
-
-/**
- Get key value for IP address. Key value is a string representation of
- normalized IP address.
-
- 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
-
- If IPv6 is not available at compile-time, IPv4 form is used.
-
- @param [in] ip IP address
- @param [out] ip_key Key for the given IP value
-
- @note According to RFC3493 the only specified member of the in6_addr
- structure is s6_addr.
-
- @note It is possible to call hostname_cache_get_key() with zeroed IP
- address (ip->sa_family == 0). In this case hostname_cache_get_key()
- returns TRUE (error status).
-
- @return Error status.
- @retval FALSE Success
- @retval TRUE Error
-*/
-
-static bool hostname_cache_get_key(const struct sockaddr *ip, char *ip_key)
-{
- const struct sockaddr *ip_to_generate_key= ip;
-
- if (ip->sa_family == 0)
- return TRUE; /* IP address is not set. */
-
-#ifdef HAVE_STRUCT_IN6_ADDR
- /* Prepare normalized IP address. */
-
- struct sockaddr_storage norm_ip;
- struct in6_addr *norm_ip6= &((sockaddr_in6 *) &norm_ip)->sin6_addr;
- uint32 *norm_ip6_int32= (uint32 *) norm_ip6->s6_addr;
-
- memset(&norm_ip, 0, sizeof (sockaddr_storage));
-
- switch (ip->sa_family) {
- case AF_INET:
- {
- struct in_addr *ip4= &((struct sockaddr_in *) ip)->sin_addr;
-
- norm_ip6_int32[0]= 0;
- norm_ip6_int32[1]= 0;
- norm_ip6_int32[2]= htonl(0xffff);
- norm_ip6_int32[3]= ip4->s_addr; /* in net byte order */
-
- DBUG_ASSERT(IN6_IS_ADDR_V4MAPPED(norm_ip6));
- break;
- }
-
- case AF_INET6:
- {
- struct in6_addr *ip6= &((struct sockaddr_in6 *) ip)->sin6_addr;
- uint32 *ip6_int32= (uint32 *) ip6->s6_addr;
-
- if (IN6_IS_ADDR_V4COMPAT(ip6))
- {
- norm_ip6_int32[0]= 0;
- norm_ip6_int32[1]= 0;
- norm_ip6_int32[2]= htonl(0xffff);
- norm_ip6_int32[3]= ip6_int32[3]; /* in net byte order */
- DBUG_ASSERT(IN6_IS_ADDR_V4MAPPED(norm_ip6));
- }
- else
- {
- /* All in net byte order: just copy 16 bytes. */
- memcpy(norm_ip6_int32, ip6_int32, 4 * sizeof (uint32));
- }
-
- break;
- }
-
- default:
- DBUG_ASSERT(FALSE);
- break;
- }
-
- norm_ip.ss_family= AF_INET6;
- ip_to_generate_key= (sockaddr *) &norm_ip;
-#endif /* HAVE_STRUCT_IN6_ADDR */
-
- /*
- Zero all bytes of the key, because it's not just 0-terminated string.
- All bytes are taken into account during hash search.
- */
-
- memset(ip_key, 0, HOST_ENTRY_KEY_SIZE);
-
- /* Get numeric representation of the normalized IP address. */
- get_ip_string(ip_to_generate_key, ip_key, HOST_ENTRY_KEY_SIZE);
-
- return FALSE;
-}
-
+#define HOST_ENTRY_KEY_SIZE INET6_ADDRSTRLEN
/**
An entry in the hostname hash table cache.
@@ -257,7 +71,7 @@ public:
This IP address is never used to connect to a socket.
*/
- char ip[HOST_ENTRY_KEY_SIZE];
+ char ip_key[HOST_ENTRY_KEY_SIZE];
/**
Number of errors during handshake phase from the IP address.
@@ -265,7 +79,7 @@ public:
uint connect_errors;
/**
- One of host names for the IP address. May be NULL.
+ One of the host names for the IP address. May be NULL.
*/
const char *hostname;
};
@@ -281,7 +95,7 @@ void hostname_cache_refresh()
bool hostname_cache_init()
{
Host_entry tmp;
- uint key_offset= (uint) ((char*) (&tmp.ip) - (char*) &tmp);
+ uint key_offset= (uint) ((char*) (&tmp.ip_key) - (char*) &tmp);
if (!(hostname_cache= new hash_filo(HOST_CACHE_SIZE,
key_offset, HOST_ENTRY_KEY_SIZE,
@@ -301,34 +115,43 @@ void hostname_cache_free()
}
-static inline Host_entry *hostname_cache_search(const char *ip)
+static void prepare_hostname_cache_key(const char *ip_string,
+ char *ip_key)
+{
+ int ip_string_length= strlen(ip_string);
+ DBUG_ASSERT(ip_string_length < HOST_ENTRY_KEY_SIZE);
+
+ memset(ip_key, 0, HOST_ENTRY_KEY_SIZE);
+ memcpy_fixed(ip_key, ip_string, ip_string_length);
+}
+
+static inline Host_entry *hostname_cache_search(const char *ip_key)
{
- return (Host_entry *) hostname_cache->search((uchar *) ip, 0);
+ return (Host_entry *) hostname_cache->search((uchar *) ip_key, 0);
}
-static bool add_hostname_impl(const char *ip, const char *hostname)
+static bool add_hostname_impl(const char *ip_key, const char *hostname)
{
- if (hostname_cache_search(ip))
+ if (hostname_cache_search(ip_key))
return FALSE;
- uint hostname_length= hostname ? (uint) strlen(hostname) : 0;
+ size_t hostname_size= hostname ? strlen(hostname) + 1 : 0;
- Host_entry *entry= (Host_entry *) malloc(sizeof (Host_entry) +
- hostname_length + 1);
+ Host_entry *entry= (Host_entry *) malloc(sizeof (Host_entry) + hostname_size);
if (!entry)
return TRUE;
char *hostname_copy;
- memcpy_fixed(&entry->ip, ip, HOST_ENTRY_KEY_SIZE);
+ memcpy_fixed(&entry->ip_key, ip_key, HOST_ENTRY_KEY_SIZE);
- if (hostname_length)
+ if (hostname_size)
{
hostname_copy= (char *) (entry + 1);
- memcpy(hostname_copy, hostname, hostname_length + 1);
+ memcpy(hostname_copy, hostname, hostname_size);
DBUG_PRINT("info", ("Adding '%s' -> '%s' to the hostname cache...'",
- (const char *) ip,
+ (const char *) ip_key,
(const char *) hostname_copy));
}
else
@@ -336,7 +159,7 @@ static bool add_hostname_impl(const char
hostname_copy= NULL;
DBUG_PRINT("info", ("Adding '%s' -> NULL to the hostname cache...'",
- (const char *) ip));
+ (const char *) ip_key));
}
entry->hostname= hostname_copy;
@@ -346,30 +169,31 @@ static bool add_hostname_impl(const char
}
-static bool add_hostname(const char *ip, const char *hostname)
+static bool add_hostname(const char *ip_key, const char *hostname)
{
if (specialflag & SPECIAL_NO_HOST_CACHE)
return FALSE;
pthread_mutex_lock(&hostname_cache->lock);
- bool err_status= add_hostname_impl(ip, hostname);
+ bool err_status= add_hostname_impl(ip_key, hostname);
pthread_mutex_unlock(&hostname_cache->lock);
return err_status;
}
-void inc_host_errors(struct sockaddr_storage *ip)
+void inc_host_errors(const char *ip_string)
{
- char key[HOST_ENTRY_KEY_SIZE];
-
- if (hostname_cache_get_key((struct sockaddr *) ip, key))
+ if (!ip_string)
return;
+ char ip_key[HOST_ENTRY_KEY_SIZE];
+ prepare_hostname_cache_key(ip_string, ip_key);
+
VOID(pthread_mutex_lock(&hostname_cache->lock));
- Host_entry *entry= hostname_cache_search(key);
+ Host_entry *entry= hostname_cache_search(ip_key);
if (entry)
entry->connect_errors++;
@@ -377,16 +201,17 @@ void inc_host_errors(struct sockaddr_sto
VOID(pthread_mutex_unlock(&hostname_cache->lock));
}
-void reset_host_errors(struct sockaddr_storage *ip)
+void reset_host_errors(const char* ip_string)
{
- char key[HOST_ENTRY_KEY_SIZE];
-
- if (hostname_cache_get_key((struct sockaddr *) ip, key))
+ if (!ip_string)
return;
+ char ip_key[HOST_ENTRY_KEY_SIZE];
+ prepare_hostname_cache_key(ip_string, ip_key);
+
VOID(pthread_mutex_lock(&hostname_cache->lock));
- Host_entry *entry= hostname_cache_search(key);
+ Host_entry *entry= hostname_cache_search(ip_key);
if (entry)
entry->connect_errors= 0;
@@ -402,37 +227,22 @@ static inline bool is_ip_loopback(const
{
/* Check for IPv4 127.0.0.1. */
struct in_addr *ip4= &((struct sockaddr_in *) ip)->sin_addr;
- return ip4->s_addr == INADDR_LOOPBACK;
+ return ntohl(ip4->s_addr) == INADDR_LOOPBACK;
}
-#ifdef HAVE_STRUCT_IN6_ADDR
+#ifdef HAVE_IPV6
case AF_INET6:
{
- /*
- Check if we have loopback here:
- - IPv6 loopback (::1)
- - IPv4-compatible 127.0.0.1 (0:0:0:0:0:0000:7f00:0001)
- - IPv4-mapped 127.0.0.1 (0:0:0:0:0:ffff:7f00:0001)
- */
+ /* Check for IPv6 ::1. */
struct in6_addr *ip6= &((struct sockaddr_in6 *) ip)->sin6_addr;
- if (IN6_IS_ADDR_V4COMPAT(ip6) || IN6_IS_ADDR_V4MAPPED(ip6))
- {
- uint32 *ip6_int32= (uint32 *) ip6->s6_addr;
- return ntohl(ip6_int32[3]) == INADDR_LOOPBACK;
- }
- else
- {
- return IN6_IS_ADDR_LOOPBACK(ip6);
- }
+ return IN6_IS_ADDR_LOOPBACK(ip6);
}
-#endif /* HAVE_STRUCT_IN6_ADDR */
+#endif /* HAVE_IPV6 */
default:
- DBUG_ASSERT(FALSE);
return FALSE;
}
}
-
static inline bool is_hostname_valid(const char *hostname)
{
/*
@@ -464,7 +274,8 @@ static inline bool is_hostname_valid(con
NOTE: connect_errors are counted (are supported) only for the clients
where IP-address can be resolved and FCrDNS check is passed.
- @param [in] IP address. Must be set.
+ @param [in] ip_storage IP address (sockaddr). Must be set.
+ @param [in] ip_string IP address (string). Must be set.
@param [out] hostname
@param [out] connect_errors
@@ -478,18 +289,18 @@ static inline bool is_hostname_valid(con
*/
bool ip_to_hostname(struct sockaddr_storage *ip_storage,
+ const char *ip_string,
char **hostname, uint *connect_errors)
{
const struct sockaddr *ip= (const sockaddr *) ip_storage;
- char ip_string[HOST_ENTRY_KEY_SIZE];
int err_code;
+ bool err_status;
DBUG_ENTER("ip_to_hostname");
- /* IP address must be set properly. */
-
- DBUG_ASSERT(ip_storage->ss_family == AF_INET ||
- ip_storage->ss_family == AF_INET6);
+ DBUG_PRINT("info", ("IP address: '%s'; family: %d.",
+ (const char *) ip_string,
+ (int) ip->sa_family));
/* Check if we have loopback address (127.0.0.1 or ::1). */
@@ -503,15 +314,10 @@ bool ip_to_hostname(struct sockaddr_stor
DBUG_RETURN(FALSE);
}
- /* Get hostname cache key for the IP address. */
+ /* Prepare host name cache key. */
- {
- bool err_status= hostname_cache_get_key(ip, ip_string);
- DBUG_ASSERT(!err_status);
- (void)err_status; // Remove compiler warning
- }
-
- DBUG_PRINT("info", ("IP address: '%s'.", (const char *) ip_string));
+ char ip_key[HOST_ENTRY_KEY_SIZE];
+ prepare_hostname_cache_key(ip_string, ip_key);
/* Check first if we have host name in the cache. */
@@ -519,7 +325,7 @@ bool ip_to_hostname(struct sockaddr_stor
{
VOID(pthread_mutex_lock(&hostname_cache->lock));
- Host_entry *entry= hostname_cache_search(ip_string);
+ Host_entry *entry= hostname_cache_search(ip_key);
if (entry)
{
@@ -531,7 +337,7 @@ bool ip_to_hostname(struct sockaddr_stor
DBUG_PRINT("info",("IP (%s) has been found in the cache. "
"Hostname: '%s'; connect_errors: %d",
- (const char *) ip_string,
+ (const char *) ip_key,
(const char *) (*hostname? *hostname : "null"),
(int) *connect_errors));
@@ -549,10 +355,10 @@ bool ip_to_hostname(struct sockaddr_stor
char hostname_buffer[NI_MAXHOST];
- DBUG_PRINT("info", ("Resolving '%s'...", (const char *) ip_string));
+ DBUG_PRINT("info", ("Resolving '%s'...", (const char *) ip_key));
- err_code= getnameinfo(ip, sizeof (sockaddr_storage),
- hostname_buffer, NI_MAXHOST, NULL, 0, NI_NAMEREQD);
+ err_code= vio_getnameinfo(ip, hostname_buffer, NI_MAXHOST, NULL, 0,
+ NI_NAMEREQD);
if (err_code == EAI_NONAME)
{
@@ -563,13 +369,13 @@ bool ip_to_hostname(struct sockaddr_stor
DBUG_PRINT("error", ("IP address '%s' could not be resolved: "
"no reverse address mapping.",
- (const char *) ip_string));
+ (const char *) ip_key));
sql_print_warning("IP address '%s' could not be resolved: "
"no reverse address mapping.",
- (const char *) ip_string);
+ (const char *) ip_key);
- bool err_status= add_hostname(ip_string, NULL);
+ bool err_status= add_hostname(ip_key, NULL);
*hostname= NULL;
*connect_errors= 0; /* New IP added to the cache. */
@@ -580,19 +386,19 @@ bool ip_to_hostname(struct sockaddr_stor
{
DBUG_PRINT("error", ("IP address '%s' could not be resolved: "
"getnameinfo() returned %d.",
- (const char *) ip_string,
+ (const char *) ip_key,
(int) err_code));
sql_print_warning("IP address '%s' could not be resolved: "
"getnameinfo() returned error (code: %d).",
- (const char *) ip_string,
+ (const char *) ip_key,
(int) err_code);
DBUG_RETURN(TRUE);
}
DBUG_PRINT("info", ("IP '%s' resolved to '%s'.",
- (const char *) ip_string,
+ (const char *) ip_key,
(const char *) hostname_buffer));
/*
@@ -603,7 +409,7 @@ bool ip_to_hostname(struct sockaddr_stor
address (123.example.org, or 1.2 or even 1.2.3.4). We have to deny such
host names because ACL-systems is not designed to work with them.
- For exmaple, it is possible to specify a host name mask (like
+ For example, it is possible to specify a host name mask (like
192.168.1.%) for an ACL rule. Then, if IPv4-like hostnames are allowed,
there is a security hole: instead of allowing access for
192.168.1.0/255 network (which was assumed by the user), the access
@@ -615,16 +421,16 @@ bool ip_to_hostname(struct sockaddr_stor
DBUG_PRINT("error", ("IP address '%s' has been resolved "
"to the host name '%s', which resembles "
"IPv4-address itself.",
- (const char *) ip_string,
+ (const char *) ip_key,
(const char *) hostname_buffer));
sql_print_warning("IP address '%s' has been resolved "
"to the host name '%s', which resembles "
"IPv4-address itself.",
- (const char *) ip_string,
+ (const char *) ip_key,
(const char *) hostname_buffer);
- bool err_status= add_hostname(ip_string, NULL);
+ bool err_status= add_hostname(ip_key, NULL);
*hostname= NULL;
*connect_errors= 0; /* New IP added to the cache. */
@@ -647,7 +453,7 @@ bool ip_to_hostname(struct sockaddr_stor
err_code= getaddrinfo(hostname_buffer, NULL, &hints, &addr_info_list);
- if (err_code == MY_NONAME_ERR_CODE)
+ if (err_code == EAI_NONAME)
{
/*
Don't cache responses when the DNS server is down, as otherwise
@@ -655,7 +461,7 @@ bool ip_to_hostname(struct sockaddr_stor
that attempted to connect during the outage) unable to connect
indefinitely.
*/
- bool err_status= add_hostname(ip_string, NULL);
+ bool err_status= add_hostname(ip_key, NULL);
*hostname= NULL;
*connect_errors= 0; /* New IP added to the cache. */
@@ -677,18 +483,15 @@ bool ip_to_hostname(struct sockaddr_stor
addr_info; addr_info= addr_info->ai_next)
{
- struct sockaddr *resolved_ip= addr_info->ai_addr;
- char resolved_ip_key[HOST_ENTRY_KEY_SIZE];
+ char ip_buffer[HOST_ENTRY_KEY_SIZE];
- {
- bool err_status= hostname_cache_get_key(resolved_ip, resolved_ip_key);
- DBUG_ASSERT(!err_status);
- (void)err_status; // Remove compiler warning
- }
+ vio_get_normalized_ip_string(addr_info->ai_addr, addr_info->ai_addrlen,
+ ip_buffer, sizeof(ip_buffer));
+ DBUG_ASSERT(!err_status);
- DBUG_PRINT("info", (" - '%s'", (const char *) resolved_ip_key));
+ DBUG_PRINT("info", (" - '%s'", (const char*) ip_buffer));
- if (strcmp(ip_string, resolved_ip_key) == 0)
+ if (strcmp(ip_key, ip_buffer) == 0)
{
/* Copy host name string to be stored in the cache. */
@@ -712,7 +515,7 @@ bool ip_to_hostname(struct sockaddr_stor
{
sql_print_information("Hostname '%s' does not resolve to '%s'.",
(const char *) hostname_buffer,
- (const char *) ip_string);
+ (const char *) ip_key);
sql_print_information("Hostname '%s' has the following IP addresses:",
(const char *) hostname_buffer);
@@ -720,12 +523,13 @@ bool ip_to_hostname(struct sockaddr_stor
addr_info; addr_info= addr_info->ai_next)
{
- struct sockaddr *resolved_ip= addr_info->ai_addr;
- char resolved_ip_key[HOST_ENTRY_KEY_SIZE];
+ char ip_buffer[HOST_ENTRY_KEY_SIZE];
- hostname_cache_get_key(resolved_ip, resolved_ip_key);
+ vio_get_normalized_ip_string(addr_info->ai_addr, addr_info->ai_addrlen,
+ ip_buffer, sizeof(ip_buffer));
+ DBUG_ASSERT(err_status);
- sql_print_information(" - %s\n", (const char *) resolved_ip_key);
+ sql_print_information(" - %s\n", (const char *) ip_buffer);
}
}
@@ -735,18 +539,16 @@ bool ip_to_hostname(struct sockaddr_stor
/* Add an entry for the IP to the cache. */
- bool err_status;
-
if (*hostname)
{
- err_status= add_hostname(ip_string, *hostname);
+ err_status= add_hostname(ip_key, *hostname);
*connect_errors= 0;
}
else
{
DBUG_PRINT("error",("Couldn't verify hostname with getaddrinfo()."));
- err_status= add_hostname(ip_string, NULL);
+ err_status= add_hostname(ip_key, NULL);
*hostname= NULL;
*connect_errors= 0;
}
=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h 2009-08-05 14:37:58 +0000
+++ b/sql/mysql_priv.h 2009-08-11 15:56:39 +0000
@@ -2304,9 +2304,10 @@ uint build_table_shadow_filename(char *b
/* from hostname.cc */
bool ip_to_hostname(struct sockaddr_storage *ip_storage,
+ const char *ip_string,
char **hostname, uint *connect_errors);
-void inc_host_errors(struct sockaddr_storage *in);
-void reset_host_errors(struct sockaddr_storage *in);
+void inc_host_errors(const char *ip_string);
+void reset_host_errors(const char *ip_string);
bool hostname_cache_init();
void hostname_cache_free();
void hostname_cache_refresh(void);
=== modified file 'sql/sql_connect.cc'
--- a/sql/sql_connect.cc 2009-08-05 14:37:58 +0000
+++ b/sql/sql_connect.cc 2009-08-11 15:56:39 +0000
@@ -375,7 +375,7 @@ check_user(THD *thd, enum enum_server_co
if (send_old_password_request(thd) ||
my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
{
- inc_host_errors(&net->vio->remote);
+ inc_host_errors(thd->main_security_ctx.ip);
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
DBUG_RETURN(1);
}
@@ -665,7 +665,7 @@ static int check_connection(THD *thd)
thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
if (!(specialflag & SPECIAL_NO_RESOLVE))
{
- if (ip_to_hostname(&net->vio->remote,
+ if (ip_to_hostname(&net->vio->remote, thd->main_security_ctx.ip,
&thd->main_security_ctx.host, &connect_errors))
{
my_error(ER_BAD_HOST_ERROR, MYF(0), ip);
@@ -759,7 +759,7 @@ static int check_connection(THD *thd)
(pkt_len= my_net_read(net)) == packet_error ||
pkt_len < MIN_HANDSHAKE_SIZE)
{
- inc_host_errors(&net->vio->remote);
+ inc_host_errors(thd->main_security_ctx.ip);
my_error(ER_HANDSHAKE_ERROR, MYF(0),
thd->main_security_ctx.host_or_ip);
return 1;
@@ -769,7 +769,7 @@ static int check_connection(THD *thd)
#include "_cust_sql_parse.h"
#endif
if (connect_errors)
- reset_host_errors(&net->vio->remote);
+ reset_host_errors(thd->main_security_ctx.ip);
if (thd->packet.alloc(thd->variables.net_buffer_length))
return 1; /* The error is set by alloc(). */
@@ -803,7 +803,7 @@ static int check_connection(THD *thd)
/* Do the SSL layering. */
if (!ssl_acceptor_fd)
{
- inc_host_errors(&net->vio->remote);
+ inc_host_errors(thd->main_security_ctx.ip);
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
return 1;
}
@@ -811,7 +811,7 @@ static int check_connection(THD *thd)
if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout))
{
DBUG_PRINT("error", ("Failed to accept new SSL connection"));
- inc_host_errors(&net->vio->remote);
+ inc_host_errors(thd->main_security_ctx.ip);
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
return 1;
}
@@ -821,7 +821,7 @@ static int check_connection(THD *thd)
{
DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
pkt_len));
- inc_host_errors(&net->vio->remote);
+ inc_host_errors(thd->main_security_ctx.ip);
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
return 1;
}
@@ -830,7 +830,7 @@ static int check_connection(THD *thd)
if (end >= (char*) net->read_pos+ pkt_len +2)
{
- inc_host_errors(&net->vio->remote);
+ inc_host_errors(thd->main_security_ctx.ip);
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
return 1;
}
@@ -868,7 +868,7 @@ static int check_connection(THD *thd)
if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
{
- inc_host_errors(&net->vio->remote);
+ inc_host_errors(thd->main_security_ctx.ip);
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
return 1;
}
=== modified file 'vio/viosocket.c'
--- a/vio/viosocket.c 2009-08-05 14:37:58 +0000
+++ b/vio/viosocket.c 2009-08-11 15:56:39 +0000
@@ -311,6 +311,93 @@ my_socket vio_fd(Vio* vio)
return vio->sd;
}
+/**
+ Convert a sock-address (AF_INET or AF_INET6) into the "normalized" form,
+ which is the IPv4 form for IPv4-mapped or IPv4-compatible IPv6 addresses.
+
+ @note Background: when IPv4 and IPv6 are used simultaneously, IPv4
+ addresses may be written in a form of IPv4-mapped or IPv4-compatible IPv6
+ addresses. That means, one address (a.b.c.d) can be written in three forms:
+ - IPv4: a.b.c.d;
+ - IPv4-compatible IPv6: ::a.b.c.d;
+ - IPv4-mapped IPv4: ::ffff:a.b.c.d;
+
+ Having three forms of one address makes it a little difficult to compare
+ addresses with each other (the IPv4-compatible IPv6-address of foo.bar
+ will be different from the IPv4-mapped IPv6-address of foo.bar).
+
+ @note This function can be made public when it's needed.
+
+ @param src [in] source IP address (AF_INET or AF_INET6).
+ @param src_length [in] length of the src.
+ @param dst [out] a buffer to store normalized IP address
+ (sockaddr_storage).
+ @param dst_length [out] actual length of the normalized IP address.
+*/
+static void vio_get_normalized_ip(const struct sockaddr *src,
+ int src_length,
+ struct sockaddr *dst,
+ int *dst_length)
+{
+ switch (src->sa_family) {
+ case AF_INET:
+ memcpy(dst, src, src_length);
+ *dst_length= src_length;
+ break;
+
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ {
+ const struct sockaddr_in6 *src_addr6= (const struct sockaddr_in6 *) src;
+ const struct in6_addr *src_ip6= &(src_addr6->sin6_addr);
+ const uint32 *src_ip6_int32= (uint32 *) src_ip6->s6_addr;
+
+ if (IN6_IS_ADDR_V4MAPPED(src_ip6) || IN6_IS_ADDR_V4COMPAT(src_ip6))
+ {
+ struct sockaddr_in *dst_ip4= (struct sockaddr_in *) dst;
+
+ /*
+ This is an IPv4-mapped or IPv4-compatible IPv6 address. It should
+ be converted to the IPv4 form.
+ */
+
+ *dst_length= sizeof (struct sockaddr_in);
+
+ memset(dst_ip4, 0, *dst_length);
+ dst_ip4->sin_family= AF_INET;
+ dst_ip4->sin_port= src_addr6->sin6_port;
+
+ /*
+ In an IPv4 mapped or compatible address, the last 32 bits represent
+ the IPv4 address. The byte orders for IPv6 and IPv4 addresses are
+ the same, so a simple copy is possible.
+ */
+ dst_ip4->sin_addr.s_addr= src_ip6_int32[3];
+ }
+ else
+ {
+ /* This is a "native" IPv6 address. */
+
+ memcpy(dst, src, src_length);
+ *dst_length= src_length;
+ }
+
+ break;
+ }
+#endif /* HAVE_IPV6 */
+ }
+}
+
+
+/**
+ Return IP address and port of a VIO client socket.
+
+ The function returns an IPv4 address if IPv6 support is disabled.
+
+ The function returns an IPv4 address if the client socket is associated
+ with an IPv4-compatible or IPv4-mapped IPv6 address. Otherwise, the native
+ IPv6 address is returned.
+*/
my_bool vio_peer_addr(Vio * vio, char *ip_buffer, uint16 *port,
size_t ip_buffer_size)
@@ -320,6 +407,20 @@ my_bool vio_peer_addr(Vio * vio, char *i
MY_SOCKET_FORMAT_VALUE(vio->sd)));
if (vio->localhost)
{
+ /*
+ Initialize vio->remote and vio->addLen. Set vio->remote to IPv4 loopback
+ address.
+ */
+ struct in_addr *ip4= &((struct sockaddr_in *)
+ &(vio->remote))->sin_addr;
+
+ vio->remote.ss_family= AF_INET;
+ vio->addrLen= sizeof (struct sockaddr_in);
+
+ ip4->s_addr= htonl(INADDR_LOOPBACK);
+
+ /* Initialize ip_buffer and port. */
+
strmov(ip_buffer,"127.0.0.1");
*port= 0;
}
@@ -328,19 +429,13 @@ my_bool vio_peer_addr(Vio * vio, char *i
int err_code;
char port_buffer[NI_MAXSERV];
- struct sockaddr *addr= (struct sockaddr *) (&vio->remote);
- size_socket addr_size = sizeof (vio->remote);
-
- struct sockaddr *resolving_addr= addr;
- uint resolving_addr_size= addr_size;
-
-#ifdef HAVE_STRUCT_IN6_ADDR
struct sockaddr_storage addr_storage;
-#endif
+ struct sockaddr *addr= (struct sockaddr *) &addr_storage;
+ size_socket addr_length= sizeof (addr_storage);
- /* Get sockaddr by socked fd (fill vio->remote) */
+ /* Get sockaddr by socked fd */
- err_code= my_getpeername(vio->sd, addr, &addr_size);
+ err_code= my_getpeername(vio->sd, addr, &addr_length);
if (err_code)
{
@@ -348,55 +443,26 @@ my_bool vio_peer_addr(Vio * vio, char *i
DBUG_RETURN(TRUE);
}
- vio->addrLen= (int) addr_size;
-
- /*
- Convert IPv6 address to IPv4 if it is IPv4-mapped or IPv4-compatible.
- */
-
-#ifdef HAVE_STRUCT_IN6_ADDR
- if (addr->sa_family == AF_INET6)
- {
- const struct sockaddr_in6 *addr6= (const struct sockaddr_in6 *) addr;
- const struct in6_addr *ip6= &(addr6->sin6_addr);
- const uint32 *ip6_int32= (uint32 *) ip6->s6_addr;
-
- memset(&addr_storage, 0, sizeof (addr_storage));
+ /* Normalize IP address. */
- if (IN6_IS_ADDR_V4MAPPED(ip6) || IN6_IS_ADDR_V4COMPAT(ip6))
- {
- struct sockaddr_in *ip4= (struct sockaddr_in *) &addr_storage;
- ip4->sin_family= AF_INET;
- ip4->sin_port= 0;
-
- /*
- In an IPv4 mapped or compatible address, the last 32 bits represent
- the IPv4 address. The byte orders for IPv6 and IPv4 addresses are
- the same, so a simple copy is possible.
- */
- ip4->sin_addr.s_addr= ip6_int32[3];
-
- resolving_addr= (struct sockaddr *) ip4;
- resolving_addr_size= sizeof (addr_storage);
- }
- }
-#endif /* HAVE_STRUCT_IN6_ADDR */
+ vio_get_normalized_ip(addr, addr_length,
+ (struct sockaddr *) &vio->remote, &vio->addrLen);
/* Get IP address & port number. */
+
+ err_code= vio_getnameinfo((struct sockaddr *) &vio->remote,
+ ip_buffer, ip_buffer_size,
+ port_buffer, NI_MAXSERV,
+ NI_NUMERICHOST | NI_NUMERICSERV);
- err_code= getnameinfo(resolving_addr, resolving_addr_size,
- ip_buffer, ip_buffer_size,
- port_buffer, NI_MAXSERV,
- NI_NUMERICHOST | NI_NUMERICSERV);
-
- if (err_code)
+ if(err_code)
{
DBUG_PRINT("exit", ("getnameinfo() gave error: %s",
gai_strerror(err_code)));
DBUG_RETURN(TRUE);
}
-
- *port= (uint16) strtol(port_buffer, (char **) NULL, 10);
+
+ *port= (uint16) strtol(port_buffer, NULL, 10);
}
@@ -694,3 +760,82 @@ int vio_close_shared_memory(Vio * vio)
}
#endif /* HAVE_SMEM */
#endif /* __WIN__ */
+
+
+/**
+ Return the normalized IP address string for a sock-address.
+
+ The idea is to return an IPv4-address for an IPv4-mapped and
+ IPv4-compatible IPv6 address.
+
+ The function writes the normalized IP address to the given buffer.
+ The buffer should have enough space, otherwise error flag is returned.
+ The system constant INET6_ADDRSTRLEN can be used to reserve buffers of
+ the right size.
+
+ @param addr [in] sockaddr object (AF_INET or AF_INET6).
+ @param addr_length [in] length of the addr.
+ @param ip_string [out] buffer to write normalized IP address.
+ @param ip_string_size [in] size of the ip_string.
+
+ @return Error status.
+ @retval TRUE in case of error (the ip_string buffer is not enough).
+ @retval FALSE on success.
+*/
+
+my_bool vio_get_normalized_ip_string(const struct sockaddr *addr,
+ int addr_length,
+ char *ip_string,
+ size_t ip_string_size)
+{
+ struct sockaddr_storage norm_addr_storage;
+ struct sockaddr *norm_addr= (struct sockaddr *) &norm_addr_storage;
+ int norm_addr_length;
+ int err_code;
+
+ vio_get_normalized_ip(addr, addr_length, norm_addr, &norm_addr_length);
+
+ err_code= vio_getnameinfo(norm_addr, ip_string, ip_string_size, NULL, 0,
+ NI_NUMERICHOST);
+
+ if (!err_code)
+ return FALSE;
+
+ DBUG_PRINT("error", ("getnameinfo() failed with %d (%s).",
+ (int) err_code,
+ (const char *) gai_strerror(err_code)));
+ return TRUE;
+}
+
+
+/**
+ This is a wrapper for the system getnameinfo(), because different OS
+ differ in the getnameinfo() implementation. For instance, Solaris 10
+ requires that the 2nd argument (salen) must match the actual size of the
+ struct sockaddr_storage passed to it.
+*/
+
+int vio_getnameinfo(const struct sockaddr *sa,
+ char *hostname, size_t hostname_size,
+ char *port, size_t port_size,
+ int flags)
+{
+ int sa_length= 0;
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ sa_length= sizeof (struct sockaddr_in);
+ break;
+
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ sa_length= sizeof (struct sockaddr_in6);
+ break;
+#endif /* HAVE_IPV6 */
+ }
+
+ return getnameinfo(sa, sa_length,
+ hostname, hostname_size,
+ port, port_size,
+ flags);
+}
| Thread |
|---|
| • bzr commit into mysql-5.1-telco-7.0 branch (frazer:2953) Bug#46336 | Frazer Clement | 11 Aug |