connect: always prefer ipv6 in IP eyeballing

Always try ipv6 addresses first, ipv4 second after a delay.

If neither ipv4/6 are amongst the supplied addresses, start a happy
eyeballer for the first address family present. This is for AF_UNIX
connects.

Fixes #14761
Reported-by: janedenone on hackerone
Closes #14768
This commit is contained in:
Stefan Eissing 2024-09-03 14:30:32 +02:00 committed by Daniel Stenberg
parent 933e202eb5
commit 81a3342877
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
2 changed files with 23 additions and 25 deletions

View File

@ -767,9 +767,9 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
struct cf_he_ctx *ctx = cf->ctx;
struct connectdata *conn = cf->conn;
CURLcode result = CURLE_COULDNT_CONNECT;
int ai_family0, ai_family1;
int ai_family0 = 0, ai_family1 = 0;
timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
const struct Curl_addrinfo *addr0, *addr1;
const struct Curl_addrinfo *addr0 = NULL, *addr1 = NULL;
if(timeout_ms < 0) {
/* a precaution, no need to continue if time already is up */
@ -788,33 +788,31 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
* the 2 connect attempt ballers to try different families, if possible.
*
*/
if(conn->ip_version == CURL_IPRESOLVE_WHATEVER) {
/* any IP version is allowed */
ai_family0 = remotehost->addr?
remotehost->addr->ai_family : 0;
if(conn->ip_version == CURL_IPRESOLVE_V6) {
#ifdef USE_IPV6
ai_family1 = ai_family0 == AF_INET6 ?
AF_INET : AF_INET6;
#else
ai_family1 = AF_UNSPEC;
ai_family0 = AF_INET6;
addr0 = addr_first_match(remotehost->addr, ai_family0);
#endif
}
else if(conn->ip_version == CURL_IPRESOLVE_V4) {
ai_family0 = AF_INET;
addr0 = addr_first_match(remotehost->addr, ai_family0);
}
else {
/* only one IP version is allowed */
ai_family0 = (conn->ip_version == CURL_IPRESOLVE_V4) ?
AF_INET :
#ifdef USE_IPV6
AF_INET6;
#else
AF_UNSPEC;
#endif
ai_family1 = AF_UNSPEC;
/* no user preference, we try ipv6 always first when available */
ai_family0 = AF_INET6;
addr0 = addr_first_match(remotehost->addr, ai_family0);
/* next candidate is ipv4 */
ai_family1 = AF_INET;
addr1 = addr_first_match(remotehost->addr, ai_family1);
/* no ip address families, probably AF_UNIX or something, use the
* address family given to us */
if(!addr1 && !addr0 && remotehost->addr) {
ai_family0 = remotehost->addr->ai_family;
addr0 = addr_first_match(remotehost->addr, ai_family0);
}
}
/* Get the first address in the list that matches the family,
* this might give NULL, if we do not have any matches. */
addr0 = addr_first_match(remotehost->addr, ai_family0);
addr1 = addr_first_match(remotehost->addr, ai_family1);
if(!addr0 && addr1) {
/* switch around, so a single baller always uses addr0 */
addr0 = addr1;

View File

@ -377,8 +377,8 @@ static struct test_case TEST_CASES[] = {
/* 2 ipv6, fails after ~400ms, reports COULDNT_CONNECT */
{ 5, TURL, "test.com:123:192.0.2.1,::1", CURL_IPRESOLVE_WHATEVER,
CNCT_TMOT, 150, 200, 200, 1, 1, 350, TC_TMOT, R_FAIL, "v4" },
/* mixed ip4+6, v4 starts, v6 kicks in on HE, fails after ~350ms */
CNCT_TMOT, 150, 200, 200, 1, 1, 350, TC_TMOT, R_FAIL, "v6" },
/* mixed ip4+6, v6 always first, v4 kicks in on HE, fails after ~350ms */
{ 6, TURL, "test.com:123:::1,192.0.2.1", CURL_IPRESOLVE_WHATEVER,
CNCT_TMOT, 150, 200, 200, 1, 1, 350, TC_TMOT, R_FAIL, "v6" },
/* mixed ip6+4, v6 starts, v4 never starts due to high HE, TIMEOUT */