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