]> sjero.net Git - wget/blob - src/host.c
[svn] Update the license to include the OpenSSL exception.
[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 INET6
85 int     ip_default_family = AF_INET6;
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 refcount;                 /* so we know whether to free it or not. */
103 };
104
105 /* Get the bounds of the address list.  */
106
107 void
108 address_list_get_bounds (struct address_list *al, int *start, int *end)
109 {
110   *start = al->faulty;
111   *end   = al->count;
112 }
113
114 /* Copy address number INDEX to IP_STORE.  */
115
116 void
117 address_list_copy_one (struct address_list *al, int index, ip_address *ip_store)
118 {
119   assert (index >= al->faulty && index < al->count);
120   memcpy (ip_store, al->addresses + index, sizeof (ip_address));
121 }
122
123 /* Check whether two address lists have all their IPs in common.  */
124
125 int
126 address_list_match_all (struct address_list *al1, struct address_list *al2)
127 {
128   if (al1 == al2)
129     return 1;
130   if (al1->count != al2->count)
131     return 0;
132   return 0 == memcmp (al1->addresses, al2->addresses,
133                       al1->count * sizeof (ip_address));
134 }
135
136 /* Mark the INDEXth element of AL as faulty, so that the next time
137    this address list is used, the faulty element will be skipped.  */
138
139 void
140 address_list_set_faulty (struct address_list *al, int index)
141 {
142   /* We assume that the address list is traversed in order, so that a
143      "faulty" attempt is always preceded with all-faulty addresses,
144      and this is how Wget uses it.  */
145   assert (index == al->faulty);
146
147   ++al->faulty;
148   if (al->faulty >= al->count)
149     /* All addresses have been proven faulty.  Since there's not much
150        sense in returning the user an empty address list the next
151        time, we'll rather make them all clean, so that they can be
152        retried anew.  */
153     al->faulty = 0;
154 }
155
156 #ifdef INET6
157 /**
158   * address_list_from_addrinfo
159   *
160   * This function transform an addrinfo links list in and address_list.
161   *
162   * Input:
163   * addrinfo*           Linkt list of addrinfo
164   *
165   * Output:
166   * address_list*       New allocated address_list
167   */
168 static struct address_list *
169 address_list_from_addrinfo (struct addrinfo *ai)
170 {
171   struct address_list *al;
172   struct addrinfo *ai_head = ai;
173   int cnt = 0;
174   int i;
175
176   for (ai = ai_head; ai; ai = ai->ai_next)
177     if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6)
178       ++cnt;
179   if (cnt == 0)
180     return NULL;
181
182   al = xmalloc (sizeof (struct address_list));
183   al->addresses = xmalloc (cnt * sizeof (ip_address));
184   al->count     = cnt;
185   al->faulty    = 0;
186   al->refcount  = 1;
187
188   for (i = 0, ai = ai_head; ai; ai = ai->ai_next)
189     if (ai->ai_family == AF_INET6) 
190       {
191         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
192         memcpy (al->addresses + i, &sin6->sin6_addr, 16);
193         ++i;
194       } 
195     else if (ai->ai_family == AF_INET)
196       {
197         struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
198         map_ipv4_to_ip ((ip4_address *)&sin->sin_addr, al->addresses + i);
199         ++i;
200       }
201   assert (i == cnt);
202   return al;
203 }
204 #else
205 /* Create an address_list out of a NULL-terminated list of addresses,
206    as returned by gethostbyname.  */
207 static struct address_list *
208 address_list_new (char **h_addr_list)
209 {
210   int count = 0, i;
211
212   struct address_list *al = xmalloc (sizeof (struct address_list));
213
214   while (h_addr_list[count])
215     ++count;
216   assert (count > 0);
217   al->count     = count;
218   al->faulty    = 0;
219   al->addresses = xmalloc (count * sizeof (ip_address));
220   al->refcount  = 1;
221
222   for (i = 0; i < count; i++)
223     map_ipv4_to_ip ((ip4_address *)h_addr_list[i], al->addresses + i);
224
225   return al;
226 }
227 #endif
228
229 /* Like address_list_new, but initialized with only one address. */
230
231 static struct address_list *
232 address_list_new_one (ip_address *addr)
233 {
234   struct address_list *al = xmalloc (sizeof (struct address_list));
235   al->count     = 1;
236   al->faulty    = 0;
237   al->addresses = xmalloc (sizeof (ip_address));
238   al->refcount  = 1;
239   memcpy (al->addresses, addr, sizeof (ip_address));
240
241   return al;
242 }
243
244 static void
245 address_list_delete (struct address_list *al)
246 {
247   xfree (al->addresses);
248   xfree (al);
249 }
250
251 void
252 address_list_release (struct address_list *al)
253 {
254   --al->refcount;
255   DEBUGP (("Releasing %p (new refcount %d).\n", al, al->refcount));
256   if (al->refcount <= 0)
257     {
258       DEBUGP (("Deleting unused %p.\n", al));
259       address_list_delete (al);
260     }
261 }
262 \f
263 /**
264   * wget_sockaddr_set_address
265   *
266   * This function takes an wget_sockaddr and fill in the protocol type,
267   * the port number and the address, there NULL in address means wildcard.
268   * Unsuported adress family will abort the whole programm.
269   *
270   * Input:
271   * wget_sockaddr*      The space to be filled
272   * int                 The wished protocol
273   * unsigned short      The port
274   * const ip_address    The Binary IP adress
275   *
276   * Return:
277   * -                   Only modify 1. param
278   */
279 void
280 wget_sockaddr_set_address (wget_sockaddr *sa, 
281                            int ip_family, unsigned short port, ip_address *addr)
282 {
283   if (ip_family == AF_INET) 
284     {
285       sa->sin.sin_family = ip_family;
286       sa->sin.sin_port = htons (port);
287       if (addr == NULL) 
288         memset (&sa->sin.sin_addr, 0,      sizeof(ip4_address));
289       else
290         {
291           ip4_address addr4;
292           if (!map_ip_to_ipv4 (addr, &addr4))
293             /* should the callers have prevented this? */
294             abort ();
295           memcpy (&sa->sin.sin_addr, &addr4, sizeof(ip4_address));
296         }
297       return;
298     }
299 #ifdef INET6
300   if (ip_family == AF_INET6) 
301     {
302       sa->sin6.sin6_family = ip_family;
303       sa->sin6.sin6_port = htons (port);
304       if (addr == NULL) 
305         memset (&sa->sin6.sin6_addr, 0   , 16);
306       else           
307         memcpy (&sa->sin6.sin6_addr, addr, 16);
308       return;
309     }
310 #endif  
311   abort();
312 }
313
314 /**
315   * wget_sockaddr_set_port
316   *
317   * This funtion only fill the port of the socket information.
318   * If the protocol is not supported nothing is done.
319   * Unsuported adress family will abort the whole programm.
320   * 
321   * Require:
322   * that the IP-Protocol already is set.
323   *
324   * Input:
325   * wget_sockaddr*      The space there port should be entered
326   * unsigned int        The port that should be entered in host order
327   *
328   * Return:
329   * -                   Only modify 1. param
330   */
331 void 
332 wget_sockaddr_set_port (wget_sockaddr *sa, unsigned short port)
333 {
334   if (sa->sa.sa_family == AF_INET)
335     {
336       sa->sin.sin_port = htons (port);
337       return;
338     }  
339 #ifdef INET6
340   if (sa->sa.sa_family == AF_INET6)
341     {
342       sa->sin6.sin6_port = htons (port);
343       return;
344     }
345 #endif
346   abort();
347 }
348
349 /**
350   * wget_sockaddr_get_addr
351   *
352   * This function return the adress from an sockaddr as byte string.
353   * Unsuported adress family will abort the whole programm.
354   * 
355   * Require:
356   * that the IP-Protocol already is set.
357   *
358   * Input:
359   * wget_sockaddr*      Socket Information
360   *
361   * Output:
362   * unsigned char *     IP address as byte string.
363   */
364 void *
365 wget_sockaddr_get_addr (wget_sockaddr *sa)
366
367   if (sa->sa.sa_family == AF_INET)
368     return &sa->sin.sin_addr;
369 #ifdef INET6
370   if (sa->sa.sa_family == AF_INET6)
371     return &sa->sin6.sin6_addr;
372 #endif
373   abort();
374   /* unreached */
375   return NULL;
376 }
377
378 /**
379   * wget_sockaddr_get_port
380   *
381   * This function only return the port from the input structure
382   * Unsuported adress family will abort the whole programm.
383   * 
384   * Require:
385   * that the IP-Protocol already is set.
386   *
387   * Input:
388   * wget_sockaddr*      Information where to get the port
389   *
390   * Output:
391   * unsigned short      Port Number in host order.
392   */
393 unsigned short 
394 wget_sockaddr_get_port (const wget_sockaddr *sa)
395 {
396   if (sa->sa.sa_family == AF_INET)
397       return htons (sa->sin.sin_port);
398 #ifdef INET6
399   if (sa->sa.sa_family == AF_INET6)
400       return htons (sa->sin6.sin6_port);
401 #endif
402   abort();
403   /* do not complain about return nothing */
404   return -1;
405 }
406
407 /**
408   * sockaddr_len
409   *
410   * This function return the length of the sockaddr corresponding to 
411   * the acutall prefered protocol for (bind, connect etc...)
412   * Unsuported adress family will abort the whole programm.
413   * 
414   * Require:
415   * that the IP-Protocol already is set.
416   *
417   * Input:
418   * -           Public IP-Family Information
419   *
420   * Output:
421   * int         structure length for socket options
422   */
423 int 
424 sockaddr_len () 
425 {
426   if (ip_default_family == AF_INET) 
427     return sizeof (struct sockaddr_in);
428 #ifdef INET6
429   if (ip_default_family == AF_INET6) 
430     return sizeof (struct sockaddr_in6);
431 #endif
432   abort();
433   /* do not complain about return nothing */
434   return 0;
435 }
436
437 /**
438   * Map an IPv4 adress to the internal adress format.
439   */
440 void 
441 map_ipv4_to_ip (ip4_address *ipv4, ip_address *ip) 
442 {
443 #ifdef INET6
444   static unsigned char ipv64[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
445   memcpy ((char *)ip + 12, ipv4 , 4);
446   memcpy ((char *)ip + 0, ipv64, 12);
447 #else
448   if ((char *)ip != (char *)ipv4)
449     memcpy (ip, ipv4, 4);
450 #endif
451 }
452
453 /* Detect whether an IP adress represents an IPv4 address and, if so,
454    copy it to IPV4.  0 is returned on failure.
455    This operation always succeeds when Wget is compiled without IPv6.
456    If IPV4 is NULL, don't copy, just detect.  */
457
458 int 
459 map_ip_to_ipv4 (ip_address *ip, ip4_address *ipv4) 
460 {
461 #ifdef INET6
462   static unsigned char ipv64[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
463   if (0 != memcmp (ip, ipv64, 12))
464     return 0;
465   if (ipv4)
466     memcpy (ipv4, (char *)ip + 12, 4);
467 #else
468   if (ipv4)
469     memcpy (ipv4, (char *)ip, 4);
470 #endif
471   return 1;
472 }
473 \f
474 /* Versions of gethostbyname and getaddrinfo that support timeout. */
475
476 #ifndef INET6
477
478 struct ghbnwt_context {
479   const char *host_name;
480   struct hostent *hptr;
481 };
482
483 static void
484 gethostbyname_with_timeout_callback (void *arg)
485 {
486   struct ghbnwt_context *ctx = (struct ghbnwt_context *)arg;
487   ctx->hptr = gethostbyname (ctx->host_name);
488 }
489
490 /* Just like gethostbyname, except it times out after TIMEOUT seconds.
491    In case of timeout, NULL is returned and errno is set to ETIMEDOUT.
492    The function makes sure that when NULL is returned for reasons
493    other than timeout, errno is reset.  */
494
495 static struct hostent *
496 gethostbyname_with_timeout (const char *host_name, int timeout)
497 {
498   struct ghbnwt_context ctx;
499   ctx.host_name = host_name;
500   if (run_with_timeout (timeout, gethostbyname_with_timeout_callback, &ctx))
501     {
502       SET_H_ERRNO (HOST_NOT_FOUND);
503       errno = ETIMEDOUT;
504       return NULL;
505     }
506   if (!ctx.hptr)
507     errno = 0;
508   return ctx.hptr;
509 }
510
511 #else  /* INET6 */
512
513 struct gaiwt_context {
514   const char *node;
515   const char *service;
516   const struct addrinfo *hints;
517   struct addrinfo **res;
518   int exit_code;
519 };
520
521 static void
522 getaddrinfo_with_timeout_callback (void *arg)
523 {
524   struct gaiwt_context *ctx = (struct gaiwt_context *)arg;
525   ctx->exit_code = getaddrinfo (ctx->node, ctx->service, ctx->hints, ctx->res);
526 }
527
528 /* Just like getaddrinfo, except it times out after TIMEOUT seconds.
529    In case of timeout, the EAI_SYSTEM error code is returned and errno
530    is set to ETIMEDOUT.  */
531
532 static int
533 getaddrinfo_with_timeout (const char *node, const char *service,
534                           const struct addrinfo *hints, struct addrinfo **res,
535                           int timeout)
536 {
537   struct gaiwt_context ctx;
538   ctx.node = node;
539   ctx.service = service;
540   ctx.hints = hints;
541   ctx.res = res;
542
543   if (run_with_timeout (timeout, getaddrinfo_with_timeout_callback, &ctx))
544     {
545       errno = ETIMEDOUT;
546       return EAI_SYSTEM;
547     }
548   return ctx.exit_code;
549 }
550
551 #endif /* INET6 */
552 \f
553 /* Pretty-print ADDR.  When compiled without IPv6, this is the same as
554    inet_ntoa.  With IPv6, it either prints an IPv6 address or an IPv4
555    address.  */
556
557 char *
558 pretty_print_address (ip_address *addr)
559 {
560 #ifdef INET6
561   ip4_address addr4;
562   static char buf[128];
563
564   if (map_ip_to_ipv4 (addr, &addr4))
565     return inet_ntoa (*(struct in_addr *)&addr4);
566
567   if (!inet_ntop (AF_INET6, addr, buf, sizeof (buf)))
568     return "<unknown>";
569   return buf;
570 #endif
571   return inet_ntoa (*(struct in_addr *)addr);
572 }
573
574 /* Add host name HOST with the address ADDR_TEXT to the cache.
575    ADDR_LIST is a NULL-terminated list of addresses, as in struct
576    hostent.  */
577
578 static void
579 cache_host_lookup (const char *host, struct address_list *al)
580 {
581   if (!host_name_addresses_map)
582     host_name_addresses_map = make_nocase_string_hash_table (0);
583
584   ++al->refcount;
585   hash_table_put (host_name_addresses_map, xstrdup_lower (host), al);
586
587 #ifdef DEBUG
588   if (opt.debug)
589     {
590       int i;
591       debug_logprintf ("Caching %s =>", host);
592       for (i = 0; i < al->count; i++)
593         debug_logprintf (" %s", pretty_print_address (al->addresses + i));
594       debug_logprintf ("\n");
595     }
596 #endif
597 }
598
599 struct address_list *
600 lookup_host (const char *host, int silent)
601 {
602   struct address_list *al = NULL;
603   unsigned long addr_ipv4;      /* #### use a 32-bit type here. */
604   ip_address addr;
605
606   /* First, try to check whether the address is already a numeric
607      address.  */
608
609 #ifdef INET6
610   if (inet_pton (AF_INET6, host, &addr) > 0)
611     return address_list_new_one (&addr);
612 #endif
613
614   addr_ipv4 = (unsigned long)inet_addr (host);
615   if ((int)addr_ipv4 != -1)
616     {
617       /* ADDR is defined to be in network byte order, which is what
618          this returns, so we can just copy it to STORE_IP.  However,
619          on big endian 64-bit architectures the value will be stored
620          in the *last*, not first four bytes.  OFFSET makes sure that
621          we copy the correct four bytes.  */
622       int offset = 0;
623 #ifdef WORDS_BIGENDIAN
624       offset = sizeof (unsigned long) - sizeof (ip4_address);
625 #endif
626       map_ipv4_to_ip ((ip4_address *)((char *)&addr_ipv4 + offset), &addr);
627       return address_list_new_one (&addr);
628     }
629
630   if (host_name_addresses_map)
631     {
632       al = hash_table_get (host_name_addresses_map, host);
633
634       if (al)
635         {
636           DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al));
637           ++al->refcount;
638           return al;
639         }
640     }
641
642   if (!silent)
643     logprintf (LOG_VERBOSE, _("Resolving %s... "), host);
644
645   /* Host name lookup goes on below. */
646
647 #ifdef INET6
648   {
649     struct addrinfo hints, *ai;
650     int err;
651
652     memset (&hints, 0, sizeof (hints));
653     if (ip_default_family == AF_INET)
654       hints.ai_family   = AF_INET;
655     else
656       hints.ai_family   = PF_UNSPEC;
657     hints.ai_socktype = SOCK_STREAM;
658     err = getaddrinfo_with_timeout (host, NULL, &hints, &ai, opt.timeout);
659
660     if (err != 0 || ai == NULL)
661       {
662         if (!silent)
663           logprintf (LOG_VERBOSE, _("failed: %s.\n"),
664                      err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno));
665         return NULL;
666       }
667     al = address_list_from_addrinfo (ai);
668     freeaddrinfo (ai);
669   }
670 #else
671   {
672     struct hostent *hptr = gethostbyname_with_timeout (host, opt.timeout);
673     if (!hptr)
674       {
675         if (!silent)
676           {
677             if (errno != ETIMEDOUT)
678               logprintf (LOG_VERBOSE, _("failed: %s.\n"), herrmsg (h_errno));
679             else
680               logputs (LOG_VERBOSE, _("failed: timed out.\n"));
681           }
682         return NULL;
683       }
684     /* Do all systems have h_addr_list, or is it a newer thing?  If
685        the latter, use address_list_new_one.  */
686     al = address_list_new (hptr->h_addr_list);
687   }
688 #endif
689
690   if (!silent)
691     logprintf (LOG_VERBOSE, _("done.\n"));
692
693   /* Cache the lookup information. */
694   cache_host_lookup (host, al);
695
696   return al;
697 }
698 \f
699 /* Determine whether a URL is acceptable to be followed, according to
700    a list of domains to accept.  */
701 int
702 accept_domain (struct url *u)
703 {
704   assert (u->host != NULL);
705   if (opt.domains)
706     {
707       if (!sufmatch ((const char **)opt.domains, u->host))
708         return 0;
709     }
710   if (opt.exclude_domains)
711     {
712       if (sufmatch ((const char **)opt.exclude_domains, u->host))
713         return 0;
714     }
715   return 1;
716 }
717
718 /* Check whether WHAT is matched in LIST, each element of LIST being a
719    pattern to match WHAT against, using backward matching (see
720    match_backwards() in utils.c).
721
722    If an element of LIST matched, 1 is returned, 0 otherwise.  */
723 int
724 sufmatch (const char **list, const char *what)
725 {
726   int i, j, k, lw;
727
728   lw = strlen (what);
729   for (i = 0; list[i]; i++)
730     {
731       for (j = strlen (list[i]), k = lw; j >= 0 && k >= 0; j--, k--)
732         if (TOLOWER (list[i][j]) != TOLOWER (what[k]))
733           break;
734       /* The domain must be first to reach to beginning.  */
735       if (j == -1)
736         return 1;
737     }
738   return 0;
739 }
740
741 /* Print error messages for host errors.  */
742 char *
743 herrmsg (int error)
744 {
745   /* Can't use switch since some constants are equal (at least on my
746      system), and the compiler signals "duplicate case value".  */
747   if (error == HOST_NOT_FOUND
748       || error == NO_RECOVERY
749       || error == NO_DATA
750       || error == NO_ADDRESS
751       || error == TRY_AGAIN)
752     return _("Host not found");
753   else
754     return _("Unknown error");
755 }
756
757 static int
758 host_cleanup_mapper (void *key, void *value, void *arg_ignored)
759 {
760   struct address_list *al;
761
762   xfree (key);                  /* host */
763
764   al = (struct address_list *)value;
765   assert (al->refcount == 1);
766   address_list_delete (al);
767
768   return 0;
769 }
770
771 void
772 host_cleanup (void)
773 {
774   if (host_name_addresses_map)
775     {
776       hash_table_map (host_name_addresses_map, host_cleanup_mapper, NULL);
777       hash_table_destroy (host_name_addresses_map);
778       host_name_addresses_map = NULL;
779     }
780 }