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