MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
hostname.cc
Go to the documentation of this file.
1 /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software Foundation,
14  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
15 
16 
27 #include "my_global.h"
28 #include "sql_priv.h"
29 #include "hostname.h"
30 #include "hash_filo.h"
31 #include <m_ctype.h>
32 #include "log.h" // sql_print_warning,
33  // sql_print_information
34 #include "violite.h" // vio_getnameinfo,
35  // vio_get_normalized_ip_string
36 #ifdef __cplusplus
37 extern "C" { // Because of SCO 3.2V4.2
38 #endif
39 #if !defined( __WIN__)
40 #ifdef HAVE_SYS_UN_H
41 #include <sys/un.h>
42 #endif
43 #include <sys/utsname.h>
44 #endif // __WIN__
45 #ifdef __cplusplus
46 }
47 #endif
48 
49 Host_errors::Host_errors()
50 : m_connect(0),
51  m_host_blocked(0),
52  m_nameinfo_transient(0),
53  m_nameinfo_permanent(0),
54  m_format(0),
55  m_addrinfo_transient(0),
56  m_addrinfo_permanent(0),
57  m_FCrDNS(0),
58  m_host_acl(0),
59  m_no_auth_plugin(0),
60  m_auth_plugin(0),
61  m_handshake(0),
62  m_proxy_user(0),
63  m_proxy_user_acl(0),
64  m_authentication(0),
65  m_ssl(0),
66  m_max_user_connection(0),
67  m_max_user_connection_per_hour(0),
68  m_default_database(0),
69  m_init_connect(0),
70  m_local(0)
71 {}
72 
73 Host_errors::~Host_errors()
74 {}
75 
76 void Host_errors::reset()
77 {
78  m_connect= 0;
79  m_host_blocked= 0;
82  m_format= 0;
85  m_FCrDNS= 0;
86  m_host_acl= 0;
88  m_auth_plugin= 0;
89  m_handshake= 0;
90  m_proxy_user= 0;
93  m_ssl= 0;
97  m_init_connect= 0;
98  m_local= 0;
99 }
100 
101 void Host_errors::aggregate(const Host_errors *errors)
102 {
103  m_connect+= errors->m_connect;
104  m_host_blocked+= errors->m_host_blocked;
107  m_format+= errors->m_format;
110  m_FCrDNS+= errors->m_FCrDNS;
111  m_host_acl+= errors->m_host_acl;
113  m_auth_plugin+= errors->m_auth_plugin;
114  m_handshake+= errors->m_handshake;
115  m_proxy_user+= errors->m_proxy_user;
118  m_ssl+= errors->m_ssl;
122  m_init_connect+= errors->m_init_connect;
123  m_local+= errors->m_local;
124 }
125 
126 static hash_filo *hostname_cache;
128 
129 void hostname_cache_refresh()
130 {
131  hostname_cache->clear();
132 }
133 
134 uint hostname_cache_size()
135 {
136  return hostname_cache->size();
137 }
138 
139 void hostname_cache_resize(uint size)
140 {
141  hostname_cache->resize(size);
142 }
143 
144 bool hostname_cache_init()
145 {
146  Host_entry tmp;
147  uint key_offset= (uint) ((char*) (&tmp.ip_key) - (char*) &tmp);
148 
149  if (!(hostname_cache= new hash_filo(HOST_CACHE_SIZE,
150  key_offset, HOST_ENTRY_KEY_SIZE,
151  NULL, (my_hash_free_key) free,
152  &my_charset_bin)))
153  return 1;
154 
155  hostname_cache->clear();
156 
157  return 0;
158 }
159 
160 void hostname_cache_free()
161 {
162  delete hostname_cache;
163  hostname_cache= NULL;
164 }
165 
166 void hostname_cache_lock()
167 {
168  mysql_mutex_lock(&hostname_cache->lock);
169 }
170 
171 void hostname_cache_unlock()
172 {
173  mysql_mutex_unlock(&hostname_cache->lock);
174 }
175 
176 static void prepare_hostname_cache_key(const char *ip_string,
177  char *ip_key)
178 {
179  int ip_string_length= strlen(ip_string);
180  DBUG_ASSERT(ip_string_length < HOST_ENTRY_KEY_SIZE);
181 
182  memset(ip_key, 0, HOST_ENTRY_KEY_SIZE);
183  memcpy(ip_key, ip_string, ip_string_length);
184 }
185 
186 Host_entry *hostname_cache_first()
187 { return (Host_entry *) hostname_cache->first(); }
188 
189 static inline Host_entry *hostname_cache_search(const char *ip_key)
190 {
191  return (Host_entry *) hostname_cache->search((uchar *) ip_key, 0);
192 }
193 
194 static void add_hostname_impl(const char *ip_key, const char *hostname,
195  bool validated, Host_errors *errors,
196  ulonglong now)
197 {
198  Host_entry *entry;
199  bool need_add= false;
200 
201  entry= hostname_cache_search(ip_key);
202 
203  if (likely(entry == NULL))
204  {
205  entry= (Host_entry *) malloc(sizeof (Host_entry));
206  if (entry == NULL)
207  return;
208 
209  need_add= true;
210  memcpy(&entry->ip_key, ip_key, HOST_ENTRY_KEY_SIZE);
211  entry->m_errors.reset();
212  entry->m_hostname_length= 0;
213  entry->m_host_validated= false;
214  entry->m_first_seen= now;
215  entry->m_last_seen= now;
216  entry->m_first_error_seen= 0;
217  entry->m_last_error_seen= 0;
218  }
219  else
220  {
221  entry->m_last_seen= now;
222  }
223 
224  if (validated)
225  {
226  if (hostname != NULL)
227  {
228  uint len= strlen(hostname);
229  if (len > sizeof(entry->m_hostname) - 1)
230  len= sizeof(entry->m_hostname) - 1;
231  memcpy(entry->m_hostname, hostname, len);
232  entry->m_hostname[len]= '\0';
233  entry->m_hostname_length= len;
234 
235  DBUG_PRINT("info",
236  ("Adding/Updating '%s' -> '%s' (validated) to the hostname cache...'",
237  (const char *) ip_key,
238  (const char *) entry->m_hostname));
239  }
240  else
241  {
242  entry->m_hostname_length= 0;
243  DBUG_PRINT("info",
244  ("Adding/Updating '%s' -> NULL (validated) to the hostname cache...'",
245  (const char *) ip_key));
246  }
247  entry->m_host_validated= true;
248  /*
249  New errors that are considered 'blocking',
250  that will eventually cause the IP to be black listed and blocked.
251  */
252  errors->sum_connect_errors();
253  }
254  else
255  {
256  entry->m_hostname_length= 0;
257  entry->m_host_validated= false;
258  /* Do not count new blocking errors during DNS failures. */
259  errors->clear_connect_errors();
260  DBUG_PRINT("info",
261  ("Adding/Updating '%s' -> NULL (not validated) to the hostname cache...'",
262  (const char *) ip_key));
263  }
264 
265  if (errors->has_error())
266  entry->set_error_timestamps(now);
267 
268  entry->m_errors.aggregate(errors);
269 
270  if (need_add)
271  hostname_cache->add(entry);
272 
273  return;
274 }
275 
276 static void add_hostname(const char *ip_key, const char *hostname,
277  bool validated, Host_errors *errors)
278 {
279  if (specialflag & SPECIAL_NO_HOST_CACHE)
280  return;
281 
282  ulonglong now= my_micro_time();
283 
284  mysql_mutex_lock(&hostname_cache->lock);
285 
286  add_hostname_impl(ip_key, hostname, validated, errors, now);
287 
288  mysql_mutex_unlock(&hostname_cache->lock);
289 
290  return;
291 }
292 
293 void inc_host_errors(const char *ip_string, Host_errors *errors)
294 {
295  if (!ip_string)
296  return;
297 
298  ulonglong now= my_micro_time();
299  char ip_key[HOST_ENTRY_KEY_SIZE];
300  prepare_hostname_cache_key(ip_string, ip_key);
301 
302  mysql_mutex_lock(&hostname_cache->lock);
303 
304  Host_entry *entry= hostname_cache_search(ip_key);
305 
306  if (entry)
307  {
308  if (entry->m_host_validated)
309  errors->sum_connect_errors();
310  else
311  errors->clear_connect_errors();
312 
313  entry->m_errors.aggregate(errors);
314  entry->set_error_timestamps(now);
315  }
316 
317  mysql_mutex_unlock(&hostname_cache->lock);
318 }
319 
320 
321 void reset_host_connect_errors(const char *ip_string)
322 {
323  if (!ip_string)
324  return;
325 
326  char ip_key[HOST_ENTRY_KEY_SIZE];
327  prepare_hostname_cache_key(ip_string, ip_key);
328 
329  mysql_mutex_lock(&hostname_cache->lock);
330 
331  Host_entry *entry= hostname_cache_search(ip_key);
332 
333  if (entry)
334  entry->m_errors.clear_connect_errors();
335 
336  mysql_mutex_unlock(&hostname_cache->lock);
337 }
338 
339 
340 static inline bool is_ip_loopback(const struct sockaddr *ip)
341 {
342  switch (ip->sa_family) {
343  case AF_INET:
344  {
345  /* Check for IPv4 127.0.0.1. */
346  struct in_addr *ip4= &((struct sockaddr_in *) ip)->sin_addr;
347  return ntohl(ip4->s_addr) == INADDR_LOOPBACK;
348  }
349 
350 #ifdef HAVE_IPV6
351  case AF_INET6:
352  {
353  /* Check for IPv6 ::1. */
354  struct in6_addr *ip6= &((struct sockaddr_in6 *) ip)->sin6_addr;
355  return IN6_IS_ADDR_LOOPBACK(ip6);
356  }
357 #endif /* HAVE_IPV6 */
358 
359  default:
360  return FALSE;
361  }
362 }
363 
364 static inline bool is_hostname_valid(const char *hostname)
365 {
366  /*
367  A hostname is invalid if it starts with a number followed by a dot
368  (IPv4 address).
369  */
370 
371  if (!my_isdigit(&my_charset_latin1, hostname[0]))
372  return TRUE;
373 
374  const char *p= hostname + 1;
375 
376  while (my_isdigit(&my_charset_latin1, *p))
377  ++p;
378 
379  return *p != '.';
380 }
381 
410 int ip_to_hostname(struct sockaddr_storage *ip_storage,
411  const char *ip_string,
412  char **hostname,
413  uint *connect_errors)
414 {
415  const struct sockaddr *ip= (const sockaddr *) ip_storage;
416  int err_code;
417  bool err_status;
418  Host_errors errors;
419 
420  DBUG_ENTER("ip_to_hostname");
421  DBUG_PRINT("info", ("IP address: '%s'; family: %d.",
422  (const char *) ip_string,
423  (int) ip->sa_family));
424 
425  /* Default output values, for most cases. */
426  *hostname= NULL;
427  *connect_errors= 0;
428 
429  /* Check if we have loopback address (127.0.0.1 or ::1). */
430 
431  if (is_ip_loopback(ip))
432  {
433  DBUG_PRINT("info", ("Loopback address detected."));
434 
435  /* Do not count connect errors from localhost. */
436  *hostname= (char *) my_localhost;
437 
438  DBUG_RETURN(0);
439  }
440 
441  /* Prepare host name cache key. */
442 
443  char ip_key[HOST_ENTRY_KEY_SIZE];
444  prepare_hostname_cache_key(ip_string, ip_key);
445 
446  /* Check first if we have host name in the cache. */
447 
448  if (!(specialflag & SPECIAL_NO_HOST_CACHE))
449  {
450  ulonglong now= my_micro_time();
451 
452  mysql_mutex_lock(&hostname_cache->lock);
453 
454  Host_entry *entry= hostname_cache_search(ip_key);
455 
456  if (entry)
457  {
458  entry->m_last_seen= now;
459  *connect_errors= entry->m_errors.m_connect;
460 
461  if (entry->m_errors.m_connect >= max_connect_errors)
462  {
463  entry->m_errors.m_host_blocked++;
464  entry->set_error_timestamps(now);
465  mysql_mutex_unlock(&hostname_cache->lock);
466  DBUG_RETURN(RC_BLOCKED_HOST);
467  }
468 
469  /*
470  If there is an IP -> HOSTNAME association in the cache,
471  but for a hostname that was not validated,
472  do not return that hostname: perform the network validation again.
473  */
474  if (entry->m_host_validated)
475  {
476  if (entry->m_hostname_length)
477  *hostname= my_strdup(entry->m_hostname, MYF(0));
478 
479  DBUG_PRINT("info",("IP (%s) has been found in the cache. "
480  "Hostname: '%s'",
481  (const char *) ip_key,
482  (const char *) (*hostname? *hostname : "null")
483  ));
484 
485  mysql_mutex_unlock(&hostname_cache->lock);
486 
487  DBUG_RETURN(0);
488  }
489  }
490 
491  mysql_mutex_unlock(&hostname_cache->lock);
492  }
493 
494  /*
495  Resolve host name. Return an error if a host name can not be resolved
496  (instead of returning the numeric form of the host name).
497  */
498 
499  char hostname_buffer[NI_MAXHOST];
500 
501  DBUG_PRINT("info", ("Resolving '%s'...", (const char *) ip_key));
502 
503  err_code= vio_getnameinfo(ip, hostname_buffer, NI_MAXHOST, NULL, 0,
504  NI_NAMEREQD);
505 
506  /*
507  ===========================================================================
508  DEBUG code only (begin)
509  Simulate various output from vio_getnameinfo().
510  ===========================================================================
511  */
512 
513  DBUG_EXECUTE_IF("getnameinfo_error_noname",
514  {
515  strcpy(hostname_buffer, "<garbage>");
516  err_code= EAI_NONAME;
517  }
518  );
519 
520  DBUG_EXECUTE_IF("getnameinfo_error_again",
521  {
522  strcpy(hostname_buffer, "<garbage>");
523  err_code= EAI_AGAIN;
524  }
525  );
526 
527  DBUG_EXECUTE_IF("getnameinfo_fake_ipv4",
528  {
529  strcpy(hostname_buffer, "santa.claus.ipv4.example.com");
530  err_code= 0;
531  }
532  );
533 
534  DBUG_EXECUTE_IF("getnameinfo_fake_ipv6",
535  {
536  strcpy(hostname_buffer, "santa.claus.ipv6.example.com");
537  err_code= 0;
538  }
539  );
540 
541  DBUG_EXECUTE_IF("getnameinfo_format_ipv4",
542  {
543  strcpy(hostname_buffer, "12.12.12.12");
544  err_code= 0;
545  }
546  );
547 
548  DBUG_EXECUTE_IF("getnameinfo_format_ipv6",
549  {
550  strcpy(hostname_buffer, "12:DEAD:BEEF:0");
551  err_code= 0;
552  }
553  );
554 
555  /*
556  ===========================================================================
557  DEBUG code only (end)
558  ===========================================================================
559  */
560 
561  if (err_code)
562  {
563  // NOTE: gai_strerror() returns a string ending by a dot.
564 
565  DBUG_PRINT("error", ("IP address '%s' could not be resolved: %s",
566  (const char *) ip_key,
567  (const char *) gai_strerror(err_code)));
568 
569  sql_print_warning("IP address '%s' could not be resolved: %s",
570  (const char *) ip_key,
571  (const char *) gai_strerror(err_code));
572 
573  bool validated;
574  if (vio_is_no_name_error(err_code))
575  {
576  /*
577  The no-name error means that there is no reverse address mapping
578  for the IP address. A host name can not be resolved.
579  */
580  errors.m_nameinfo_permanent= 1;
581  validated= true;
582  }
583  else
584  {
585  /*
586  If it is not the no-name error, we should not cache the hostname
587  (or rather its absence), because the failure might be transient.
588  Only the ip error statistics are cached.
589  */
590  errors.m_nameinfo_transient= 1;
591  validated= false;
592  }
593  add_hostname(ip_key, NULL, validated, &errors);
594 
595  DBUG_RETURN(0);
596  }
597 
598  DBUG_PRINT("info", ("IP '%s' resolved to '%s'.",
599  (const char *) ip_key,
600  (const char *) hostname_buffer));
601 
602  /*
603  Validate hostname: the server does not accept host names, which
604  resemble IP addresses.
605 
606  The thing is that theoretically, a host name can be in a form of IPv4
607  address (123.example.org, or 1.2 or even 1.2.3.4). We have to deny such
608  host names because ACL-systems is not designed to work with them.
609 
610  For example, it is possible to specify a host name mask (like
611  192.168.1.%) for an ACL rule. Then, if IPv4-like hostnames are allowed,
612  there is a security hole: instead of allowing access for
613  192.168.1.0/255 network (which was assumed by the user), the access
614  will be allowed for host names like 192.168.1.example.org.
615  */
616 
617  if (!is_hostname_valid(hostname_buffer))
618  {
619  DBUG_PRINT("error", ("IP address '%s' has been resolved "
620  "to the host name '%s', which resembles "
621  "IPv4-address itself.",
622  (const char *) ip_key,
623  (const char *) hostname_buffer));
624 
625  sql_print_warning("IP address '%s' has been resolved "
626  "to the host name '%s', which resembles "
627  "IPv4-address itself.",
628  (const char *) ip_key,
629  (const char *) hostname_buffer);
630 
631  errors.m_format= 1;
632  add_hostname(ip_key, hostname_buffer, false, &errors);
633 
634  DBUG_RETURN(false);
635  }
636 
637  /* Get IP-addresses for the resolved host name (FCrDNS technique). */
638 
639  struct addrinfo hints;
640  struct addrinfo *addr_info_list;
641  /*
642  Makes fault injection with DBUG_EXECUTE_IF easier.
643  Invoking free_addr_info(NULL) crashes on some platforms.
644  */
645  bool free_addr_info_list= false;
646 
647  memset(&hints, 0, sizeof (struct addrinfo));
648  hints.ai_flags= AI_PASSIVE;
649  hints.ai_socktype= SOCK_STREAM;
650  hints.ai_family= AF_UNSPEC;
651 
652  DBUG_PRINT("info", ("Getting IP addresses for hostname '%s'...",
653  (const char *) hostname_buffer));
654 
655  err_code= getaddrinfo(hostname_buffer, NULL, &hints, &addr_info_list);
656  if (err_code == 0)
657  free_addr_info_list= true;
658 
659  /*
660  ===========================================================================
661  DEBUG code only (begin)
662  Simulate various output from getaddrinfo().
663  ===========================================================================
664  */
665  DBUG_EXECUTE_IF("getaddrinfo_error_noname",
666  {
667  if (free_addr_info_list)
668  freeaddrinfo(addr_info_list);
669 
670  addr_info_list= NULL;
671  err_code= EAI_NONAME;
672  free_addr_info_list= false;
673  }
674  );
675 
676  DBUG_EXECUTE_IF("getaddrinfo_error_again",
677  {
678  if (free_addr_info_list)
679  freeaddrinfo(addr_info_list);
680 
681  addr_info_list= NULL;
682  err_code= EAI_AGAIN;
683  free_addr_info_list= false;
684  }
685  );
686 
687  DBUG_EXECUTE_IF("getaddrinfo_fake_bad_ipv4",
688  {
689  if (free_addr_info_list)
690  freeaddrinfo(addr_info_list);
691 
692  struct sockaddr_in *debug_addr;
693  /*
694  Not thread safe, which is ok.
695  Only one connection at a time is tested with
696  fault injection.
697  */
698  static struct sockaddr_in debug_sock_addr[2];
699  static struct addrinfo debug_addr_info[2];
700  /* Simulating ipv4 192.0.2.126 */
701  debug_addr= & debug_sock_addr[0];
702  debug_addr->sin_family= AF_INET;
703  debug_addr->sin_addr.s_addr= inet_addr("192.0.2.126");
704 
705  /* Simulating ipv4 192.0.2.127 */
706  debug_addr= & debug_sock_addr[1];
707  debug_addr->sin_family= AF_INET;
708  debug_addr->sin_addr.s_addr= inet_addr("192.0.2.127");
709 
710  debug_addr_info[0].ai_addr= (struct sockaddr*) & debug_sock_addr[0];
711  debug_addr_info[0].ai_addrlen= sizeof (struct sockaddr_in);
712  debug_addr_info[0].ai_next= & debug_addr_info[1];
713 
714  debug_addr_info[1].ai_addr= (struct sockaddr*) & debug_sock_addr[1];
715  debug_addr_info[1].ai_addrlen= sizeof (struct sockaddr_in);
716  debug_addr_info[1].ai_next= NULL;
717 
718  addr_info_list= & debug_addr_info[0];
719  err_code= 0;
720  free_addr_info_list= false;
721  }
722  );
723 
724  DBUG_EXECUTE_IF("getaddrinfo_fake_good_ipv4",
725  {
726  if (free_addr_info_list)
727  freeaddrinfo(addr_info_list);
728 
729  struct sockaddr_in *debug_addr;
730  static struct sockaddr_in debug_sock_addr[2];
731  static struct addrinfo debug_addr_info[2];
732  /* Simulating ipv4 192.0.2.5 */
733  debug_addr= & debug_sock_addr[0];
734  debug_addr->sin_family= AF_INET;
735  debug_addr->sin_addr.s_addr= inet_addr("192.0.2.5");
736 
737  /* Simulating ipv4 192.0.2.4 */
738  debug_addr= & debug_sock_addr[1];
739  debug_addr->sin_family= AF_INET;
740  debug_addr->sin_addr.s_addr= inet_addr("192.0.2.4");
741 
742  debug_addr_info[0].ai_addr= (struct sockaddr*) & debug_sock_addr[0];
743  debug_addr_info[0].ai_addrlen= sizeof (struct sockaddr_in);
744  debug_addr_info[0].ai_next= & debug_addr_info[1];
745 
746  debug_addr_info[1].ai_addr= (struct sockaddr*) & debug_sock_addr[1];
747  debug_addr_info[1].ai_addrlen= sizeof (struct sockaddr_in);
748  debug_addr_info[1].ai_next= NULL;
749 
750  addr_info_list= & debug_addr_info[0];
751  err_code= 0;
752  free_addr_info_list= false;
753  }
754  );
755 
756 #ifdef HAVE_IPV6
757  DBUG_EXECUTE_IF("getaddrinfo_fake_bad_ipv6",
758  {
759  if (free_addr_info_list)
760  freeaddrinfo(addr_info_list);
761 
762  struct sockaddr_in6 *debug_addr;
763  struct in6_addr *ip6;
764  /*
765  Not thread safe, which is ok.
766  Only one connection at a time is tested with
767  fault injection.
768  */
769  static struct sockaddr_in6 debug_sock_addr[2];
770  static struct addrinfo debug_addr_info[2];
771  /* Simulating ipv6 2001:DB8::6:7E */
772  debug_addr= & debug_sock_addr[0];
773  debug_addr->sin6_family= AF_INET6;
774  ip6= & debug_addr->sin6_addr;
775  /* inet_pton not available on Windows XP. */
776  ip6->s6_addr[ 0] = 0x20;
777  ip6->s6_addr[ 1] = 0x01;
778  ip6->s6_addr[ 2] = 0x0d;
779  ip6->s6_addr[ 3] = 0xb8;
780  ip6->s6_addr[ 4] = 0x00;
781  ip6->s6_addr[ 5] = 0x00;
782  ip6->s6_addr[ 6] = 0x00;
783  ip6->s6_addr[ 7] = 0x00;
784  ip6->s6_addr[ 8] = 0x00;
785  ip6->s6_addr[ 9] = 0x00;
786  ip6->s6_addr[10] = 0x00;
787  ip6->s6_addr[11] = 0x00;
788  ip6->s6_addr[12] = 0x00;
789  ip6->s6_addr[13] = 0x06;
790  ip6->s6_addr[14] = 0x00;
791  ip6->s6_addr[15] = 0x7e;
792 
793  /* Simulating ipv6 2001:DB8::6:7F */
794  debug_addr= & debug_sock_addr[1];
795  debug_addr->sin6_family= AF_INET6;
796  ip6= & debug_addr->sin6_addr;
797  ip6->s6_addr[ 0] = 0x20;
798  ip6->s6_addr[ 1] = 0x01;
799  ip6->s6_addr[ 2] = 0x0d;
800  ip6->s6_addr[ 3] = 0xb8;
801  ip6->s6_addr[ 4] = 0x00;
802  ip6->s6_addr[ 5] = 0x00;
803  ip6->s6_addr[ 6] = 0x00;
804  ip6->s6_addr[ 7] = 0x00;
805  ip6->s6_addr[ 8] = 0x00;
806  ip6->s6_addr[ 9] = 0x00;
807  ip6->s6_addr[10] = 0x00;
808  ip6->s6_addr[11] = 0x00;
809  ip6->s6_addr[12] = 0x00;
810  ip6->s6_addr[13] = 0x06;
811  ip6->s6_addr[14] = 0x00;
812  ip6->s6_addr[15] = 0x7f;
813 
814  debug_addr_info[0].ai_addr= (struct sockaddr*) & debug_sock_addr[0];
815  debug_addr_info[0].ai_addrlen= sizeof (struct sockaddr_in6);
816  debug_addr_info[0].ai_next= & debug_addr_info[1];
817 
818  debug_addr_info[1].ai_addr= (struct sockaddr*) & debug_sock_addr[1];
819  debug_addr_info[1].ai_addrlen= sizeof (struct sockaddr_in6);
820  debug_addr_info[1].ai_next= NULL;
821 
822  addr_info_list= & debug_addr_info[0];
823  err_code= 0;
824  free_addr_info_list= false;
825  }
826  );
827 
828  DBUG_EXECUTE_IF("getaddrinfo_fake_good_ipv6",
829  {
830  if (free_addr_info_list)
831  freeaddrinfo(addr_info_list);
832 
833  struct sockaddr_in6 *debug_addr;
834  struct in6_addr *ip6;
835  /*
836  Not thread safe, which is ok.
837  Only one connection at a time is tested with
838  fault injection.
839  */
840  static struct sockaddr_in6 debug_sock_addr[2];
841  static struct addrinfo debug_addr_info[2];
842  /* Simulating ipv6 2001:DB8::6:7 */
843  debug_addr= & debug_sock_addr[0];
844  debug_addr->sin6_family= AF_INET6;
845  ip6= & debug_addr->sin6_addr;
846  ip6->s6_addr[ 0] = 0x20;
847  ip6->s6_addr[ 1] = 0x01;
848  ip6->s6_addr[ 2] = 0x0d;
849  ip6->s6_addr[ 3] = 0xb8;
850  ip6->s6_addr[ 4] = 0x00;
851  ip6->s6_addr[ 5] = 0x00;
852  ip6->s6_addr[ 6] = 0x00;
853  ip6->s6_addr[ 7] = 0x00;
854  ip6->s6_addr[ 8] = 0x00;
855  ip6->s6_addr[ 9] = 0x00;
856  ip6->s6_addr[10] = 0x00;
857  ip6->s6_addr[11] = 0x00;
858  ip6->s6_addr[12] = 0x00;
859  ip6->s6_addr[13] = 0x06;
860  ip6->s6_addr[14] = 0x00;
861  ip6->s6_addr[15] = 0x07;
862 
863  /* Simulating ipv6 2001:DB8::6:6 */
864  debug_addr= & debug_sock_addr[1];
865  debug_addr->sin6_family= AF_INET6;
866  ip6= & debug_addr->sin6_addr;
867  ip6->s6_addr[ 0] = 0x20;
868  ip6->s6_addr[ 1] = 0x01;
869  ip6->s6_addr[ 2] = 0x0d;
870  ip6->s6_addr[ 3] = 0xb8;
871  ip6->s6_addr[ 4] = 0x00;
872  ip6->s6_addr[ 5] = 0x00;
873  ip6->s6_addr[ 6] = 0x00;
874  ip6->s6_addr[ 7] = 0x00;
875  ip6->s6_addr[ 8] = 0x00;
876  ip6->s6_addr[ 9] = 0x00;
877  ip6->s6_addr[10] = 0x00;
878  ip6->s6_addr[11] = 0x00;
879  ip6->s6_addr[12] = 0x00;
880  ip6->s6_addr[13] = 0x06;
881  ip6->s6_addr[14] = 0x00;
882  ip6->s6_addr[15] = 0x06;
883 
884  debug_addr_info[0].ai_addr= (struct sockaddr*) & debug_sock_addr[0];
885  debug_addr_info[0].ai_addrlen= sizeof (struct sockaddr_in6);
886  debug_addr_info[0].ai_next= & debug_addr_info[1];
887 
888  debug_addr_info[1].ai_addr= (struct sockaddr*) & debug_sock_addr[1];
889  debug_addr_info[1].ai_addrlen= sizeof (struct sockaddr_in6);
890  debug_addr_info[1].ai_next= NULL;
891 
892  addr_info_list= & debug_addr_info[0];
893  err_code= 0;
894  free_addr_info_list= false;
895  }
896  );
897 #endif /* HAVE_IPV6 */
898 
899  /*
900  ===========================================================================
901  DEBUG code only (end)
902  ===========================================================================
903  */
904 
905  if (err_code != 0)
906  {
907  sql_print_warning("Host name '%s' could not be resolved: %s",
908  (const char *) hostname_buffer,
909  (const char *) gai_strerror(err_code));
910 
911  bool validated;
912 
913  if (err_code == EAI_NONAME)
914  {
915  errors.m_addrinfo_permanent= 1;
916  validated= true;
917  }
918  else
919  {
920  /*
921  Don't cache responses when the DNS server is down, as otherwise
922  transient DNS failure may leave any number of clients (those
923  that attempted to connect during the outage) unable to connect
924  indefinitely.
925  Only cache error statistics.
926  */
927  errors.m_addrinfo_transient= 1;
928  validated= false;
929  }
930  add_hostname(ip_key, NULL, validated, &errors);
931 
932  DBUG_RETURN(false);
933  }
934 
935  /* Check that getaddrinfo() returned the used IP (FCrDNS technique). */
936 
937  DBUG_PRINT("info", ("The following IP addresses found for '%s':",
938  (const char *) hostname_buffer));
939 
940  for (struct addrinfo *addr_info= addr_info_list;
941  addr_info; addr_info= addr_info->ai_next)
942  {
943  char ip_buffer[HOST_ENTRY_KEY_SIZE];
944 
945  {
946  err_status=
947  vio_get_normalized_ip_string(addr_info->ai_addr, addr_info->ai_addrlen,
948  ip_buffer, sizeof (ip_buffer));
949  DBUG_ASSERT(!err_status);
950  }
951 
952  DBUG_PRINT("info", (" - '%s'", (const char *) ip_buffer));
953 
954  if (strcasecmp(ip_key, ip_buffer) == 0)
955  {
956  /* Copy host name string to be stored in the cache. */
957 
958  *hostname= my_strdup(hostname_buffer, MYF(0));
959 
960  if (!*hostname)
961  {
962  DBUG_PRINT("error", ("Out of memory."));
963 
964  if (free_addr_info_list)
965  freeaddrinfo(addr_info_list);
966  DBUG_RETURN(true);
967  }
968 
969  break;
970  }
971  }
972 
973  /* Log resolved IP-addresses if no match was found. */
974 
975  if (!*hostname)
976  {
977  errors.m_FCrDNS= 1;
978 
979  sql_print_warning("Hostname '%s' does not resolve to '%s'.",
980  (const char *) hostname_buffer,
981  (const char *) ip_key);
982  sql_print_information("Hostname '%s' has the following IP addresses:",
983  (const char *) hostname_buffer);
984 
985  for (struct addrinfo *addr_info= addr_info_list;
986  addr_info; addr_info= addr_info->ai_next)
987  {
988  char ip_buffer[HOST_ENTRY_KEY_SIZE];
989 
990  err_status=
991  vio_get_normalized_ip_string(addr_info->ai_addr, addr_info->ai_addrlen,
992  ip_buffer, sizeof (ip_buffer));
993  DBUG_ASSERT(!err_status);
994 
995  sql_print_information(" - %s", (const char *) ip_buffer);
996  }
997  }
998 
999  /* Add an entry for the IP to the cache. */
1000  add_hostname(ip_key, *hostname, true, &errors);
1001 
1002  /* Free the result of getaddrinfo(). */
1003  if (free_addr_info_list)
1004  freeaddrinfo(addr_info_list);
1005 
1006  DBUG_RETURN(false);
1007 }