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