1 /* Copyright (c) 2000, 2021, Oracle and/or its affiliates.
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, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software Foundation,
21 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22
23
24 /**
25 @file
26
27 @brief
28 Get hostname for an IP address.
29
30 Hostnames are checked with reverse name lookup and checked that they
31 doesn't resemble an IP address.
32 */
33
34 #include "my_global.h"
35 #include "hostname.h"
36 #include "hash_filo.h"
37 #include <m_ctype.h>
38 #include "log.h" // sql_print_warning,
39 // sql_print_information
40 #include "violite.h" // vio_getnameinfo,
41 // vio_get_normalized_ip_string
42
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
45 #endif
46 #ifdef HAVE_SYS_UN_H
47 #include <sys/un.h>
48 #endif
49 #if !defined(_WIN32)
50 #include <sys/utsname.h>
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 *hostname_cache;
131
hostname_cache_refresh()132 void hostname_cache_refresh()
133 {
134 hostname_cache->clear();
135 }
136
hostname_cache_size()137 uint hostname_cache_size()
138 {
139 return hostname_cache->size();
140 }
141
hostname_cache_resize(uint size)142 void hostname_cache_resize(uint size)
143 {
144 hostname_cache->resize(size);
145 }
146
hostname_cache_init(uint size)147 bool hostname_cache_init(uint size)
148 {
149 Host_entry tmp;
150 uint key_offset= (uint) ((char*) (&tmp.ip_key) - (char*) &tmp);
151
152 if (!(hostname_cache= new hash_filo(key_memory_host_cache_hostname,
153 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
hostname_cache_free()164 void hostname_cache_free()
165 {
166 delete hostname_cache;
167 hostname_cache= NULL;
168 }
169
hostname_cache_lock()170 void hostname_cache_lock()
171 {
172 mysql_mutex_lock(&hostname_cache->lock);
173 }
174
hostname_cache_unlock()175 void hostname_cache_unlock()
176 {
177 mysql_mutex_unlock(&hostname_cache->lock);
178 }
179
prepare_hostname_cache_key(const char * ip_string,char * ip_key)180 static void prepare_hostname_cache_key(const char *ip_string,
181 char *ip_key)
182 {
183 size_t ip_string_length= strlen(ip_string);
184 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
hostname_cache_first()190 Host_entry *hostname_cache_first()
191 { return (Host_entry *) hostname_cache->first(); }
192
hostname_cache_search(const char * ip_key)193 static inline Host_entry *hostname_cache_search(const char *ip_key)
194 {
195 return (Host_entry *) hostname_cache->search((uchar *) ip_key, 0);
196 }
197
add_hostname_impl(const char * ip_key,const char * hostname,bool validated,Host_errors * errors,ulonglong now)198 static 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= static_cast<uint>(len);
238
239 DBUG_PRINT("info",
240 ("Adding/Updating '%s' -> '%s' (validated) to the hostname cache...'",
241 ip_key,
242 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 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 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
add_hostname(const char * ip_key,const char * hostname,bool validated,Host_errors * errors)280 static 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_micro_time();
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
inc_host_errors(const char * ip_string,Host_errors * errors)297 void inc_host_errors(const char *ip_string, Host_errors *errors)
298 {
299 if (!ip_string)
300 return;
301
302 ulonglong now= my_micro_time();
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
324
reset_host_connect_errors(const char * ip_string)325 void reset_host_connect_errors(const char *ip_string)
326 {
327 if (!ip_string)
328 return;
329
330 char ip_key[HOST_ENTRY_KEY_SIZE];
331 prepare_hostname_cache_key(ip_string, ip_key);
332
333 mysql_mutex_lock(&hostname_cache->lock);
334
335 Host_entry *entry= hostname_cache_search(ip_key);
336
337 if (entry)
338 entry->m_errors.clear_connect_errors();
339
340 mysql_mutex_unlock(&hostname_cache->lock);
341 }
342
343
is_ip_loopback(const struct sockaddr * ip)344 static inline bool is_ip_loopback(const struct sockaddr *ip)
345 {
346 switch (ip->sa_family) {
347 case AF_INET:
348 {
349 /* Check for IPv4 127.0.0.1. */
350 struct in_addr *ip4= &((struct sockaddr_in *) ip)->sin_addr;
351 return ntohl(ip4->s_addr) == INADDR_LOOPBACK;
352 }
353
354 #ifdef HAVE_IPV6
355 case AF_INET6:
356 {
357 /* Check for IPv6 ::1. */
358 struct in6_addr *ip6= &((struct sockaddr_in6 *) ip)->sin6_addr;
359 return IN6_IS_ADDR_LOOPBACK(ip6);
360 }
361 #endif /* HAVE_IPV6 */
362
363 default:
364 return FALSE;
365 }
366 }
367
is_hostname_valid(const char * hostname)368 static inline bool is_hostname_valid(const char *hostname)
369 {
370 /*
371 A hostname is invalid if it starts with a number followed by a dot
372 (IPv4 address).
373 */
374
375 if (!my_isdigit(&my_charset_latin1, hostname[0]))
376 return TRUE;
377
378 const char *p= hostname + 1;
379
380 while (my_isdigit(&my_charset_latin1, *p))
381 ++p;
382
383 return *p != '.';
384 }
385
386 /**
387 Resolve IP-address to host name.
388
389 This function does the following things:
390 - resolves IP-address;
391 - employs Forward Confirmed Reverse DNS technique to validate IP-address;
392 - returns host name if IP-address is validated;
393 - set value to out-variable connect_errors -- this variable represents the
394 number of connection errors from the specified IP-address.
395 - update the host_cache statistics
396
397 NOTE: connect_errors are counted (are supported) only for the clients
398 where IP-address can be resolved and FCrDNS check is passed.
399
400 @param [in] ip_storage IP address (sockaddr). Must be set.
401 @param [in] ip_string IP address (string). Must be set.
402 @param [out] hostname
403 @param [out] connect_errors
404
405 @return Error status
406 @retval 0 Success
407 @retval RC_BLOCKED_HOST The host is blocked.
408
409 The function does not set/report MySQL server error in case of failure.
410 It's caller's responsibility to handle failures of this function
411 properly.
412 */
413
ip_to_hostname(struct sockaddr_storage * ip_storage,const char * ip_string,char ** hostname,uint * connect_errors)414 int ip_to_hostname(struct sockaddr_storage *ip_storage,
415 const char *ip_string,
416 char **hostname,
417 uint *connect_errors)
418 {
419 const struct sockaddr *ip= (const sockaddr *) ip_storage;
420 int err_code;
421 Host_errors errors;
422
423 DBUG_ENTER("ip_to_hostname");
424 DBUG_PRINT("info", ("IP address: '%s'; family: %d.",
425 ip_string,
426 (int) ip->sa_family));
427
428 /* Default output values, for most cases. */
429 *hostname= NULL;
430 *connect_errors= 0;
431
432 /* Check if we have loopback address (127.0.0.1 or ::1). */
433
434 if (is_ip_loopback(ip))
435 {
436 DBUG_PRINT("info", ("Loopback address detected."));
437
438 /* Do not count connect errors from localhost. */
439 *hostname= (char *) my_localhost;
440
441 DBUG_RETURN(0);
442 }
443
444 /* Prepare host name cache key. */
445
446 char ip_key[HOST_ENTRY_KEY_SIZE];
447 prepare_hostname_cache_key(ip_string, ip_key);
448
449 /* Check first if we have host name in the cache. */
450
451 if (!(specialflag & SPECIAL_NO_HOST_CACHE))
452 {
453 ulonglong now= my_micro_time();
454
455 mysql_mutex_lock(&hostname_cache->lock);
456
457 Host_entry *entry= hostname_cache_search(ip_key);
458
459 if (entry)
460 {
461 entry->m_last_seen= now;
462 *connect_errors= entry->m_errors.m_connect;
463
464 if (entry->m_errors.m_connect >= max_connect_errors)
465 {
466 entry->m_errors.m_host_blocked++;
467 entry->set_error_timestamps(now);
468 mysql_mutex_unlock(&hostname_cache->lock);
469 DBUG_RETURN(RC_BLOCKED_HOST);
470 }
471
472 /*
473 If there is an IP -> HOSTNAME association in the cache,
474 but for a hostname that was not validated,
475 do not return that hostname: perform the network validation again.
476 */
477 if (entry->m_host_validated)
478 {
479 if (entry->m_hostname_length)
480 *hostname= my_strdup(key_memory_host_cache_hostname,
481 entry->m_hostname, MYF(0));
482
483 DBUG_PRINT("info",("IP (%s) has been found in the cache. "
484 "Hostname: '%s'",
485 ip_key,
486 (*hostname? *hostname : "null")
487 ));
488
489 mysql_mutex_unlock(&hostname_cache->lock);
490
491 DBUG_RETURN(0);
492 }
493 }
494
495 mysql_mutex_unlock(&hostname_cache->lock);
496 }
497
498 /*
499 Resolve host name. Return an error if a host name can not be resolved
500 (instead of returning the numeric form of the host name).
501 */
502
503 char hostname_buffer[NI_MAXHOST];
504
505 DBUG_PRINT("info", ("Resolving '%s'...", (const char *) ip_key));
506
507 err_code= vio_getnameinfo(ip, hostname_buffer, NI_MAXHOST, NULL, 0,
508 NI_NAMEREQD);
509
510 /*
511 ===========================================================================
512 DEBUG code only (begin)
513 Simulate various output from vio_getnameinfo().
514 ===========================================================================
515 */
516
517 DBUG_EXECUTE_IF("getnameinfo_error_noname",
518 {
519 strcpy(hostname_buffer, "<garbage>");
520 err_code= EAI_NONAME;
521 }
522 );
523
524 DBUG_EXECUTE_IF("getnameinfo_error_again",
525 {
526 strcpy(hostname_buffer, "<garbage>");
527 err_code= EAI_AGAIN;
528 }
529 );
530
531 DBUG_EXECUTE_IF("getnameinfo_fake_ipv4",
532 {
533 strcpy(hostname_buffer, "santa.claus.ipv4.example.com");
534 err_code= 0;
535 }
536 );
537
538 DBUG_EXECUTE_IF("getnameinfo_fake_ipv6",
539 {
540 strcpy(hostname_buffer, "santa.claus.ipv6.example.com");
541 err_code= 0;
542 }
543 );
544
545 DBUG_EXECUTE_IF("getnameinfo_format_ipv4",
546 {
547 strcpy(hostname_buffer, "12.12.12.12");
548 err_code= 0;
549 }
550 );
551
552 DBUG_EXECUTE_IF("getnameinfo_format_ipv6",
553 {
554 strcpy(hostname_buffer, "12:DEAD:BEEF:0");
555 err_code= 0;
556 }
557 );
558
559
560 DBUG_EXECUTE_IF ("getnameinfo_fake_max_length",
561 {
562 std::string s(NI_MAXHOST-1, 'a');
563 strcpy(hostname_buffer, s.c_str());
564 err_code= 0;
565 }
566 );
567
568 /*
569 ===========================================================================
570 DEBUG code only (end)
571 ===========================================================================
572 */
573
574 if (err_code)
575 {
576 // NOTE: gai_strerror() returns a string ending by a dot.
577
578 DBUG_PRINT("error", ("IP address '%s' could not be resolved: %s",
579 ip_key,
580 gai_strerror(err_code)));
581
582 sql_print_warning("IP address '%s' could not be resolved: %s",
583 ip_key,
584 gai_strerror(err_code));
585
586 bool validated;
587 if (vio_is_no_name_error(err_code))
588 {
589 /*
590 The no-name error means that there is no reverse address mapping
591 for the IP address. A host name can not be resolved.
592 */
593 errors.m_nameinfo_permanent= 1;
594 validated= true;
595 }
596 else
597 {
598 /*
599 If it is not the no-name error, we should not cache the hostname
600 (or rather its absence), because the failure might be transient.
601 Only the ip error statistics are cached.
602 */
603 errors.m_nameinfo_transient= 1;
604 validated= false;
605 }
606 add_hostname(ip_key, NULL, validated, &errors);
607
608 DBUG_RETURN(0);
609 }
610
611 DBUG_PRINT("info", ("IP '%s' resolved to '%s'.",
612 (const char *) ip_key,
613 (const char *) hostname_buffer));
614
615 /*
616 Validate hostname: the server does not accept host names, which
617 resemble IP addresses.
618
619 The thing is that theoretically, a host name can be in a form of IPv4
620 address (123.example.org, or 1.2 or even 1.2.3.4). We have to deny such
621 host names because ACL-systems is not designed to work with them.
622
623 For example, it is possible to specify a host name mask (like
624 192.168.1.%) for an ACL rule. Then, if IPv4-like hostnames are allowed,
625 there is a security hole: instead of allowing access for
626 192.168.1.0/255 network (which was assumed by the user), the access
627 will be allowed for host names like 192.168.1.example.org.
628 */
629
630 if (!is_hostname_valid(hostname_buffer))
631 {
632 DBUG_PRINT("error", ("IP address '%s' has been resolved "
633 "to the host name '%s', which resembles "
634 "IPv4-address itself.",
635 ip_key,
636 hostname_buffer));
637
638 sql_print_warning("IP address '%s' has been resolved "
639 "to the host name '%s', which resembles "
640 "IPv4-address itself.",
641 ip_key,
642 hostname_buffer);
643
644 errors.m_format= 1;
645 add_hostname(ip_key, hostname_buffer, false, &errors);
646
647 DBUG_RETURN(false);
648 }
649
650 /* Get IP-addresses for the resolved host name (FCrDNS technique). */
651
652 struct addrinfo hints;
653 struct addrinfo *addr_info_list;
654 /*
655 Makes fault injection with DBUG_EXECUTE_IF easier.
656 Invoking free_addr_info(NULL) crashes on some platforms.
657 */
658 bool free_addr_info_list= false;
659
660 memset(&hints, 0, sizeof (struct addrinfo));
661 hints.ai_flags= AI_PASSIVE;
662 hints.ai_socktype= SOCK_STREAM;
663 hints.ai_family= AF_UNSPEC;
664
665 DBUG_PRINT("info", ("Getting IP addresses for hostname '%s'...",
666 hostname_buffer));
667
668 err_code= getaddrinfo(hostname_buffer, NULL, &hints, &addr_info_list);
669 if (err_code == 0)
670 free_addr_info_list= true;
671
672 /*
673 ===========================================================================
674 DEBUG code only (begin)
675 Simulate various output from getaddrinfo().
676 ===========================================================================
677 */
678 DBUG_EXECUTE_IF("getaddrinfo_error_noname",
679 {
680 if (free_addr_info_list)
681 freeaddrinfo(addr_info_list);
682
683 addr_info_list= NULL;
684 err_code= EAI_NONAME;
685 free_addr_info_list= false;
686 }
687 );
688
689 DBUG_EXECUTE_IF("getaddrinfo_error_again",
690 {
691 if (free_addr_info_list)
692 freeaddrinfo(addr_info_list);
693
694 addr_info_list= NULL;
695 err_code= EAI_AGAIN;
696 free_addr_info_list= false;
697 }
698 );
699
700 DBUG_EXECUTE_IF("getaddrinfo_fake_bad_ipv4",
701 {
702 if (free_addr_info_list)
703 freeaddrinfo(addr_info_list);
704
705 struct sockaddr_in *debug_addr;
706 /*
707 Not thread safe, which is ok.
708 Only one connection at a time is tested with
709 fault injection.
710 */
711 static struct sockaddr_in debug_sock_addr[2];
712 static struct addrinfo debug_addr_info[2];
713 /* Simulating ipv4 192.0.2.126 */
714 debug_addr= & debug_sock_addr[0];
715 debug_addr->sin_family= AF_INET;
716 debug_addr->sin_addr.s_addr= inet_addr("192.0.2.126");
717
718 /* Simulating ipv4 192.0.2.127 */
719 debug_addr= & debug_sock_addr[1];
720 debug_addr->sin_family= AF_INET;
721 debug_addr->sin_addr.s_addr= inet_addr("192.0.2.127");
722
723 debug_addr_info[0].ai_addr= (struct sockaddr*) & debug_sock_addr[0];
724 debug_addr_info[0].ai_addrlen= sizeof (struct sockaddr_in);
725 debug_addr_info[0].ai_next= & debug_addr_info[1];
726
727 debug_addr_info[1].ai_addr= (struct sockaddr*) & debug_sock_addr[1];
728 debug_addr_info[1].ai_addrlen= sizeof (struct sockaddr_in);
729 debug_addr_info[1].ai_next= NULL;
730
731 addr_info_list= & debug_addr_info[0];
732 err_code= 0;
733 free_addr_info_list= false;
734 }
735 );
736
737 DBUG_EXECUTE_IF("getaddrinfo_fake_good_ipv4",
738 {
739 if (free_addr_info_list)
740 freeaddrinfo(addr_info_list);
741
742 struct sockaddr_in *debug_addr;
743 static struct sockaddr_in debug_sock_addr[2];
744 static struct addrinfo debug_addr_info[2];
745 /* Simulating ipv4 192.0.2.5 */
746 debug_addr= & debug_sock_addr[0];
747 debug_addr->sin_family= AF_INET;
748 debug_addr->sin_addr.s_addr= inet_addr("192.0.2.5");
749
750 /* Simulating ipv4 192.0.2.4 */
751 debug_addr= & debug_sock_addr[1];
752 debug_addr->sin_family= AF_INET;
753 debug_addr->sin_addr.s_addr= inet_addr("192.0.2.4");
754
755 debug_addr_info[0].ai_addr= (struct sockaddr*) & debug_sock_addr[0];
756 debug_addr_info[0].ai_addrlen= sizeof (struct sockaddr_in);
757 debug_addr_info[0].ai_next= & debug_addr_info[1];
758
759 debug_addr_info[1].ai_addr= (struct sockaddr*) & debug_sock_addr[1];
760 debug_addr_info[1].ai_addrlen= sizeof (struct sockaddr_in);
761 debug_addr_info[1].ai_next= NULL;
762
763 addr_info_list= & debug_addr_info[0];
764 err_code= 0;
765 free_addr_info_list= false;
766 }
767 );
768
769 #ifdef HAVE_IPV6
770 DBUG_EXECUTE_IF("getaddrinfo_fake_bad_ipv6",
771 {
772 if (free_addr_info_list)
773 freeaddrinfo(addr_info_list);
774
775 struct sockaddr_in6 *debug_addr;
776 struct in6_addr *ip6;
777 /*
778 Not thread safe, which is ok.
779 Only one connection at a time is tested with
780 fault injection.
781 */
782 static struct sockaddr_in6 debug_sock_addr[2];
783 static struct addrinfo debug_addr_info[2];
784 /* Simulating ipv6 2001:DB8::6:7E */
785 debug_addr= & debug_sock_addr[0];
786 debug_addr->sin6_family= AF_INET6;
787 ip6= & debug_addr->sin6_addr;
788 /* inet_pton not available on Windows XP. */
789 ip6->s6_addr[ 0] = 0x20;
790 ip6->s6_addr[ 1] = 0x01;
791 ip6->s6_addr[ 2] = 0x0d;
792 ip6->s6_addr[ 3] = 0xb8;
793 ip6->s6_addr[ 4] = 0x00;
794 ip6->s6_addr[ 5] = 0x00;
795 ip6->s6_addr[ 6] = 0x00;
796 ip6->s6_addr[ 7] = 0x00;
797 ip6->s6_addr[ 8] = 0x00;
798 ip6->s6_addr[ 9] = 0x00;
799 ip6->s6_addr[10] = 0x00;
800 ip6->s6_addr[11] = 0x00;
801 ip6->s6_addr[12] = 0x00;
802 ip6->s6_addr[13] = 0x06;
803 ip6->s6_addr[14] = 0x00;
804 ip6->s6_addr[15] = 0x7e;
805
806 /* Simulating ipv6 2001:DB8::6:7F */
807 debug_addr= & debug_sock_addr[1];
808 debug_addr->sin6_family= AF_INET6;
809 ip6= & debug_addr->sin6_addr;
810 ip6->s6_addr[ 0] = 0x20;
811 ip6->s6_addr[ 1] = 0x01;
812 ip6->s6_addr[ 2] = 0x0d;
813 ip6->s6_addr[ 3] = 0xb8;
814 ip6->s6_addr[ 4] = 0x00;
815 ip6->s6_addr[ 5] = 0x00;
816 ip6->s6_addr[ 6] = 0x00;
817 ip6->s6_addr[ 7] = 0x00;
818 ip6->s6_addr[ 8] = 0x00;
819 ip6->s6_addr[ 9] = 0x00;
820 ip6->s6_addr[10] = 0x00;
821 ip6->s6_addr[11] = 0x00;
822 ip6->s6_addr[12] = 0x00;
823 ip6->s6_addr[13] = 0x06;
824 ip6->s6_addr[14] = 0x00;
825 ip6->s6_addr[15] = 0x7f;
826
827 debug_addr_info[0].ai_addr= (struct sockaddr*) & debug_sock_addr[0];
828 debug_addr_info[0].ai_addrlen= sizeof (struct sockaddr_in6);
829 debug_addr_info[0].ai_next= & debug_addr_info[1];
830
831 debug_addr_info[1].ai_addr= (struct sockaddr*) & debug_sock_addr[1];
832 debug_addr_info[1].ai_addrlen= sizeof (struct sockaddr_in6);
833 debug_addr_info[1].ai_next= NULL;
834
835 addr_info_list= & debug_addr_info[0];
836 err_code= 0;
837 free_addr_info_list= false;
838 }
839 );
840
841 DBUG_EXECUTE_IF("getaddrinfo_fake_good_ipv6",
842 {
843 if (free_addr_info_list)
844 freeaddrinfo(addr_info_list);
845
846 struct sockaddr_in6 *debug_addr;
847 struct in6_addr *ip6;
848 /*
849 Not thread safe, which is ok.
850 Only one connection at a time is tested with
851 fault injection.
852 */
853 static struct sockaddr_in6 debug_sock_addr[2];
854 static struct addrinfo debug_addr_info[2];
855 /* Simulating ipv6 2001:DB8::6:7 */
856 debug_addr= & debug_sock_addr[0];
857 debug_addr->sin6_family= AF_INET6;
858 ip6= & debug_addr->sin6_addr;
859 ip6->s6_addr[ 0] = 0x20;
860 ip6->s6_addr[ 1] = 0x01;
861 ip6->s6_addr[ 2] = 0x0d;
862 ip6->s6_addr[ 3] = 0xb8;
863 ip6->s6_addr[ 4] = 0x00;
864 ip6->s6_addr[ 5] = 0x00;
865 ip6->s6_addr[ 6] = 0x00;
866 ip6->s6_addr[ 7] = 0x00;
867 ip6->s6_addr[ 8] = 0x00;
868 ip6->s6_addr[ 9] = 0x00;
869 ip6->s6_addr[10] = 0x00;
870 ip6->s6_addr[11] = 0x00;
871 ip6->s6_addr[12] = 0x00;
872 ip6->s6_addr[13] = 0x06;
873 ip6->s6_addr[14] = 0x00;
874 ip6->s6_addr[15] = 0x07;
875
876 /* Simulating ipv6 2001:DB8::6:6 */
877 debug_addr= & debug_sock_addr[1];
878 debug_addr->sin6_family= AF_INET6;
879 ip6= & debug_addr->sin6_addr;
880 ip6->s6_addr[ 0] = 0x20;
881 ip6->s6_addr[ 1] = 0x01;
882 ip6->s6_addr[ 2] = 0x0d;
883 ip6->s6_addr[ 3] = 0xb8;
884 ip6->s6_addr[ 4] = 0x00;
885 ip6->s6_addr[ 5] = 0x00;
886 ip6->s6_addr[ 6] = 0x00;
887 ip6->s6_addr[ 7] = 0x00;
888 ip6->s6_addr[ 8] = 0x00;
889 ip6->s6_addr[ 9] = 0x00;
890 ip6->s6_addr[10] = 0x00;
891 ip6->s6_addr[11] = 0x00;
892 ip6->s6_addr[12] = 0x00;
893 ip6->s6_addr[13] = 0x06;
894 ip6->s6_addr[14] = 0x00;
895 ip6->s6_addr[15] = 0x06;
896
897 debug_addr_info[0].ai_addr= (struct sockaddr*) & debug_sock_addr[0];
898 debug_addr_info[0].ai_addrlen= sizeof (struct sockaddr_in6);
899 debug_addr_info[0].ai_next= & debug_addr_info[1];
900
901 debug_addr_info[1].ai_addr= (struct sockaddr*) & debug_sock_addr[1];
902 debug_addr_info[1].ai_addrlen= sizeof (struct sockaddr_in6);
903 debug_addr_info[1].ai_next= NULL;
904
905 addr_info_list= & debug_addr_info[0];
906 err_code= 0;
907 free_addr_info_list= false;
908 }
909 );
910 #endif /* HAVE_IPV6 */
911
912 /*
913 ===========================================================================
914 DEBUG code only (end)
915 ===========================================================================
916 */
917
918 if (err_code != 0)
919 {
920 sql_print_warning("Host name '%s' could not be resolved: %s",
921 hostname_buffer,
922 gai_strerror(err_code));
923
924 bool validated;
925
926 if (err_code == EAI_NONAME)
927 {
928 errors.m_addrinfo_permanent= 1;
929 validated= true;
930 }
931 else
932 {
933 /*
934 Don't cache responses when the DNS server is down, as otherwise
935 transient DNS failure may leave any number of clients (those
936 that attempted to connect during the outage) unable to connect
937 indefinitely.
938 Only cache error statistics.
939 */
940 errors.m_addrinfo_transient= 1;
941 validated= false;
942 }
943 add_hostname(ip_key, NULL, validated, &errors);
944
945 DBUG_RETURN(false);
946 }
947
948 /* Check that getaddrinfo() returned the used IP (FCrDNS technique). */
949
950 DBUG_PRINT("info", ("The following IP addresses found for '%s':",
951 hostname_buffer));
952
953 for (struct addrinfo *addr_info= addr_info_list;
954 addr_info; addr_info= addr_info->ai_next)
955 {
956 char ip_buffer[HOST_ENTRY_KEY_SIZE];
957
958 {
959 bool err_status MY_ATTRIBUTE((unused));
960 err_status=
961 vio_get_normalized_ip_string(addr_info->ai_addr, addr_info->ai_addrlen,
962 ip_buffer, sizeof (ip_buffer));
963 assert(!err_status);
964 }
965
966 DBUG_PRINT("info", (" - '%s'", ip_buffer));
967
968 if (native_strcasecmp(ip_key, ip_buffer) == 0)
969 {
970 /* Copy host name string to be stored in the cache. */
971
972 *hostname= my_strdup(key_memory_host_cache_hostname,
973 hostname_buffer, MYF(0));
974
975 if (!*hostname)
976 {
977 DBUG_PRINT("error", ("Out of memory."));
978
979 if (free_addr_info_list)
980 freeaddrinfo(addr_info_list);
981 DBUG_RETURN(true);
982 }
983
984 break;
985 }
986 }
987
988 /* Log resolved IP-addresses if no match was found. */
989
990 if (!*hostname)
991 {
992 errors.m_FCrDNS= 1;
993
994 sql_print_warning("Hostname '%s' does not resolve to '%s'.",
995 hostname_buffer,
996 ip_key);
997 sql_print_information("Hostname '%s' has the following IP addresses:",
998 hostname_buffer);
999
1000 for (struct addrinfo *addr_info= addr_info_list;
1001 addr_info; addr_info= addr_info->ai_next)
1002 {
1003 char ip_buffer[HOST_ENTRY_KEY_SIZE];
1004
1005 #ifndef NDEBUG
1006 bool err_status=
1007 #endif
1008 vio_get_normalized_ip_string(addr_info->ai_addr, addr_info->ai_addrlen,
1009 ip_buffer, sizeof (ip_buffer));
1010 assert(!err_status);
1011
1012 sql_print_information(" - %s", ip_buffer);
1013 }
1014 }
1015
1016 /* Add an entry for the IP to the cache. */
1017 add_hostname(ip_key, *hostname, true, &errors);
1018
1019 /* Free the result of getaddrinfo(). */
1020 if (free_addr_info_list)
1021 freeaddrinfo(addr_info_list);
1022
1023 DBUG_RETURN(false);
1024 }
1025