]> sjero.net Git - wget/blob - src/host.c
b550d786d3a05cfbff7cfcf8d1d6daaa77ff315a
[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 #ifdef WINDOWS
47 # include <winsock.h>
48 # define SET_H_ERRNO(err) WSASetLastError (err)
49 #else
50 # include <sys/socket.h>
51 # include <netinet/in.h>
52 # ifndef __BEOS__
53 #  include <arpa/inet.h>
54 # endif
55 # include <netdb.h>
56 # define SET_H_ERRNO(err) ((void)(h_errno = (err)))
57 #endif /* WINDOWS */
58
59 #ifndef NO_ADDRESS
60 # define NO_ADDRESS NO_DATA
61 #endif
62
63 #include <errno.h>
64
65 #include "wget.h"
66 #include "utils.h"
67 #include "host.h"
68 #include "url.h"
69 #include "hash.h"
70 #include "connect.h"            /* for socket_has_inet6 */
71
72 #ifndef errno
73 extern int errno;
74 #endif
75
76 #ifndef h_errno
77 # ifndef __CYGWIN__
78 extern int h_errno;
79 # endif
80 #endif
81
82 /* Lists of IP addresses that result from running DNS queries.  See
83    lookup_host for details.  */
84
85 struct address_list {
86   int count;                    /* number of adrresses */
87   ip_address *addresses;        /* pointer to the string of addresses */
88
89   int faulty;                   /* number of addresses known not to work. */
90   int connected;                /* whether we were able to connect to
91                                    one of the addresses in the list,
92                                    at least once. */
93
94   int refcount;                 /* reference count; when it drops to
95                                    0, the entry is freed. */
96 };
97
98 /* Get the bounds of the address list.  */
99
100 void
101 address_list_get_bounds (const struct address_list *al, int *start, int *end)
102 {
103   *start = al->faulty;
104   *end   = al->count;
105 }
106
107 /* Return a pointer to the address at position POS.  */
108
109 const ip_address *
110 address_list_address_at (const struct address_list *al, int pos)
111 {
112   assert (pos >= al->faulty && pos < al->count);
113   return al->addresses + pos;
114 }
115
116 /* Return non-zero if AL contains IP, zero otherwise.  */
117
118 int
119 address_list_contains (const struct address_list *al, const ip_address *ip)
120 {
121   int i;
122   switch (ip->type)
123     {
124     case IPV4_ADDRESS:
125       for (i = 0; i < al->count; i++)
126         {
127           ip_address *cur = al->addresses + i;
128           if (cur->type == IPV4_ADDRESS
129               && (ADDRESS_IPV4_IN_ADDR (cur).s_addr
130                   ==
131                   ADDRESS_IPV4_IN_ADDR (ip).s_addr))
132             return 1;
133         }
134       return 0;
135 #ifdef ENABLE_IPV6
136     case IPV6_ADDRESS:
137       for (i = 0; i < al->count; i++)
138         {
139           ip_address *cur = al->addresses + i;
140           if (cur->type == IPV6_ADDRESS
141 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
142               && ADDRESS_IPV6_SCOPE (cur) == ADDRESS_IPV6_SCOPE (ip)
143 #endif
144               && IN6_ARE_ADDR_EQUAL (&ADDRESS_IPV6_IN6_ADDR (cur),
145                                      &ADDRESS_IPV6_IN6_ADDR (ip)))
146             return 1;
147         }
148       return 0;
149 #endif /* ENABLE_IPV6 */
150     default:
151       abort ();
152       return 0;
153     }
154 }
155
156 /* Mark the INDEXth element of AL as faulty, so that the next time
157    this address list is used, the faulty element will be skipped.  */
158
159 void
160 address_list_set_faulty (struct address_list *al, int index)
161 {
162   /* We assume that the address list is traversed in order, so that a
163      "faulty" attempt is always preceded with all-faulty addresses,
164      and this is how Wget uses it.  */
165   assert (index == al->faulty);
166
167   ++al->faulty;
168   if (al->faulty >= al->count)
169     /* All addresses have been proven faulty.  Since there's not much
170        sense in returning the user an empty address list the next
171        time, we'll rather make them all clean, so that they can be
172        retried anew.  */
173     al->faulty = 0;
174 }
175
176 /* Set the "connected" flag to true.  This flag used by connect.c to
177    see if the host perhaps needs to be resolved again.  */
178
179 void
180 address_list_set_connected (struct address_list *al)
181 {
182   al->connected = 1;
183 }
184
185 /* Return the value of the "connected" flag. */
186
187 int
188 address_list_connected_p (const struct address_list *al)
189 {
190   return al->connected;
191 }
192
193 #ifdef ENABLE_IPV6
194
195 /* Create an address_list from the addresses in the given struct
196    addrinfo.  */
197
198 static struct address_list *
199 address_list_from_addrinfo (const struct addrinfo *ai)
200 {
201   struct address_list *al;
202   const struct addrinfo *ptr;
203   int cnt;
204   ip_address *ip;
205
206   cnt = 0;
207   for (ptr = ai; ptr != NULL ; ptr = ptr->ai_next)
208     if (ptr->ai_family == AF_INET || ptr->ai_family == AF_INET6)
209       ++cnt;
210   if (cnt == 0)
211     return NULL;
212
213   al = xnew0 (struct address_list);
214   al->addresses = xnew_array (ip_address, cnt);
215   al->count     = cnt;
216   al->refcount  = 1;
217
218   ip = al->addresses;
219   for (ptr = ai; ptr != NULL; ptr = ptr->ai_next)
220     if (ptr->ai_family == AF_INET6) 
221       {
222         const struct sockaddr_in6 *sin6 =
223           (const struct sockaddr_in6 *)ptr->ai_addr;
224         ip->type = IPV6_ADDRESS;
225         ADDRESS_IPV6_IN6_ADDR (ip) = sin6->sin6_addr;
226 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
227         ADDRESS_IPV6_SCOPE (ip) = sin6->sin6_scope_id;
228 #endif
229         ++ip;
230       } 
231     else if (ptr->ai_family == AF_INET)
232       {
233         const struct sockaddr_in *sin =
234           (const struct sockaddr_in *)ptr->ai_addr;
235         ip->type = IPV4_ADDRESS;
236         ADDRESS_IPV4_IN_ADDR (ip) = sin->sin_addr;
237         ++ip;
238       }
239   assert (ip - al->addresses == cnt);
240   return al;
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->type = IPV4_ADDRESS;
267       memcpy (ADDRESS_IPV4_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 %p (new refcount %d).\n", al, al->refcount));
291   if (al->refcount <= 0)
292     {
293       DEBUGP (("Deleting unused %p.\n", al));
294       address_list_delete (al);
295     }
296 }
297 \f
298 /* Versions of gethostbyname and getaddrinfo that support timeout. */
299
300 #ifndef ENABLE_IPV6
301
302 struct ghbnwt_context {
303   const char *host_name;
304   struct hostent *hptr;
305 };
306
307 static void
308 gethostbyname_with_timeout_callback (void *arg)
309 {
310   struct ghbnwt_context *ctx = (struct ghbnwt_context *)arg;
311   ctx->hptr = gethostbyname (ctx->host_name);
312 }
313
314 /* Just like gethostbyname, except it times out after TIMEOUT seconds.
315    In case of timeout, NULL is returned and errno is set to ETIMEDOUT.
316    The function makes sure that when NULL is returned for reasons
317    other than timeout, errno is reset.  */
318
319 static struct hostent *
320 gethostbyname_with_timeout (const char *host_name, double timeout)
321 {
322   struct ghbnwt_context ctx;
323   ctx.host_name = host_name;
324   if (run_with_timeout (timeout, gethostbyname_with_timeout_callback, &ctx))
325     {
326       SET_H_ERRNO (HOST_NOT_FOUND);
327       errno = ETIMEDOUT;
328       return NULL;
329     }
330   if (!ctx.hptr)
331     errno = 0;
332   return ctx.hptr;
333 }
334
335 /* Print error messages for host errors.  */
336 static char *
337 host_errstr (int error)
338 {
339   /* Can't use switch since some of these constants can be equal,
340      which makes the compiler complain about duplicate case
341      values.  */
342   if (error == HOST_NOT_FOUND
343       || error == NO_RECOVERY
344       || error == NO_DATA
345       || error == NO_ADDRESS)
346     return _("Unknown host");
347   else if (error == TRY_AGAIN)
348     /* Message modeled after what gai_strerror returns in similar
349        circumstances.  */
350     return _("Temporary failure in name resolution");
351   else
352     return _("Unknown error");
353 }
354
355 #else  /* ENABLE_IPV6 */
356
357 struct gaiwt_context {
358   const char *node;
359   const char *service;
360   const struct addrinfo *hints;
361   struct addrinfo **res;
362   int exit_code;
363 };
364
365 static void
366 getaddrinfo_with_timeout_callback (void *arg)
367 {
368   struct gaiwt_context *ctx = (struct gaiwt_context *)arg;
369   ctx->exit_code = getaddrinfo (ctx->node, ctx->service, ctx->hints, ctx->res);
370 }
371
372 /* Just like getaddrinfo, except it times out after TIMEOUT seconds.
373    In case of timeout, the EAI_SYSTEM error code is returned and errno
374    is set to ETIMEDOUT.  */
375
376 static int
377 getaddrinfo_with_timeout (const char *node, const char *service,
378                           const struct addrinfo *hints, struct addrinfo **res,
379                           double timeout)
380 {
381   struct gaiwt_context ctx;
382   ctx.node = node;
383   ctx.service = service;
384   ctx.hints = hints;
385   ctx.res = res;
386
387   if (run_with_timeout (timeout, getaddrinfo_with_timeout_callback, &ctx))
388     {
389       errno = ETIMEDOUT;
390       return EAI_SYSTEM;
391     }
392   return ctx.exit_code;
393 }
394
395 #endif /* ENABLE_IPV6 */
396 \f
397 /* Pretty-print ADDR.  When compiled without IPv6, this is the same as
398    inet_ntoa.  With IPv6, it either prints an IPv6 address or an IPv4
399    address.  */
400
401 const char *
402 pretty_print_address (const ip_address *addr)
403 {
404   switch (addr->type) 
405     {
406     case IPV4_ADDRESS:
407       return inet_ntoa (ADDRESS_IPV4_IN_ADDR (addr));
408 #ifdef ENABLE_IPV6
409     case IPV6_ADDRESS:
410       {
411         static char buf[128];
412         inet_ntop (AF_INET6, &ADDRESS_IPV6_IN6_ADDR (addr), buf, sizeof (buf));
413 #if 0
414 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
415         {
416           /* append "%SCOPE_ID" for all ?non-global? addresses */
417           char *p = buf + strlen (buf);
418           *p++ = '%';
419           number_to_string (p, ADDRESS_IPV6_SCOPE (addr));
420         }
421 #endif
422 #endif
423         buf[sizeof (buf) - 1] = '\0';
424         return buf;
425       }
426 #endif
427     }
428   abort ();
429   return NULL;
430 }
431
432 /* The following two functions were adapted from glibc. */
433
434 static int
435 is_valid_ipv4_address (const char *str, const char *end)
436 {
437   int saw_digit = 0;
438   int octets = 0;
439   int val = 0;
440
441   while (str < end)
442     {
443       int ch = *str++;
444
445       if (ch >= '0' && ch <= '9')
446         {
447           val = val * 10 + (ch - '0');
448
449           if (val > 255)
450             return 0;
451           if (saw_digit == 0)
452             {
453               if (++octets > 4)
454                 return 0;
455               saw_digit = 1;
456             }
457         }
458       else if (ch == '.' && saw_digit == 1)
459         {
460           if (octets == 4)
461             return 0;
462           val = 0;
463           saw_digit = 0;
464         }
465       else
466         return 0;
467     }
468   if (octets < 4)
469     return 0;
470   
471   return 1;
472 }
473
474 int
475 is_valid_ipv6_address (const char *str, const char *end)
476 {
477   enum {
478     NS_INADDRSZ  = 4,
479     NS_IN6ADDRSZ = 16,
480     NS_INT16SZ   = 2
481   };
482
483   const char *curtok;
484   int tp;
485   const char *colonp;
486   int saw_xdigit;
487   unsigned int val;
488
489   tp = 0;
490   colonp = NULL;
491
492   if (str == end)
493     return 0;
494   
495   /* Leading :: requires some special handling. */
496   if (*str == ':')
497     {
498       ++str;
499       if (str == end || *str != ':')
500         return 0;
501     }
502
503   curtok = str;
504   saw_xdigit = 0;
505   val = 0;
506
507   while (str < end)
508     {
509       int ch = *str++;
510
511       /* if ch is a number, add it to val. */
512       if (ISXDIGIT (ch))
513         {
514           val <<= 4;
515           val |= XDIGIT_TO_NUM (ch);
516           if (val > 0xffff)
517             return 0;
518           saw_xdigit = 1;
519           continue;
520         }
521
522       /* if ch is a colon ... */
523       if (ch == ':')
524         {
525           curtok = str;
526           if (saw_xdigit == 0)
527             {
528               if (colonp != NULL)
529                 return 0;
530               colonp = str + tp;
531               continue;
532             }
533           else if (str == end)
534             return 0;
535           if (tp > NS_IN6ADDRSZ - NS_INT16SZ)
536             return 0;
537           tp += NS_INT16SZ;
538           saw_xdigit = 0;
539           val = 0;
540           continue;
541         }
542
543       /* if ch is a dot ... */
544       if (ch == '.' && (tp <= NS_IN6ADDRSZ - NS_INADDRSZ)
545           && is_valid_ipv4_address (curtok, end) == 1)
546         {
547           tp += NS_INADDRSZ;
548           saw_xdigit = 0;
549           break;
550         }
551     
552       return 0;
553     }
554
555   if (saw_xdigit == 1)
556     {
557       if (tp > NS_IN6ADDRSZ - NS_INT16SZ) 
558         return 0;
559       tp += NS_INT16SZ;
560     }
561
562   if (colonp != NULL)
563     {
564       if (tp == NS_IN6ADDRSZ) 
565         return 0;
566       tp = NS_IN6ADDRSZ;
567     }
568
569   if (tp != NS_IN6ADDRSZ)
570     return 0;
571
572   return 1;
573 }
574 \f
575 /* Simple host cache, used by lookup_host to speed up resolving.  The
576    cache doesn't handle TTL because Wget is a fairly short-lived
577    application.  Refreshing is attempted when connect fails, though --
578    see connect_to_host.  */
579
580 /* Mapping between known hosts and to lists of their addresses. */
581 static struct hash_table *host_name_addresses_map;
582
583
584 /* Return the host's resolved addresses from the cache, if
585    available.  */
586
587 static struct address_list *
588 cache_query (const char *host)
589 {
590   struct address_list *al;
591   if (!host_name_addresses_map)
592     return NULL;
593   al = hash_table_get (host_name_addresses_map, host);
594   if (al)
595     {
596       DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al));
597       ++al->refcount;
598       return al;
599     }
600   return NULL;
601 }
602
603 /* Cache the DNS lookup of HOST.  Subsequent invocations of
604    lookup_host will return the cached value.  */
605
606 static void
607 cache_store (const char *host, struct address_list *al)
608 {
609   if (!host_name_addresses_map)
610     host_name_addresses_map = make_nocase_string_hash_table (0);
611
612   ++al->refcount;
613   hash_table_put (host_name_addresses_map, xstrdup_lower (host), al);
614
615 #ifdef ENABLE_DEBUG
616   if (opt.debug)
617     {
618       int i;
619       debug_logprintf ("Caching %s =>", host);
620       for (i = 0; i < al->count; i++)
621         debug_logprintf (" %s", pretty_print_address (al->addresses + i));
622       debug_logprintf ("\n");
623     }
624 #endif
625 }
626
627 /* Remove HOST from the DNS cache.  Does nothing is HOST is not in
628    the cache.  */
629
630 static void
631 cache_remove (const char *host)
632 {
633   struct address_list *al;
634   if (!host_name_addresses_map)
635     return;
636   al = hash_table_get (host_name_addresses_map, host);
637   if (al)
638     {
639       address_list_release (al);
640       hash_table_remove (host_name_addresses_map, host);
641     }
642 }
643 \f
644 /* Look up HOST in DNS and return a list of IP addresses.  The
645    addresses in the list are in the same order in which
646    gethostbyname/getaddrinfo returned them.
647
648    This function caches its result so that, if the same host is passed
649    the second time, the addresses are returned without DNS lookup.
650    (Use LH_REFRESH to force lookup, or set opt.dns_cache to 0 to
651    globally disable caching.)
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   int silent = flags & LH_SILENT;
666   int use_cache;
667   int numeric_address = 0;
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 = 1;
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 = 0;
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       {
741         hints.ai_family = AF_UNSPEC;
742 #ifdef AI_ADDRCONFIG
743         hints.ai_flags |= AI_ADDRCONFIG;
744 #else
745         /* On systems without AI_ADDRCONFIG, emulate it by manually
746            checking whether the system supports IPv6 sockets.  */
747         if (!socket_has_inet6 ())
748           hints.ai_family = AF_INET;
749 #endif
750       }
751     if (flags & LH_BIND)
752       hints.ai_flags |= AI_PASSIVE;
753
754 #ifdef AI_NUMERICHOST
755     if (numeric_address)
756       {
757         /* Where available, the AI_NUMERICHOST hint can prevent costly
758            access to DNS servers.  */
759         hints.ai_flags |= AI_NUMERICHOST;
760         timeout = 0;            /* no timeout needed when "resolving"
761                                    numeric hosts -- avoid setting up
762                                    signal handlers and such. */
763       }
764 #endif
765
766     err = getaddrinfo_with_timeout (host, NULL, &hints, &res, timeout);
767     if (err != 0 || res == NULL)
768       {
769         if (!silent)
770           logprintf (LOG_VERBOSE, _("failed: %s.\n"),
771                      err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno));
772         return NULL;
773       }
774     al = address_list_from_addrinfo (res);
775     freeaddrinfo (res);
776     if (!al)
777       {
778         logprintf (LOG_VERBOSE,
779                    _("failed: No IPv4/IPv6 addresses for host.\n"));
780         return NULL;
781       }
782   }
783 #else  /* not ENABLE_IPV6 */
784   {
785     struct hostent *hptr = gethostbyname_with_timeout (host, timeout);
786     if (!hptr)
787       {
788         if (!silent)
789           {
790             if (errno != ETIMEDOUT)
791               logprintf (LOG_VERBOSE, _("failed: %s.\n"),
792                          host_errstr (h_errno));
793             else
794               logputs (LOG_VERBOSE, _("failed: timed out.\n"));
795           }
796         return NULL;
797       }
798     /* Do older systems have h_addr_list?  */
799     al = address_list_from_ipv4_addresses (hptr->h_addr_list);
800   }
801 #endif /* not ENABLE_IPV6 */
802
803   /* Print the addresses determined by DNS lookup, but no more than
804      three.  */
805   if (!silent && !numeric_address)
806     {
807       int i;
808       int printmax = al->count <= 3 ? al->count : 3;
809       for (i = 0; i < printmax; i++)
810         {
811           logprintf (LOG_VERBOSE, "%s",
812                      pretty_print_address (al->addresses + i));
813           if (i < printmax - 1)
814             logputs (LOG_VERBOSE, ", ");
815         }
816       if (printmax != al->count)
817         logputs (LOG_VERBOSE, ", ...");
818       logputs (LOG_VERBOSE, "\n");
819     }
820
821   /* Cache the lookup information. */
822   if (use_cache)
823     cache_store (host, al);
824
825   return al;
826 }
827 \f
828 /* Determine whether a URL is acceptable to be followed, according to
829    a list of domains to accept.  */
830 int
831 accept_domain (struct url *u)
832 {
833   assert (u->host != NULL);
834   if (opt.domains)
835     {
836       if (!sufmatch ((const char **)opt.domains, u->host))
837         return 0;
838     }
839   if (opt.exclude_domains)
840     {
841       if (sufmatch ((const char **)opt.exclude_domains, u->host))
842         return 0;
843     }
844   return 1;
845 }
846
847 /* Check whether WHAT is matched in LIST, each element of LIST being a
848    pattern to match WHAT against, using backward matching (see
849    match_backwards() in utils.c).
850
851    If an element of LIST matched, 1 is returned, 0 otherwise.  */
852 int
853 sufmatch (const char **list, const char *what)
854 {
855   int i, j, k, lw;
856
857   lw = strlen (what);
858   for (i = 0; list[i]; i++)
859     {
860       for (j = strlen (list[i]), k = lw; j >= 0 && k >= 0; j--, k--)
861         if (TOLOWER (list[i][j]) != TOLOWER (what[k]))
862           break;
863       /* The domain must be first to reach to beginning.  */
864       if (j == -1)
865         return 1;
866     }
867   return 0;
868 }
869
870 static int
871 host_cleanup_mapper (void *key, void *value, void *arg_ignored)
872 {
873   struct address_list *al;
874
875   xfree (key);                  /* host */
876
877   al = (struct address_list *)value;
878   assert (al->refcount == 1);
879   address_list_delete (al);
880
881   return 0;
882 }
883
884 void
885 host_cleanup (void)
886 {
887   if (host_name_addresses_map)
888     {
889       hash_table_map (host_name_addresses_map, host_cleanup_mapper, NULL);
890       hash_table_destroy (host_name_addresses_map);
891       host_name_addresses_map = NULL;
892     }
893 }