]> sjero.net Git - wget/blob - src/host.c
[svn] Added reordering of addresses to try IPv4 first and the associated
[wget] / src / host.c
1 /* Host name resolution and matching.
2    Copyright (C) 1995, 1996, 1997, 2000, 2001 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10
11 GNU Wget is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables.  You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL".  If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so.  If you do not wish to do
28 so, delete this exception statement from your version.  */
29
30 #include <config.h>
31
32 #ifndef WINDOWS
33 #include <netdb.h>
34 #endif
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #ifdef HAVE_STRING_H
39 # include <string.h>
40 #else
41 # include <strings.h>
42 #endif
43 #include <assert.h>
44 #include <sys/types.h>
45
46 #ifndef WINDOWS
47 # include <sys/socket.h>
48 # include <netinet/in.h>
49 # ifndef __BEOS__
50 #  include <arpa/inet.h>
51 # endif
52 # include <netdb.h>
53 # define SET_H_ERRNO(err) ((void)(h_errno = (err)))
54 #else  /* WINDOWS */
55 # define SET_H_ERRNO(err) WSASetLastError (err)
56 #endif /* WINDOWS */
57
58 #include <errno.h>
59
60 #include "wget.h"
61 #include "utils.h"
62 #include "host.h"
63 #include "url.h"
64 #include "hash.h"
65 #include "connect.h"            /* for socket_has_inet6 */
66
67 #ifndef errno
68 extern int errno;
69 #endif
70
71 #ifndef h_errno
72 # ifndef __CYGWIN__
73 extern int h_errno;
74 # endif
75 #endif
76
77 #ifndef NO_ADDRESS
78 # define NO_ADDRESS NO_DATA
79 #endif
80
81 /* Lists of IP addresses that result from running DNS queries.  See
82    lookup_host for details.  */
83
84 struct address_list {
85   int count;                    /* number of adrresses */
86   ip_address *addresses;        /* pointer to the string of addresses */
87
88   int faulty;                   /* number of addresses known not to work. */
89   int connected;                /* whether we were able to connect to
90                                    one of the addresses in the list,
91                                    at least once. */
92
93   int refcount;                 /* reference count; when it drops to
94                                    0, the entry is freed. */
95 };
96
97 /* Get the bounds of the address list.  */
98
99 void
100 address_list_get_bounds (const struct address_list *al, int *start, int *end)
101 {
102   *start = al->faulty;
103   *end   = al->count;
104 }
105
106 /* Return a pointer to the address at position POS.  */
107
108 const ip_address *
109 address_list_address_at (const struct address_list *al, int pos)
110 {
111   assert (pos >= al->faulty && pos < al->count);
112   return al->addresses + pos;
113 }
114
115 /* Return non-zero if AL contains IP, zero otherwise.  */
116
117 int
118 address_list_contains (const struct address_list *al, const ip_address *ip)
119 {
120   int i;
121   switch (ip->type)
122     {
123     case IPV4_ADDRESS:
124       for (i = 0; i < al->count; i++)
125         {
126           ip_address *cur = al->addresses + i;
127           if (cur->type == IPV4_ADDRESS
128               && (ADDRESS_IPV4_IN_ADDR (cur).s_addr
129                   ==
130                   ADDRESS_IPV4_IN_ADDR (ip).s_addr))
131             return 1;
132         }
133       return 0;
134 #ifdef ENABLE_IPV6
135     case IPV6_ADDRESS:
136       for (i = 0; i < al->count; i++)
137         {
138           ip_address *cur = al->addresses + i;
139           if (cur->type == IPV6_ADDRESS
140 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
141               && ADDRESS_IPV6_SCOPE (cur) == ADDRESS_IPV6_SCOPE (ip)
142 #endif
143               && IN6_ARE_ADDR_EQUAL (&ADDRESS_IPV6_IN6_ADDR (cur),
144                                      &ADDRESS_IPV6_IN6_ADDR (ip)))
145             return 1;
146         }
147       return 0;
148 #endif /* ENABLE_IPV6 */
149     default:
150       abort ();
151       return 0;
152     }
153 }
154
155 /* Mark the INDEXth element of AL as faulty, so that the next time
156    this address list is used, the faulty element will be skipped.  */
157
158 void
159 address_list_set_faulty (struct address_list *al, int index)
160 {
161   /* We assume that the address list is traversed in order, so that a
162      "faulty" attempt is always preceded with all-faulty addresses,
163      and this is how Wget uses it.  */
164   assert (index == al->faulty);
165
166   ++al->faulty;
167   if (al->faulty >= al->count)
168     /* All addresses have been proven faulty.  Since there's not much
169        sense in returning the user an empty address list the next
170        time, we'll rather make them all clean, so that they can be
171        retried anew.  */
172     al->faulty = 0;
173 }
174
175 /* Set the "connected" flag to true.  This flag used by connect.c to
176    see if the host perhaps needs to be resolved again.  */
177
178 void
179 address_list_set_connected (struct address_list *al)
180 {
181   al->connected = 1;
182 }
183
184 /* Return the value of the "connected" flag. */
185
186 int
187 address_list_connected_p (const struct address_list *al)
188 {
189   return al->connected;
190 }
191
192 #ifdef ENABLE_IPV6
193
194 /* Create an address_list from the addresses in the given struct
195    addrinfo.  */
196
197 static struct address_list *
198 address_list_from_addrinfo (const struct addrinfo *ai)
199 {
200   struct address_list *al;
201   const struct addrinfo *ptr;
202   int cnt;
203   ip_address *ip;
204
205   cnt = 0;
206   for (ptr = ai; ptr != NULL ; ptr = ptr->ai_next)
207     if (ptr->ai_family == AF_INET || ptr->ai_family == AF_INET6)
208       ++cnt;
209   if (cnt == 0)
210     return NULL;
211
212   al = xnew0 (struct address_list);
213   al->addresses = xnew_array (ip_address, cnt);
214   al->count     = cnt;
215   al->refcount  = 1;
216
217   ip = al->addresses;
218   for (ptr = ai; ptr != NULL; ptr = ptr->ai_next)
219     if (ptr->ai_family == AF_INET6) 
220       {
221         const struct sockaddr_in6 *sin6 =
222           (const struct sockaddr_in6 *)ptr->ai_addr;
223         ip->type = IPV6_ADDRESS;
224         ADDRESS_IPV6_IN6_ADDR (ip) = sin6->sin6_addr;
225 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
226         ADDRESS_IPV6_SCOPE (ip) = sin6->sin6_scope_id;
227 #endif
228         ++ip;
229       } 
230     else if (ptr->ai_family == AF_INET)
231       {
232         const struct sockaddr_in *sin =
233           (const struct sockaddr_in *)ptr->ai_addr;
234         ip->type = IPV4_ADDRESS;
235         ADDRESS_IPV4_IN_ADDR (ip) = sin->sin_addr;
236         ++ip;
237       }
238   assert (ip - al->addresses == cnt);
239   return al;
240 }
241
242 #define IS_IPV4(addr) (((const ip_address *) addr)->type == IPV4_ADDRESS)
243
244 /* Compare two IP addresses by type, giving preference to the IPv4
245    address (sorting it first).  In other words, return -1 if ADDR1 is
246    IPv4 and ADDR2 is IPv6, +1 if ADDR1 is IPv6 and ADDR2 is IPv4, and
247    0 otherwise.
248
249    This is intended to be used as the comparator arg to a qsort-like
250    sorting function, which is why it accepts generic pointers.  */
251
252 static int
253 cmp_prefer_ipv4 (const void *addr1, const void *addr2)
254 {
255   return !IS_IPV4 (addr1) - !IS_IPV4 (addr2);
256 }
257
258 #define IS_IPV6(addr) (((const ip_address *) addr)->type == IPV6_ADDRESS)
259
260 /* Like the above, but give preference to the IPv6 address.  */
261
262 static int
263 cmp_prefer_ipv6 (const void *addr1, const void *addr2)
264 {
265   return !IS_IPV6 (addr1) - !IS_IPV6 (addr2);
266 }
267
268 #else  /* not ENABLE_IPV6 */
269
270 /* Create an address_list from a NULL-terminated vector of IPv4
271    addresses.  This kind of vector is returned by gethostbyname.  */
272
273 static struct address_list *
274 address_list_from_ipv4_addresses (char **vec)
275 {
276   int count, i;
277   struct address_list *al = xnew0 (struct address_list);
278
279   count = 0;
280   while (vec[count])
281     ++count;
282   assert (count > 0);
283
284   al->addresses = xnew_array (ip_address, count);
285   al->count     = count;
286   al->refcount  = 1;
287
288   for (i = 0; i < count; i++)
289     {
290       ip_address *ip = &al->addresses[i];
291       ip->type = IPV4_ADDRESS;
292       memcpy (ADDRESS_IPV4_DATA (ip), vec[i], 4);
293     }
294
295   return al;
296 }
297
298 #endif /* not ENABLE_IPV6 */
299
300 static void
301 address_list_delete (struct address_list *al)
302 {
303   xfree (al->addresses);
304   xfree (al);
305 }
306
307 /* Mark the address list as being no longer in use.  This will reduce
308    its reference count which will cause the list to be freed when the
309    count reaches 0.  */
310
311 void
312 address_list_release (struct address_list *al)
313 {
314   --al->refcount;
315   DEBUGP (("Releasing %p (new refcount %d).\n", al, al->refcount));
316   if (al->refcount <= 0)
317     {
318       DEBUGP (("Deleting unused %p.\n", al));
319       address_list_delete (al);
320     }
321 }
322 \f
323 /* Versions of gethostbyname and getaddrinfo that support timeout. */
324
325 #ifndef ENABLE_IPV6
326
327 struct ghbnwt_context {
328   const char *host_name;
329   struct hostent *hptr;
330 };
331
332 static void
333 gethostbyname_with_timeout_callback (void *arg)
334 {
335   struct ghbnwt_context *ctx = (struct ghbnwt_context *)arg;
336   ctx->hptr = gethostbyname (ctx->host_name);
337 }
338
339 /* Just like gethostbyname, except it times out after TIMEOUT seconds.
340    In case of timeout, NULL is returned and errno is set to ETIMEDOUT.
341    The function makes sure that when NULL is returned for reasons
342    other than timeout, errno is reset.  */
343
344 static struct hostent *
345 gethostbyname_with_timeout (const char *host_name, double timeout)
346 {
347   struct ghbnwt_context ctx;
348   ctx.host_name = host_name;
349   if (run_with_timeout (timeout, gethostbyname_with_timeout_callback, &ctx))
350     {
351       SET_H_ERRNO (HOST_NOT_FOUND);
352       errno = ETIMEDOUT;
353       return NULL;
354     }
355   if (!ctx.hptr)
356     errno = 0;
357   return ctx.hptr;
358 }
359
360 /* Print error messages for host errors.  */
361 static char *
362 host_errstr (int error)
363 {
364   /* Can't use switch since some of these constants can be equal,
365      which makes the compiler complain about duplicate case
366      values.  */
367   if (error == HOST_NOT_FOUND
368       || error == NO_RECOVERY
369       || error == NO_DATA
370       || error == NO_ADDRESS)
371     return _("Unknown host");
372   else if (error == TRY_AGAIN)
373     /* Message modeled after what gai_strerror returns in similar
374        circumstances.  */
375     return _("Temporary failure in name resolution");
376   else
377     return _("Unknown error");
378 }
379
380 #else  /* ENABLE_IPV6 */
381
382 struct gaiwt_context {
383   const char *node;
384   const char *service;
385   const struct addrinfo *hints;
386   struct addrinfo **res;
387   int exit_code;
388 };
389
390 static void
391 getaddrinfo_with_timeout_callback (void *arg)
392 {
393   struct gaiwt_context *ctx = (struct gaiwt_context *)arg;
394   ctx->exit_code = getaddrinfo (ctx->node, ctx->service, ctx->hints, ctx->res);
395 }
396
397 /* Just like getaddrinfo, except it times out after TIMEOUT seconds.
398    In case of timeout, the EAI_SYSTEM error code is returned and errno
399    is set to ETIMEDOUT.  */
400
401 static int
402 getaddrinfo_with_timeout (const char *node, const char *service,
403                           const struct addrinfo *hints, struct addrinfo **res,
404                           double timeout)
405 {
406   struct gaiwt_context ctx;
407   ctx.node = node;
408   ctx.service = service;
409   ctx.hints = hints;
410   ctx.res = res;
411
412   if (run_with_timeout (timeout, getaddrinfo_with_timeout_callback, &ctx))
413     {
414       errno = ETIMEDOUT;
415       return EAI_SYSTEM;
416     }
417   return ctx.exit_code;
418 }
419
420 #endif /* ENABLE_IPV6 */
421 \f
422 /* Pretty-print ADDR.  When compiled without IPv6, this is the same as
423    inet_ntoa.  With IPv6, it either prints an IPv6 address or an IPv4
424    address.  */
425
426 const char *
427 pretty_print_address (const ip_address *addr)
428 {
429   switch (addr->type) 
430     {
431     case IPV4_ADDRESS:
432       return inet_ntoa (ADDRESS_IPV4_IN_ADDR (addr));
433 #ifdef ENABLE_IPV6
434     case IPV6_ADDRESS:
435       {
436         static char buf[128];
437         inet_ntop (AF_INET6, &ADDRESS_IPV6_IN6_ADDR (addr), buf, sizeof (buf));
438 #if 0
439 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
440         {
441           /* append "%SCOPE_ID" for all ?non-global? addresses */
442           char *p = buf + strlen (buf);
443           *p++ = '%';
444           number_to_string (p, ADDRESS_IPV6_SCOPE (addr));
445         }
446 #endif
447 #endif
448         buf[sizeof (buf) - 1] = '\0';
449         return buf;
450       }
451 #endif
452     }
453   abort ();
454   return NULL;
455 }
456
457 /* The following two functions were adapted from glibc. */
458
459 static int
460 is_valid_ipv4_address (const char *str, const char *end)
461 {
462   int saw_digit = 0;
463   int octets = 0;
464   int val = 0;
465
466   while (str < end)
467     {
468       int ch = *str++;
469
470       if (ch >= '0' && ch <= '9')
471         {
472           val = val * 10 + (ch - '0');
473
474           if (val > 255)
475             return 0;
476           if (saw_digit == 0)
477             {
478               if (++octets > 4)
479                 return 0;
480               saw_digit = 1;
481             }
482         }
483       else if (ch == '.' && saw_digit == 1)
484         {
485           if (octets == 4)
486             return 0;
487           val = 0;
488           saw_digit = 0;
489         }
490       else
491         return 0;
492     }
493   if (octets < 4)
494     return 0;
495   
496   return 1;
497 }
498
499 int
500 is_valid_ipv6_address (const char *str, const char *end)
501 {
502   /* Use lower-case for these to avoid clash with system headers.  */
503   enum {
504     ns_inaddrsz  = 4,
505     ns_in6addrsz = 16,
506     ns_int16sz   = 2
507   };
508
509   const char *curtok;
510   int tp;
511   const char *colonp;
512   int saw_xdigit;
513   unsigned int val;
514
515   tp = 0;
516   colonp = NULL;
517
518   if (str == end)
519     return 0;
520   
521   /* Leading :: requires some special handling. */
522   if (*str == ':')
523     {
524       ++str;
525       if (str == end || *str != ':')
526         return 0;
527     }
528
529   curtok = str;
530   saw_xdigit = 0;
531   val = 0;
532
533   while (str < end)
534     {
535       int ch = *str++;
536
537       /* if ch is a number, add it to val. */
538       if (ISXDIGIT (ch))
539         {
540           val <<= 4;
541           val |= XDIGIT_TO_NUM (ch);
542           if (val > 0xffff)
543             return 0;
544           saw_xdigit = 1;
545           continue;
546         }
547
548       /* if ch is a colon ... */
549       if (ch == ':')
550         {
551           curtok = str;
552           if (saw_xdigit == 0)
553             {
554               if (colonp != NULL)
555                 return 0;
556               colonp = str + tp;
557               continue;
558             }
559           else if (str == end)
560             return 0;
561           if (tp > ns_in6addrsz - ns_int16sz)
562             return 0;
563           tp += ns_int16sz;
564           saw_xdigit = 0;
565           val = 0;
566           continue;
567         }
568
569       /* if ch is a dot ... */
570       if (ch == '.' && (tp <= ns_in6addrsz - ns_inaddrsz)
571           && is_valid_ipv4_address (curtok, end) == 1)
572         {
573           tp += ns_inaddrsz;
574           saw_xdigit = 0;
575           break;
576         }
577     
578       return 0;
579     }
580
581   if (saw_xdigit == 1)
582     {
583       if (tp > ns_in6addrsz - ns_int16sz) 
584         return 0;
585       tp += ns_int16sz;
586     }
587
588   if (colonp != NULL)
589     {
590       if (tp == ns_in6addrsz) 
591         return 0;
592       tp = ns_in6addrsz;
593     }
594
595   if (tp != ns_in6addrsz)
596     return 0;
597
598   return 1;
599 }
600 \f
601 /* Simple host cache, used by lookup_host to speed up resolving.  The
602    cache doesn't handle TTL because Wget is a fairly short-lived
603    application.  Refreshing is attempted when connect fails, though --
604    see connect_to_host.  */
605
606 /* Mapping between known hosts and to lists of their addresses. */
607 static struct hash_table *host_name_addresses_map;
608
609
610 /* Return the host's resolved addresses from the cache, if
611    available.  */
612
613 static struct address_list *
614 cache_query (const char *host)
615 {
616   struct address_list *al;
617   if (!host_name_addresses_map)
618     return NULL;
619   al = hash_table_get (host_name_addresses_map, host);
620   if (al)
621     {
622       DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al));
623       ++al->refcount;
624       return al;
625     }
626   return NULL;
627 }
628
629 /* Cache the DNS lookup of HOST.  Subsequent invocations of
630    lookup_host will return the cached value.  */
631
632 static void
633 cache_store (const char *host, struct address_list *al)
634 {
635   if (!host_name_addresses_map)
636     host_name_addresses_map = make_nocase_string_hash_table (0);
637
638   ++al->refcount;
639   hash_table_put (host_name_addresses_map, xstrdup_lower (host), al);
640
641 #ifdef ENABLE_DEBUG
642   if (opt.debug)
643     {
644       int i;
645       debug_logprintf ("Caching %s =>", host);
646       for (i = 0; i < al->count; i++)
647         debug_logprintf (" %s", pretty_print_address (al->addresses + i));
648       debug_logprintf ("\n");
649     }
650 #endif
651 }
652
653 /* Remove HOST from the DNS cache.  Does nothing is HOST is not in
654    the cache.  */
655
656 static void
657 cache_remove (const char *host)
658 {
659   struct address_list *al;
660   if (!host_name_addresses_map)
661     return;
662   al = hash_table_get (host_name_addresses_map, host);
663   if (al)
664     {
665       address_list_release (al);
666       hash_table_remove (host_name_addresses_map, host);
667     }
668 }
669 \f
670 /* Look up HOST in DNS and return a list of IP addresses.
671
672    This function caches its result so that, if the same host is passed
673    the second time, the addresses are returned without DNS lookup.
674    (Use LH_REFRESH to force lookup, or set opt.dns_cache to 0 to
675    globally disable caching.)
676
677    The order of the returned addresses is affected by the setting of
678    opt.prefer_family: if it is set to prefer_ipv4, IPv4 addresses are
679    placed at the beginning; if it is prefer_ipv6, IPv6 ones are placed
680    at the beginning; otherwise, the order is left intact.  The
681    relative order of addresses with the same family is left
682    undisturbed in either case.
683
684    FLAGS can be a combination of:
685      LH_SILENT  - don't print the "resolving ... done" messages.
686      LH_BIND    - resolve addresses for use with bind, which under
687                   IPv6 means to use AI_PASSIVE flag to getaddrinfo.
688                   Passive lookups are not cached under IPv6.
689      LH_REFRESH - if HOST is cached, remove the entry from the cache
690                   and resolve it anew.  */
691
692 struct address_list *
693 lookup_host (const char *host, int flags)
694 {
695   struct address_list *al;
696   int silent = flags & LH_SILENT;
697   int use_cache;
698   int numeric_address = 0;
699   double timeout = opt.dns_timeout;
700
701 #ifndef ENABLE_IPV6
702   /* If we're not using getaddrinfo, first check if HOST specifies a
703      numeric IPv4 address.  Some implementations of gethostbyname
704      (e.g. the Ultrix one and possibly Winsock) don't accept
705      dotted-decimal IPv4 addresses.  */
706   {
707     uint32_t addr_ipv4 = (uint32_t)inet_addr (host);
708     if (addr_ipv4 != (uint32_t) -1)
709       {
710         /* No need to cache host->addr relation, just return the
711            address.  */
712         char *vec[2];
713         vec[0] = (char *)&addr_ipv4;
714         vec[1] = NULL;
715         return address_list_from_ipv4_addresses (vec);
716       }
717   }
718 #else  /* ENABLE_IPV6 */
719   /* If we're using getaddrinfo, at least check whether the address is
720      already numeric, in which case there is no need to print the
721      "Resolving..." output.  (This comes at no additional cost since
722      the is_valid_ipv*_address are already required for
723      url_parse.)  */
724   {
725     const char *end = host + strlen (host);
726     if (is_valid_ipv4_address (host, end) || is_valid_ipv6_address (host, end))
727       numeric_address = 1;
728   }
729 #endif
730
731   /* Cache is normally on, but can be turned off with --no-dns-cache.
732      Don't cache passive lookups under IPv6.  */
733   use_cache = opt.dns_cache;
734 #ifdef ENABLE_IPV6
735   if ((flags & LH_BIND) || numeric_address)
736     use_cache = 0;
737 #endif
738
739   /* Try to find the host in the cache so we don't need to talk to the
740      resolver.  If LH_REFRESH is requested, remove HOST from the cache
741      instead.  */
742   if (use_cache)
743     {
744       if (!(flags & LH_REFRESH))
745         {
746           al = cache_query (host);
747           if (al)
748             return al;
749         }
750       else
751         cache_remove (host);
752     }
753
754   /* No luck with the cache; resolve HOST. */
755
756   if (!silent && !numeric_address)
757     logprintf (LOG_VERBOSE, _("Resolving %s... "), escnonprint (host));
758
759 #ifdef ENABLE_IPV6
760   {
761     int err;
762     struct addrinfo hints, *res;
763
764     xzero (hints);
765     hints.ai_socktype = SOCK_STREAM;
766     if (opt.ipv4_only)
767       hints.ai_family = AF_INET;
768     else if (opt.ipv6_only)
769       hints.ai_family = AF_INET6;
770     else
771       {
772         hints.ai_family = AF_UNSPEC;
773 #ifdef AI_ADDRCONFIG
774         hints.ai_flags |= AI_ADDRCONFIG;
775 #else
776         /* On systems without AI_ADDRCONFIG, emulate it by manually
777            checking whether the system supports IPv6 sockets.  */
778         if (!socket_has_inet6 ())
779           hints.ai_family = AF_INET;
780 #endif
781       }
782     if (flags & LH_BIND)
783       hints.ai_flags |= AI_PASSIVE;
784
785 #ifdef AI_NUMERICHOST
786     if (numeric_address)
787       {
788         /* Where available, the AI_NUMERICHOST hint can prevent costly
789            access to DNS servers.  */
790         hints.ai_flags |= AI_NUMERICHOST;
791         timeout = 0;            /* no timeout needed when "resolving"
792                                    numeric hosts -- avoid setting up
793                                    signal handlers and such. */
794       }
795 #endif
796
797     err = getaddrinfo_with_timeout (host, NULL, &hints, &res, timeout);
798     if (err != 0 || res == NULL)
799       {
800         if (!silent)
801           logprintf (LOG_VERBOSE, _("failed: %s.\n"),
802                      err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno));
803         return NULL;
804       }
805     al = address_list_from_addrinfo (res);
806     freeaddrinfo (res);
807     if (!al)
808       {
809         logprintf (LOG_VERBOSE,
810                    _("failed: No IPv4/IPv6 addresses for host.\n"));
811         return NULL;
812       }
813
814     /* Reorder addresses so that IPv4 ones (or IPv6 ones, as per
815        --prefer-family) come first.  Sorting is stable so the order of
816        the addresses with the same family is undisturbed.  */
817     if (al->count > 1 && opt.prefer_family != prefer_none)
818       stable_sort (al->addresses, al->count, sizeof (ip_address),
819                    opt.prefer_family == prefer_ipv4
820                    ? cmp_prefer_ipv4 : cmp_prefer_ipv6);
821   }
822 #else  /* not ENABLE_IPV6 */
823   {
824     struct hostent *hptr = gethostbyname_with_timeout (host, timeout);
825     if (!hptr)
826       {
827         if (!silent)
828           {
829             if (errno != ETIMEDOUT)
830               logprintf (LOG_VERBOSE, _("failed: %s.\n"),
831                          host_errstr (h_errno));
832             else
833               logputs (LOG_VERBOSE, _("failed: timed out.\n"));
834           }
835         return NULL;
836       }
837     /* Do older systems have h_addr_list?  */
838     al = address_list_from_ipv4_addresses (hptr->h_addr_list);
839   }
840 #endif /* not ENABLE_IPV6 */
841
842   /* Print the addresses determined by DNS lookup, but no more than
843      three.  */
844   if (!silent && !numeric_address)
845     {
846       int i;
847       int printmax = al->count <= 3 ? al->count : 3;
848       for (i = 0; i < printmax; i++)
849         {
850           logprintf (LOG_VERBOSE, "%s",
851                      pretty_print_address (al->addresses + i));
852           if (i < printmax - 1)
853             logputs (LOG_VERBOSE, ", ");
854         }
855       if (printmax != al->count)
856         logputs (LOG_VERBOSE, ", ...");
857       logputs (LOG_VERBOSE, "\n");
858     }
859
860   /* Cache the lookup information. */
861   if (use_cache)
862     cache_store (host, al);
863
864   return al;
865 }
866 \f
867 /* Determine whether a URL is acceptable to be followed, according to
868    a list of domains to accept.  */
869 int
870 accept_domain (struct url *u)
871 {
872   assert (u->host != NULL);
873   if (opt.domains)
874     {
875       if (!sufmatch ((const char **)opt.domains, u->host))
876         return 0;
877     }
878   if (opt.exclude_domains)
879     {
880       if (sufmatch ((const char **)opt.exclude_domains, u->host))
881         return 0;
882     }
883   return 1;
884 }
885
886 /* Check whether WHAT is matched in LIST, each element of LIST being a
887    pattern to match WHAT against, using backward matching (see
888    match_backwards() in utils.c).
889
890    If an element of LIST matched, 1 is returned, 0 otherwise.  */
891 int
892 sufmatch (const char **list, const char *what)
893 {
894   int i, j, k, lw;
895
896   lw = strlen (what);
897   for (i = 0; list[i]; i++)
898     {
899       for (j = strlen (list[i]), k = lw; j >= 0 && k >= 0; j--, k--)
900         if (TOLOWER (list[i][j]) != TOLOWER (what[k]))
901           break;
902       /* The domain must be first to reach to beginning.  */
903       if (j == -1)
904         return 1;
905     }
906   return 0;
907 }
908
909 static int
910 host_cleanup_mapper (void *key, void *value, void *arg_ignored)
911 {
912   struct address_list *al;
913
914   xfree (key);                  /* host */
915
916   al = (struct address_list *)value;
917   assert (al->refcount == 1);
918   address_list_delete (al);
919
920   return 0;
921 }
922
923 void
924 host_cleanup (void)
925 {
926   if (host_name_addresses_map)
927     {
928       hash_table_map (host_name_addresses_map, host_cleanup_mapper, NULL);
929       hash_table_destroy (host_name_addresses_map);
930       host_name_addresses_map = NULL;
931     }
932 }