X-Git-Url: http://sjero.net/git/?p=wget;a=blobdiff_plain;f=src%2Fhost.c;h=86bf83b3dfe04ccb6abcfeaa7ea5656248691ae0;hp=11de5944352d91d6b805b8bc00ad832ee8097ca3;hb=HEAD;hpb=4d7c5e087b2bc82c9f503dff003916d1047903ce diff --git a/src/host.c b/src/host.c index 11de5944..86bf83b3 100644 --- a/src/host.c +++ b/src/host.c @@ -1,5 +1,7 @@ /* Host name resolution and matching. - Copyright (C) 1996-2006 Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, + 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, + Inc. This file is part of GNU Wget. @@ -16,17 +18,18 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wget. If not, see . -In addition, as a special exception, the Free Software Foundation -gives permission to link the code of its release of Wget with the -OpenSSL project's "OpenSSL" library (or with modified versions of it -that use the same license as the "OpenSSL" library), and distribute -the linked executables. You must obey the GNU General Public License -in all respects for all of the code used other than "OpenSSL". If you -modify this file, you may extend this exception to your version of the -file, but you are not obligated to do so. If you do not wish to do -so, delete this exception statement from your version. */ +Additional permission under GNU GPL version 3 section 7 -#include +If you modify this program, or any covered work, by linking or +combining it with the OpenSSL project's OpenSSL library (or a +modified version of that library), containing parts covered by the +terms of the OpenSSL or SSLeay licenses, the Free Software Foundation +grants you additional permission to convey the resulting work. +Corresponding Source for a non-source form of such a combination +shall include the source code for the parts of OpenSSL used as well +as that of the covered work. */ + +#include "wget.h" #include #include @@ -34,20 +37,26 @@ so, delete this exception statement from your version. */ #include #ifndef WINDOWS +# include # include # include # ifndef __BEOS__ # include # endif -# include +# ifdef __VMS +# include "vms_ip.h" +# else /* def __VMS */ +# include +# endif /* def __VMS [else] */ # define SET_H_ERRNO(err) ((void)(h_errno = (err))) #else /* WINDOWS */ +# include +# include # define SET_H_ERRNO(err) WSASetLastError (err) #endif /* WINDOWS */ #include -#include "wget.h" #include "utils.h" #include "host.h" #include "url.h" @@ -57,20 +66,25 @@ so, delete this exception statement from your version. */ # define NO_ADDRESS NO_DATA #endif +#if !HAVE_DECL_H_ERRNO && !defined(WINDOWS) +extern int h_errno; +#endif + + /* Lists of IP addresses that result from running DNS queries. See lookup_host for details. */ struct address_list { - int count; /* number of adrresses */ - ip_address *addresses; /* pointer to the string of addresses */ + int count; /* number of adrresses */ + ip_address *addresses; /* pointer to the string of addresses */ - int faulty; /* number of addresses known not to work. */ - bool connected; /* whether we were able to connect to - one of the addresses in the list, - at least once. */ + int faulty; /* number of addresses known not to work. */ + bool connected; /* whether we were able to connect to + one of the addresses in the list, + at least once. */ - int refcount; /* reference count; when it drops to - 0, the entry is freed. */ + int refcount; /* reference count; when it drops to + 0, the entry is freed. */ }; /* Get the bounds of the address list. */ @@ -101,25 +115,25 @@ address_list_contains (const struct address_list *al, const ip_address *ip) { case AF_INET: for (i = 0; i < al->count; i++) - { - ip_address *cur = al->addresses + i; - if (cur->family == AF_INET - && (cur->data.d4.s_addr == ip->data.d4.s_addr)) - return true; - } + { + ip_address *cur = al->addresses + i; + if (cur->family == AF_INET + && (cur->data.d4.s_addr == ip->data.d4.s_addr)) + return true; + } return false; #ifdef ENABLE_IPV6 case AF_INET6: for (i = 0; i < al->count; i++) - { - ip_address *cur = al->addresses + i; - if (cur->family == AF_INET6 + { + ip_address *cur = al->addresses + i; + if (cur->family == AF_INET6 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID - && cur->ipv6_scope == ip->ipv6_scope + && cur->ipv6_scope == ip->ipv6_scope #endif - && IN6_ARE_ADDR_EQUAL (&cur->data.d6, &ip->data.d6)) - return true; - } + && IN6_ARE_ADDR_EQUAL (&cur->data.d6, &ip->data.d6)) + return true; + } return false; #endif /* ENABLE_IPV6 */ default: @@ -191,24 +205,24 @@ address_list_from_addrinfo (const struct addrinfo *ai) ip = al->addresses; for (ptr = ai; ptr != NULL; ptr = ptr->ai_next) - if (ptr->ai_family == AF_INET6) + if (ptr->ai_family == AF_INET6) { - const struct sockaddr_in6 *sin6 = - (const struct sockaddr_in6 *)ptr->ai_addr; - ip->family = AF_INET6; - ip->data.d6 = sin6->sin6_addr; + const struct sockaddr_in6 *sin6 = + (const struct sockaddr_in6 *)ptr->ai_addr; + ip->family = AF_INET6; + ip->data.d6 = sin6->sin6_addr; #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID - ip->ipv6_scope = sin6->sin6_scope_id; + ip->ipv6_scope = sin6->sin6_scope_id; #endif - ++ip; - } + ++ip; + } else if (ptr->ai_family == AF_INET) { - const struct sockaddr_in *sin = - (const struct sockaddr_in *)ptr->ai_addr; - ip->family = AF_INET; - ip->data.d4 = sin->sin_addr; - ++ip; + const struct sockaddr_in *sin = + (const struct sockaddr_in *)ptr->ai_addr; + ip->family = AF_INET; + ip->data.d4 = sin->sin_addr; + ++ip; } assert (ip - al->addresses == cnt); return al; @@ -288,7 +302,7 @@ address_list_release (struct address_list *al) { --al->refcount; DEBUGP (("Releasing 0x%0*lx (new refcount %d).\n", PTR_FORMAT (al), - al->refcount)); + al->refcount)); if (al->refcount <= 0) { DEBUGP (("Deleting unused 0x%0*lx.\n", PTR_FORMAT (al))); @@ -334,7 +348,7 @@ gethostbyname_with_timeout (const char *host_name, double timeout) } /* Print error messages for host errors. */ -static char * +static const char * host_errstr (int error) { /* Can't use switch since some of these constants can be equal, @@ -376,8 +390,8 @@ getaddrinfo_with_timeout_callback (void *arg) static int getaddrinfo_with_timeout (const char *node, const char *service, - const struct addrinfo *hints, struct addrinfo **res, - double timeout) + const struct addrinfo *hints, struct addrinfo **res, + double timeout) { struct gaiwt_context ctx; ctx.node = node; @@ -427,31 +441,31 @@ is_valid_ipv4_address (const char *str, const char *end) int ch = *str++; if (ch >= '0' && ch <= '9') - { - val = val * 10 + (ch - '0'); - - if (val > 255) - return false; - if (!saw_digit) - { - if (++octets > 4) - return false; - saw_digit = true; - } - } + { + val = val * 10 + (ch - '0'); + + if (val > 255) + return false; + if (!saw_digit) + { + if (++octets > 4) + return false; + saw_digit = true; + } + } else if (ch == '.' && saw_digit) - { - if (octets == 4) - return false; - val = 0; - saw_digit = false; - } + { + if (octets == 4) + return false; + val = 0; + saw_digit = false; + } else - return false; + return false; } if (octets < 4) return false; - + return true; } @@ -476,13 +490,13 @@ is_valid_ipv6_address (const char *str, const char *end) if (str == end) return false; - + /* Leading :: requires some special handling. */ if (*str == ':') { ++str; if (str == end || *str != ':') - return false; + return false; } curtok = str; @@ -494,60 +508,60 @@ is_valid_ipv6_address (const char *str, const char *end) int ch = *str++; /* if ch is a number, add it to val. */ - if (ISXDIGIT (ch)) - { - val <<= 4; - val |= XDIGIT_TO_NUM (ch); - if (val > 0xffff) - return false; - saw_xdigit = true; - continue; - } + if (c_isxdigit (ch)) + { + val <<= 4; + val |= XDIGIT_TO_NUM (ch); + if (val > 0xffff) + return false; + saw_xdigit = true; + continue; + } /* if ch is a colon ... */ if (ch == ':') - { - curtok = str; - if (!saw_xdigit) - { - if (colonp != NULL) - return false; - colonp = str + tp; - continue; - } - else if (str == end) - return false; - if (tp > ns_in6addrsz - ns_int16sz) - return false; - tp += ns_int16sz; - saw_xdigit = false; - val = 0; - continue; - } + { + curtok = str; + if (!saw_xdigit) + { + if (colonp != NULL) + return false; + colonp = str + tp; + continue; + } + else if (str == end) + return false; + if (tp > ns_in6addrsz - ns_int16sz) + return false; + tp += ns_int16sz; + saw_xdigit = false; + val = 0; + continue; + } /* if ch is a dot ... */ if (ch == '.' && (tp <= ns_in6addrsz - ns_inaddrsz) - && is_valid_ipv4_address (curtok, end) == 1) - { - tp += ns_inaddrsz; - saw_xdigit = false; - break; - } - + && is_valid_ipv4_address (curtok, end) == 1) + { + tp += ns_inaddrsz; + saw_xdigit = false; + break; + } + return false; } if (saw_xdigit) { - if (tp > ns_in6addrsz - ns_int16sz) - return false; + if (tp > ns_in6addrsz - ns_int16sz) + return false; tp += ns_int16sz; } if (colonp != NULL) { - if (tp == ns_in6addrsz) - return false; + if (tp == ns_in6addrsz) + return false; tp = ns_in6addrsz; } @@ -602,7 +616,7 @@ cache_store (const char *host, struct address_list *al) int i; debug_logprintf ("Caching %s =>", host); for (i = 0; i < al->count; i++) - debug_logprintf (" %s", print_address (al->addresses + i)); + debug_logprintf (" %s", print_address (al->addresses + i)); debug_logprintf ("\n"); } } @@ -642,7 +656,7 @@ cache_remove (const char *host) LH_SILENT - don't print the "resolving ... done" messages. LH_BIND - resolve addresses for use with bind, which under IPv6 means to use AI_PASSIVE flag to getaddrinfo. - Passive lookups are not cached under IPv6. + Passive lookups are not cached under IPv6. LH_REFRESH - if HOST is cached, remove the entry from the cache and resolve it anew. */ @@ -664,12 +678,12 @@ lookup_host (const char *host, int flags) uint32_t addr_ipv4 = (uint32_t)inet_addr (host); if (addr_ipv4 != (uint32_t) -1) { - /* No need to cache host->addr relation, just return the - address. */ - char *vec[2]; - vec[0] = (char *)&addr_ipv4; - vec[1] = NULL; - return address_list_from_ipv4_addresses (vec); + /* No need to cache host->addr relation, just return the + address. */ + char *vec[2]; + vec[0] = (char *)&addr_ipv4; + vec[1] = NULL; + return address_list_from_ipv4_addresses (vec); } } #else /* ENABLE_IPV6 */ @@ -699,19 +713,36 @@ lookup_host (const char *host, int flags) if (use_cache) { if (!(flags & LH_REFRESH)) - { - al = cache_query (host); - if (al) - return al; - } + { + al = cache_query (host); + if (al) + return al; + } else - cache_remove (host); + cache_remove (host); } /* No luck with the cache; resolve HOST. */ if (!silent && !numeric_address) - logprintf (LOG_VERBOSE, _("Resolving %s... "), escnonprint (host)); + { + char *str = NULL, *name; + + if (opt.enable_iri && (name = idn_decode ((char *) host)) != NULL) + { + int len = strlen (host) + strlen (name) + 4; + str = xmalloc (len); + snprintf (str, len, "%s (%s)", name, host); + str[len-1] = '\0'; + xfree (name); + } + + logprintf (LOG_VERBOSE, _("Resolving %s... "), + quotearg_style (escape_quoting_style, str ? str : host)); + + if (str) + xfree (str); + } #ifdef ENABLE_IPV6 { @@ -726,9 +757,9 @@ lookup_host (const char *host, int flags) hints.ai_family = AF_INET6; else /* We tried using AI_ADDRCONFIG, but removed it because: it - misinterprets IPv6 loopbacks, it is broken on AIX 5.1, and - it's unneeded since we sort the addresses anyway. */ - hints.ai_family = AF_UNSPEC; + misinterprets IPv6 loopbacks, it is broken on AIX 5.1, and + it's unneeded since we sort the addresses anyway. */ + hints.ai_family = AF_UNSPEC; if (flags & LH_BIND) hints.ai_flags |= AI_PASSIVE; @@ -736,30 +767,30 @@ lookup_host (const char *host, int flags) #ifdef AI_NUMERICHOST if (numeric_address) { - /* Where available, the AI_NUMERICHOST hint can prevent costly - access to DNS servers. */ - hints.ai_flags |= AI_NUMERICHOST; - timeout = 0; /* no timeout needed when "resolving" - numeric hosts -- avoid setting up - signal handlers and such. */ + /* Where available, the AI_NUMERICHOST hint can prevent costly + access to DNS servers. */ + hints.ai_flags |= AI_NUMERICHOST; + timeout = 0; /* no timeout needed when "resolving" + numeric hosts -- avoid setting up + signal handlers and such. */ } #endif err = getaddrinfo_with_timeout (host, NULL, &hints, &res, timeout); if (err != 0 || res == NULL) { - if (!silent) - logprintf (LOG_VERBOSE, _("failed: %s.\n"), - err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno)); - return NULL; + if (!silent) + logprintf (LOG_VERBOSE, _("failed: %s.\n"), + err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno)); + return NULL; } al = address_list_from_addrinfo (res); freeaddrinfo (res); if (!al) { - logprintf (LOG_VERBOSE, - _("failed: No IPv4/IPv6 addresses for host.\n")); - return NULL; + logprintf (LOG_VERBOSE, + _("failed: No IPv4/IPv6 addresses for host.\n")); + return NULL; } /* Reorder addresses so that IPv4 ones (or IPv6 ones, as per @@ -767,23 +798,23 @@ lookup_host (const char *host, int flags) the addresses with the same family is undisturbed. */ if (al->count > 1 && opt.prefer_family != prefer_none) stable_sort (al->addresses, al->count, sizeof (ip_address), - opt.prefer_family == prefer_ipv4 - ? cmp_prefer_ipv4 : cmp_prefer_ipv6); + opt.prefer_family == prefer_ipv4 + ? cmp_prefer_ipv4 : cmp_prefer_ipv6); } #else /* not ENABLE_IPV6 */ { struct hostent *hptr = gethostbyname_with_timeout (host, timeout); if (!hptr) { - if (!silent) - { - if (errno != ETIMEDOUT) - logprintf (LOG_VERBOSE, _("failed: %s.\n"), - host_errstr (h_errno)); - else - logputs (LOG_VERBOSE, _("failed: timed out.\n")); - } - return NULL; + if (!silent) + { + if (errno != ETIMEDOUT) + logprintf (LOG_VERBOSE, _("failed: %s.\n"), + host_errstr (h_errno)); + else + logputs (LOG_VERBOSE, _("failed: timed out.\n")); + } + return NULL; } /* Do older systems have h_addr_list? */ al = address_list_from_ipv4_addresses (hptr->h_addr_list); @@ -791,19 +822,23 @@ lookup_host (const char *host, int flags) #endif /* not ENABLE_IPV6 */ /* Print the addresses determined by DNS lookup, but no more than - three. */ + three if show_all_dns_entries is not specified. */ if (!silent && !numeric_address) { int i; - int printmax = al->count <= 3 ? al->count : 3; + int printmax = al->count; + + if (!opt.show_all_dns_entries && printmax > 3) + printmax = 3; + for (i = 0; i < printmax; i++) - { - logputs (LOG_VERBOSE, print_address (al->addresses + i)); - if (i < printmax - 1) - logputs (LOG_VERBOSE, ", "); - } + { + logputs (LOG_VERBOSE, print_address (al->addresses + i)); + if (i < printmax - 1) + logputs (LOG_VERBOSE, ", "); + } if (printmax != al->count) - logputs (LOG_VERBOSE, ", ..."); + logputs (LOG_VERBOSE, ", ..."); logputs (LOG_VERBOSE, "\n"); } @@ -823,12 +858,12 @@ accept_domain (struct url *u) if (opt.domains) { if (!sufmatch ((const char **)opt.domains, u->host)) - return false; + return false; } if (opt.exclude_domains) { if (sufmatch ((const char **)opt.exclude_domains, u->host)) - return false; + return false; } return true; } @@ -846,12 +881,15 @@ sufmatch (const char **list, const char *what) lw = strlen (what); for (i = 0; list[i]; i++) { + if (list[i][0] == '\0') + continue; + for (j = strlen (list[i]), k = lw; j >= 0 && k >= 0; j--, k--) - if (TOLOWER (list[i][j]) != TOLOWER (what[k])) - break; + if (c_tolower (list[i][j]) != c_tolower (what[k])) + break; /* The domain must be first to reach to beginning. */ if (j == -1) - return true; + return true; } return false; } @@ -863,16 +901,31 @@ host_cleanup (void) { hash_table_iterator iter; for (hash_table_iterate (host_name_addresses_map, &iter); - hash_table_iter_next (&iter); - ) - { - char *host = iter.key; - struct address_list *al = iter.value; - xfree (host); - assert (al->refcount == 1); - address_list_delete (al); - } + hash_table_iter_next (&iter); + ) + { + char *host = iter.key; + struct address_list *al = iter.value; + xfree (host); + assert (al->refcount == 1); + address_list_delete (al); + } hash_table_destroy (host_name_addresses_map); host_name_addresses_map = NULL; } } + +bool +is_valid_ip_address (const char *name) +{ + const char *endp; + + endp = name + strlen(name); + if (is_valid_ipv4_address (name, endp)) + return true; +#ifdef ENABLE_IPV6 + if (is_valid_ipv6_address (name, endp)) + return true; +#endif + return false; +}