]> sjero.net Git - wget/blob - src/host.c
[svn] Change u_int32_t to uint32_t.
[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_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 HAVE_GETADDRINFO
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 vector of
206    addresses, as returned by gethostbyname.  */
207 static struct address_list *
208 address_list_from_vector (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_from_vector, but initialized with a single
230    address. */
231
232 static struct address_list *
233 address_list_from_single (ip_address *addr)
234 {
235   struct address_list *al = xmalloc (sizeof (struct address_list));
236   al->count     = 1;
237   al->faulty    = 0;
238   al->addresses = xmalloc (sizeof (ip_address));
239   al->refcount  = 1;
240   memcpy (al->addresses, addr, sizeof (ip_address));
241
242   return al;
243 }
244
245 static void
246 address_list_delete (struct address_list *al)
247 {
248   xfree (al->addresses);
249   xfree (al);
250 }
251
252 void
253 address_list_release (struct address_list *al)
254 {
255   --al->refcount;
256   DEBUGP (("Releasing %p (new refcount %d).\n", al, al->refcount));
257   if (al->refcount <= 0)
258     {
259       DEBUGP (("Deleting unused %p.\n", al));
260       address_list_delete (al);
261     }
262 }
263 \f
264 /**
265   * wget_sockaddr_set_address
266   *
267   * This function takes an wget_sockaddr and fill in the protocol type,
268   * the port number and the address, there NULL in address means wildcard.
269   * Unsuported adress family will abort the whole programm.
270   *
271   * Input:
272   * wget_sockaddr*      The space to be filled
273   * int                 The wished protocol
274   * unsigned short      The port
275   * const ip_address    The Binary IP adress
276   *
277   * Return:
278   * -                   Only modify 1. param
279   */
280 void
281 wget_sockaddr_set_address (wget_sockaddr *sa, 
282                            int ip_family, unsigned short port, ip_address *addr)
283 {
284   if (ip_family == AF_INET) 
285     {
286       sa->sin.sin_family = ip_family;
287       sa->sin.sin_port = htons (port);
288       if (addr == NULL) 
289         memset (&sa->sin.sin_addr, 0,      sizeof(ip4_address));
290       else
291         {
292           ip4_address addr4;
293           if (!map_ip_to_ipv4 (addr, &addr4))
294             /* should the callers have prevented this? */
295             abort ();
296           memcpy (&sa->sin.sin_addr, &addr4, sizeof(ip4_address));
297         }
298       return;
299     }
300 #ifdef ENABLE_IPV6
301   if (ip_family == AF_INET6) 
302     {
303       sa->sin6.sin6_family = ip_family;
304       sa->sin6.sin6_port = htons (port);
305       if (addr == NULL) 
306         memset (&sa->sin6.sin6_addr, 0   , 16);
307       else           
308         memcpy (&sa->sin6.sin6_addr, addr, 16);
309       return;
310     }
311 #endif  
312   abort();
313 }
314
315 /**
316   * wget_sockaddr_set_port
317   *
318   * This funtion only fill the port of the socket information.
319   * If the protocol is not supported nothing is done.
320   * Unsuported adress family will abort the whole programm.
321   * 
322   * Require:
323   * that the IP-Protocol already is set.
324   *
325   * Input:
326   * wget_sockaddr*      The space there port should be entered
327   * unsigned int        The port that should be entered in host order
328   *
329   * Return:
330   * -                   Only modify 1. param
331   */
332 void 
333 wget_sockaddr_set_port (wget_sockaddr *sa, unsigned short port)
334 {
335   if (sa->sa.sa_family == AF_INET)
336     {
337       sa->sin.sin_port = htons (port);
338       return;
339     }  
340 #ifdef ENABLE_IPV6
341   if (sa->sa.sa_family == AF_INET6)
342     {
343       sa->sin6.sin6_port = htons (port);
344       return;
345     }
346 #endif
347   abort();
348 }
349
350 /**
351   * wget_sockaddr_get_addr
352   *
353   * This function return the adress from an sockaddr as byte string.
354   * Unsuported adress family will abort the whole programm.
355   * 
356   * Require:
357   * that the IP-Protocol already is set.
358   *
359   * Input:
360   * wget_sockaddr*      Socket Information
361   *
362   * Output:
363   * unsigned char *     IP address as byte string.
364   */
365 void *
366 wget_sockaddr_get_addr (wget_sockaddr *sa)
367
368   if (sa->sa.sa_family == AF_INET)
369     return &sa->sin.sin_addr;
370 #ifdef ENABLE_IPV6
371   if (sa->sa.sa_family == AF_INET6)
372     return &sa->sin6.sin6_addr;
373 #endif
374   abort();
375   /* unreached */
376   return NULL;
377 }
378
379 /**
380   * wget_sockaddr_get_port
381   *
382   * This function only return the port from the input structure
383   * Unsuported adress family will abort the whole programm.
384   * 
385   * Require:
386   * that the IP-Protocol already is set.
387   *
388   * Input:
389   * wget_sockaddr*      Information where to get the port
390   *
391   * Output:
392   * unsigned short      Port Number in host order.
393   */
394 unsigned short 
395 wget_sockaddr_get_port (const wget_sockaddr *sa)
396 {
397   if (sa->sa.sa_family == AF_INET)
398       return htons (sa->sin.sin_port);
399 #ifdef ENABLE_IPV6
400   if (sa->sa.sa_family == AF_INET6)
401       return htons (sa->sin6.sin6_port);
402 #endif
403   abort();
404   /* do not complain about return nothing */
405   return -1;
406 }
407
408 /**
409   * sockaddr_len
410   *
411   * This function return the length of the sockaddr corresponding to 
412   * the acutall prefered protocol for (bind, connect etc...)
413   * Unsuported adress family will abort the whole programm.
414   * 
415   * Require:
416   * that the IP-Protocol already is set.
417   *
418   * Input:
419   * -           Public IP-Family Information
420   *
421   * Output:
422   * socklen_t   structure length for socket options
423   */
424 socklen_t
425 sockaddr_len () 
426 {
427   if (ip_default_family == AF_INET) 
428     return sizeof (struct sockaddr_in);
429 #ifdef ENABLE_IPV6
430   if (ip_default_family == AF_INET6) 
431     return sizeof (struct sockaddr_in6);
432 #endif
433   abort();
434   /* do not complain about return nothing */
435   return 0;
436 }
437
438 /**
439   * Map an IPv4 adress to the internal adress format.
440   */
441 void 
442 map_ipv4_to_ip (ip4_address *ipv4, ip_address *ip) 
443 {
444 #ifdef ENABLE_IPV6
445   static unsigned char ipv64[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
446   memcpy ((char *)ip + 12, ipv4 , 4);
447   memcpy ((char *)ip + 0, ipv64, 12);
448 #else
449   if ((char *)ip != (char *)ipv4)
450     memcpy (ip, ipv4, 4);
451 #endif
452 }
453
454 /* Detect whether an IP adress represents an IPv4 address and, if so,
455    copy it to IPV4.  0 is returned on failure.
456    This operation always succeeds when Wget is compiled without IPv6.
457    If IPV4 is NULL, don't copy, just detect.  */
458
459 int 
460 map_ip_to_ipv4 (ip_address *ip, ip4_address *ipv4) 
461 {
462 #ifdef ENABLE_IPV6
463   static unsigned char ipv64[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
464   if (0 != memcmp (ip, ipv64, 12))
465     return 0;
466   if (ipv4)
467     memcpy (ipv4, (char *)ip + 12, 4);
468 #else
469   if (ipv4)
470     memcpy (ipv4, (char *)ip, 4);
471 #endif
472   return 1;
473 }
474 \f
475 /* Versions of gethostbyname and getaddrinfo that support timeout. */
476
477 #ifndef ENABLE_IPV6
478
479 struct ghbnwt_context {
480   const char *host_name;
481   struct hostent *hptr;
482 };
483
484 static void
485 gethostbyname_with_timeout_callback (void *arg)
486 {
487   struct ghbnwt_context *ctx = (struct ghbnwt_context *)arg;
488   ctx->hptr = gethostbyname (ctx->host_name);
489 }
490
491 /* Just like gethostbyname, except it times out after TIMEOUT seconds.
492    In case of timeout, NULL is returned and errno is set to ETIMEDOUT.
493    The function makes sure that when NULL is returned for reasons
494    other than timeout, errno is reset.  */
495
496 static struct hostent *
497 gethostbyname_with_timeout (const char *host_name, double timeout)
498 {
499   struct ghbnwt_context ctx;
500   ctx.host_name = host_name;
501   if (run_with_timeout (timeout, gethostbyname_with_timeout_callback, &ctx))
502     {
503       SET_H_ERRNO (HOST_NOT_FOUND);
504       errno = ETIMEDOUT;
505       return NULL;
506     }
507   if (!ctx.hptr)
508     errno = 0;
509   return ctx.hptr;
510 }
511
512 #else  /* ENABLE_IPV6 */
513
514 struct gaiwt_context {
515   const char *node;
516   const char *service;
517   const struct addrinfo *hints;
518   struct addrinfo **res;
519   int exit_code;
520 };
521
522 static void
523 getaddrinfo_with_timeout_callback (void *arg)
524 {
525   struct gaiwt_context *ctx = (struct gaiwt_context *)arg;
526   ctx->exit_code = getaddrinfo (ctx->node, ctx->service, ctx->hints, ctx->res);
527 }
528
529 /* Just like getaddrinfo, except it times out after TIMEOUT seconds.
530    In case of timeout, the EAI_SYSTEM error code is returned and errno
531    is set to ETIMEDOUT.  */
532
533 static int
534 getaddrinfo_with_timeout (const char *node, const char *service,
535                           const struct addrinfo *hints, struct addrinfo **res,
536                           double timeout)
537 {
538   struct gaiwt_context ctx;
539   ctx.node = node;
540   ctx.service = service;
541   ctx.hints = hints;
542   ctx.res = res;
543
544   if (run_with_timeout (timeout, getaddrinfo_with_timeout_callback, &ctx))
545     {
546       errno = ETIMEDOUT;
547       return EAI_SYSTEM;
548     }
549   return ctx.exit_code;
550 }
551
552 #endif /* ENABLE_IPV6 */
553 \f
554 /* Pretty-print ADDR.  When compiled without IPv6, this is the same as
555    inet_ntoa.  With IPv6, it either prints an IPv6 address or an IPv4
556    address.  */
557
558 char *
559 pretty_print_address (ip_address *addr)
560 {
561 #ifdef ENABLE_IPV6
562   ip4_address addr4;
563   static char buf[128];
564
565   if (map_ip_to_ipv4 (addr, &addr4))
566     return inet_ntoa (*(struct in_addr *)&addr4);
567
568   if (!inet_ntop (AF_INET6, addr, buf, sizeof (buf)))
569     return "<unknown>";
570   return buf;
571 #endif
572   return inet_ntoa (*(struct in_addr *)addr);
573 }
574
575 /* Add host name HOST with the address ADDR_TEXT to the cache.
576    ADDR_LIST is a NULL-terminated list of addresses, as in struct
577    hostent.  */
578
579 static void
580 cache_host_lookup (const char *host, struct address_list *al)
581 {
582   if (!host_name_addresses_map)
583     host_name_addresses_map = make_nocase_string_hash_table (0);
584
585   ++al->refcount;
586   hash_table_put (host_name_addresses_map, xstrdup_lower (host), al);
587
588 #ifdef ENABLE_DEBUG
589   if (opt.debug)
590     {
591       int i;
592       debug_logprintf ("Caching %s =>", host);
593       for (i = 0; i < al->count; i++)
594         debug_logprintf (" %s", pretty_print_address (al->addresses + i));
595       debug_logprintf ("\n");
596     }
597 #endif
598 }
599
600 struct address_list *
601 lookup_host (const char *host, int silent)
602 {
603   struct address_list *al = NULL;
604   uint32_t addr_ipv4;
605   ip_address addr;
606
607   /* First, try to check whether the address is already a numeric
608      address.  */
609
610 #ifdef ENABLE_IPV6
611   if (inet_pton (AF_INET6, host, &addr) > 0)
612     return address_list_from_single (&addr);
613 #endif
614
615   addr_ipv4 = (uint32_t)inet_addr (host);
616   if (addr_ipv4 != (uint32_t)-1)
617     {
618       /* ADDR is defined to be in network byte order, which is what
619          this returns, so we can just copy it to STORE_IP.  */
620       map_ipv4_to_ip ((ip4_address *)&addr_ipv4, &addr);
621       return address_list_from_single (&addr);
622     }
623
624   if (host_name_addresses_map)
625     {
626       al = hash_table_get (host_name_addresses_map, host);
627       if (al)
628         {
629           DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al));
630           ++al->refcount;
631           return al;
632         }
633     }
634
635   if (!silent)
636     logprintf (LOG_VERBOSE, _("Resolving %s... "), host);
637
638   /* Host name lookup goes on below. */
639
640 #ifdef HAVE_GETADDRINFO
641   {
642     struct addrinfo hints, *ai;
643     int err;
644
645     memset (&hints, 0, sizeof (hints));
646     if (ip_default_family == AF_INET)
647       hints.ai_family   = AF_INET;
648     else
649       hints.ai_family   = PF_UNSPEC;
650     hints.ai_socktype = SOCK_STREAM;
651     err = getaddrinfo_with_timeout (host, NULL, &hints, &ai, opt.dns_timeout);
652
653     if (err != 0 || ai == NULL)
654       {
655         if (!silent)
656           logprintf (LOG_VERBOSE, _("failed: %s.\n"),
657                      err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno));
658         return NULL;
659       }
660     al = address_list_from_addrinfo (ai);
661     freeaddrinfo (ai);
662   }
663 #else
664   {
665     struct hostent *hptr;
666     hptr = gethostbyname_with_timeout (host, opt.dns_timeout);
667     if (!hptr)
668       {
669         if (!silent)
670           {
671             if (errno != ETIMEDOUT)
672               logprintf (LOG_VERBOSE, _("failed: %s.\n"), herrmsg (h_errno));
673             else
674               logputs (LOG_VERBOSE, _("failed: timed out.\n"));
675           }
676         return NULL;
677       }
678     /* Do all systems have h_addr_list, or is it a newer thing?  If
679        the latter, use address_list_from_single.  */
680     al = address_list_from_vector (hptr->h_addr_list);
681   }
682 #endif
683
684   /* Print the addresses determined by DNS lookup, but no more than
685      three.  */
686   if (!silent)
687     {
688       int i;
689       int printmax = al->count <= 3 ? al->count : 3;
690       for (i = 0; i < printmax; i++)
691         {
692           logprintf (LOG_VERBOSE, "%s",
693                      pretty_print_address (al->addresses + i));
694           if (i < printmax - 1)
695             logputs (LOG_VERBOSE, ", ");
696         }
697       if (printmax != al->count)
698         logputs (LOG_VERBOSE, ", ...");
699       logputs (LOG_VERBOSE, "\n");
700     }
701
702   /* Cache the lookup information. */
703   if (opt.dns_cache)
704     cache_host_lookup (host, al);
705
706   return al;
707 }
708 \f
709 /* Determine whether a URL is acceptable to be followed, according to
710    a list of domains to accept.  */
711 int
712 accept_domain (struct url *u)
713 {
714   assert (u->host != NULL);
715   if (opt.domains)
716     {
717       if (!sufmatch ((const char **)opt.domains, u->host))
718         return 0;
719     }
720   if (opt.exclude_domains)
721     {
722       if (sufmatch ((const char **)opt.exclude_domains, u->host))
723         return 0;
724     }
725   return 1;
726 }
727
728 /* Check whether WHAT is matched in LIST, each element of LIST being a
729    pattern to match WHAT against, using backward matching (see
730    match_backwards() in utils.c).
731
732    If an element of LIST matched, 1 is returned, 0 otherwise.  */
733 int
734 sufmatch (const char **list, const char *what)
735 {
736   int i, j, k, lw;
737
738   lw = strlen (what);
739   for (i = 0; list[i]; i++)
740     {
741       for (j = strlen (list[i]), k = lw; j >= 0 && k >= 0; j--, k--)
742         if (TOLOWER (list[i][j]) != TOLOWER (what[k]))
743           break;
744       /* The domain must be first to reach to beginning.  */
745       if (j == -1)
746         return 1;
747     }
748   return 0;
749 }
750
751 /* Print error messages for host errors.  */
752 char *
753 herrmsg (int error)
754 {
755   /* Can't use switch since some constants are equal (at least on my
756      system), and the compiler signals "duplicate case value".  */
757   if (error == HOST_NOT_FOUND
758       || error == NO_RECOVERY
759       || error == NO_DATA
760       || error == NO_ADDRESS
761       || error == TRY_AGAIN)
762     return _("Host not found");
763   else
764     return _("Unknown error");
765 }
766
767 static int
768 host_cleanup_mapper (void *key, void *value, void *arg_ignored)
769 {
770   struct address_list *al;
771
772   xfree (key);                  /* host */
773
774   al = (struct address_list *)value;
775   assert (al->refcount == 1);
776   address_list_delete (al);
777
778   return 0;
779 }
780
781 void
782 host_cleanup (void)
783 {
784   if (host_name_addresses_map)
785     {
786       hash_table_map (host_name_addresses_map, host_cleanup_mapper, NULL);
787       hash_table_destroy (host_name_addresses_map);
788       host_name_addresses_map = NULL;
789     }
790 }