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