]> sjero.net Git - wget/blob - src/host.c
[svn] Commit IPv6 support by Thomas Lussnig.
[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 && ip_store!=NULL );
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     memcpy (al->addresses + i, h_addr_list[i], sizeof (ip_address));
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 ((unsigned char*)&sa->sin.sin_addr, 0,    sizeof(ip_address));
274       else       
275         memcpy ((unsigned char*)&sa->sin.sin_addr, addr, sizeof(ip_address));
276       return;
277     }
278 #ifdef INET6
279   if (ip_family == AF_INET6) 
280     {
281       sa->sin6.sin6_family = ip_family;
282       sa->sin6.sin6_port = htons (port);
283       if (addr == NULL) 
284         memset (&sa->sin6.sin6_addr, 0   , sizeof(ip_address));
285       else           
286         memcpy (&sa->sin6.sin6_addr, addr, sizeof(ip_address));
287       return;
288     }
289 #endif  
290   abort();
291 }
292
293 /**
294   * wget_sockaddr_set_port
295   *
296   * This funtion only fill the port of the socket information.
297   * If the protocol is not supported nothing is done.
298   * Unsuported adress family will abort the whole programm.
299   * 
300   * Require:
301   * that the IP-Protocol already is set.
302   *
303   * Input:
304   * wget_sockaddr*      The space there port should be entered
305   * unsigned int        The port that should be entered in host order
306   *
307   * Return:
308   * -                   Only modify 1. param
309   */
310 void 
311 wget_sockaddr_set_port (wget_sockaddr *sa, unsigned short port)
312 {
313   if (sa->sa.sa_family == AF_INET)
314     {
315       sa->sin.sin_port = htons (port);
316       return;
317     }  
318 #ifdef INET6
319   if (sa->sa.sa_family == AF_INET6)
320     {
321       sa->sin6.sin6_port = htons (port);
322       return;
323     }
324 #endif
325   abort();
326 }
327
328 /**
329   * wget_sockaddr_get_addr
330   *
331   * This function return the adress from an sockaddr as byte string.
332   * Unsuported adress family will abort the whole programm.
333   * 
334   * Require:
335   * that the IP-Protocol already is set.
336   *
337   * Input:
338   * wget_sockaddr*      Socket Information
339   *
340   * Output:
341   * unsigned char *     IP address as byte string.
342   */
343 void *
344 wget_sockaddr_get_addr (wget_sockaddr *sa)
345
346   if (sa->sa.sa_family == AF_INET)
347     return &sa->sin.sin_addr;
348 #ifdef INET6
349   if (sa->sa.sa_family == AF_INET6)
350     return &sa->sin6.sin6_addr;
351 #endif
352   abort();
353   /* unreached */
354   return NULL;
355 }
356
357 /**
358   * wget_sockaddr_get_port
359   *
360   * This function only return the port from the input structure
361   * Unsuported adress family will abort the whole programm.
362   * 
363   * Require:
364   * that the IP-Protocol already is set.
365   *
366   * Input:
367   * wget_sockaddr*      Information where to get the port
368   *
369   * Output:
370   * unsigned short      Port Number in host order.
371   */
372 unsigned short 
373 wget_sockaddr_get_port (const wget_sockaddr *sa)
374 {
375   if (sa->sa.sa_family == AF_INET)
376       return htons (sa->sin.sin_port);
377 #ifdef INET6
378   if (sa->sa.sa_family == AF_INET6)
379       return htons (sa->sin6.sin6_port);
380 #endif
381   abort();
382   /* do not complain about return nothing */
383   return -1;
384 }
385
386 /**
387   * sockaddr_len
388   *
389   * This function return the length of the sockaddr corresponding to 
390   * the acutall prefered protocol for (bind, connect etc...)
391   * Unsuported adress family will abort the whole programm.
392   * 
393   * Require:
394   * that the IP-Protocol already is set.
395   *
396   * Input:
397   * -           Public IP-Family Information
398   *
399   * Output:
400   * int         structure length for socket options
401   */
402 int 
403 sockaddr_len () 
404 {
405   if (ip_default_family == AF_INET) 
406     return sizeof (struct sockaddr_in);
407 #ifdef INET6
408   if (ip_default_family == AF_INET6) 
409     return sizeof (struct sockaddr_in6);
410 #endif
411   abort();
412   /* do not complain about return nothing */
413   return 0;
414 }
415
416 /**
417   * Map an IPv4 adress to the internal adress format.
418   */
419 void 
420 map_ipv4_to_ip (ip4_address *ipv4, ip_address *ip) 
421 {
422 #ifdef INET6
423   static unsigned char ipv64[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
424   memcpy ((char *)ip + 12, ipv4 , 4);
425   memcpy ((char *)ip + 0, ipv64, 12);
426 #else
427   if ((char *)ip != (char *)ipv4)
428     memcpy (ip, ipv4, 4);
429 #endif
430 }
431
432 /* Detect whether an IP adress represents an IPv4 address and, if so,
433    copy it to IPV4.  0 is returned on failure.
434    This operation always succeeds when Wget is compiled without IPv6.
435    If IPV4 is NULL, don't copy, just detect.  */
436
437 int 
438 map_ip_to_ipv4 (ip_address *ip, ip4_address *ipv4) 
439 {
440 #ifdef INET6
441   static unsigned char ipv64[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
442   if (0 != memcmp (ip, ipv64, 12))
443     return 0;
444   if (ipv4)
445     memcpy (ipv4, (char *)ip + 12, 4);
446 #else
447   if (ipv4)
448     memcpy (ipv4, (char *)ip, 4);
449 #endif
450   return 1;
451 }
452 \f
453 /* Pretty-print ADDR.  When compiled without IPv6, this is the same as
454    inet_ntoa.  With IPv6, it either prints an IPv6 address or an IPv4
455    address.  */
456
457 char *
458 pretty_print_address (ip_address *addr)
459 {
460 #ifdef INET6
461   ip4_address addr4;
462   static char buf[128];
463
464   if (map_ip_to_ipv4 (addr, &addr4))
465     return inet_ntoa (*(struct in_addr *)&addr4);
466
467   if (!inet_ntop (AF_INET6, addr, buf, sizeof (buf)))
468     return "<unknown>";
469   return buf;
470 #endif
471   return inet_ntoa (*(struct in_addr *)addr);
472 }
473
474 /* Add host name HOST with the address ADDR_TEXT to the cache.
475    ADDR_LIST is a NULL-terminated list of addresses, as in struct
476    hostent.  */
477
478 static void
479 cache_host_lookup (const char *host, struct address_list *al)
480 {
481   if (!host_name_addresses_map)
482     host_name_addresses_map = make_nocase_string_hash_table (0);
483
484   ++al->refcount;
485   hash_table_put (host_name_addresses_map, xstrdup_lower (host), al);
486
487 #ifdef DEBUG
488   if (opt.debug)
489     {
490       int i;
491       debug_logprintf ("Caching %s =>", host);
492       for (i = 0; i < al->count; i++)
493         debug_logprintf (" %s", pretty_print_address (al->addresses + i));
494       debug_logprintf ("\n");
495     }
496 #endif
497 }
498
499 struct address_list *
500 lookup_host (const char *host, int silent)
501 {
502   struct address_list *al = NULL;
503   unsigned long addr_ipv4;      /* #### use a 32-bit type here. */
504   ip_address addr;
505
506   /* First, try to check whether the address is already a numeric
507      address.  */
508
509 #ifdef INET6
510   if (inet_pton (AF_INET6, host, &addr) > 0)
511     return address_list_new_one (&addr);
512 #endif
513
514   addr_ipv4 = (unsigned long)inet_addr (host);
515   if ((int)addr_ipv4 != -1)
516     {
517       /* ADDR is defined to be in network byte order, which is what
518          this returns, so we can just copy it to STORE_IP.  However,
519          on big endian 64-bit architectures the value will be stored
520          in the *last*, not first four bytes.  OFFSET makes sure that
521          we copy the correct four bytes.  */
522       int offset = 0;
523 #ifdef WORDS_BIGENDIAN
524       offset = sizeof (unsigned long) - sizeof (ip_address);
525 #endif
526       map_ipv4_to_ip ((ip4_address *)((char *)&addr_ipv4 + offset), &addr);
527       return address_list_new_one (&addr);
528     }
529
530   if (host_name_addresses_map)
531     {
532       al = hash_table_get (host_name_addresses_map, host);
533
534       if (al)
535         {
536           DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al));
537           ++al->refcount;
538           return al;
539         }
540     }
541
542   if (!silent)
543     logprintf (LOG_VERBOSE, _("Resolving %s... "), host);
544
545 #ifdef INET6
546   {
547     struct addrinfo hints, *ai;
548     int err;
549
550     memset (&hints, 0, sizeof (hints));
551     hints.ai_family   = PF_UNSPEC;
552     hints.ai_socktype = SOCK_STREAM;
553     err = getaddrinfo (host, NULL, &hints, &ai);
554
555     if (err != 0 || ai == NULL)
556       {
557         if (!silent)
558           logprintf (LOG_VERBOSE, _("failed: %s.\n"), gai_strerror (err));
559         return NULL;
560       }
561     al = address_list_from_addrinfo (ai);
562     freeaddrinfo (ai);
563   }
564 #else
565   {
566     struct hostent *hptr = gethostbyname (host);
567     if (!hptr)
568       {
569         if (!silent)
570           logprintf (LOG_VERBOSE, _("failed: %s.\n"), herrmsg (h_errno));
571         return NULL;
572       }
573     /* Do all systems have h_addr_list, or is it a newer thing?  If
574        the latter, use address_list_new_one.  */
575     al = address_list_new (hptr->h_addr_list);
576   }
577 #endif
578
579   if (!silent)
580     logprintf (LOG_VERBOSE, _("done.\n"));
581
582   /* Cache the lookup information. */
583   cache_host_lookup (host, al);
584
585   return al;
586 }
587 \f
588 /* Determine whether a URL is acceptable to be followed, according to
589    a list of domains to accept.  */
590 int
591 accept_domain (struct url *u)
592 {
593   assert (u->host != NULL);
594   if (opt.domains)
595     {
596       if (!sufmatch ((const char **)opt.domains, u->host))
597         return 0;
598     }
599   if (opt.exclude_domains)
600     {
601       if (sufmatch ((const char **)opt.exclude_domains, u->host))
602         return 0;
603     }
604   return 1;
605 }
606
607 /* Check whether WHAT is matched in LIST, each element of LIST being a
608    pattern to match WHAT against, using backward matching (see
609    match_backwards() in utils.c).
610
611    If an element of LIST matched, 1 is returned, 0 otherwise.  */
612 int
613 sufmatch (const char **list, const char *what)
614 {
615   int i, j, k, lw;
616
617   lw = strlen (what);
618   for (i = 0; list[i]; i++)
619     {
620       for (j = strlen (list[i]), k = lw; j >= 0 && k >= 0; j--, k--)
621         if (TOLOWER (list[i][j]) != TOLOWER (what[k]))
622           break;
623       /* The domain must be first to reach to beginning.  */
624       if (j == -1)
625         return 1;
626     }
627   return 0;
628 }
629
630 /* Print error messages for host errors.  */
631 char *
632 herrmsg (int error)
633 {
634   /* Can't use switch since some constants are equal (at least on my
635      system), and the compiler signals "duplicate case value".  */
636   if (error == HOST_NOT_FOUND
637       || error == NO_RECOVERY
638       || error == NO_DATA
639       || error == NO_ADDRESS
640       || error == TRY_AGAIN)
641     return _("Host not found");
642   else
643     return _("Unknown error");
644 }
645
646 static int
647 host_cleanup_mapper (void *key, void *value, void *arg_ignored)
648 {
649   struct address_list *al;
650
651   xfree (key);                  /* host */
652
653   al = (struct address_list *)value;
654   assert (al->refcount == 1);
655   address_list_delete (al);
656
657   return 0;
658 }
659
660 void
661 host_cleanup (void)
662 {
663   if (host_name_addresses_map)
664     {
665       hash_table_map (host_name_addresses_map, host_cleanup_mapper, NULL);
666       hash_table_destroy (host_name_addresses_map);
667       host_name_addresses_map = NULL;
668     }
669 }