diff options
Diffstat (limited to 'Utilities/cmcurl/lib/hostip.c')
-rw-r--r-- | Utilities/cmcurl/lib/hostip.c | 210 |
1 files changed, 176 insertions, 34 deletions
diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c index e0e3cfc..911d5ed 100644 --- a/Utilities/cmcurl/lib/hostip.c +++ b/Utilities/cmcurl/lib/hostip.c @@ -56,13 +56,13 @@ #include "hash.h" #include "rand.h" #include "share.h" -#include "strerror.h" #include "url.h" #include "inet_ntop.h" #include "inet_pton.h" #include "multiif.h" #include "doh.h" #include "warnless.h" +#include "strcase.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -289,7 +289,7 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data, user.cache_timeout = data->set.dns_cache_timeout; if(hostcache_timestamp_remove(&user, dns)) { - infof(data, "Hostname in DNS cache was stale, zapped\n"); + infof(data, "Hostname in DNS cache was stale, zapped"); dns = NULL; /* the memory deallocation is being handled by the hash */ Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1); } @@ -460,6 +460,127 @@ Curl_cache_addr(struct Curl_easy *data, return dns; } +#ifdef ENABLE_IPV6 +/* return a static IPv6 resolve for 'localhost' */ +static struct Curl_addrinfo *get_localhost6(int port) +{ + struct Curl_addrinfo *ca; + const size_t ss_size = sizeof(struct sockaddr_in6); + const size_t hostlen = strlen("localhost"); + struct sockaddr_in6 sa6; + unsigned char ipv6[16]; + unsigned short port16 = (unsigned short)(port & 0xffff); + ca = calloc(sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1, 1); + if(!ca) + return NULL; + + sa6.sin6_family = AF_INET6; + sa6.sin6_port = htons(port16); + sa6.sin6_flowinfo = 0; + sa6.sin6_scope_id = 0; + if(Curl_inet_pton(AF_INET6, "::1", ipv6) < 1) + return NULL; + memcpy(&sa6.sin6_addr, ipv6, sizeof(ipv6)); + + ca->ai_flags = 0; + ca->ai_family = AF_INET6; + ca->ai_socktype = SOCK_STREAM; + ca->ai_protocol = IPPROTO_TCP; + ca->ai_addrlen = (curl_socklen_t)ss_size; + ca->ai_next = NULL; + ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo)); + memcpy(ca->ai_addr, &sa6, ss_size); + ca->ai_canonname = (char *)ca->ai_addr + ss_size; + strcpy(ca->ai_canonname, "localhost"); + return ca; +} +#else +#define get_localhost6(x) NULL +#endif + +/* return a static IPv4 resolve for 'localhost' */ +static struct Curl_addrinfo *get_localhost(int port) +{ + struct Curl_addrinfo *ca; + const size_t ss_size = sizeof(struct sockaddr_in); + const size_t hostlen = strlen("localhost"); + struct sockaddr_in sa; + unsigned int ipv4; + unsigned short port16 = (unsigned short)(port & 0xffff); + + /* memset to clear the sa.sin_zero field */ + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(port16); + if(Curl_inet_pton(AF_INET, "127.0.0.1", (char *)&ipv4) < 1) + return NULL; + memcpy(&sa.sin_addr, &ipv4, sizeof(ipv4)); + + ca = calloc(sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1, 1); + if(!ca) + return NULL; + ca->ai_flags = 0; + ca->ai_family = AF_INET; + ca->ai_socktype = SOCK_STREAM; + ca->ai_protocol = IPPROTO_TCP; + ca->ai_addrlen = (curl_socklen_t)ss_size; + ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo)); + memcpy(ca->ai_addr, &sa, ss_size); + ca->ai_canonname = (char *)ca->ai_addr + ss_size; + strcpy(ca->ai_canonname, "localhost"); + ca->ai_next = get_localhost6(port); + return ca; +} + +#ifdef ENABLE_IPV6 +/* + * Curl_ipv6works() returns TRUE if IPv6 seems to work. + */ +bool Curl_ipv6works(struct Curl_easy *data) +{ + if(data) { + /* the nature of most system is that IPv6 status doesn't come and go + during a program's lifetime so we only probe the first time and then we + have the info kept for fast re-use */ + DEBUGASSERT(data); + DEBUGASSERT(data->multi); + return data->multi->ipv6_works; + } + else { + int ipv6_works = -1; + /* probe to see if we have a working IPv6 stack */ + curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0); + if(s == CURL_SOCKET_BAD) + /* an IPv6 address was requested but we can't get/use one */ + ipv6_works = 0; + else { + ipv6_works = 1; + sclose(s); + } + return (ipv6_works>0)?TRUE:FALSE; + } +} +#endif /* ENABLE_IPV6 */ + +/* + * Curl_host_is_ipnum() returns TRUE if the given string is a numerical IPv4 + * (or IPv6 if supported) address. + */ +bool Curl_host_is_ipnum(const char *hostname) +{ + struct in_addr in; +#ifdef ENABLE_IPV6 + struct in6_addr in6; +#endif + if(Curl_inet_pton(AF_INET, hostname, &in) > 0 +#ifdef ENABLE_IPV6 + || Curl_inet_pton(AF_INET6, hostname, &in6) > 0 +#endif + ) + return TRUE; + return FALSE; +} + /* * Curl_resolv() is the main name resolve function within libcurl. It resolves * a name and returns a pointer to the entry in the 'entry' argument (if one @@ -487,9 +608,12 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, CURLcode result; enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */ struct connectdata *conn = data->conn; - *entry = NULL; +#ifndef CURL_DISABLE_DOH conn->bits.doh = FALSE; /* default is not */ +#else + (void)allowDOH; +#endif if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); @@ -497,7 +621,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, dns = fetch_addr(data, hostname, port); if(dns) { - infof(data, "Hostname %s was found in DNS cache\n", hostname); + infof(data, "Hostname %s was found in DNS cache", hostname); dns->inuse++; /* we use it! */ rc = CURLRESOLV_RESOLVED; } @@ -510,11 +634,15 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, struct Curl_addrinfo *addr = NULL; int respwait = 0; +#if !defined(CURL_DISABLE_DOH) || !defined(USE_RESOLVE_ON_IPS) struct in_addr in; +#endif +#ifndef CURL_DISABLE_DOH #ifndef USE_RESOLVE_ON_IPS const #endif bool ipnum = FALSE; +#endif /* notify the resolver start callback */ if(data->set.resolver_start) { @@ -534,16 +662,20 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, } #if defined(ENABLE_IPV6) && defined(CURL_OSX_CALL_COPYPROXIES) - /* - * The automagic conversion from IPv4 literals to IPv6 literals only works - * if the SCDynamicStoreCopyProxies system function gets called first. As - * Curl currently doesn't support system-wide HTTP proxies, we therefore - * don't use any value this function might return. - * - * This function is only available on a macOS and is not needed for - * IPv4-only builds, hence the conditions above. - */ - SCDynamicStoreCopyProxies(NULL); + { + /* + * The automagic conversion from IPv4 literals to IPv6 literals only + * works if the SCDynamicStoreCopyProxies system function gets called + * first. As Curl currently doesn't support system-wide HTTP proxies, we + * therefore don't use any value this function might return. + * + * This function is only available on a macOS and is not needed for + * IPv4-only builds, hence the conditions above. + */ + CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL); + if(dict) + CFRelease(dict); + } #endif #ifndef USE_RESOLVE_ON_IPS @@ -562,6 +694,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, #endif /* ENABLE_IPV6 */ #else /* if USE_RESOLVE_ON_IPS */ +#ifndef CURL_DISABLE_DOH /* First check if this is an IPv4 address string */ if(Curl_inet_pton(AF_INET, hostname, &in) > 0) /* This is a dotted IP address 123.123.123.123-style */ @@ -575,19 +708,25 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, ipnum = TRUE; } #endif /* ENABLE_IPV6 */ +#endif /* CURL_DISABLE_DOH */ #endif /* !USE_RESOLVE_ON_IPS */ if(!addr) { - /* Check what IP specifics the app has requested and if we can provide - * it. If not, bail out. */ - if(!Curl_ipvalid(data, conn)) + if(conn->ip_version == CURL_IPRESOLVE_V6 && !Curl_ipv6works(data)) return CURLRESOLV_ERROR; - if(allowDOH && data->set.doh && !ipnum) { + if(strcasecompare(hostname, "localhost")) + addr = get_localhost(port); +#ifndef CURL_DISABLE_DOH + else if(allowDOH && data->set.doh && !ipnum) addr = Curl_doh(data, hostname, port, &respwait); - } +#endif else { + /* Check what IP specifics the app has requested and if we can provide + * it. If not, bail out. */ + if(!Curl_ipvalid(data, conn)) + return CURLRESOLV_ERROR; /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a non-zero value indicating that we need to wait for the response to the resolve call */ @@ -757,7 +896,7 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data, #else #ifndef CURLRES_ASYNCH if(timeoutms) - infof(data, "timeout on name lookup is not supported\n"); + infof(data, "timeout on name lookup is not supported"); #else (void)timeoutms; /* timeoutms not used with an async resolver */ #endif @@ -850,12 +989,12 @@ static void freednsentry(void *freethis) } /* - * Curl_mk_dnscache() inits a new DNS cache and returns success/failure. + * Curl_init_dnscache() inits a new DNS cache. */ -int Curl_mk_dnscache(struct Curl_hash *hash) +void Curl_init_dnscache(struct Curl_hash *hash) { - return Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare, - freednsentry); + Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare, + freednsentry); } /* @@ -895,7 +1034,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) size_t entry_len; if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) { - infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'!\n", + infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'", hostp->data); continue; } @@ -984,7 +1123,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) #ifndef ENABLE_IPV6 if(strchr(address, ':')) { - infof(data, "Ignoring resolve address '%s', missing IPv6 support.\n", + infof(data, "Ignoring resolve address '%s', missing IPv6 support.", address); continue; } @@ -992,7 +1131,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) ai = Curl_str2addr(address, port); if(!ai) { - infof(data, "Resolve address '%s' found illegal!\n", address); + infof(data, "Resolve address '%s' found illegal!", address); goto err; } @@ -1011,10 +1150,10 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) error = false; err: if(error) { - infof(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!\n", + failf(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!", hostp->data); Curl_freeaddrinfo(head); - continue; + return CURLE_SETOPT_OPTION_SYNTAX; } /* Create an entry id, based upon the hostname and port */ @@ -1028,7 +1167,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1); if(dns) { - infof(data, "RESOLVE %s:%d is - old addresses discarded!\n", + infof(data, "RESOLVE %s:%d is - old addresses discarded!", hostname, port); /* delete old entry, there are two reasons for this 1. old entry may have different addresses. @@ -1061,12 +1200,12 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) Curl_freeaddrinfo(head); return CURLE_OUT_OF_MEMORY; } - infof(data, "Added %s:%d:%s to DNS cache%s\n", + infof(data, "Added %s:%d:%s to DNS cache%s", hostname, port, addresses, permanent ? "" : " (non-permanent)"); /* Wildcard hostname */ if(hostname[0] == '*' && hostname[1] == '\0') { - infof(data, "RESOLVE %s:%d is wildcard, enabling wildcard checks\n", + infof(data, "RESOLVE %s:%d is wildcard, enabling wildcard checks", hostname, port); data->state.wildcard_resolve = true; } @@ -1083,9 +1222,10 @@ CURLcode Curl_resolv_check(struct Curl_easy *data, #if defined(CURL_DISABLE_DOH) && !defined(CURLRES_ASYNCH) (void)dns; #endif - +#ifndef CURL_DISABLE_DOH if(data->conn->bits.doh) return Curl_doh_is_resolved(data, dns); +#endif return Curl_resolver_is_resolved(data, dns); } @@ -1093,10 +1233,12 @@ int Curl_resolv_getsock(struct Curl_easy *data, curl_socket_t *socks) { #ifdef CURLRES_ASYNCH +#ifndef CURL_DISABLE_DOH if(data->conn->bits.doh) - /* nothing to wait for during DOH resolve, those handles have their own + /* nothing to wait for during DoH resolve, those handles have their own sockets */ return GETSOCK_BLANK; +#endif return Curl_resolver_getsock(data, socks); #else (void)data; |