]> sjero.net Git - wget/blob - src/host.c
585b93c7ea8ffa73834fbeb8e16087e1bddf8269
[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 #else  /* not ENABLE_IPV6 */
243
244 /* Create an address_list from a NULL-terminated vector of IPv4
245    addresses.  This kind of vector is returned by gethostbyname.  */
246
247 static struct address_list *
248 address_list_from_ipv4_addresses (char **vec)
249 {
250   int count, i;
251   struct address_list *al = xnew0 (struct address_list);
252
253   count = 0;
254   while (vec[count])
255     ++count;
256   assert (count > 0);
257
258   al->addresses = xnew_array (ip_address, count);
259   al->count     = count;
260   al->refcount  = 1;
261
262   for (i = 0; i < count; i++)
263     {
264       ip_address *ip = &al->addresses[i];
265       ip->type = IPV4_ADDRESS;
266       memcpy (ADDRESS_IPV4_DATA (ip), vec[i], 4);
267     }
268
269   return al;
270 }
271
272 #endif /* not ENABLE_IPV6 */
273
274 static void
275 address_list_delete (struct address_list *al)
276 {
277   xfree (al->addresses);
278   xfree (al);
279 }
280
281 /* Mark the address list as being no longer in use.  This will reduce
282    its reference count which will cause the list to be freed when the
283    count reaches 0.  */
284
285 void
286 address_list_release (struct address_list *al)
287 {
288   --al->refcount;
289   DEBUGP (("Releasing %p (new refcount %d).\n", al, al->refcount));
290   if (al->refcount <= 0)
291     {
292       DEBUGP (("Deleting unused %p.\n", al));
293       address_list_delete (al);
294     }
295 }
296 \f
297 /* Versions of gethostbyname and getaddrinfo that support timeout. */
298
299 #ifndef ENABLE_IPV6
300
301 struct ghbnwt_context {
302   const char *host_name;
303   struct hostent *hptr;
304 };
305
306 static void
307 gethostbyname_with_timeout_callback (void *arg)
308 {
309   struct ghbnwt_context *ctx = (struct ghbnwt_context *)arg;
310   ctx->hptr = gethostbyname (ctx->host_name);
311 }
312
313 /* Just like gethostbyname, except it times out after TIMEOUT seconds.
314    In case of timeout, NULL is returned and errno is set to ETIMEDOUT.
315    The function makes sure that when NULL is returned for reasons
316    other than timeout, errno is reset.  */
317
318 static struct hostent *
319 gethostbyname_with_timeout (const char *host_name, double timeout)
320 {
321   struct ghbnwt_context ctx;
322   ctx.host_name = host_name;
323   if (run_with_timeout (timeout, gethostbyname_with_timeout_callback, &ctx))
324     {
325       SET_H_ERRNO (HOST_NOT_FOUND);
326       errno = ETIMEDOUT;
327       return NULL;
328     }
329   if (!ctx.hptr)
330     errno = 0;
331   return ctx.hptr;
332 }
333
334 /* Print error messages for host errors.  */
335 static char *
336 host_errstr (int error)
337 {
338   /* Can't use switch since some of these constants can be equal,
339      which makes the compiler complain about duplicate case
340      values.  */
341   if (error == HOST_NOT_FOUND
342       || error == NO_RECOVERY
343       || error == NO_DATA
344       || error == NO_ADDRESS)
345     return _("Unknown host");
346   else if (error == TRY_AGAIN)
347     /* Message modeled after what gai_strerror returns in similar
348        circumstances.  */
349     return _("Temporary failure in name resolution");
350   else
351     return _("Unknown error");
352 }
353
354 #else  /* ENABLE_IPV6 */
355
356 struct gaiwt_context {
357   const char *node;
358   const char *service;
359   const struct addrinfo *hints;
360   struct addrinfo **res;
361   int exit_code;
362 };
363
364 static void
365 getaddrinfo_with_timeout_callback (void *arg)
366 {
367   struct gaiwt_context *ctx = (struct gaiwt_context *)arg;
368   ctx->exit_code = getaddrinfo (ctx->node, ctx->service, ctx->hints, ctx->res);
369 }
370
371 /* Just like getaddrinfo, except it times out after TIMEOUT seconds.
372    In case of timeout, the EAI_SYSTEM error code is returned and errno
373    is set to ETIMEDOUT.  */
374
375 static int
376 getaddrinfo_with_timeout (const char *node, const char *service,
377                           const struct addrinfo *hints, struct addrinfo **res,
378                           double timeout)
379 {
380   struct gaiwt_context ctx;
381   ctx.node = node;
382   ctx.service = service;
383   ctx.hints = hints;
384   ctx.res = res;
385
386   if (run_with_timeout (timeout, getaddrinfo_with_timeout_callback, &ctx))
387     {
388       errno = ETIMEDOUT;
389       return EAI_SYSTEM;
390     }
391   return ctx.exit_code;
392 }
393
394 #endif /* ENABLE_IPV6 */
395 \f
396 /* Pretty-print ADDR.  When compiled without IPv6, this is the same as
397    inet_ntoa.  With IPv6, it either prints an IPv6 address or an IPv4
398    address.  */
399
400 const char *
401 pretty_print_address (const ip_address *addr)
402 {
403   switch (addr->type) 
404     {
405     case IPV4_ADDRESS:
406       return inet_ntoa (ADDRESS_IPV4_IN_ADDR (addr));
407 #ifdef ENABLE_IPV6
408     case IPV6_ADDRESS:
409       {
410         static char buf[128];
411         inet_ntop (AF_INET6, &ADDRESS_IPV6_IN6_ADDR (addr), buf, sizeof (buf));
412 #if 0
413 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
414         {
415           /* append "%SCOPE_ID" for all ?non-global? addresses */
416           char *p = buf + strlen (buf);
417           *p++ = '%';
418           number_to_string (p, ADDRESS_IPV6_SCOPE (addr));
419         }
420 #endif
421 #endif
422         buf[sizeof (buf) - 1] = '\0';
423         return buf;
424       }
425 #endif
426     }
427   abort ();
428   return NULL;
429 }
430
431 /* The following two functions were adapted from glibc. */
432
433 static int
434 is_valid_ipv4_address (const char *str, const char *end)
435 {
436   int saw_digit = 0;
437   int octets = 0;
438   int val = 0;
439
440   while (str < end)
441     {
442       int ch = *str++;
443
444       if (ch >= '0' && ch <= '9')
445         {
446           val = val * 10 + (ch - '0');
447
448           if (val > 255)
449             return 0;
450           if (saw_digit == 0)
451             {
452               if (++octets > 4)
453                 return 0;
454               saw_digit = 1;
455             }
456         }
457       else if (ch == '.' && saw_digit == 1)
458         {
459           if (octets == 4)
460             return 0;
461           val = 0;
462           saw_digit = 0;
463         }
464       else
465         return 0;
466     }
467   if (octets < 4)
468     return 0;
469   
470   return 1;
471 }
472
473 int
474 is_valid_ipv6_address (const char *str, const char *end)
475 {
476   enum {
477     NS_INADDRSZ  = 4,
478     NS_IN6ADDRSZ = 16,
479     NS_INT16SZ   = 2
480   };
481
482   const char *curtok;
483   int tp;
484   const char *colonp;
485   int saw_xdigit;
486   unsigned int val;
487
488   tp = 0;
489   colonp = NULL;
490
491   if (str == end)
492     return 0;
493   
494   /* Leading :: requires some special handling. */
495   if (*str == ':')
496     {
497       ++str;
498       if (str == end || *str != ':')
499         return 0;
500     }
501
502   curtok = str;
503   saw_xdigit = 0;
504   val = 0;
505
506   while (str < end)
507     {
508       int ch = *str++;
509
510       /* if ch is a number, add it to val. */
511       if (ISXDIGIT (ch))
512         {
513           val <<= 4;
514           val |= XDIGIT_TO_NUM (ch);
515           if (val > 0xffff)
516             return 0;
517           saw_xdigit = 1;
518           continue;
519         }
520
521       /* if ch is a colon ... */
522       if (ch == ':')
523         {
524           curtok = str;
525           if (saw_xdigit == 0)
526             {
527               if (colonp != NULL)
528                 return 0;
529               colonp = str + tp;
530               continue;
531             }
532           else if (str == end)
533             return 0;
534           if (tp > NS_IN6ADDRSZ - NS_INT16SZ)
535             return 0;
536           tp += NS_INT16SZ;
537           saw_xdigit = 0;
538           val = 0;
539           continue;
540         }
541
542       /* if ch is a dot ... */
543       if (ch == '.' && (tp <= NS_IN6ADDRSZ - NS_INADDRSZ)
544           && is_valid_ipv4_address (curtok, end) == 1)
545         {
546           tp += NS_INADDRSZ;
547           saw_xdigit = 0;
548           break;
549         }
550     
551       return 0;
552     }
553
554   if (saw_xdigit == 1)
555     {
556       if (tp > NS_IN6ADDRSZ - NS_INT16SZ) 
557         return 0;
558       tp += NS_INT16SZ;
559     }
560
561   if (colonp != NULL)
562     {
563       if (tp == NS_IN6ADDRSZ) 
564         return 0;
565       tp = NS_IN6ADDRSZ;
566     }
567
568   if (tp != NS_IN6ADDRSZ)
569     return 0;
570
571   return 1;
572 }
573 \f
574 /* Simple host cache, used by lookup_host to speed up resolving.  The
575    cache doesn't handle TTL because Wget is a fairly short-lived
576    application.  Refreshing is attempted when connect fails, though --
577    see connect_to_host.  */
578
579 /* Mapping between known hosts and to lists of their addresses. */
580 static struct hash_table *host_name_addresses_map;
581
582
583 /* Return the host's resolved addresses from the cache, if
584    available.  */
585
586 static struct address_list *
587 cache_query (const char *host)
588 {
589   struct address_list *al;
590   if (!host_name_addresses_map)
591     return NULL;
592   al = hash_table_get (host_name_addresses_map, host);
593   if (al)
594     {
595       DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al));
596       ++al->refcount;
597       return al;
598     }
599   return NULL;
600 }
601
602 /* Cache the DNS lookup of HOST.  Subsequent invocations of
603    lookup_host will return the cached value.  */
604
605 static void
606 cache_store (const char *host, struct address_list *al)
607 {
608   if (!host_name_addresses_map)
609     host_name_addresses_map = make_nocase_string_hash_table (0);
610
611   ++al->refcount;
612   hash_table_put (host_name_addresses_map, xstrdup_lower (host), al);
613
614 #ifdef ENABLE_DEBUG
615   if (opt.debug)
616     {
617       int i;
618       debug_logprintf ("Caching %s =>", host);
619       for (i = 0; i < al->count; i++)
620         debug_logprintf (" %s", pretty_print_address (al->addresses + i));
621       debug_logprintf ("\n");
622     }
623 #endif
624 }
625
626 /* Remove HOST from the DNS cache.  Does nothing is HOST is not in
627    the cache.  */
628
629 static void
630 cache_remove (const char *host)
631 {
632   struct address_list *al;
633   if (!host_name_addresses_map)
634     return;
635   al = hash_table_get (host_name_addresses_map, host);
636   if (al)
637     {
638       address_list_release (al);
639       hash_table_remove (host_name_addresses_map, host);
640     }
641 }
642 \f
643 /* Look up HOST in DNS and return a list of IP addresses.  The
644    addresses in the list are in the same order in which
645    gethostbyname/getaddrinfo returned them.
646
647    This function caches its result so that, if the same host is passed
648    the second time, the addresses are returned without DNS lookup.
649    (Use LH_REFRESH to force lookup, or set opt.dns_cache to 0 to
650    globally disable caching.)
651
652    FLAGS can be a combination of:
653      LH_SILENT  - don't print the "resolving ... done" messages.
654      LH_BIND    - resolve addresses for use with bind, which under
655                   IPv6 means to use AI_PASSIVE flag to getaddrinfo.
656                   Passive lookups are not cached under IPv6.
657      LH_REFRESH - if HOST is cached, remove the entry from the cache
658                   and resolve it anew.  */
659
660 struct address_list *
661 lookup_host (const char *host, int flags)
662 {
663   struct address_list *al;
664   int silent = flags & LH_SILENT;
665   int use_cache;
666   int numeric_address = 0;
667   double timeout = opt.dns_timeout;
668
669 #ifndef ENABLE_IPV6
670   /* If we're not using getaddrinfo, first check if HOST specifies a
671      numeric IPv4 address.  Some implementations of gethostbyname
672      (e.g. the Ultrix one and possibly Winsock) don't accept
673      dotted-decimal IPv4 addresses.  */
674   {
675     uint32_t addr_ipv4 = (uint32_t)inet_addr (host);
676     if (addr_ipv4 != (uint32_t) -1)
677       {
678         /* No need to cache host->addr relation, just return the
679            address.  */
680         char *vec[2];
681         vec[0] = (char *)&addr_ipv4;
682         vec[1] = NULL;
683         return address_list_from_ipv4_addresses (vec);
684       }
685   }
686 #else  /* ENABLE_IPV6 */
687   /* If we're using getaddrinfo, at least check whether the address is
688      already numeric, in which case there is no need to print the
689      "Resolving..." output.  (This comes at no additional cost since
690      the is_valid_ipv*_address are already required for
691      url_parse.)  */
692   {
693     const char *end = host + strlen (host);
694     if (is_valid_ipv4_address (host, end) || is_valid_ipv6_address (host, end))
695       numeric_address = 1;
696   }
697 #endif
698
699   /* Cache is normally on, but can be turned off with --no-dns-cache.
700      Don't cache passive lookups under IPv6.  */
701   use_cache = opt.dns_cache;
702 #ifdef ENABLE_IPV6
703   if ((flags & LH_BIND) || numeric_address)
704     use_cache = 0;
705 #endif
706
707   /* Try to find the host in the cache so we don't need to talk to the
708      resolver.  If LH_REFRESH is requested, remove HOST from the cache
709      instead.  */
710   if (use_cache)
711     {
712       if (!(flags & LH_REFRESH))
713         {
714           al = cache_query (host);
715           if (al)
716             return al;
717         }
718       else
719         cache_remove (host);
720     }
721
722   /* No luck with the cache; resolve HOST. */
723
724   if (!silent && !numeric_address)
725     logprintf (LOG_VERBOSE, _("Resolving %s... "), escnonprint (host));
726
727 #ifdef ENABLE_IPV6
728   {
729     int err;
730     struct addrinfo hints, *res;
731
732     xzero (hints);
733     hints.ai_socktype = SOCK_STREAM;
734     if (opt.ipv4_only)
735       hints.ai_family = AF_INET;
736     else if (opt.ipv6_only)
737       hints.ai_family = AF_INET6;
738     else
739       {
740         hints.ai_family = AF_UNSPEC;
741 #ifdef AI_ADDRCONFIG
742         hints.ai_flags |= AI_ADDRCONFIG;
743 #else
744         /* On systems without AI_ADDRCONFIG, emulate it by manually
745            checking whether the system supports IPv6 sockets.  */
746         if (!socket_has_inet6 ())
747           hints.ai_family = AF_INET;
748 #endif
749       }
750     if (flags & LH_BIND)
751       hints.ai_flags |= AI_PASSIVE;
752
753 #ifdef AI_NUMERICHOST
754     if (numeric_address)
755       {
756         /* Where available, the AI_NUMERICHOST hint can prevent costly
757            access to DNS servers.  */
758         hints.ai_flags |= AI_NUMERICHOST;
759         timeout = 0;            /* no timeout needed when "resolving"
760                                    numeric hosts -- avoid setting up
761                                    signal handlers and such. */
762       }
763 #endif
764
765     err = getaddrinfo_with_timeout (host, NULL, &hints, &res, timeout);
766     if (err != 0 || res == NULL)
767       {
768         if (!silent)
769           logprintf (LOG_VERBOSE, _("failed: %s.\n"),
770                      err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno));
771         return NULL;
772       }
773     al = address_list_from_addrinfo (res);
774     freeaddrinfo (res);
775     if (!al)
776       {
777         logprintf (LOG_VERBOSE,
778                    _("failed: No IPv4/IPv6 addresses for host.\n"));
779         return NULL;
780       }
781   }
782 #else  /* not ENABLE_IPV6 */
783   {
784     struct hostent *hptr = gethostbyname_with_timeout (host, timeout);
785     if (!hptr)
786       {
787         if (!silent)
788           {
789             if (errno != ETIMEDOUT)
790               logprintf (LOG_VERBOSE, _("failed: %s.\n"),
791                          host_errstr (h_errno));
792             else
793               logputs (LOG_VERBOSE, _("failed: timed out.\n"));
794           }
795         return NULL;
796       }
797     /* Do older systems have h_addr_list?  */
798     al = address_list_from_ipv4_addresses (hptr->h_addr_list);
799   }
800 #endif /* not ENABLE_IPV6 */
801
802   /* Print the addresses determined by DNS lookup, but no more than
803      three.  */
804   if (!silent && !numeric_address)
805     {
806       int i;
807       int printmax = al->count <= 3 ? al->count : 3;
808       for (i = 0; i < printmax; i++)
809         {
810           logprintf (LOG_VERBOSE, "%s",
811                      pretty_print_address (al->addresses + i));
812           if (i < printmax - 1)
813             logputs (LOG_VERBOSE, ", ");
814         }
815       if (printmax != al->count)
816         logputs (LOG_VERBOSE, ", ...");
817       logputs (LOG_VERBOSE, "\n");
818     }
819
820   /* Cache the lookup information. */
821   if (use_cache)
822     cache_store (host, al);
823
824   return al;
825 }
826 \f
827 /* Determine whether a URL is acceptable to be followed, according to
828    a list of domains to accept.  */
829 int
830 accept_domain (struct url *u)
831 {
832   assert (u->host != NULL);
833   if (opt.domains)
834     {
835       if (!sufmatch ((const char **)opt.domains, u->host))
836         return 0;
837     }
838   if (opt.exclude_domains)
839     {
840       if (sufmatch ((const char **)opt.exclude_domains, u->host))
841         return 0;
842     }
843   return 1;
844 }
845
846 /* Check whether WHAT is matched in LIST, each element of LIST being a
847    pattern to match WHAT against, using backward matching (see
848    match_backwards() in utils.c).
849
850    If an element of LIST matched, 1 is returned, 0 otherwise.  */
851 int
852 sufmatch (const char **list, const char *what)
853 {
854   int i, j, k, lw;
855
856   lw = strlen (what);
857   for (i = 0; list[i]; i++)
858     {
859       for (j = strlen (list[i]), k = lw; j >= 0 && k >= 0; j--, k--)
860         if (TOLOWER (list[i][j]) != TOLOWER (what[k]))
861           break;
862       /* The domain must be first to reach to beginning.  */
863       if (j == -1)
864         return 1;
865     }
866   return 0;
867 }
868
869 static int
870 host_cleanup_mapper (void *key, void *value, void *arg_ignored)
871 {
872   struct address_list *al;
873
874   xfree (key);                  /* host */
875
876   al = (struct address_list *)value;
877   assert (al->refcount == 1);
878   address_list_delete (al);
879
880   return 0;
881 }
882
883 void
884 host_cleanup (void)
885 {
886   if (host_name_addresses_map)
887     {
888       hash_table_map (host_name_addresses_map, host_cleanup_mapper, NULL);
889       hash_table_destroy (host_name_addresses_map);
890       host_name_addresses_map = NULL;
891     }
892 }