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