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