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