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-1335 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
41 extern "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
Host_errors()53 Host_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
~Host_errors()77 Host_errors::~Host_errors()
78 {}
79
reset()80 void 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
aggregate(const Host_errors * errors)105 void 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
130 static Hash_filo<Host_entry> *hostname_cache;
131 ulong host_cache_size;
132
hostname_cache_refresh()133 void hostname_cache_refresh()
134 {
135 hostname_cache->clear();
136 }
137
hostname_cache_size()138 uint hostname_cache_size()
139 {
140 return hostname_cache->size();
141 }
142
hostname_cache_resize(uint size)143 void hostname_cache_resize(uint size)
144 {
145 hostname_cache->resize(size);
146 }
147
hostname_cache_init()148 bool 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>(key_memory_host_cache_hostname,
154 host_cache_size, key_offset, HOST_ENTRY_KEY_SIZE,
155 NULL, (my_hash_free_key) free, &my_charset_bin)))
156 return 1;
157
158 hostname_cache->clear();
159
160 return 0;
161 }
162
hostname_cache_free()163 void hostname_cache_free()
164 {
165 delete hostname_cache;
166 hostname_cache= NULL;
167 }
168
hostname_cache_lock()169 void hostname_cache_lock()
170 {
171 mysql_mutex_lock(&hostname_cache->lock);
172 }
173
hostname_cache_unlock()174 void hostname_cache_unlock()
175 {
176 mysql_mutex_unlock(&hostname_cache->lock);
177 }
178
prepare_hostname_cache_key(const char * ip_string,char * ip_key)179 static void prepare_hostname_cache_key(const char *ip_string,
180 char *ip_key)
181 {
182 size_t ip_string_length= strlen(ip_string);
183 DBUG_ASSERT(ip_string_length < HOST_ENTRY_KEY_SIZE);
184
185 memset(ip_key, 0, HOST_ENTRY_KEY_SIZE);
186 memcpy(ip_key, ip_string, ip_string_length);
187 }
188
hostname_cache_first()189 Host_entry *hostname_cache_first()
190 { return hostname_cache->first(); }
191
hostname_cache_search(const char * ip_key)192 static inline Host_entry *hostname_cache_search(const char *ip_key)
193 {
194 return hostname_cache->search((uchar *) ip_key, 0);
195 }
196
add_hostname_impl(const char * ip_key,const char * hostname,bool validated,Host_errors * errors,ulonglong now)197 static void add_hostname_impl(const char *ip_key, const char *hostname,
198 bool validated, Host_errors *errors,
199 ulonglong now)
200 {
201 Host_entry *entry;
202 bool need_add= false;
203
204 entry= hostname_cache_search(ip_key);
205
206 if (likely(entry == NULL))
207 {
208 entry= (Host_entry *) malloc(sizeof (Host_entry));
209 if (entry == NULL)
210 return;
211
212 need_add= true;
213 memcpy(&entry->ip_key, ip_key, HOST_ENTRY_KEY_SIZE);
214 entry->m_errors.reset();
215 entry->m_hostname_length= 0;
216 entry->m_host_validated= false;
217 entry->m_first_seen= now;
218 entry->m_last_seen= now;
219 entry->m_first_error_seen= 0;
220 entry->m_last_error_seen= 0;
221 }
222 else
223 {
224 entry->m_last_seen= now;
225 }
226
227 if (validated)
228 {
229 if (hostname != NULL)
230 {
231 size_t len= strlen(hostname);
232 if (len > sizeof(entry->m_hostname) - 1)
233 len= sizeof(entry->m_hostname) - 1;
234 memcpy(entry->m_hostname, hostname, len);
235 entry->m_hostname[len]= '\0';
236 entry->m_hostname_length= (uint)len;
237
238 DBUG_PRINT("info",
239 ("Adding/Updating '%s' -> '%s' (validated) to the hostname cache...'",
240 (const char *) ip_key,
241 (const char *) entry->m_hostname));
242 }
243 else
244 {
245 entry->m_hostname_length= 0;
246 DBUG_PRINT("info",
247 ("Adding/Updating '%s' -> NULL (validated) to the hostname cache...'",
248 (const char *) ip_key));
249 }
250 entry->m_host_validated= true;
251 /*
252 New errors that are considered 'blocking',
253 that will eventually cause the IP to be black listed and blocked.
254 */
255 errors->sum_connect_errors();
256 }
257 else
258 {
259 entry->m_hostname_length= 0;
260 entry->m_host_validated= false;
261 /* Do not count new blocking errors during DNS failures. */
262 errors->clear_connect_errors();
263 DBUG_PRINT("info",
264 ("Adding/Updating '%s' -> NULL (not validated) to the hostname cache...'",
265 (const char *) ip_key));
266 }
267
268 if (errors->has_error())
269 entry->set_error_timestamps(now);
270
271 entry->m_errors.aggregate(errors);
272
273 if (need_add)
274 hostname_cache->add(entry);
275
276 return;
277 }
278
add_hostname(const char * ip_key,const char * hostname,bool validated,Host_errors * errors)279 static void add_hostname(const char *ip_key, const char *hostname,
280 bool validated, Host_errors *errors)
281 {
282 if (specialflag & SPECIAL_NO_HOST_CACHE)
283 return;
284
285 ulonglong now= my_hrtime().val;
286
287 mysql_mutex_lock(&hostname_cache->lock);
288
289 add_hostname_impl(ip_key, hostname, validated, errors, now);
290
291 mysql_mutex_unlock(&hostname_cache->lock);
292
293 return;
294 }
295
inc_host_errors(const char * ip_string,Host_errors * errors)296 void inc_host_errors(const char *ip_string, Host_errors *errors)
297 {
298 if (!ip_string)
299 return;
300
301 ulonglong now= my_hrtime().val;
302 char ip_key[HOST_ENTRY_KEY_SIZE];
303 prepare_hostname_cache_key(ip_string, ip_key);
304
305 mysql_mutex_lock(&hostname_cache->lock);
306
307 Host_entry *entry= hostname_cache_search(ip_key);
308
309 if (entry)
310 {
311 if (entry->m_host_validated)
312 errors->sum_connect_errors();
313 else
314 errors->clear_connect_errors();
315
316 entry->m_errors.aggregate(errors);
317 entry->set_error_timestamps(now);
318 }
319
320 mysql_mutex_unlock(&hostname_cache->lock);
321 }
322
reset_host_connect_errors(const char * ip_string)323 void reset_host_connect_errors(const char *ip_string)
324 {
325 if (!ip_string)
326 return;
327
328 char ip_key[HOST_ENTRY_KEY_SIZE];
329 prepare_hostname_cache_key(ip_string, ip_key);
330
331 mysql_mutex_lock(&hostname_cache->lock);
332
333 Host_entry *entry= hostname_cache_search(ip_key);
334
335 if (entry)
336 entry->m_errors.clear_connect_errors();
337
338 mysql_mutex_unlock(&hostname_cache->lock);
339 }
340
is_ip_loopback(const struct sockaddr * ip)341 static inline bool is_ip_loopback(const struct sockaddr *ip)
342 {
343 switch (ip->sa_family) {
344 case AF_INET:
345 {
346 /* Check for IPv4 127.0.0.1. */
347 struct in_addr *ip4= &((struct sockaddr_in *) ip)->sin_addr;
348 return ntohl(ip4->s_addr) == INADDR_LOOPBACK;
349 }
350
351 #ifdef HAVE_IPV6
352 case AF_INET6:
353 {
354 /* Check for IPv6 ::1. */
355 struct in6_addr *ip6= &((struct sockaddr_in6 *) ip)->sin6_addr;
356 return IN6_IS_ADDR_LOOPBACK(ip6);
357 }
358 #endif /* HAVE_IPV6 */
359
360 default:
361 return FALSE;
362 }
363 }
364
is_hostname_valid(const char * hostname)365 static inline bool is_hostname_valid(const char *hostname)
366 {
367 /*
368 A hostname is invalid if it starts with a number followed by a dot
369 (IPv4 address).
370 */
371
372 if (!my_isdigit(&my_charset_latin1, hostname[0]))
373 return TRUE;
374
375 const char *p= hostname + 1;
376
377 while (my_isdigit(&my_charset_latin1, *p))
378 ++p;
379
380 return *p != '.';
381 }
382
383 /**
384 Resolve IP-address to host name.
385
386 This function does the following things:
387 - resolves IP-address;
388 - employs Forward Confirmed Reverse DNS technique to validate IP-address;
389 - returns host name if IP-address is validated;
390 - set value to out-variable connect_errors -- this variable represents the
391 number of connection errors from the specified IP-address.
392 - update the host_cache statistics
393
394 NOTE: connect_errors are counted (are supported) only for the clients
395 where IP-address can be resolved and FCrDNS check is passed.
396
397 @param [in] ip_storage IP address (sockaddr). Must be set.
398 @param [in] ip_string IP address (string). Must be set.
399 @param [out] hostname
400 @param [out] connect_errors
401
402 @return Error status
403 @retval 0 Success
404 @retval RC_BLOCKED_HOST The host is blocked.
405
406 The function does not set/report MySQL server error in case of failure.
407 It's caller's responsibility to handle failures of this function
408 properly.
409 */
410
ip_to_hostname(struct sockaddr_storage * ip_storage,const char * ip_string,const char ** hostname,uint * connect_errors)411 int ip_to_hostname(struct sockaddr_storage *ip_storage,
412 const char *ip_string,
413 const char **hostname,
414 uint *connect_errors)
415 {
416 const struct sockaddr *ip= (const sockaddr *) ip_storage;
417 int err_code;
418 bool err_status __attribute__((unused));
419 Host_errors errors;
420
421 DBUG_ENTER("ip_to_hostname");
422 DBUG_PRINT("info", ("IP address: '%s'; family: %d.",
423 (const char *) ip_string,
424 (int) ip->sa_family));
425
426 /* Default output values, for most cases. */
427 *hostname= NULL;
428 *connect_errors= 0;
429
430 /* Check if we have loopback address (127.0.0.1 or ::1). */
431
432 if (is_ip_loopback(ip))
433 {
434 DBUG_PRINT("info", ("Loopback address detected."));
435
436 /* Do not count connect errors from localhost. */
437 *hostname= my_localhost;
438
439 DBUG_RETURN(0);
440 }
441
442 /* Prepare host name cache key. */
443
444 char ip_key[HOST_ENTRY_KEY_SIZE];
445 prepare_hostname_cache_key(ip_string, ip_key);
446
447 /* Check first if we have host name in the cache. */
448
449 if (!(specialflag & SPECIAL_NO_HOST_CACHE))
450 {
451 ulonglong now= my_hrtime().val;
452
453 mysql_mutex_lock(&hostname_cache->lock);
454
455 Host_entry *entry= hostname_cache_search(ip_key);
456
457 if (entry)
458 {
459 entry->m_last_seen= now;
460 *connect_errors= entry->m_errors.m_connect;
461
462 if (unlikely(entry->m_errors.m_connect >= max_connect_errors))
463 {
464 entry->m_errors.m_host_blocked++;
465 entry->set_error_timestamps(now);
466 mysql_mutex_unlock(&hostname_cache->lock);
467 DBUG_RETURN(RC_BLOCKED_HOST);
468 }
469
470 /*
471 If there is an IP -> HOSTNAME association in the cache,
472 but for a hostname that was not validated,
473 do not return that hostname: perform the network validation again.
474 */
475 if (entry->m_host_validated)
476 {
477 if (entry->m_hostname_length)
478 *hostname= my_strdup(key_memory_host_cache_hostname,
479 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(key_memory_host_cache_hostname,
930 hostname_buffer, MYF(0));
931
932 if (!*hostname)
933 {
934 DBUG_PRINT("error", ("Out of memory."));
935
936 if (free_addr_info_list)
937 freeaddrinfo(addr_info_list);
938 DBUG_RETURN(true);
939 }
940
941 break;
942 }
943 }
944
945 /* Log resolved IP-addresses if no match was found. */
946
947 if (!*hostname)
948 {
949 errors.m_FCrDNS= 1;
950
951 sql_print_warning("Hostname '%s' does not resolve to '%s'.",
952 (const char *) hostname_buffer,
953 (const char *) ip_key);
954 sql_print_information("Hostname '%s' has the following IP addresses:",
955 (const char *) hostname_buffer);
956
957 for (struct addrinfo *addr_info= addr_info_list;
958 addr_info; addr_info= addr_info->ai_next)
959 {
960 char ip_buffer[HOST_ENTRY_KEY_SIZE];
961
962 err_status=
963 vio_get_normalized_ip_string(addr_info->ai_addr, (int)addr_info->ai_addrlen,
964 ip_buffer, sizeof (ip_buffer));
965 DBUG_ASSERT(!err_status);
966
967 sql_print_information(" - %s", (const char *) ip_buffer);
968 }
969 }
970
971 /* Add an entry for the IP to the cache. */
972 add_hostname(ip_key, *hostname, true, &errors);
973
974 /* Free the result of getaddrinfo(). */
975 if (free_addr_info_list)
976 freeaddrinfo(addr_info_list);
977
978 DBUG_RETURN(false);
979 }
980