cf-dns: connection filter for DNS queries

New connection filter `cf-dns` that manages DNS queries. If hands
out addresses and HTTPS-RR records to anyone interested. Used by
HTTPS and IP happy eyeballing.

Information may become available *before* the libcurl "dns entry"
is complete, e.g. all queries have been answered. The cf-ip-happy
filter uses this information to start connection attempts as soon
as the first address is available.

The multi MSTATE_RESOLVING was removed. A new connection always
goes to MSTATE_CONNECTING. The connectdata bit `dns_resolved`
indicates when DNS information is complete. This is used for
error reporting and starting the progress meter.

Removed dns entries `data->state.dns[i]`, as the `cf-dns` filter
now keeps the reference now.

Many minor tweaks for making this work and pass address information
around safely.

Closes #21027
This commit is contained in:
Stefan Eissing 2026-03-25 15:07:10 +01:00 committed by Daniel Stenberg
parent 89741958e8
commit 335dc0e3c5
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
44 changed files with 1785 additions and 1017 deletions

View file

@ -188,7 +188,7 @@ RETR %TESTNUMBER
QUIT
</protocol>
<limits>
Allocations: 170
Allocations: 180
Maximum allocated: 150000
</limits>
</verify>

View file

@ -72,7 +72,7 @@ via: 1.1 nghttpx
s/^server: nghttpx.*\r?\n//
</stripfile>
<limits>
Allocations: 160
Allocations: 170
Maximum allocated: 1800000
</limits>
</verify>

View file

@ -54,7 +54,7 @@ Accept: */*
</protocol>
<limits>
Allocations: 82
Allocations: 90
Maximum allocated: 33400
</limits>
</verify>

View file

@ -93,128 +93,128 @@ CURLOPT_SHARE
lock: share [Pigs in space]: 0
unlock: share [Pigs in space]: 1
CURLOPT_COOKIELIST injected_and_clobbered
lock: cookie [Pigs in space]: 0
unlock: cookie [Pigs in space]: 1
CURLOPT_COOKIELIST ALL
lock: cookie [Pigs in space]: 2
unlock: cookie [Pigs in space]: 3
CURLOPT_COOKIELIST ALL
CURLOPT_COOKIELIST session
lock: cookie [Pigs in space]: 4
unlock: cookie [Pigs in space]: 5
CURLOPT_COOKIELIST session
CURLOPT_COOKIELIST injected
lock: cookie [Pigs in space]: 6
unlock: cookie [Pigs in space]: 7
CURLOPT_COOKIELIST injected
CURLOPT_COOKIELIST SESS
lock: cookie [Pigs in space]: 8
unlock: cookie [Pigs in space]: 9
CURLOPT_COOKIELIST SESS
CLEANUP
lock: cookie [Pigs in space]: 10
unlock: cookie [Pigs in space]: 11
CLEANUP
lock: cookie [Pigs in space]: 12
unlock: cookie [Pigs in space]: 13
lock: share [Pigs in space]: 14
unlock: share [Pigs in space]: 15
lock: share [Pigs in space]: 2
unlock: share [Pigs in space]: 3
*** run 1
CURLOPT_SHARE
lock: share [Pigs in space]: 16
unlock: share [Pigs in space]: 17
lock: share [Pigs in space]: 4
unlock: share [Pigs in space]: 5
PERFORM
lock: cookie [Pigs in space]: 12
unlock: cookie [Pigs in space]: 13
lock: cookie [Pigs in space]: 14
unlock: cookie [Pigs in space]: 15
lock: dns [Pigs in space]: 0
unlock: dns [Pigs in space]: 1
lock: dns [Pigs in space]: 2
unlock: dns [Pigs in space]: 3
lock: dns [Pigs in space]: 4
unlock: dns [Pigs in space]: 5
lock: cookie [Pigs in space]: 16
unlock: cookie [Pigs in space]: 17
lock: cookie [Pigs in space]: 18
unlock: cookie [Pigs in space]: 19
lock: cookie [Pigs in space]: 20
unlock: cookie [Pigs in space]: 21
lock: dns [Pigs in space]: 22
unlock: dns [Pigs in space]: 23
lock: dns [Pigs in space]: 24
unlock: dns [Pigs in space]: 25
lock: cookie [Pigs in space]: 22
unlock: cookie [Pigs in space]: 23
run 1: set cookie 1, 2 and 3
lock: dns [Pigs in space]: 6
unlock: dns [Pigs in space]: 7
CLEANUP
lock: cookie [Pigs in space]: 24
unlock: cookie [Pigs in space]: 25
lock: share [Pigs in space]: 6
unlock: share [Pigs in space]: 7
*** run 2
CURLOPT_SHARE
lock: share [Pigs in space]: 8
unlock: share [Pigs in space]: 9
PERFORM
lock: cookie [Pigs in space]: 26
unlock: cookie [Pigs in space]: 27
lock: cookie [Pigs in space]: 28
unlock: cookie [Pigs in space]: 29
lock: dns [Pigs in space]: 8
unlock: dns [Pigs in space]: 9
lock: dns [Pigs in space]: 10
unlock: dns [Pigs in space]: 11
lock: cookie [Pigs in space]: 30
unlock: cookie [Pigs in space]: 31
lock: cookie [Pigs in space]: 32
unlock: cookie [Pigs in space]: 33
run 1: set cookie 1, 2 and 3
lock: dns [Pigs in space]: 34
unlock: dns [Pigs in space]: 35
lock: dns [Pigs in space]: 36
unlock: dns [Pigs in space]: 37
lock: cookie [Pigs in space]: 34
unlock: cookie [Pigs in space]: 35
run 2: set cookie 4 and 5
lock: dns [Pigs in space]: 12
unlock: dns [Pigs in space]: 13
CLEANUP
lock: cookie [Pigs in space]: 36
unlock: cookie [Pigs in space]: 37
lock: share [Pigs in space]: 10
unlock: share [Pigs in space]: 11
*** run 3
CURLOPT_SHARE
lock: share [Pigs in space]: 12
unlock: share [Pigs in space]: 13
CURLOPT_COOKIEJAR
CURLOPT_COOKIELIST FLUSH
lock: cookie [Pigs in space]: 38
unlock: cookie [Pigs in space]: 39
lock: share [Pigs in space]: 40
unlock: share [Pigs in space]: 41
*** run 2
CURLOPT_SHARE
lock: share [Pigs in space]: 42
unlock: share [Pigs in space]: 43
PERFORM
lock: cookie [Pigs in space]: 40
unlock: cookie [Pigs in space]: 41
lock: dns [Pigs in space]: 14
unlock: dns [Pigs in space]: 15
lock: dns [Pigs in space]: 16
unlock: dns [Pigs in space]: 17
lock: cookie [Pigs in space]: 42
unlock: cookie [Pigs in space]: 43
lock: cookie [Pigs in space]: 44
unlock: cookie [Pigs in space]: 45
lock: cookie [Pigs in space]: 46
unlock: cookie [Pigs in space]: 47
lock: dns [Pigs in space]: 48
unlock: dns [Pigs in space]: 49
lock: cookie [Pigs in space]: 48
unlock: cookie [Pigs in space]: 49
lock: cookie [Pigs in space]: 50
unlock: cookie [Pigs in space]: 51
run 3: overwrite cookie 1 and 4, set cookie 6 with and without tailmatch
lock: dns [Pigs in space]: 18
unlock: dns [Pigs in space]: 19
CLEANUP
lock: cookie [Pigs in space]: 52
unlock: cookie [Pigs in space]: 53
lock: share [Pigs in space]: 14
unlock: share [Pigs in space]: 15
CURLOPT_SHARE
lock: share [Pigs in space]: 16
unlock: share [Pigs in space]: 17
CURLOPT_COOKIELIST ALL
lock: cookie [Pigs in space]: 54
unlock: cookie [Pigs in space]: 55
run 2: set cookie 4 and 5
lock: dns [Pigs in space]: 56
unlock: dns [Pigs in space]: 57
lock: dns [Pigs in space]: 58
unlock: dns [Pigs in space]: 59
CLEANUP
lock: cookie [Pigs in space]: 60
unlock: cookie [Pigs in space]: 61
lock: share [Pigs in space]: 62
unlock: share [Pigs in space]: 63
*** run 3
CURLOPT_SHARE
lock: share [Pigs in space]: 64
unlock: share [Pigs in space]: 65
CURLOPT_COOKIEJAR
CURLOPT_COOKIELIST FLUSH
lock: cookie [Pigs in space]: 66
unlock: cookie [Pigs in space]: 67
PERFORM
lock: cookie [Pigs in space]: 68
unlock: cookie [Pigs in space]: 69
lock: dns [Pigs in space]: 70
unlock: dns [Pigs in space]: 71
lock: cookie [Pigs in space]: 72
unlock: cookie [Pigs in space]: 73
lock: cookie [Pigs in space]: 74
unlock: cookie [Pigs in space]: 75
lock: cookie [Pigs in space]: 76
unlock: cookie [Pigs in space]: 77
lock: cookie [Pigs in space]: 78
unlock: cookie [Pigs in space]: 79
lock: cookie [Pigs in space]: 80
unlock: cookie [Pigs in space]: 81
run 3: overwrite cookie 1 and 4, set cookie 6 with and without tailmatch
lock: dns [Pigs in space]: 82
unlock: dns [Pigs in space]: 83
lock: dns [Pigs in space]: 84
unlock: dns [Pigs in space]: 85
CLEANUP
lock: cookie [Pigs in space]: 86
unlock: cookie [Pigs in space]: 87
lock: share [Pigs in space]: 88
unlock: share [Pigs in space]: 89
CURLOPT_SHARE
lock: share [Pigs in space]: 90
unlock: share [Pigs in space]: 91
CURLOPT_COOKIELIST ALL
lock: cookie [Pigs in space]: 92
unlock: cookie [Pigs in space]: 93
CURLOPT_COOKIEJAR
CURLOPT_COOKIELIST RELOAD
lock: cookie [Pigs in space]: 94
unlock: cookie [Pigs in space]: 95
lock: cookie [Pigs in space]: 96
unlock: cookie [Pigs in space]: 97
lock: cookie [Pigs in space]: 56
unlock: cookie [Pigs in space]: 57
lock: cookie [Pigs in space]: 58
unlock: cookie [Pigs in space]: 59
loaded cookies:
-----------------
www.host.foo.com FALSE / FALSE %days[400] test6 six_more
@ -229,13 +229,13 @@ loaded cookies:
try SHARE_CLEANUP...
SHARE_CLEANUP failed, correct
CLEANUP
lock: cookie [Pigs in space]: 98
unlock: cookie [Pigs in space]: 99
lock: share [Pigs in space]: 100
unlock: share [Pigs in space]: 101
lock: cookie [Pigs in space]: 60
unlock: cookie [Pigs in space]: 61
lock: share [Pigs in space]: 18
unlock: share [Pigs in space]: 19
SHARE_CLEANUP
lock: share [Pigs in space]: 102
unlock: share [Pigs in space]: 103
lock: share [Pigs in space]: 20
unlock: share [Pigs in space]: 21
GLOBAL_CLEANUP
</stdout>
<file name="%LOGDIR/jar%TESTNUMBER" mode="text">

View file

@ -35,7 +35,9 @@ struct t506_Tdata {
struct t506_userdata {
const char *text;
int counter;
int share_counter;
int dns_counter;
int cookie_counter;
};
static int locks[3];
@ -46,7 +48,7 @@ static void t506_test_lock(CURL *curl, curl_lock_data data,
{
const char *what;
struct t506_userdata *user = (struct t506_userdata *)useptr;
int locknum;
int locknum, *pcounter;
(void)curl;
(void)laccess;
@ -55,14 +57,17 @@ static void t506_test_lock(CURL *curl, curl_lock_data data,
case CURL_LOCK_DATA_SHARE:
what = "share";
locknum = 0;
pcounter = &user->share_counter;
break;
case CURL_LOCK_DATA_DNS:
what = "dns";
locknum = 1;
pcounter = &user->dns_counter;
break;
case CURL_LOCK_DATA_COOKIE:
what = "cookie";
locknum = 2;
pcounter = &user->cookie_counter;
break;
default:
curl_mfprintf(stderr, "lock: no such data: %d\n", data);
@ -76,8 +81,8 @@ static void t506_test_lock(CURL *curl, curl_lock_data data,
}
locks[locknum]++;
curl_mprintf("lock: %-6s [%s]: %d\n", what, user->text, user->counter);
user->counter++;
curl_mprintf("lock: %-6s [%s]: %d\n", what, user->text, *pcounter);
(*pcounter)++;
}
/* unlock callback */
@ -85,19 +90,22 @@ static void t506_test_unlock(CURL *curl, curl_lock_data data, void *useptr)
{
const char *what;
struct t506_userdata *user = (struct t506_userdata *)useptr;
int locknum;
int locknum, *pcounter;
(void)curl;
switch(data) {
case CURL_LOCK_DATA_SHARE:
what = "share";
locknum = 0;
pcounter = &user->share_counter;
break;
case CURL_LOCK_DATA_DNS:
what = "dns";
locknum = 1;
pcounter = &user->dns_counter;
break;
case CURL_LOCK_DATA_COOKIE:
what = "cookie";
pcounter = &user->cookie_counter;
locknum = 2;
break;
default:
@ -112,8 +120,8 @@ static void t506_test_unlock(CURL *curl, curl_lock_data data, void *useptr)
}
locks[locknum]--;
curl_mprintf("unlock: %-6s [%s]: %d\n", what, user->text, user->counter);
user->counter++;
curl_mprintf("unlock: %-6s [%s]: %d\n", what, user->text, *pcounter);
(*pcounter)++;
}
/* build host entry */
@ -178,8 +186,8 @@ static CURLcode test_lib506(const char *URL)
const char *jar = libtest_arg2;
memset(&user, 0, sizeof(user));
user.text = "Pigs in space";
user.counter = 0;
curl_mprintf("GLOBAL_INIT\n");
if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {

View file

@ -73,16 +73,14 @@ static CURLcode test_unit1620(const char *arg)
CURLcode result;
struct Curl_easy *empty;
enum dupstring i;
bool async = FALSE;
bool protocol_connect = FALSE;
bool connected = FALSE;
result = Curl_open(&empty);
if(result)
goto unit_test_abort;
fail_unless(result == CURLE_OK, "Curl_open() failed");
result = Curl_connect(empty, &async, &protocol_connect);
result = Curl_connect(empty, &connected);
fail_unless(result == CURLE_URL_MALFORMAT,
"Curl_connect() failed to return CURLE_URL_MALFORMAT");
@ -90,7 +88,7 @@ static CURLcode test_unit1620(const char *arg)
"empty->magic should be equal to CURLEASY_MAGIC_NUMBER");
/* double invoke to ensure no dependency on internal state */
result = Curl_connect(empty, &async, &protocol_connect);
result = Curl_connect(empty, &connected);
fail_unless(result == CURLE_URL_MALFORMAT,
"Curl_connect() failed to return CURLE_URL_MALFORMAT");

View file

@ -161,7 +161,7 @@ static CURLcode cf_test_adjust_pollset(struct Curl_cfilter *cf,
static CURLcode cf_test_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
struct connectdata *conn,
const struct Curl_addrinfo *ai,
struct Curl_sockaddr_ex *addr,
uint8_t transport)
{
static const struct Curl_cftype cft_test = {
@ -195,7 +195,7 @@ static CURLcode cf_test_create(struct Curl_cfilter **pcf,
goto out;
}
ctx->idx = test_idx++;
ctx->ai_family = ai->ai_family;
ctx->ai_family = addr->family;
ctx->transport = transport;
ctx->started = curlx_now();
#ifdef USE_IPV6