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