hostip: resolve user supplied ip addresses
No binary (build failed)
—
(log yok)
| @@ -167,7 +167,13 @@ static CURLcode cf_dns_start(struct Curl_cfilter *cf, | |
| #endif | |
| /* Resolve target host right on */ | |
| - | CURL_TRC_CF(data, cf, "resolve host %s:%u", ctx->hostname, ctx->port); |
| + | CURL_TRC_CF(data, cf, "cf_dns_start host %s:%u", ctx->hostname, ctx->port); |
| + | if(Curl_is_ipv4addr(ctx->hostname)) |
| + | ctx->dns_queries |= CURL_DNSQ_A; |
| + | #ifdef USE_IPV6 |
| + | else if(Curl_is_ipaddr(ctx->hostname)) /* not ipv4, must be ipv6 then */ |
| + | ctx->dns_queries |= CURL_DNSQ_AAAA; |
| + | #endif |
| result = Curl_resolv(data, ctx->dns_queries, | |
| ctx->hostname, ctx->port, ctx->transport, | |
| timeout_ms, &ctx->resolv_id, pdns); | |
| @@ -495,10 +501,18 @@ CURLcode Curl_conn_dns_result(struct connectdata *conn, int sockindex) | |
| } | |
| static const struct Curl_addrinfo * | |
| - | cf_dns_get_nth_ai(const struct Curl_addrinfo *ai, |
| + | cf_dns_get_nth_ai(struct Curl_cfilter *cf, const struct Curl_addrinfo *ai, |
| int ai_family, unsigned int index) | |
| { | |
| + | struct cf_dns_ctx *ctx = cf->ctx; |
| unsigned int i = 0; | |
| + | |
| + | if((ai_family == AF_INET) && !(ctx->dns_queries & CURL_DNSQ_A)) |
| + | return NULL; |
| + | #ifdef USE_IPV6 |
| + | if((ai_family == AF_INET6) && !(ctx->dns_queries & CURL_DNSQ_AAAA)) |
| + | return NULL; |
| + | #endif |
| for(i = 0; ai; ai = ai->ai_next) { | |
| if(ai->ai_family == ai_family) { | |
| if(i == index) | |
| @@ -550,7 +564,7 @@ Curl_cf_dns_get_ai(struct Curl_cfilter *cf, | |
| if(ctx->resolv_result) | |
| return NULL; | |
| else if(ctx->dns) | |
| - | return cf_dns_get_nth_ai(ctx->dns->addr, ai_family, index); |
| + | return cf_dns_get_nth_ai(cf, ctx->dns->addr, ai_family, index); |
| else | |
| return Curl_resolv_get_ai(data, ctx->resolv_id, ai_family, index); | |
| } | |
| @@ -297,7 +297,7 @@ static void cf_ip_ballers_clear(struct Curl_cfilter *cf, | |
| bs->winner = NULL; | |
| } | |
| - | static CURLcode cf_ip_ballers_init(struct cf_ip_ballers *bs, int ip_version, |
| + | static CURLcode cf_ip_ballers_init(struct cf_ip_ballers *bs, |
| struct Curl_cfilter *cf, | |
| cf_ip_connect_create *cf_create, | |
| uint8_t transport, | |
| @@ -320,19 +320,9 @@ static CURLcode cf_ip_ballers_init(struct cf_ip_ballers *bs, int ip_version, | |
| } | |
| else { /* TCP/UDP/QUIC */ | |
| #ifdef USE_IPV6 | |
| - | if(ip_version == CURL_IPRESOLVE_V6) |
| - | cf_ai_iter_init(&bs->addr_iter, NULL, AF_INET); |
| - | else |
| - | cf_ai_iter_init(&bs->addr_iter, cf, AF_INET); |
| - | |
| - | if(ip_version == CURL_IPRESOLVE_V4) |
| - | cf_ai_iter_init(&bs->ipv6_iter, NULL, AF_INET6); |
| - | else |
| - | cf_ai_iter_init(&bs->ipv6_iter, cf, AF_INET6); |
| - | #else |
| - | (void)ip_version; |
| - | cf_ai_iter_init(&bs->addr_iter, cf, AF_INET); |
| + | cf_ai_iter_init(&bs->ipv6_iter, cf, AF_INET6); |
| #endif | |
| + | cf_ai_iter_init(&bs->addr_iter, cf, AF_INET); |
| } | |
| return CURLE_OK; | |
| } | |
| @@ -748,7 +738,7 @@ static CURLcode cf_ip_happy_init(struct Curl_cfilter *cf, | |
| CURL_TRC_CF(data, cf, "init ip ballers for transport %u", ctx->transport); | |
| ctx->started = *Curl_pgrs_now(data); | |
| - | return cf_ip_ballers_init(&ctx->ballers, cf->conn->ip_version, cf, |
| + | return cf_ip_ballers_init(&ctx->ballers, cf, |
| ctx->cf_create, ctx->transport, | |
| data->set.happy_eyeballs_timeout, | |
| IP_HE_MAX_CONCURRENT_ATTEMPTS); | |
| @@ -448,8 +448,15 @@ Curl_resolv_get_ai(struct Curl_easy *data, uint32_t resolv_id, | |
| { | |
| #ifdef CURLRES_ASYNCH | |
| struct Curl_resolv_async *async = Curl_async_get(data, resolv_id); | |
| - | if(async) |
| + | if(async) { |
| + | if((ai_family == AF_INET) && !(async->dns_queries & CURL_DNSQ_A)) |
| + | return NULL; |
| + | #ifdef USE_IPV6 |
| + | if((ai_family == AF_INET6) && !(async->dns_queries & CURL_DNSQ_AAAA)) |
| + | return NULL; |
| + | #endif |
| return Curl_async_get_ai(data, async, ai_family, index); | |
| + | } |
| #else | |
| (void)data; | |
| (void)resolv_id; | |
| @@ -385,3 +385,31 @@ class TestProxy: | |
| else: | |
| r.check_response(count=1, http_status=200, | |
| protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1') | |
| + | |
| + | # download via http: ipv4 proxy (no tunnel) using IP address, IPv6 only |
| + | @pytest.mark.skipif(condition=not Env.curl_has_feature('IPv6'), |
| + | reason='no ipv6 support') |
| + | def test_10_15_proxy_ip_addr(self, env: Env, httpd): |
| + | proto = 'http/1.1' |
| + | curl = CurlClient(env=env, force_resolv=False) |
| + | url = f'http://localhost:{env.http_port}/data.json' |
| + | xargs = curl.get_proxy_args(proto=proto, use_ip=True, proxys=False) |
| + | xargs.append('-6') |
| + | r = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True, |
| + | extra_args=xargs) |
| + | r.check_exit_code(0), f'{r}' |
| + | r.check_response(count=1, http_status=200, protocol='HTTP/1.1') |
| + | |
| + | # download via http: ipv6 proxy (no tunnel) using IP address, IPv4 only |
| + | @pytest.mark.skipif(condition=not Env.curl_has_feature('IPv6'), |
| + | reason='no ipv6 support') |
| + | def test_10_16_proxy_ip_addr(self, env: Env, httpd): |
| + | proto = 'http/1.1' |
| + | curl = CurlClient(env=env, force_resolv=False) |
| + | url = f'http://localhost:{env.http_port}/data.json' |
| + | xargs = curl.get_proxy_args(proto=proto, use_ipv6=True, proxys=False) |
| + | xargs.append('-4') |
| + | r = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True, |
| + | extra_args=xargs) |
| + | r.check_exit_code(0), f'{r}' |
| + | r.check_response(count=1, http_status=200, protocol='HTTP/1.1') |
| @@ -684,22 +684,25 @@ class CurlClient: | |
| def get_proxy_args(self, proto: str = 'http/1.1', | |
| proxys: bool = True, tunnel: bool = False, | |
| - | use_ip: bool = False): |
| - | proxy_name = self._server_addr if use_ip else self.env.proxy_domain |
| + | use_ip: bool = False, use_ipv6: bool = False): |
| + | proxy_name = '[::1]' if use_ipv6 else \ |
| + | self._server_addr if use_ip else self.env.proxy_domain |
| if proxys: | |
| pport = self.env.pts_port(proto) if tunnel else self.env.proxys_port | |
| xargs = [ | |
| '--proxy', f'https://{proxy_name}:{pport}/', | |
| - | '--resolve', f'{proxy_name}:{pport}:{self._server_addr}', |
| '--proxy-cacert', self.env.ca.cert_file, | |
| ] | |
| + | if self._force_resolv and not use_ip and not use_ipv6: |
| + | xargs.extend(['--resolve', f'{proxy_name}:{pport}:{self._server_addr}']) |
| if proto == 'h2': | |
| xargs.append('--proxy-http2') | |
| else: | |
| xargs = [ | |
| '--proxy', f'http://{proxy_name}:{self.env.proxy_port}/', | |
| - | '--resolve', f'{proxy_name}:{self.env.proxy_port}:{self._server_addr}', |
| ] | |
| + | if self._force_resolv and not use_ip and not use_ipv6: |
| + | xargs.extend(['--resolve', f'{proxy_name}:{self.env.proxy_port}:{self._server_addr}']) |
| if tunnel: | |
| xargs.append('--proxytunnel') | |
| return xargs | |
| @@ -506,6 +506,7 @@ class Httpd: | |
| return [ | |
| ' <Proxy "*">', | |
| ' Require ip 127.0.0.1', | |
| + | ' Require ip ::1', |
| ' </Proxy>', | |
| ] | |