]> sjero.net Git - wget/blob - src/host.c
[svn] Use a more standard error message.
[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   /* If we're not using getaddrinfo, first check if HOST names a
497      numeric IPv4 address.  This was necessary under old (e.g. Ultrix)
498      implementations of gethostbyname that couldn't handle numeric
499      addresses (!).  This is not done under IPv6 because getaddrinfo
500      always handles numeric addresses.  */
501 #ifndef ENABLE_IPV6
502   {
503     uint32_t addr_ipv4 = (uint32_t)inet_addr (host);
504     if (addr_ipv4 != (uint32_t) -1)
505       {
506         /* No need to cache host->addr relation, just return the
507            address.  */
508         char *vec[2];
509         vec[0] = (char *)&addr_ipv4;
510         vec[1] = NULL;
511         return address_list_from_ipv4_addresses (vec);
512       }
513   }
514 #endif
515
516   /* Try to find the host in the cache. */
517
518   if (host_name_addresses_map)
519     {
520       al = hash_table_get (host_name_addresses_map, host);
521       if (al)
522         {
523           DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al));
524           ++al->refcount;
525           return al;
526         }
527     }
528
529   /* No luck with the cache; resolve the host name. */
530
531   if (!silent)
532     logprintf (LOG_VERBOSE, _("Resolving %s... "), host);
533
534 #ifdef ENABLE_IPV6
535   {
536     int err;
537     struct addrinfo hints, *res;
538
539     xzero (hints);
540     hints.ai_socktype = SOCK_STREAM;
541     hints.ai_family = requested_family;
542     hints.ai_flags = 0;
543
544     err = getaddrinfo_with_timeout (host, NULL, &hints, &res, opt.dns_timeout);
545     if (err != 0 || res == NULL)
546       {
547         if (!silent)
548           logprintf (LOG_VERBOSE, _("failed: %s.\n"),
549                      err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno));
550         return NULL;
551       }
552     al = address_list_from_addrinfo (res);
553     freeaddrinfo (res);
554   }
555 #else
556   {
557     struct hostent *hptr = gethostbyname_with_timeout (host, opt.dns_timeout);
558     if (!hptr)
559       {
560         if (!silent)
561           {
562             if (errno != ETIMEDOUT)
563               logprintf (LOG_VERBOSE, _("failed: %s.\n"),
564                          host_errstr (h_errno));
565             else
566               logputs (LOG_VERBOSE, _("failed: timed out.\n"));
567           }
568         return NULL;
569       }
570     /* Do older systems have h_addr_list?  */
571     al = address_list_from_ipv4_addresses (hptr->h_addr_list);
572   }
573 #endif
574
575   /* Print the addresses determined by DNS lookup, but no more than
576      three.  */
577   if (!silent)
578     {
579       int i;
580       int printmax = al->count <= 3 ? al->count : 3;
581       for (i = 0; i < printmax; i++)
582         {
583           logprintf (LOG_VERBOSE, "%s",
584                      pretty_print_address (al->addresses + i));
585           if (i < printmax - 1)
586             logputs (LOG_VERBOSE, ", ");
587         }
588       if (printmax != al->count)
589         logputs (LOG_VERBOSE, ", ...");
590       logputs (LOG_VERBOSE, "\n");
591     }
592
593   /* Cache the lookup information. */
594   if (opt.dns_cache)
595     cache_host_lookup (host, al);
596
597   return al;
598 }
599
600 /* Resolve HOST to get an address for use with bind(2).  Do *not* use
601    this for sockets to be used with connect(2).
602
603    This is a function separate from lookup_host because the results it
604    returns are different -- it uses the AI_PASSIVE flag to
605    getaddrinfo.  Because of this distinction, it doesn't store the
606    results in the cache.  It prints nothing and implements no timeouts
607    because it should normally only be used with local addresses
608    (typically "localhost" or numeric addresses of different local
609    interfaces.)
610
611    Without IPv6, this function just calls lookup_host.  */
612
613 struct address_list *
614 lookup_host_passive (const char *host)
615 {
616 #ifdef ENABLE_IPV6
617   struct address_list *al = NULL;
618   int err;
619   struct addrinfo hints, *res;
620
621   xzero (hints);
622   hints.ai_socktype = SOCK_STREAM;
623   hints.ai_family = requested_family;
624   hints.ai_flags = AI_PASSIVE;
625
626   err = getaddrinfo (host, NULL, &hints, &res);
627   if (err != 0 || res == NULL)
628     return NULL;
629   al = address_list_from_addrinfo (res);
630   freeaddrinfo (res);
631   return al;
632 #else
633   return lookup_host (host, 1);
634 #endif
635 }
636 \f
637 /* Determine whether a URL is acceptable to be followed, according to
638    a list of domains to accept.  */
639 int
640 accept_domain (struct url *u)
641 {
642   assert (u->host != NULL);
643   if (opt.domains)
644     {
645       if (!sufmatch ((const char **)opt.domains, u->host))
646         return 0;
647     }
648   if (opt.exclude_domains)
649     {
650       if (sufmatch ((const char **)opt.exclude_domains, u->host))
651         return 0;
652     }
653   return 1;
654 }
655
656 /* Check whether WHAT is matched in LIST, each element of LIST being a
657    pattern to match WHAT against, using backward matching (see
658    match_backwards() in utils.c).
659
660    If an element of LIST matched, 1 is returned, 0 otherwise.  */
661 int
662 sufmatch (const char **list, const char *what)
663 {
664   int i, j, k, lw;
665
666   lw = strlen (what);
667   for (i = 0; list[i]; i++)
668     {
669       for (j = strlen (list[i]), k = lw; j >= 0 && k >= 0; j--, k--)
670         if (TOLOWER (list[i][j]) != TOLOWER (what[k]))
671           break;
672       /* The domain must be first to reach to beginning.  */
673       if (j == -1)
674         return 1;
675     }
676   return 0;
677 }
678
679 static int
680 host_cleanup_mapper (void *key, void *value, void *arg_ignored)
681 {
682   struct address_list *al;
683
684   xfree (key);                  /* host */
685
686   al = (struct address_list *)value;
687   assert (al->refcount == 1);
688   address_list_delete (al);
689
690   return 0;
691 }
692
693 void
694 host_cleanup (void)
695 {
696   if (host_name_addresses_map)
697     {
698       hash_table_map (host_name_addresses_map, host_cleanup_mapper, NULL);
699       hash_table_destroy (host_name_addresses_map);
700       host_name_addresses_map = NULL;
701     }
702 }