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