From: Stefan Eissing Date: Tue, 3 Sep 2024 12:30:32 +0000 (+0200) Subject: connect: always prefer ipv6 in IP eyeballing X-Git-Tag: curl-8_10_0~52 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=81a33428773bac7bb02c56278d4be8c17a40dbfe;p=thirdparty%2Fcurl.git 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 --- diff --git a/lib/connect.c b/lib/connect.c index 04f4e0bbe7..fb785f2750 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -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; diff --git a/tests/unit/unit2600.c b/tests/unit/unit2600.c index 5a3def4076..bcc53c08be 100644 --- a/tests/unit/unit2600.c +++ b/tests/unit/unit2600.c @@ -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 */