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