]> sjero.net Git - wget/blob - src/host.c
[svn] Add support for -4/-6.
[wget] / src / host.c
1 /* Host name resolution and matching.
2    Copyright (C) 1995, 1996, 1997, 2000, 2001 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10
11 GNU Wget is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables.  You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL".  If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so.  If you do not wish to do
28 so, delete this exception statement from your version.  */
29
30 #include <config.h>
31
32 #ifndef WINDOWS
33 #include <netdb.h>
34 #endif
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #ifdef HAVE_STRING_H
39 # include <string.h>
40 #else
41 # include <strings.h>
42 #endif
43 #include <assert.h>
44 #include <sys/types.h>
45
46 #ifdef WINDOWS
47 # include <winsock.h>
48 # define SET_H_ERRNO(err) WSASetLastError (err)
49 #else
50 # include <sys/socket.h>
51 # include <netinet/in.h>
52 # ifndef __BEOS__
53 #  include <arpa/inet.h>
54 # endif
55 # include <netdb.h>
56 # define SET_H_ERRNO(err) ((void)(h_errno = (err)))
57 #endif /* WINDOWS */
58
59 #ifndef NO_ADDRESS
60 # define NO_ADDRESS NO_DATA
61 #endif
62
63 #include <errno.h>
64
65 #include "wget.h"
66 #include "utils.h"
67 #include "host.h"
68 #include "url.h"
69 #include "hash.h"
70
71 #ifndef errno
72 extern int errno;
73 #endif
74
75 #ifndef h_errno
76 # ifndef __CYGWIN__
77 extern int h_errno;
78 # endif
79 #endif
80
81 /* Lists of IP addresses that result from running DNS queries.  See
82    lookup_host for details.  */
83
84 struct address_list {
85   int count;                    /* number of adrresses */
86   ip_address *addresses;        /* pointer to the string of addresses */
87
88   int faulty;                   /* number of addresses known not to work. */
89   int connected;                /* whether we were able to connect to
90                                    one of the addresses in the list,
91                                    at least once. */
92
93   int refcount;                 /* reference count; when it drops to
94                                    0, the entry is freed. */
95 };
96
97 /* Get the bounds of the address list.  */
98
99 void
100 address_list_get_bounds (const struct address_list *al, int *start, int *end)
101 {
102   *start = al->faulty;
103   *end   = al->count;
104 }
105
106 /* Return a pointer to the address at position POS.  */
107
108 const ip_address *
109 address_list_address_at (const struct address_list *al, int pos)
110 {
111   assert (pos >= al->faulty && pos < al->count);
112   return al->addresses + pos;
113 }
114
115 /* Return 1 if IP is one of the addresses in AL. */
116
117 int
118 address_list_find (const struct address_list *al, const ip_address *ip)
119 {
120   int i;
121   switch (ip->type)
122     {
123     case IPV4_ADDRESS:
124       for (i = 0; i < al->count; i++)
125         {
126           ip_address *cur = al->addresses + i;
127           if (cur->type == IPV4_ADDRESS
128               && (ADDRESS_IPV4_IN_ADDR (cur).s_addr
129                   ==
130                   ADDRESS_IPV4_IN_ADDR (ip).s_addr))
131             return 1;
132         }
133       return 0;
134 #ifdef ENABLE_IPV6
135     case IPV6_ADDRESS:
136       for (i = 0; i < al->count; i++)
137         {
138           ip_address *cur = al->addresses + i;
139           if (cur->type == IPV6_ADDRESS
140 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
141               && ADDRESS_IPV6_SCOPE (cur) == ADDRESS_IPV6_SCOPE (ip)
142 #endif
143               && IN6_ARE_ADDR_EQUAL (&ADDRESS_IPV6_IN6_ADDR (cur),
144                                      &ADDRESS_IPV6_IN6_ADDR (ip)))
145             return 1;
146         }
147       return 0;
148 #endif /* ENABLE_IPV6 */
149     default:
150       abort ();
151       return 1;
152     }
153 }
154
155 /* Mark the INDEXth element of AL as faulty, so that the next time
156    this address list is used, the faulty element will be skipped.  */
157
158 void
159 address_list_set_faulty (struct address_list *al, int index)
160 {
161   /* We assume that the address list is traversed in order, so that a
162      "faulty" attempt is always preceded with all-faulty addresses,
163      and this is how Wget uses it.  */
164   assert (index == al->faulty);
165
166   ++al->faulty;
167   if (al->faulty >= al->count)
168     /* All addresses have been proven faulty.  Since there's not much
169        sense in returning the user an empty address list the next
170        time, we'll rather make them all clean, so that they can be
171        retried anew.  */
172     al->faulty = 0;
173 }
174
175 /* Set the "connected" flag to true.  This flag used by connect.c to
176    see if the host perhaps needs to be resolved again.  */
177
178 void
179 address_list_set_connected (struct address_list *al)
180 {
181   al->connected = 1;
182 }
183
184 /* Return the value of the "connected" flag. */
185
186 int
187 address_list_connected_p (const struct address_list *al)
188 {
189   return al->connected;
190 }
191
192 #ifdef ENABLE_IPV6
193
194 /* Create an address_list from the addresses in the given struct
195    addrinfo.  */
196
197 static struct address_list *
198 address_list_from_addrinfo (const struct addrinfo *ai)
199 {
200   struct address_list *al;
201   const struct addrinfo *ptr;
202   int cnt;
203   ip_address *ip;
204
205   cnt = 0;
206   for (ptr = ai; ptr != NULL ; ptr = ptr->ai_next)
207     if (ptr->ai_family == AF_INET || ptr->ai_family == AF_INET6)
208       ++cnt;
209   if (cnt == 0)
210     return NULL;
211
212   al = xnew0 (struct address_list);
213   al->addresses  = xnew_array (ip_address, cnt);
214   al->count      = cnt;
215   al->refcount   = 1;
216
217   ip = al->addresses;
218   for (ptr = ai; ptr != NULL; ptr = ptr->ai_next)
219     if (ptr->ai_family == AF_INET6) 
220       {
221         const struct sockaddr_in6 *sin6 =
222           (const struct sockaddr_in6 *)ptr->ai_addr;
223         ip->type = IPV6_ADDRESS;
224         ADDRESS_IPV6_IN6_ADDR (ip) = sin6->sin6_addr;
225 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
226         ADDRESS_IPV6_SCOPE (ip) = sin6->sin6_scope_id;
227 #endif
228         ++ip;
229       } 
230     else if (ptr->ai_family == AF_INET)
231       {
232         const struct sockaddr_in *sin =
233           (const struct sockaddr_in *)ptr->ai_addr;
234         ip->type = IPV4_ADDRESS;
235         ADDRESS_IPV4_IN_ADDR (ip) = sin->sin_addr;
236         ++ip;
237       }
238   assert (ip - al->addresses == cnt);
239   return al;
240 }
241
242 #else  /* not ENABLE_IPV6 */
243
244 /* Create an address_list from a NULL-terminated vector of IPv4
245    addresses.  This kind of vector is returned by gethostbyname.  */
246
247 static struct address_list *
248 address_list_from_ipv4_addresses (char **vec)
249 {
250   int count, i;
251   struct address_list *al = xnew0 (struct address_list);
252
253   count = 0;
254   while (vec[count])
255     ++count;
256   assert (count > 0);
257
258   al->addresses = xnew_array (ip_address, count);
259   al->count     = count;
260   al->refcount  = 1;
261
262   for (i = 0; i < count; i++)
263     {
264       ip_address *ip = &al->addresses[i];
265       ip->type = IPV4_ADDRESS;
266       memcpy (ADDRESS_IPV4_DATA (ip), vec[i], 4);
267     }
268
269   return al;
270 }
271
272 #endif /* not ENABLE_IPV6 */
273
274 static void
275 address_list_delete (struct address_list *al)
276 {
277   xfree (al->addresses);
278   xfree (al);
279 }
280
281 /* Mark the address list as being no longer in use.  This will reduce
282    its reference count which will cause the list to be freed when the
283    count reaches 0.  */
284
285 void
286 address_list_release (struct address_list *al)
287 {
288   --al->refcount;
289   DEBUGP (("Releasing %p (new refcount %d).\n", al, al->refcount));
290   if (al->refcount <= 0)
291     {
292       DEBUGP (("Deleting unused %p.\n", al));
293       address_list_delete (al);
294     }
295 }
296 \f
297 /* Versions of gethostbyname and getaddrinfo that support timeout. */
298
299 #ifndef ENABLE_IPV6
300
301 struct ghbnwt_context {
302   const char *host_name;
303   struct hostent *hptr;
304 };
305
306 static void
307 gethostbyname_with_timeout_callback (void *arg)
308 {
309   struct ghbnwt_context *ctx = (struct ghbnwt_context *)arg;
310   ctx->hptr = gethostbyname (ctx->host_name);
311 }
312
313 /* Just like gethostbyname, except it times out after TIMEOUT seconds.
314    In case of timeout, NULL is returned and errno is set to ETIMEDOUT.
315    The function makes sure that when NULL is returned for reasons
316    other than timeout, errno is reset.  */
317
318 static struct hostent *
319 gethostbyname_with_timeout (const char *host_name, double timeout)
320 {
321   struct ghbnwt_context ctx;
322   ctx.host_name = host_name;
323   if (run_with_timeout (timeout, gethostbyname_with_timeout_callback, &ctx))
324     {
325       SET_H_ERRNO (HOST_NOT_FOUND);
326       errno = ETIMEDOUT;
327       return NULL;
328     }
329   if (!ctx.hptr)
330     errno = 0;
331   return ctx.hptr;
332 }
333
334 /* Print error messages for host errors.  */
335 static char *
336 host_errstr (int error)
337 {
338   /* Can't use switch since some of these constants can be equal,
339      which makes the compiler complain about duplicate case
340      values.  */
341   if (error == HOST_NOT_FOUND
342       || error == NO_RECOVERY
343       || error == NO_DATA
344       || error == NO_ADDRESS)
345     return _("Unknown host");
346   else if (error == TRY_AGAIN)
347     /* Message modeled after what gai_strerror returns in similar
348        circumstances.  */
349     return _("Temporary failure in name resolution");
350   else
351     return _("Unknown error");
352 }
353
354 #else  /* ENABLE_IPV6 */
355
356 struct gaiwt_context {
357   const char *node;
358   const char *service;
359   const struct addrinfo *hints;
360   struct addrinfo **res;
361   int exit_code;
362 };
363
364 static void
365 getaddrinfo_with_timeout_callback (void *arg)
366 {
367   struct gaiwt_context *ctx = (struct gaiwt_context *)arg;
368   ctx->exit_code = getaddrinfo (ctx->node, ctx->service, ctx->hints, ctx->res);
369 }
370
371 /* Just like getaddrinfo, except it times out after TIMEOUT seconds.
372    In case of timeout, the EAI_SYSTEM error code is returned and errno
373    is set to ETIMEDOUT.  */
374
375 static int
376 getaddrinfo_with_timeout (const char *node, const char *service,
377                           const struct addrinfo *hints, struct addrinfo **res,
378                           double timeout)
379 {
380   struct gaiwt_context ctx;
381   ctx.node = node;
382   ctx.service = service;
383   ctx.hints = hints;
384   ctx.res = res;
385
386   if (run_with_timeout (timeout, getaddrinfo_with_timeout_callback, &ctx))
387     {
388       errno = ETIMEDOUT;
389       return EAI_SYSTEM;
390     }
391   return ctx.exit_code;
392 }
393
394 #endif /* ENABLE_IPV6 */
395 \f
396 /* Pretty-print ADDR.  When compiled without IPv6, this is the same as
397    inet_ntoa.  With IPv6, it either prints an IPv6 address or an IPv4
398    address.  */
399
400 const char *
401 pretty_print_address (const ip_address *addr)
402 {
403   switch (addr->type) 
404     {
405     case IPV4_ADDRESS:
406       return inet_ntoa (ADDRESS_IPV4_IN_ADDR (addr));
407 #ifdef ENABLE_IPV6
408     case IPV6_ADDRESS:
409       {
410         static char buf[128];
411         inet_ntop (AF_INET6, &ADDRESS_IPV6_IN6_ADDR (addr), buf, sizeof (buf));
412 #if 0
413 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
414         {
415           /* append "%SCOPE_ID" for all ?non-global? addresses */
416           char *p = buf + strlen (buf);
417           *p++ = '%';
418           number_to_string (p, ADDRESS_IPV6_SCOPE (addr));
419         }
420 #endif
421 #endif
422         buf[sizeof (buf) - 1] = '\0';
423         return buf;
424       }
425 #endif
426     }
427   abort ();
428   return NULL;
429 }
430 \f
431 /* Simple host cache, used by lookup_host to speed up resolving.  The
432    cache doesn't handle TTL because Wget is a fairly short-lived
433    application.  Refreshing is attempted when connect fails, though --
434    see connect_to_host.  */
435
436 /* Mapping between known hosts and to lists of their addresses. */
437 static struct hash_table *host_name_addresses_map;
438
439
440 /* Return the host's resolved addresses from the cache, if
441    available.  */
442
443 static struct address_list *
444 cache_query (const char *host)
445 {
446   struct address_list *al;
447   if (!host_name_addresses_map)
448     return NULL;
449   al = hash_table_get (host_name_addresses_map, host);
450   if (al)
451     {
452       DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al));
453       ++al->refcount;
454       return al;
455     }
456   return NULL;
457 }
458
459 /* Cache the DNS lookup of HOST.  Subsequent invocations of
460    lookup_host will return the cached value.  */
461
462 static void
463 cache_store (const char *host, struct address_list *al)
464 {
465   if (!host_name_addresses_map)
466     host_name_addresses_map = make_nocase_string_hash_table (0);
467
468   ++al->refcount;
469   hash_table_put (host_name_addresses_map, xstrdup_lower (host), al);
470
471 #ifdef ENABLE_DEBUG
472   if (opt.debug)
473     {
474       int i;
475       debug_logprintf ("Caching %s =>", host);
476       for (i = 0; i < al->count; i++)
477         debug_logprintf (" %s", pretty_print_address (al->addresses + i));
478       debug_logprintf ("\n");
479     }
480 #endif
481 }
482
483 /* Remove HOST from the DNS cache.  Does nothing is HOST is not in
484    the cache.  */
485
486 static void
487 cache_remove (const char *host)
488 {
489   struct address_list *al;
490   if (!host_name_addresses_map)
491     return;
492   al = hash_table_get (host_name_addresses_map, host);
493   if (al)
494     {
495       address_list_release (al);
496       hash_table_remove (host_name_addresses_map, host);
497     }
498 }
499 \f
500 /* Look up HOST in DNS and return a list of IP addresses.  The
501    addresses in the list are in the same order in which
502    gethostbyname/getaddrinfo returned them.
503
504    This function caches its result so that, if the same host is passed
505    the second time, the addresses are returned without DNS lookup.  If
506    you want to force lookup, call forget_host_lookup() prior to this
507    function, or set opt.dns_cache to 0 to globally disable caching.
508
509    FLAGS can be a combination of:
510      LH_SILENT  - don't print the "resolving ... done" messages.
511      LH_BIND    - resolve addresses for use with bind, which under
512                   IPv6 means to use AI_PASSIVE flag to getaddrinfo.
513                   Passive lookups are not cached under IPv6.
514      LH_REFRESH - if HOST is cached, remove the entry from the cache
515                   and resolve it anew.  */
516
517 struct address_list *
518 lookup_host (const char *host, int flags)
519 {
520   struct address_list *al = NULL;
521   int silent = flags & LH_SILENT;
522   int use_cache;
523
524 #ifndef ENABLE_IPV6
525   /* If we're not using getaddrinfo, first check if HOST specifies a
526      numeric IPv4 address.  gethostbyname is not required to accept
527      dotted-decimal IPv4 addresses, and some implementations (e.g. the
528      Ultrix one and possibly Winsock) indeed don't.  */
529   {
530     uint32_t addr_ipv4 = (uint32_t)inet_addr (host);
531     if (addr_ipv4 != (uint32_t) -1)
532       {
533         /* No need to cache host->addr relation, just return the
534            address.  */
535         char *vec[2];
536         vec[0] = (char *)&addr_ipv4;
537         vec[1] = NULL;
538         return address_list_from_ipv4_addresses (vec);
539       }
540   }
541 #endif
542
543   /* Cache is normally on, but can be turned off with --no-dns-cache.
544      Don't cache passive lookups under IPv6.  */
545   use_cache = opt.dns_cache;
546 #ifdef ENABLE_IPV6
547   if (flags & LH_BIND)
548     use_cache = 0;
549 #endif
550
551   /* Try to find the host in the cache so we don't need to talk to the
552      resolver.  If LH_REFRESH is requested, remove HOST from the cache
553      instead.  */
554   if (use_cache)
555     {
556       if (!(flags & LH_REFRESH))
557         {
558           al = cache_query (host);
559           if (al)
560             return al;
561         }
562       else
563         cache_remove (host);
564     }
565
566   /* No luck with the cache; resolve HOST. */
567
568   if (!silent)
569     logprintf (LOG_VERBOSE, _("Resolving %s... "), host);
570
571 #ifdef ENABLE_IPV6
572   {
573     int err;
574     struct addrinfo hints, *res;
575
576     xzero (hints);
577     hints.ai_socktype = SOCK_STREAM;
578     hints.ai_family = AF_UNSPEC;
579     if (opt.ipv4_only && !opt.ipv6_only)
580       hints.ai_family = AF_INET;
581     else if (opt.ipv6_only && !opt.ipv4_only)
582       hints.ai_family = AF_INET6;
583
584 #ifdef HAVE_GETADDRINFO_AI_ADDRCONFIG
585     /* Use AI_ADDRCONFIG where available.  See init.c:defaults().  */
586     hints.ai_flags |= AI_ADDRCONFIG;
587 #endif
588     if (flags & LH_BIND)
589       hints.ai_flags |= AI_PASSIVE;
590
591     err = getaddrinfo_with_timeout (host, NULL, &hints, &res, opt.dns_timeout);
592     if (err != 0 || res == NULL)
593       {
594         if (!silent)
595           logprintf (LOG_VERBOSE, _("failed: %s.\n"),
596                      err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno));
597         return NULL;
598       }
599     al = address_list_from_addrinfo (res);
600     freeaddrinfo (res);
601     if (!al)
602       {
603         logprintf (LOG_VERBOSE,
604                    _("failed: No IPv4/IPv6 addresses for host.\n"));
605         return NULL;
606       }
607   }
608 #else
609   {
610     struct hostent *hptr = gethostbyname_with_timeout (host, opt.dns_timeout);
611     if (!hptr)
612       {
613         if (!silent)
614           {
615             if (errno != ETIMEDOUT)
616               logprintf (LOG_VERBOSE, _("failed: %s.\n"),
617                          host_errstr (h_errno));
618             else
619               logputs (LOG_VERBOSE, _("failed: timed out.\n"));
620           }
621         return NULL;
622       }
623     /* Do older systems have h_addr_list?  */
624     al = address_list_from_ipv4_addresses (hptr->h_addr_list);
625   }
626 #endif
627
628   /* Print the addresses determined by DNS lookup, but no more than
629      three.  */
630   if (!silent)
631     {
632       int i;
633       int printmax = al->count <= 3 ? al->count : 3;
634       for (i = 0; i < printmax; i++)
635         {
636           logprintf (LOG_VERBOSE, "%s",
637                      pretty_print_address (al->addresses + i));
638           if (i < printmax - 1)
639             logputs (LOG_VERBOSE, ", ");
640         }
641       if (printmax != al->count)
642         logputs (LOG_VERBOSE, ", ...");
643       logputs (LOG_VERBOSE, "\n");
644     }
645
646   /* Cache the lookup information. */
647   if (use_cache)
648     cache_store (host, al);
649
650   return al;
651 }
652 \f
653 /* Determine whether a URL is acceptable to be followed, according to
654    a list of domains to accept.  */
655 int
656 accept_domain (struct url *u)
657 {
658   assert (u->host != NULL);
659   if (opt.domains)
660     {
661       if (!sufmatch ((const char **)opt.domains, u->host))
662         return 0;
663     }
664   if (opt.exclude_domains)
665     {
666       if (sufmatch ((const char **)opt.exclude_domains, u->host))
667         return 0;
668     }
669   return 1;
670 }
671
672 /* Check whether WHAT is matched in LIST, each element of LIST being a
673    pattern to match WHAT against, using backward matching (see
674    match_backwards() in utils.c).
675
676    If an element of LIST matched, 1 is returned, 0 otherwise.  */
677 int
678 sufmatch (const char **list, const char *what)
679 {
680   int i, j, k, lw;
681
682   lw = strlen (what);
683   for (i = 0; list[i]; i++)
684     {
685       for (j = strlen (list[i]), k = lw; j >= 0 && k >= 0; j--, k--)
686         if (TOLOWER (list[i][j]) != TOLOWER (what[k]))
687           break;
688       /* The domain must be first to reach to beginning.  */
689       if (j == -1)
690         return 1;
691     }
692   return 0;
693 }
694
695 static int
696 host_cleanup_mapper (void *key, void *value, void *arg_ignored)
697 {
698   struct address_list *al;
699
700   xfree (key);                  /* host */
701
702   al = (struct address_list *)value;
703   assert (al->refcount == 1);
704   address_list_delete (al);
705
706   return 0;
707 }
708
709 void
710 host_cleanup (void)
711 {
712   if (host_name_addresses_map)
713     {
714       hash_table_map (host_name_addresses_map, host_cleanup_mapper, NULL);
715       hash_table_destroy (host_name_addresses_map);
716       host_name_addresses_map = NULL;
717     }
718 }