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