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