← Commit list

40d57c9f58

Stefan Eissing
Stefan Eissing
2026-04-13
SUCCESS Duration: 232s

Subject

hostip: resolve user supplied ip addresses

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/cf-dns.c+17 -3
@@ -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);
}
lib/cf-ip-happy.c+4 -14
@@ -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);
lib/hostip.c+8 -1
@@ -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;
tests/http/test_10_proxy.py+28 -0
@@ -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')
tests/http/testenv/curl.py+7 -4
@@ -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
tests/http/testenv/httpd.py+1 -0
@@ -506,6 +506,7 @@ class Httpd:
return [
' <Proxy "*">',
' Require ip 127.0.0.1',
+ ' Require ip ::1',
' </Proxy>',
]