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