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