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