From: Alexander Nozdrin Date: August 5 2009 5:50pm Subject: bzr commit into mysql branch (alik:2844) Bug#45584 List-Archive: http://lists.mysql.com/commits/80200 X-Bug: 45584 Message-Id: <20090805175015.3B11F7FC6B@quad> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="Boundary_(ID_wMjVkr/0bsNOsTuexZwBBQ)" --Boundary_(ID_wMjVkr/0bsNOsTuexZwBBQ) MIME-version: 1.0 Content-type: text/plain; CHARSET=US-ASCII Content-transfer-encoding: 7BIT Content-disposition: inline #At file:///mnt/raid/alik/MySQL/bzr/bug38247/azalea-bf-bug45584/ based on revid:alik@stripped 2844 Alexander Nozdrin 2009-08-05 Fix for Bug#45584 (Host name cache does not work as a cache). The problem is described in the bug report. The solution is the following: - Make hostname cache key type of (char *); - Use string representation of normalized IPv6 addresses as hostname cache keys when IPv6 is supported. Use string representation of normalized IPv4 addresses as hostname cache keys when IPv6 is not supported. - Use only the host part of client address for hostname cache keys; - Actually resolve IP addresses to hostnames, not to IP strings; - Minimal supported Windows version has been changed to Windows XP. We don't support Windows 2000 for the newer versions any more. Windows XP has IPv6 support, so declaring it minimal supported version removes much of "windows portability hassle". modified: include/config-win.h include/violite.h sql/hostname.cc sql/mysql_priv.h sql/sql_connect.cc vio/viosocket.c === modified file 'include/config-win.h' --- a/include/config-win.h 2009-07-31 20:21:25 +0000 +++ b/include/config-win.h 2009-08-05 17:50:09 +0000 @@ -17,11 +17,11 @@ #define BIG_TABLES -/* +/* Minimal version of Windows we should be able to run on. - Currently Windows 2000 + Currently Windows XP. */ -#define _WIN32_WINNT 0x0500 +#define _WIN32_WINNT 0x0501 #if defined(_MSC_VER) && _MSC_VER >= 1400 === modified file 'include/violite.h' --- a/include/violite.h 2009-07-23 13:07:41 +0000 +++ b/include/violite.h 2009-08-05 17:50:09 +0000 @@ -86,6 +86,9 @@ my_bool vio_poll_read(Vio *vio, uint tim my_bool vio_is_connected(Vio *vio); ssize_t vio_pending(Vio *vio); +my_bool vio_get_normalized_ip_string(const struct sockaddr *addr, int addr_length, + char *ip_string, size_t ip_string_size); + #ifdef HAVE_OPENSSL #include #if OPENSSL_VERSION_NUMBER < 0x0090700f === modified file 'sql/hostname.cc' --- a/sql/hostname.cc 2009-01-27 02:08:48 +0000 +++ b/sql/hostname.cc 2009-08-05 17:50:09 +0000 @@ -18,10 +18,10 @@ @file @brief - Get hostname for an IP. + Get hostname for an IP address. - Hostnames are checked with reverse name lookup and - checked that they doesn't resemble an ip. + Hostnames are checked with reverse name lookup and checked that they + doesn't resemble an IP address. */ #include "mysql_priv.h" @@ -40,12 +40,45 @@ extern "C" { // Because of SCO 3.2V4 } #endif -class host_entry :public hash_filo_element +/* + HOST_ENTRY_KEY_SIZE -- size of IP address string in the hash cache. +*/ + +#define HOST_ENTRY_KEY_SIZE INET6_ADDRSTRLEN + +/** + An entry in the hostname hash table cache. + + Host name cache does two things: + - caches host names to save DNS look ups; + - counts connect errors from IP. + + Host name can be NULL (that means DNS look up failed), but connect errors + still are counted. +*/ + +class Host_entry :public hash_filo_element { public: - char ip[sizeof(struct sockaddr_storage)]; - uint errors; - char *hostname; + /** + Client IP address. This is the key used with the hash table. + + The client IP address is always expressed in IPv6, even when the + network IPv6 stack is not present. + + This IP address is never used to connect to a socket. + */ + char ip_string[HOST_ENTRY_KEY_SIZE]; + + /** + Number of errors during handshake phase from the IP address. + */ + uint connect_errors; + + /** + One of the host names for the IP address. May be NULL. + */ + const char *hostname; }; static hash_filo *hostname_cache; @@ -57,13 +90,15 @@ void hostname_cache_refresh() bool hostname_cache_init() { - host_entry tmp; - uint offset= (uint) ((char*) (&tmp.ip) - (char*) &tmp); - if (!(hostname_cache=new hash_filo(HOST_CACHE_SIZE, offset, - sizeof(struct sockaddr_storage),NULL, - (my_hash_free_key) free, - &my_charset_bin))) + Host_entry tmp; + uint key_offset= (uint) ((char*) (&tmp.ip_string) - (char*) &tmp); + + if (!(hostname_cache= new hash_filo(HOST_CACHE_SIZE, + key_offset, HOST_ENTRY_KEY_SIZE, + NULL, (my_hash_free_key) free, + &my_charset_bin))) return 1; + hostname_cache->clear(); return 0; @@ -71,190 +106,432 @@ bool hostname_cache_init() void hostname_cache_free() { - if (hostname_cache) - { - delete hostname_cache; - hostname_cache= 0; - } + delete hostname_cache; + hostname_cache= NULL; } -static void add_hostname(struct sockaddr_storage *in, const char *name) +static inline Host_entry *hostname_cache_search(const char *ip_string) { - if (!(specialflag & SPECIAL_NO_HOST_CACHE)) + return (Host_entry *) hostname_cache->search((uchar *) ip_string, 0); +} + +static bool add_hostname_impl(const char *ip_string, const char *hostname) +{ + if (hostname_cache_search(ip_string)) + return FALSE; + + size_t hostname_size= hostname ? strlen(hostname) + 1 : 0; + + Host_entry *entry= (Host_entry *) malloc(sizeof (Host_entry) + hostname_size); + + if (!entry) + return TRUE; + + char *hostname_copy; + + memcpy_fixed(&entry->ip_string, ip_string, HOST_ENTRY_KEY_SIZE); + + if (hostname_size) { - pthread_mutex_lock(&hostname_cache->lock); - host_entry *entry; - if (!(entry=(host_entry*) hostname_cache->search((uchar*) in, 0))) - { - uint length=name ? (uint) strlen(name) : 0; + hostname_copy= (char *) (entry + 1); + memcpy(hostname_copy, hostname, hostname_size); - if ((entry=(host_entry*) malloc(sizeof(host_entry)+length+1))) - { - char *new_name; - memcpy_fixed(&entry->ip, in, sizeof(struct sockaddr_storage)); - if (length) - memcpy(new_name= (char *) (entry+1), name, length+1); - else - new_name=0; - entry->hostname=new_name; - entry->errors=0; - (void) hostname_cache->add(entry); - } - } - pthread_mutex_unlock(&hostname_cache->lock); + DBUG_PRINT("info", ("Adding '%s' -> '%s' to the hostname cache...'", + (const char *) ip_string, + (const char *) hostname_copy)); } + else + { + hostname_copy= NULL; + + DBUG_PRINT("info", ("Adding '%s' -> NULL to the hostname cache...'", + (const char *) ip_string)); + } + + entry->hostname= hostname_copy; + entry->connect_errors= 0; + + return hostname_cache->add(entry); } -inline void add_wrong_ip(struct sockaddr_storage *in) +static bool add_hostname(const char *ip_string, const char *hostname) { - add_hostname(in, NullS); + if (specialflag & SPECIAL_NO_HOST_CACHE) + return FALSE; + + pthread_mutex_lock(&hostname_cache->lock); + + bool err_status= add_hostname_impl(ip_string, hostname); + + pthread_mutex_unlock(&hostname_cache->lock); + + return err_status; } -void inc_host_errors(struct sockaddr_storage *in) +void inc_host_errors(const char *ip_string) { + if (!ip_string) + return; + pthread_mutex_lock(&hostname_cache->lock); - host_entry *entry; - if ((entry=(host_entry*) hostname_cache->search((uchar*)in, 0))) - entry->errors++; + Host_entry *entry= hostname_cache_search(ip_string); + + if (entry) + entry->connect_errors++; pthread_mutex_unlock(&hostname_cache->lock); } -void reset_host_errors(struct sockaddr_storage *in) +void reset_host_errors(const char *ip_string) { + if (!ip_string) + return; + pthread_mutex_lock(&hostname_cache->lock); - host_entry *entry; - if ((entry=(host_entry*) hostname_cache->search((uchar*)in, 0))) - entry->errors=0; + Host_entry *entry= hostname_cache_search(ip_string); + + if (entry) + entry->connect_errors= 0; pthread_mutex_unlock(&hostname_cache->lock); } -char *ip_to_hostname(struct sockaddr_storage *in, int addrLen, uint *errors) +static inline bool is_ip_loopback(const struct sockaddr *ip) +{ + switch (ip->sa_family) { + case AF_INET: + { + /* Check for IPv4 127.0.0.1. */ + struct in_addr *ip4= &((struct sockaddr_in *) ip)->sin_addr; + return ip4->s_addr == INADDR_LOOPBACK; + } + +#ifdef HAVE_IPV6 + case AF_INET6: + { + /* Check for IPv6 ::1. */ + struct in6_addr *ip6= &((struct sockaddr_in6 *) ip)->sin6_addr; + return IN6_IS_ADDR_LOOPBACK(ip6); + } +#endif /* HAVE_IPV6 */ + + default: + return FALSE; + } +} + +static inline bool is_hostname_valid(const char *hostname) { - char *name; + /* + A hostname is invalid if it starts with a number followed by a dot + (IPv4 address). + */ + + if (!my_isdigit(&my_charset_latin1, hostname[0])) + return TRUE; - struct addrinfo hints,*res_lst,*t_res; - int gxi_error; - char hostname_buff[NI_MAXHOST]; + const char *p= hostname + 1; + + while (my_isdigit(&my_charset_latin1, *p)) + ++p; + + return *p != '.'; +} + +/** + Resolve IP-address to host name. + + This function does the following things: + - resolves IP-address; + - employs Forward Confirmed Reverse DNS technique to validate IP-address; + - returns host name if IP-address is validated; + - set value to out-variable connect_errors -- this variable represents the + number of connection errors from the specified IP-address. + + 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_storage IP address (sockaddr). Must be set. + @param [in] ip_string IP address (string). Must be set. + @param [out] hostname + @param [out] connect_errors + + @return Error status + @retval FALSE Success + @retval TRUE Error + + The function does not set/report MySQL server error in case of failure. + It's caller's responsibility to handle failures of this function + properly. +*/ + +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; + int err_code; - host_entry *entry; DBUG_ENTER("ip_to_hostname"); - *errors=0; + DBUG_PRINT("info", ("IP address: '%s'; family: %d.", + (const char *) ip_string, + (int) ip->sa_family)); - /* 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) - { - DBUG_PRINT("error",("getnameinfo returned %d", gxi_error)); - DBUG_RETURN(0); - } - DBUG_PRINT("info",("resolved: %s", hostname_buff)); + /* Check if we have loopback address (127.0.0.1 or ::1). */ - /* 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); - } - if (!memcmp(hostname_buff, "::ffff:127.0.0.1", sizeof("::ffff:127.0.0.1"))) - { - DBUG_RETURN((char *)my_localhost); - } - if (!memcmp(hostname_buff, "::1", sizeof("::1"))) + if (is_ip_loopback(ip)) { - DBUG_RETURN((char *)my_localhost); + DBUG_PRINT("info", ("Loopback address detected.")); + + *connect_errors= 0; /* Do not count connect errors from localhost. */ + *hostname= (char *) my_localhost; + + DBUG_RETURN(FALSE); } - /* Check first if we have name in cache */ + /* Check first if we have host name in the cache. */ + if (!(specialflag & SPECIAL_NO_HOST_CACHE)) { pthread_mutex_lock(&hostname_cache->lock); - if ((entry= (host_entry*)hostname_cache->search((uchar *)&in, 0))) + + Host_entry *entry= hostname_cache_search(ip_string); + + if (entry) { + *connect_errors= entry->connect_errors; + *hostname= NULL; + if (entry->hostname) - name= my_strdup(entry->hostname, MYF(0)); - else - name= NULL; + *hostname= my_strdup(entry->hostname, MYF(0)); + + DBUG_PRINT("info",("IP (%s) has been found in the cache. " + "Hostname: '%s'; connect_errors: %d", + (const char *) ip_string, + (const char *) (*hostname? *hostname : "null"), + (int) *connect_errors)); - DBUG_PRINT("info",("cached data %s", name ? name : "null" )); - *errors= entry->errors; pthread_mutex_unlock(&hostname_cache->lock); - DBUG_RETURN(name); + + DBUG_RETURN(FALSE); } + pthread_mutex_unlock(&hostname_cache->lock); } - if (!(name= my_strdup(hostname_buff, MYF(0)))) + /* + Resolve host name. Return an error if a host name can not be resolved + (instead of returning the numeric form of the host name). + */ + + char hostname_buffer[NI_MAXHOST]; + + DBUG_PRINT("info", ("Resolving '%s'...", (const char *) ip_string)); + + err_code= getnameinfo(ip, sizeof (sockaddr_storage), + hostname_buffer, NI_MAXHOST, NULL, 0, NI_NAMEREQD); + + if (err_code == EAI_NONAME) + { + /* + There is no reverse address mapping for the IP address. A host name + can not be resolved. + */ + + DBUG_PRINT("error", ("IP address '%s' could not be resolved: " + "no reverse address mapping.", + (const char *) ip_string)); + + sql_print_warning("IP address '%s' could not be resolved: " + "no reverse address mapping.", + (const char *) ip_string); + + bool err_status= add_hostname(ip_string, NULL); + + *hostname= NULL; + *connect_errors= 0; /* New IP added to the cache. */ + + DBUG_RETURN(err_status); + } + else if (err_code) { - DBUG_PRINT("error",("out of memory")); - DBUG_RETURN(0); + DBUG_PRINT("error", ("IP address '%s' could not be resolved: " + "getnameinfo() returned %d.", + (const char *) ip_string, + (int) err_code)); + + sql_print_warning("IP address '%s' could not be resolved: " + "getnameinfo() returned error (code: %d).", + (const char *) ip_string, + (int) err_code); + + DBUG_RETURN(TRUE); } - /* Don't accept hostnames that starts with digits because they may be - false ip:s */ - if (my_isdigit(&my_charset_latin1, name[0])) + DBUG_PRINT("info", ("IP '%s' resolved to '%s'.", + (const char *) ip_string, + (const char *) hostname_buffer)); + + /* + Validate hostname: the server does not accept host names, which + resemble IP addresses. + + The thing is that theoretically, a host name can be in a form of IPv4 + 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 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 + will be allowed for host names like 192.168.1.example.org. + */ + + if (!is_hostname_valid(hostname_buffer)) { - char *pos; - for (pos= name+1 ; my_isdigit(&my_charset_latin1, *pos); pos++) ; - if (*pos == '.') - { - DBUG_PRINT("error",("mysqld doesn't accept hostnames that starts with a number followed by a '.'")); - goto add_wrong_ip_and_return; - } + 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 *) 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 *) hostname_buffer); + + bool err_status= add_hostname(ip_string, NULL); + + *hostname= NULL; + *connect_errors= 0; /* New IP added to the cache. */ + + DBUG_RETURN(err_status); } - bzero(&hints, sizeof (struct addrinfo)); + /* Get IP-addresses for the resolved host name (FCrDNS technique). */ + + struct addrinfo hints; + struct addrinfo *addr_info_list; + + memset(&hints, 0, sizeof (struct addrinfo)); hints.ai_flags= AI_PASSIVE; - hints.ai_socktype= SOCK_STREAM; + hints.ai_socktype= SOCK_STREAM; hints.ai_family= AF_UNSPEC; - gxi_error= getaddrinfo(hostname_buff, NULL, &hints, &res_lst); - if (gxi_error) + DBUG_PRINT("info", ("Getting IP addresses for hostname '%s'...", + (const char *) hostname_buffer)); + + err_code= getaddrinfo(hostname_buffer, NULL, &hints, &addr_info_list); + + if (err_code == EAI_NONAME) { /* - Don't cache responses when the DSN server is down, as otherwise + Don't cache responses when the DNS server is down, as otherwise transient DNS failure may leave any number of clients (those that attempted to connect during the outage) unable to connect indefinitely. */ - /* - When this code was written there were issues with winsock in pusbuild, - this define is in this place for this reason. - */ - DBUG_PRINT("error",("getaddrinfo returned %d", gxi_error)); -#ifdef EAI_NODATA - if (gxi_error == EAI_NODATA ) -#else - if (gxi_error == EAI_NONAME ) -#endif - add_wrong_ip(in); - my_free(name,MYF(0)); - DBUG_RETURN(0); + bool err_status= add_hostname(ip_string, NULL); + + *hostname= NULL; + *connect_errors= 0; /* New IP added to the cache. */ + + DBUG_RETURN(err_status); + } + else if (err_code) + { + DBUG_PRINT("error", ("getaddrinfo() failed with error code %d.", err_code)); + DBUG_RETURN(TRUE); + } + + /* Check that getaddrinfo() returned the used IP (FCrDNS technique). */ + + DBUG_PRINT("info", ("The following IP addresses found for '%s':", + (const char *) hostname_buffer)); + + for (struct addrinfo *addr_info= addr_info_list; + addr_info; addr_info= addr_info->ai_next) + { + char ip_buffer[HOST_ENTRY_KEY_SIZE]; + + { + bool err_status= + 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 *) ip_buffer)); + + if (strcmp(ip_string, ip_buffer) == 0) + { + /* Copy host name string to be stored in the cache. */ + + *hostname= my_strdup(hostname_buffer, MYF(0)); + + if (!*hostname) + { + DBUG_PRINT("error", ("Out of memory.")); + + freeaddrinfo(addr_info_list); + DBUG_RETURN(TRUE); + } + + break; + } } - /* Check that 'getaddrinfo' returned the used ip */ - for (t_res= res_lst; t_res; t_res=t_res->ai_next) + /* Log resolved IP-addresses if no match was found. */ + + if (!*hostname) { - if (!memcmp(&(t_res->ai_addr), in, - sizeof(struct sockaddr_storage) ) ) + sql_print_information("Hostname '%s' does not resolve to '%s'.", + (const char *) hostname_buffer, + (const char *) ip_string); + sql_print_information("Hostname '%s' has the following IP addresses:", + (const char *) hostname_buffer); + + for (struct addrinfo *addr_info= addr_info_list; + addr_info; addr_info= addr_info->ai_next) { - add_hostname(in, name); - freeaddrinfo(res_lst); - DBUG_RETURN(name); + char ip_buffer[HOST_ENTRY_KEY_SIZE]; + + bool err_status= + 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 *) ip_buffer); } } - freeaddrinfo(res_lst); - DBUG_PRINT("error",("Couldn't verify hostname with getaddrinfo")); -add_wrong_ip_and_return: - my_free(name,MYF(0)); - add_wrong_ip(in); - DBUG_RETURN(0); + /* Free the result of getaddrinfo(). */ + + freeaddrinfo(addr_info_list); + + /* Add an entry for the IP to the cache. */ + + bool err_status; + + if (*hostname) + { + err_status= add_hostname(ip_string, *hostname); + *connect_errors= 0; + } + else + { + DBUG_PRINT("error",("Couldn't verify hostname with getaddrinfo().")); + + err_status= add_hostname(ip_string, NULL); + *hostname= NULL; + *connect_errors= 0; + } + + DBUG_RETURN(err_status); } === modified file 'sql/mysql_priv.h' --- a/sql/mysql_priv.h 2009-07-31 19:46:24 +0000 +++ b/sql/mysql_priv.h 2009-08-05 17:50:09 +0000 @@ -2301,9 +2301,11 @@ uint build_table_shadow_filename(char *b #define FRM_ONLY (1 << 3) /* from hostname.cc */ -char *ip_to_hostname(struct sockaddr_storage *in, int addrLen, uint *errors); -void inc_host_errors(struct sockaddr_storage *in); -void reset_host_errors(struct sockaddr_storage *in); +bool ip_to_hostname(struct sockaddr_storage *ip_storage, + const char *ip_string, + char **hostname, uint *connect_errors); +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-06-09 14:36:52 +0000 +++ b/sql/sql_connect.cc 2009-08-05 17:50:09 +0000 @@ -377,7 +377,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); @@ -679,8 +679,13 @@ static int check_connection(THD *thd) thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip; if (!(specialflag & SPECIAL_NO_RESOLVE)) { - thd->main_security_ctx.host= - ip_to_hostname(&net->vio->remote, net->vio->addrLen, &connect_errors); + 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); + return 1; + } + /* Cut very long hostnames to avoid possible overflows */ if (thd->main_security_ctx.host) { @@ -768,7 +773,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); @@ -779,7 +784,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(). */ @@ -813,7 +818,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; } @@ -821,7 +826,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; @@ -832,7 +837,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; @@ -842,7 +847,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; @@ -881,7 +886,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 17:39:37 +0000 +++ b/vio/viosocket.c 2009-08-05 17:50:09 +0000 @@ -385,6 +385,53 @@ static void vio_get_normalized_ip(const /** + 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= getnameinfo(norm_addr, norm_addr_length, + 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; +} + + +/** Return IP address and port of a VIO client socket. The function returns an IPv4 address if IPv6 support is disabled. --Boundary_(ID_wMjVkr/0bsNOsTuexZwBBQ) MIME-version: 1.0 Content-type: text/bzr-bundle; CHARSET=US-ASCII; name="bzr/alik@stripped" Content-transfer-encoding: 7BIT Content-disposition: inline; filename="bzr/alik@stripped" # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: alik@stripped # target_branch: file:///mnt/raid/alik/MySQL/bzr/bug38247/azalea-bf-\ # bug45584/ # testament_sha1: 4eb78d28bb840d8a39525a462a77f40974f4f5c5 # timestamp: 2009-08-05 21:50:15 +0400 # base_revision_id: alik@stripped # # Begin bundle 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 JAusMomA --Boundary_(ID_wMjVkr/0bsNOsTuexZwBBQ)--