Skip to content

Commit

Permalink
https-rr: implementation improvements
Browse files Browse the repository at this point in the history
- fold DoH and async HTTPS-RR handling into common code.
  have common cleanups, etc. Have a CURLcode result in async
  handling to allow HTTPS RR parsing to fail.
- keep target, ipv4hints, ipv6hints, port and echconfig also
  when resolving via cares. We need to know `target` and `port`
  when evaluating possible ALPN candidates to not go astray.
- add CURL_TRC_DNS for tracing DNS operations
- replace DoH specific tracing with DNS, use doh as alias
  for dns in curl_global_tracea()

Closes curl#16132
  • Loading branch information
icing authored and bagder committed Feb 18, 2025
1 parent db72b8d commit 1b71038
Show file tree
Hide file tree
Showing 12 changed files with 167 additions and 96 deletions.
6 changes: 5 additions & 1 deletion docs/libcurl/curl_global_trace.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,13 @@ In order to find out all components involved in a transfer, run it with "all"
configured. You can then see all names involved in your libcurl version in the
trace.
## `dns`
Tracing of DNS operations to resolve hostnames and HTTPS records.
## `doh`
Tracing of DNS-over-HTTP operations to resolve hostnames.
Former name for DNS-over-HTTP operations. Now an alias for `dns`.
## `read`
Expand Down
6 changes: 3 additions & 3 deletions lib/asyn-ares.c
Original file line number Diff line number Diff line change
Expand Up @@ -419,14 +419,14 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
them */
res->temp_ai = NULL;

result = res->result;
if(!data->state.async.dns)
result = Curl_resolver_error(data);
else {
if(!result) {
*dns = data->state.async.dns;
#ifdef USE_HTTPSRR_ARES
{
struct Curl_https_rrinfo *lhrr =
Curl_memdup(&res->hinfo, sizeof(struct Curl_https_rrinfo));
struct Curl_https_rrinfo *lhrr = Curl_httpsrr_dup_move(&res->hinfo);
if(!lhrr)
result = CURLE_OUT_OF_MEMORY;
else
Expand Down
10 changes: 6 additions & 4 deletions lib/asyn-thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -585,17 +585,19 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
Curl_mutex_release(&td->tsd.mutx);

if(done) {
CURLcode result = td->result;
getaddrinfo_complete(data);

if(!data->state.async.dns) {
CURLcode result = Curl_resolver_error(data);
if(!result && !data->state.async.dns)
result = Curl_resolver_error(data);

if(result) {
destroy_async_data(data);
return result;
}
#ifdef USE_HTTPSRR_ARES
{
struct Curl_https_rrinfo *lhrr =
Curl_memdup(&td->hinfo, sizeof(struct Curl_https_rrinfo));
struct Curl_https_rrinfo *lhrr = Curl_httpsrr_dup_move(&td->hinfo);
if(!lhrr) {
destroy_async_data(data);
return CURLE_OUT_OF_MEMORY;
Expand Down
2 changes: 2 additions & 0 deletions lib/asyn.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ struct thread_data {
timediff_t interval_end;
struct curltime start;
struct thread_sync_data tsd;
CURLcode result; /* CURLE_OK or error handling response */
#if defined(USE_HTTPSRR) && defined(USE_ARES)
struct Curl_https_rrinfo hinfo;
ares_channel channel;
Expand All @@ -74,6 +75,7 @@ struct thread_data {
struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
parts */
int last_status;
CURLcode result; /* CURLE_OK or error handling response */
#ifndef HAVE_CARES_GETADDRINFO
struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */
#endif
Expand Down
22 changes: 21 additions & 1 deletion lib/curl_trc.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ struct curl_trc_feat Curl_trc_feat_write = {
"WRITE",
CURL_LOG_LVL_NONE,
};
struct curl_trc_feat Curl_trc_feat_dns = {
"DNS",
CURL_LOG_LVL_NONE,
};


void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
{
Expand All @@ -199,6 +204,17 @@ void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
}
}

void Curl_trc_dns(struct Curl_easy *data, const char *fmt, ...)
{
DEBUGASSERT(!strchr(fmt, '\n'));
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) {
va_list ap;
va_start(ap, fmt);
trc_infof(data, &Curl_trc_feat_dns, fmt, ap);
va_end(ap);
}
}

#ifndef CURL_DISABLE_FTP
struct curl_trc_feat Curl_trc_feat_ftp = {
"FTP",
Expand Down Expand Up @@ -284,11 +300,11 @@ struct trc_feat_def {
static struct trc_feat_def trc_feats[] = {
{ &Curl_trc_feat_read, TRC_CT_NONE },
{ &Curl_trc_feat_write, TRC_CT_NONE },
{ &Curl_trc_feat_dns, TRC_CT_NETWORK },
#ifndef CURL_DISABLE_FTP
{ &Curl_trc_feat_ftp, TRC_CT_PROTOCOL },
#endif
#ifndef CURL_DISABLE_DOH
{ &Curl_doh_trc, TRC_CT_NETWORK },
#endif
#ifndef CURL_DISABLE_SMTP
{ &Curl_trc_feat_smtp, TRC_CT_PROTOCOL },
Expand Down Expand Up @@ -395,6 +411,10 @@ static CURLcode trc_opt(const char *config)
trc_apply_level_by_category(TRC_CT_NETWORK, lvl);
else if(Curl_str_casecompare(&out, "proxy"))
trc_apply_level_by_category(TRC_CT_PROXY, lvl);
else if(Curl_str_casecompare(&out, "doh")) {
struct Curl_str dns = { "dns", 3 };
trc_apply_level_by_name(&dns, lvl);
}
else
trc_apply_level_by_name(&out, lvl);

Expand Down
7 changes: 7 additions & 0 deletions lib/curl_trc.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ void Curl_trc_write(struct Curl_easy *data,
const char *fmt, ...) CURL_PRINTF(2, 3);
void Curl_trc_read(struct Curl_easy *data,
const char *fmt, ...) CURL_PRINTF(2, 3);
void Curl_trc_dns(struct Curl_easy *data,
const char *fmt, ...) CURL_PRINTF(2, 3);

#ifndef CURL_DISABLE_FTP
extern struct curl_trc_feat Curl_trc_feat_ftp;
Expand Down Expand Up @@ -121,6 +123,9 @@ void Curl_trc_ws(struct Curl_easy *data,
#define CURL_TRC_READ(data, ...) \
do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) \
Curl_trc_read(data, __VA_ARGS__); } while(0)
#define CURL_TRC_DNS(data, ...) \
do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) \
Curl_trc_dns(data, __VA_ARGS__); } while(0)

#ifndef CURL_DISABLE_FTP
#define CURL_TRC_FTP(data, ...) \
Expand Down Expand Up @@ -149,6 +154,7 @@ void Curl_trc_ws(struct Curl_easy *data,
#define CURL_TRC_CF Curl_trc_cf_infof
#define CURL_TRC_WRITE Curl_trc_write
#define CURL_TRC_READ Curl_trc_read
#define CURL_TRC_DNS Curl_trc_dns

#ifndef CURL_DISABLE_FTP
#define CURL_TRC_FTP Curl_trc_ftp
Expand All @@ -174,6 +180,7 @@ struct curl_trc_feat {
};
extern struct curl_trc_feat Curl_trc_feat_read;
extern struct curl_trc_feat Curl_trc_feat_write;
extern struct curl_trc_feat Curl_trc_feat_dns;

#define Curl_trc_is_verbose(data) \
((data) && (data)->set.verbose && \
Expand Down
66 changes: 14 additions & 52 deletions lib/doh.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,6 @@ static const char *doh_strerror(DOHcode code)
return "bad error code";
}

struct curl_trc_feat Curl_doh_trc = {
"DoH",
CURL_LOG_LVL_NONE,
};
#endif /* !CURL_DISABLE_VERBOSE_STRINGS */

/* @unittest 1655
Expand Down Expand Up @@ -281,7 +277,7 @@ static CURLcode doh_run_probe(struct Curl_easy *data,
the gcc typecheck helpers */
doh->state.internal = TRUE;
#ifndef CURL_DISABLE_VERBOSE_STRINGS
doh->state.feat = &Curl_doh_trc;
doh->state.feat = &Curl_trc_feat_dns;
#endif
ERROR_CHECK_SETOPT(CURLOPT_URL, url);
ERROR_CHECK_SETOPT(CURLOPT_DEFAULT_PROTOCOL, "https");
Expand All @@ -305,7 +301,7 @@ static CURLcode doh_run_probe(struct Curl_easy *data,
ERROR_CHECK_SETOPT(CURLOPT_SHARE, (CURLSH *)data->share);
if(data->set.err && data->set.err != stderr)
ERROR_CHECK_SETOPT(CURLOPT_STDERR, data->set.err);
if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc))
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns))
ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L);
if(data->set.no_signal)
ERROR_CHECK_SETOPT(CURLOPT_NOSIGNAL, 1L);
Expand Down Expand Up @@ -1087,12 +1083,14 @@ static CURLcode doh_test_alpn_escapes(void)
}
#endif

static CURLcode doh_resp_decode_httpsrr(unsigned char *cp, size_t len,
static CURLcode doh_resp_decode_httpsrr(struct Curl_easy *data,
unsigned char *cp, size_t len,
struct Curl_https_rrinfo **hrr)
{
uint16_t pcode = 0, plen = 0;
struct Curl_https_rrinfo *lhrr = NULL;
char *dnsname = NULL;
CURLcode result = CURLE_OUT_OF_MEMORY;

#ifdef DEBUGBUILD
/* a few tests of escaping, should not be here but ok for now */
Expand All @@ -1116,44 +1114,9 @@ static CURLcode doh_resp_decode_httpsrr(unsigned char *cp, size_t len,
plen = doh_get16bit(cp, 2);
cp += 4;
len -= 4;
switch(pcode) {
case HTTPS_RR_CODE_ALPN:
if(Curl_httpsrr_decode_alpn(cp, plen, lhrr->alpns) != CURLE_OK)
goto err;
break;
case HTTPS_RR_CODE_NO_DEF_ALPN:
lhrr->no_def_alpn = TRUE;
break;
case HTTPS_RR_CODE_IPV4:
if(!plen)
goto err;
lhrr->ipv4hints = Curl_memdup(cp, plen);
if(!lhrr->ipv4hints)
goto err;
lhrr->ipv4hints_len = (size_t)plen;
break;
case HTTPS_RR_CODE_ECH:
if(!plen)
goto err;
lhrr->echconfiglist = Curl_memdup(cp, plen);
if(!lhrr->echconfiglist)
goto err;
lhrr->echconfiglist_len = (size_t)plen;
break;
case HTTPS_RR_CODE_IPV6:
if(!plen)
goto err;
lhrr->ipv6hints = Curl_memdup(cp, plen);
if(!lhrr->ipv6hints)
goto err;
lhrr->ipv6hints_len = (size_t)plen;
break;
case HTTPS_RR_CODE_PORT:
lhrr->port = doh_get16bit(cp, 0);
break;
default:
break;
}
result = Curl_httpsrr_set(data, lhrr, pcode, cp, plen);
if(result)
goto err;
if(plen > 0 && plen <= len) {
cp += plen;
len -= plen;
Expand All @@ -1163,10 +1126,9 @@ static CURLcode doh_resp_decode_httpsrr(unsigned char *cp, size_t len,
*hrr = lhrr;
return CURLE_OK;
err:
Curl_safefree(lhrr->target);
Curl_safefree(lhrr->echconfiglist);
Curl_httpsrr_cleanup(lhrr);
Curl_safefree(lhrr);
return CURLE_OUT_OF_MEMORY;
return result;
}

# ifdef DEBUGBUILD
Expand Down Expand Up @@ -1256,8 +1218,8 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
struct Curl_addrinfo *ai;


if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc)) {
infof(data, "[DoH] hostname: %s", dohp->host);
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) {
CURL_TRC_DNS(data, "hostname: %s", dohp->host);
doh_show(data, &de);
}

Expand Down Expand Up @@ -1291,8 +1253,8 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
#ifdef USE_HTTPSRR
if(de.numhttps_rrs > 0 && result == CURLE_OK && *dnsp) {
struct Curl_https_rrinfo *hrr = NULL;
result = doh_resp_decode_httpsrr(de.https_rrs->val, de.https_rrs->len,
&hrr);
result = doh_resp_decode_httpsrr(data, de.https_rrs->val,
de.https_rrs->len, &hrr);
if(result) {
infof(data, "Failed to decode HTTPS RR");
return result;
Expand Down
2 changes: 0 additions & 2 deletions lib/doh.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,6 @@ UNITTEST void de_init(struct dohentry *d);
UNITTEST void de_cleanup(struct dohentry *d);
#endif

extern struct curl_trc_feat Curl_doh_trc;

#else /* if DoH is disabled */
#define Curl_doh(a,b,c,d) NULL
#define Curl_doh_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
Expand Down
5 changes: 1 addition & 4 deletions lib/hostip.c
Original file line number Diff line number Diff line change
Expand Up @@ -1081,10 +1081,7 @@ static void hostcache_unlink_entry(void *entry)
Curl_freeaddrinfo(dns->addr);
#ifdef USE_HTTPSRR
if(dns->hinfo) {
free(dns->hinfo->target);
free(dns->hinfo->ipv4hints);
free(dns->hinfo->echconfiglist);
free(dns->hinfo->ipv6hints);
Curl_httpsrr_cleanup(dns->hinfo);
free(dns->hinfo);
}
#endif
Expand Down
Loading

0 comments on commit 1b71038

Please sign in to comment.