- 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 #16132
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`
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
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;
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;
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
"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, ...)
{
}
}
+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",
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 },
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);
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;
#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, ...) \
#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
};
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 && \
return "bad error code";
}
-struct curl_trc_feat Curl_doh_trc = {
- "DoH",
- CURL_LOG_LVL_NONE,
-};
#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
/* @unittest 1655
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");
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);
}
#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 */
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;
*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
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);
}
#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;
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
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
#include "httpsrr.h"
#include "connect.h"
#include "sendf.h"
+#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
return CURLE_BAD_CONTENT_ENCODING;
}
-#ifdef USE_ARES
-
-static void httpsrr_opt(struct Curl_easy *data,
- const ares_dns_rr_t *rr,
- ares_dns_rr_key_t key, size_t idx)
+CURLcode Curl_httpsrr_set(struct Curl_easy *data,
+ struct Curl_https_rrinfo *hi,
+ uint16_t rrkey, const uint8_t *val, size_t vlen)
{
- size_t len = 0;
- const unsigned char *val = NULL;
- unsigned short code;
- struct thread_data *res = &data->state.async.thdata;
- struct Curl_https_rrinfo *hi = &res->hinfo;
- code = ares_dns_rr_get_opt(rr, key, idx, &val, &len);
-
- switch(code) {
+ switch(rrkey) {
case HTTPS_RR_CODE_ALPN: /* str_list */
- Curl_httpsrr_decode_alpn(val, len, hi->alpns);
- infof(data, "HTTPS RR ALPN: %u %u %u %u",
- hi->alpns[0], hi->alpns[1], hi->alpns[2], hi->alpns[3]);
+ Curl_httpsrr_decode_alpn(val, vlen, hi->alpns);
+ CURL_TRC_DNS(data, "HTTPS RR ALPN: %u %u %u %u",
+ hi->alpns[0], hi->alpns[1], hi->alpns[2], hi->alpns[3]);
break;
case HTTPS_RR_CODE_NO_DEF_ALPN:
- infof(data, "HTTPS RR no-def-alpn");
+ hi->no_def_alpn = TRUE;
+ CURL_TRC_DNS(data, "HTTPS RR no-def-alpn");
break;
case HTTPS_RR_CODE_IPV4: /* addr4 list */
- infof(data, "HTTPS RR IPv4");
+ if(!vlen)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ hi->ipv4hints = Curl_memdup(val, vlen);
+ if(!hi->ipv4hints)
+ return CURLE_OUT_OF_MEMORY;
+ hi->ipv4hints_len = vlen;
+ CURL_TRC_DNS(data, "HTTPS RR IPv4");
break;
case HTTPS_RR_CODE_ECH:
- infof(data, "HTTPS RR ECH");
+ if(!vlen)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ hi->echconfiglist = Curl_memdup(val, vlen);
+ if(!hi->echconfiglist)
+ return CURLE_OUT_OF_MEMORY;
+ hi->echconfiglist_len = vlen;
+ CURL_TRC_DNS(data, "HTTPS RR ECH");
break;
case HTTPS_RR_CODE_IPV6: /* addr6 list */
- infof(data, "HTTPS RR IPv6");
+ if(!vlen)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ hi->ipv6hints = Curl_memdup(val, vlen);
+ if(!hi->ipv6hints)
+ return CURLE_OUT_OF_MEMORY;
+ hi->ipv6hints_len = vlen;
+ CURL_TRC_DNS(data, "HTTPS RR IPv6");
break;
case HTTPS_RR_CODE_PORT:
- infof(data, "HTTPS RR port");
+ if(vlen != 2)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ hi->port = (unsigned short)((val[0] << 8) | val[1]);
+ CURL_TRC_DNS(data, "HTTPS RR port %u", hi->port);
break;
default:
- infof(data, "HTTPS RR unknown code");
+ CURL_TRC_DNS(data, "HTTPS RR unknown code");
break;
}
+ return CURLE_OK;
+}
+
+struct Curl_https_rrinfo *
+Curl_httpsrr_dup_move(struct Curl_https_rrinfo *rrinfo)
+{
+ struct Curl_https_rrinfo *dup = Curl_memdup(rrinfo, sizeof(*rrinfo));
+ if(dup)
+ memset(rrinfo, 0, sizeof(*rrinfo));
+ return dup;
+}
+
+void Curl_httpsrr_cleanup(struct Curl_https_rrinfo *rrinfo)
+{
+ Curl_safefree(rrinfo->target);
+ Curl_safefree(rrinfo->echconfiglist);
+ Curl_safefree(rrinfo->ipv4hints);
+ Curl_safefree(rrinfo->ipv6hints);
+}
+
+
+#ifdef USE_ARES
+
+static CURLcode httpsrr_opt(struct Curl_easy *data,
+ const ares_dns_rr_t *rr,
+ ares_dns_rr_key_t key, size_t idx)
+{
+ size_t len = 0;
+ const unsigned char *val = NULL;
+ unsigned short code;
+ struct thread_data *res = &data->state.async.thdata;
+ struct Curl_https_rrinfo *hi = &res->hinfo;
+
+ code = ares_dns_rr_get_opt(rr, key, idx, &val, &len);
+ return Curl_httpsrr_set(data, hi, code, val, len);
}
void Curl_dnsrec_done_cb(void *arg, ares_status_t status,
const ares_dns_record_t *dnsrec)
{
struct Curl_easy *data = arg;
+ CURLcode result = CURLE_OK;
size_t i;
#ifdef CURLRES_ARES
struct thread_data *res = &data->state.async.thdata;
return;
for(i = 0; i < ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); i++) {
+ const char *target;
size_t opt;
const ares_dns_rr_t *rr =
ares_dns_record_rr_get_const(dnsrec, ARES_SECTION_ANSWER, i);
continue;
/* When SvcPriority is 0, the SVCB record is in AliasMode. Otherwise, it
is in ServiceMode */
- infof(data, "HTTPS RR priority: %u",
- ares_dns_rr_get_u16(rr, ARES_RR_HTTPS_PRIORITY));
+ target = ares_dns_rr_get_str(rr, ARES_RR_HTTPS_TARGET);
+ if(target && target[0]) {
+ res->hinfo.target = strdup(target);
+ if(!res->hinfo.target) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ CURL_TRC_DNS(data, "HTTPS RR target: %s", res->hinfo.target);
+ }
+ CURL_TRC_DNS(data, "HTTPS RR priority: %u",
+ ares_dns_rr_get_u16(rr, ARES_RR_HTTPS_PRIORITY));
for(opt = 0; opt < ares_dns_rr_get_opt_cnt(rr, ARES_RR_HTTPS_PARAMS);
- opt++)
- httpsrr_opt(data, rr, ARES_RR_HTTPS_PARAMS, opt);
+ opt++) {
+ result = httpsrr_opt(data, rr, ARES_RR_HTTPS_PARAMS, opt);
+ if(result)
+ break;
+ }
}
+out:
+ res->result = result;
}
#endif /* USE_ARES */
#define CURL_MAXLEN_host_name 253
#define MAX_HTTPSRR_ALPNS 4
+struct Curl_easy;
+
struct Curl_https_rrinfo {
/*
* Fields from HTTPS RR. The only mandatory fields are priority and target.
uint16_t priority;
bool no_def_alpn; /* keytag = 2 */
};
-#endif
+
+CURLcode Curl_httpsrr_set(struct Curl_easy *data,
+ struct Curl_https_rrinfo *hi,
+ uint16_t rrkey, const uint8_t *val, size_t vlen);
+
+struct Curl_https_rrinfo *
+Curl_httpsrr_dup_move(struct Curl_https_rrinfo *rrinfo);
+
+void Curl_httpsrr_cleanup(struct Curl_https_rrinfo *rrinfo);
/*
* Code points for DNS wire format SvcParams as per RFC 9460
CURLcode Curl_httpsrr_decode_alpn(const unsigned char *cp, size_t len,
unsigned char *alpns);
-#if defined(USE_ARES) && defined(USE_HTTPSRR)
+#if defined(USE_ARES)
void Curl_dnsrec_done_cb(void *arg, ares_status_t status,
size_t timeouts,
const ares_dns_record_t *dnsrec);
-#endif
+
+#endif /* USE_ARES */
+#endif /* USE_HTTPSRR */
+
#endif /* HEADER_CURL_HTTPSRR_H */
'Curl_creader_def_close' => 'internal api',
'Curl_creader_def_read' => 'internal api',
'Curl_creader_def_total_length' => 'internal api',
+ 'Curl_trc_dns' => 'internal api',
);
my %api = (