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