doh: cleanups

Mostly cleanup on identifiers of DoH code.
Always use 'Curl_doh_cleanup()' for releasing resources.

More concise and telling names (ymmv):

* prefix all static functions with 'doh_' for unity builds
* doh_encode -> doh_req_encode
* doh_decode -> doh_resp_decode
* struct dohdata -> struct doh_probes
* probe's 'serverdoh' -> 'resp_body'
* probe's 'dohbuffer' -> 'req_body'
* probe's 'headers' -> 'req_hds'
* 'dohprobe()' -> doh_run_probe()'
* 'DOH_PROBE_SLOTS' -> 'DOH_SLOT_COUNT'
* 'DOH_PROBE_SLOT_IPADDR_V4' -> 'DOH_SLOT_IPV4'
* 'DOH_PROBE_SLOT_IPADDR_V6' -> 'DOH_SLOT_IPV6'
* 'DOH_PROBE_SLOT_HTTPS' -> 'DOH_SLOT_HTTPS_RR'

Closes #14783
This commit is contained in:
Stefan Eissing 2024-09-04 13:36:01 +02:00 committed by Daniel Stenberg
parent 40017fb323
commit 435dd8aa6e
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
8 changed files with 289 additions and 299 deletions

View File

@ -231,7 +231,7 @@ purpose. This code also implements the opportunistic (``--ech true``) or hard-fa
Other than that, the main additions are in ``lib/doh.c``
where we re-use ``dohprobe()`` to retrieve an HTTPS RR value for the target
domain. If such a value is found, that is stored using a new ``store_https()``
domain. If such a value is found, that is stored using a new ``doh_store_https()``
function in a new field in the ``dohentry`` structure.
The qname for the DoH query is modified if the port number is not 443, as

215
lib/doh.c
View File

@ -46,7 +46,7 @@
#define DNS_CLASS_IN 0x01
/* local_print_buf truncates if the hex string will be more than this */
/* doh_print_buf truncates if the hex string will be more than this */
#define LOCAL_PB_HEXMAX 400
#ifndef CURL_DISABLE_VERBOSE_STRINGS
@ -82,7 +82,7 @@ struct curl_trc_feat Curl_doh_trc = {
/* @unittest 1655
*/
UNITTEST DOHcode doh_encode(const char *host,
UNITTEST DOHcode doh_req_encode(const char *host,
DNStype dnstype,
unsigned char *dnsp, /* buffer */
size_t len, /* buffer size */
@ -192,7 +192,7 @@ doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp)
}
#if defined(USE_HTTPSRR) && defined(DEBUGBUILD)
static void local_print_buf(struct Curl_easy *data,
static void doh_print_buf(struct Curl_easy *data,
const char *prefix,
unsigned char *buf, size_t len)
{
@ -214,7 +214,7 @@ static void local_print_buf(struct Curl_easy *data,
/* called from multi.c when this DoH transfer is complete */
static int doh_done(struct Curl_easy *doh, CURLcode result)
{
struct Curl_easy *data;
struct Curl_easy *data; /* the transfer that asked for the DoH probe */
data = Curl_multi_get_handle(doh->multi, doh->set.dohfor_mid);
if(!data) {
@ -223,7 +223,7 @@ static int doh_done(struct Curl_easy *doh, CURLcode result)
DEBUGASSERT(0);
}
else {
struct dohdata *dohp = data->req.doh;
struct doh_probes *dohp = data->req.doh;
/* one of the DoH request done for the 'data' transfer is now complete! */
dohp->pending--;
infof(doh, "a DoH request is completed, %u to go", dohp->pending);
@ -231,9 +231,7 @@ static int doh_done(struct Curl_easy *doh, CURLcode result)
infof(doh, "DoH request %s", curl_easy_strerror(result));
if(!dohp->pending) {
/* DoH completed */
curl_slist_free_all(dohp->headers);
dohp->headers = NULL;
/* DoH completed, run the transfer picking up the results */
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
}
@ -249,8 +247,8 @@ do { \
goto error; \
} while(0)
static CURLcode dohprobe(struct Curl_easy *data,
struct dnsprobe *p, DNStype dnstype,
static CURLcode doh_run_probe(struct Curl_easy *data,
struct doh_probe *p, DNStype dnstype,
const char *host,
const char *url, CURLM *multi,
struct curl_slist *headers)
@ -258,15 +256,15 @@ static CURLcode dohprobe(struct Curl_easy *data,
struct Curl_easy *doh = NULL;
CURLcode result = CURLE_OK;
timediff_t timeout_ms;
DOHcode d = doh_encode(host, dnstype, p->dohbuffer, sizeof(p->dohbuffer),
&p->dohlen);
DOHcode d = doh_req_encode(host, dnstype, p->req_body, sizeof(p->req_body),
&p->req_body_len);
if(d) {
failf(data, "Failed to encode DoH packet [%d]", d);
return CURLE_OUT_OF_MEMORY;
}
p->dnstype = dnstype;
Curl_dyn_init(&p->serverdoh, DYN_DOH_RESPONSE);
Curl_dyn_init(&p->resp_body, DYN_DOH_RESPONSE);
timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms <= 0) {
@ -275,10 +273,11 @@ static CURLcode dohprobe(struct Curl_easy *data,
}
/* Curl_open() is the internal version of curl_easy_init() */
result = Curl_open(&doh);
if(!result) {
if(result)
goto error;
/* pass in the struct pointer via a local variable to please coverity and
the gcc typecheck helpers */
struct dynbuf *resp = &p->serverdoh;
doh->state.internal = true;
#ifndef CURL_DISABLE_VERBOSE_STRINGS
doh->state.feat = &Curl_doh_trc;
@ -286,9 +285,9 @@ static CURLcode dohprobe(struct Curl_easy *data,
ERROR_CHECK_SETOPT(CURLOPT_URL, url);
ERROR_CHECK_SETOPT(CURLOPT_DEFAULT_PROTOCOL, "https");
ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb);
ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp);
ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer);
ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen);
ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, &p->resp_body);
ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->req_body);
ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->req_body_len);
ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
#ifdef USE_HTTP2
ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
@ -389,13 +388,11 @@ static CURLcode dohprobe(struct Curl_easy *data,
goto error;
p->easy_mid = doh->mid;
}
else
goto error;
return CURLE_OK;
error:
Curl_close(&doh);
p->easy_mid = -1;
return result;
}
@ -410,7 +407,7 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
int *waitp)
{
CURLcode result = CURLE_OK;
struct dohdata *dohp;
struct doh_probes *dohp;
struct connectdata *conn = data->conn;
size_t i;
#ifdef USE_HTTPSRR
@ -427,27 +424,27 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
DEBUGASSERT(conn);
/* start clean, consider allocating this struct on demand */
dohp = data->req.doh = calloc(1, sizeof(struct dohdata));
dohp = data->req.doh = calloc(1, sizeof(struct doh_probes));
if(!dohp)
return NULL;
for(i = 0; i < DOH_PROBE_SLOTS; ++i) {
for(i = 0; i < DOH_SLOT_COUNT; ++i) {
dohp->probe[i].easy_mid = -1;
}
conn->bits.doh = TRUE;
dohp->host = hostname;
dohp->port = port;
dohp->headers =
dohp->req_hds =
curl_slist_append(NULL,
"Content-Type: application/dns-message");
if(!dohp->headers)
if(!dohp->req_hds)
goto error;
/* create IPv4 DoH request */
result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4],
result = doh_run_probe(data, &dohp->probe[DOH_SLOT_IPV4],
DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
data->multi, dohp->headers);
data->multi, dohp->req_hds);
if(result)
goto error;
dohp->pending++;
@ -455,9 +452,9 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
#ifdef USE_IPV6
if((conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
/* create IPv6 DoH request */
result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6],
result = doh_run_probe(data, &dohp->probe[DOH_SLOT_IPV6],
DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],
data->multi, dohp->headers);
data->multi, dohp->req_hds);
if(result)
goto error;
dohp->pending++;
@ -484,9 +481,9 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
qname = aprintf("_%d._https.%s", port, hostname);
if(!qname)
goto error;
result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_HTTPS],
result = doh_run_probe(data, &dohp->probe[DOH_SLOT_HTTPS_RR],
DNS_TYPE_HTTPS, qname, data->set.str[STRING_DOH],
data->multi, dohp->headers);
data->multi, dohp->req_hds);
Curl_safefree(qname);
if(result)
goto error;
@ -502,7 +499,7 @@ error:
return NULL;
}
static DOHcode skipqname(const unsigned char *doh, size_t dohlen,
static DOHcode doh_skipqname(const unsigned char *doh, size_t dohlen,
unsigned int *indexp)
{
unsigned char length;
@ -526,12 +523,13 @@ static DOHcode skipqname(const unsigned char *doh, size_t dohlen,
return DOH_OK;
}
static unsigned short get16bit(const unsigned char *doh, unsigned int index)
static unsigned short doh_get16bit(const unsigned char *doh,
unsigned int index)
{
return (unsigned short)((doh[index] << 8) | doh[index + 1]);
}
static unsigned int get32bit(const unsigned char *doh, unsigned int index)
static unsigned int doh_get32bit(const unsigned char *doh, unsigned int index)
{
/* make clang and gcc optimize this to bswap by incrementing
the pointer first. */
@ -544,7 +542,8 @@ static unsigned int get32bit(const unsigned char *doh, unsigned int index)
((unsigned)doh[2] << 8) | doh[3];
}
static DOHcode store_a(const unsigned char *doh, int index, struct dohentry *d)
static DOHcode doh_store_a(const unsigned char *doh, int index,
struct dohentry *d)
{
/* silently ignore addresses over the limit */
if(d->numaddr < DOH_MAX_ADDR) {
@ -556,8 +555,7 @@ static DOHcode store_a(const unsigned char *doh, int index, struct dohentry *d)
return DOH_OK;
}
static DOHcode store_aaaa(const unsigned char *doh,
int index,
static DOHcode doh_store_aaaa(const unsigned char *doh, int index,
struct dohentry *d)
{
/* silently ignore addresses over the limit */
@ -571,10 +569,8 @@ static DOHcode store_aaaa(const unsigned char *doh,
}
#ifdef USE_HTTPSRR
static DOHcode store_https(const unsigned char *doh,
int index,
struct dohentry *d,
uint16_t len)
static DOHcode doh_store_https(const unsigned char *doh, int index,
struct dohentry *d, uint16_t len)
{
/* silently ignore RRs over the limit */
if(d->numhttps_rrs < DOH_MAX_HTTPS) {
@ -589,10 +585,8 @@ static DOHcode store_https(const unsigned char *doh,
}
#endif
static DOHcode store_cname(const unsigned char *doh,
size_t dohlen,
unsigned int index,
struct dohentry *d)
static DOHcode doh_store_cname(const unsigned char *doh, size_t dohlen,
unsigned int index, struct dohentry *d)
{
struct dynbuf *c;
unsigned int loop = 128; /* a valid DNS name can never loop this much */
@ -641,7 +635,7 @@ static DOHcode store_cname(const unsigned char *doh,
return DOH_OK;
}
static DOHcode rdata(const unsigned char *doh,
static DOHcode doh_rdata(const unsigned char *doh,
size_t dohlen,
unsigned short rdlength,
unsigned short type,
@ -659,26 +653,26 @@ static DOHcode rdata(const unsigned char *doh,
case DNS_TYPE_A:
if(rdlength != 4)
return DOH_DNS_RDATA_LEN;
rc = store_a(doh, index, d);
rc = doh_store_a(doh, index, d);
if(rc)
return rc;
break;
case DNS_TYPE_AAAA:
if(rdlength != 16)
return DOH_DNS_RDATA_LEN;
rc = store_aaaa(doh, index, d);
rc = doh_store_aaaa(doh, index, d);
if(rc)
return rc;
break;
#ifdef USE_HTTPSRR
case DNS_TYPE_HTTPS:
rc = store_https(doh, index, d, rdlength);
rc = doh_store_https(doh, index, d, rdlength);
if(rc)
return rc;
break;
#endif
case DNS_TYPE_CNAME:
rc = store_cname(doh, dohlen, (unsigned int)index, d);
rc = doh_store_cname(doh, dohlen, (unsigned int)index, d);
if(rc)
return rc;
break;
@ -702,7 +696,7 @@ UNITTEST void de_init(struct dohentry *de)
}
UNITTEST DOHcode doh_decode(const unsigned char *doh,
UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
size_t dohlen,
DNStype dnstype,
struct dohentry *d)
@ -725,9 +719,9 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
if(rcode)
return DOH_DNS_BAD_RCODE; /* bad rcode */
qdcount = get16bit(doh, 4);
qdcount = doh_get16bit(doh, 4);
while(qdcount) {
rc = skipqname(doh, dohlen, &index);
rc = doh_skipqname(doh, dohlen, &index);
if(rc)
return rc; /* bad qname */
if(dohlen < (index + 4))
@ -736,19 +730,19 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
qdcount--;
}
ancount = get16bit(doh, 6);
ancount = doh_get16bit(doh, 6);
while(ancount) {
unsigned short class;
unsigned int ttl;
rc = skipqname(doh, dohlen, &index);
rc = doh_skipqname(doh, dohlen, &index);
if(rc)
return rc; /* bad qname */
if(dohlen < (index + 2))
return DOH_DNS_OUT_OF_RANGE;
type = get16bit(doh, index);
type = doh_get16bit(doh, index);
if((type != DNS_TYPE_CNAME) /* may be synthesized from DNAME */
&& (type != DNS_TYPE_DNAME) /* if present, accept and ignore */
&& (type != dnstype))
@ -758,7 +752,7 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
if(dohlen < (index + 2))
return DOH_DNS_OUT_OF_RANGE;
class = get16bit(doh, index);
class = doh_get16bit(doh, index);
if(DNS_CLASS_IN != class)
return DOH_DNS_UNEXPECTED_CLASS; /* unsupported */
index += 2;
@ -766,7 +760,7 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
if(dohlen < (index + 4))
return DOH_DNS_OUT_OF_RANGE;
ttl = get32bit(doh, index);
ttl = doh_get32bit(doh, index);
if(ttl < d->ttl)
d->ttl = ttl;
index += 4;
@ -774,21 +768,21 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
if(dohlen < (index + 2))
return DOH_DNS_OUT_OF_RANGE;
rdlength = get16bit(doh, index);
rdlength = doh_get16bit(doh, index);
index += 2;
if(dohlen < (index + rdlength))
return DOH_DNS_OUT_OF_RANGE;
rc = rdata(doh, dohlen, rdlength, type, (int)index, d);
rc = doh_rdata(doh, dohlen, rdlength, type, (int)index, d);
if(rc)
return rc; /* bad rdata */
return rc; /* bad doh_rdata */
index += rdlength;
ancount--;
}
nscount = get16bit(doh, 8);
nscount = doh_get16bit(doh, 8);
while(nscount) {
rc = skipqname(doh, dohlen, &index);
rc = doh_skipqname(doh, dohlen, &index);
if(rc)
return rc; /* bad qname */
@ -800,7 +794,7 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
if(dohlen < (index + 2))
return DOH_DNS_OUT_OF_RANGE;
rdlength = get16bit(doh, index);
rdlength = doh_get16bit(doh, index);
index += 2;
if(dohlen < (index + rdlength))
return DOH_DNS_OUT_OF_RANGE;
@ -808,9 +802,9 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
nscount--;
}
arcount = get16bit(doh, 10);
arcount = doh_get16bit(doh, 10);
while(arcount) {
rc = skipqname(doh, dohlen, &index);
rc = doh_skipqname(doh, dohlen, &index);
if(rc)
return rc; /* bad qname */
@ -822,7 +816,7 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
if(dohlen < (index + 2))
return DOH_DNS_OUT_OF_RANGE;
rdlength = get16bit(doh, index);
rdlength = doh_get16bit(doh, index);
index += 2;
if(dohlen < (index + rdlength))
return DOH_DNS_OUT_OF_RANGE;
@ -845,7 +839,7 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
}
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static void showdoh(struct Curl_easy *data,
static void doh_show(struct Curl_easy *data,
const struct dohentry *d)
{
int i;
@ -879,7 +873,7 @@ static void showdoh(struct Curl_easy *data,
#ifdef USE_HTTPSRR
for(i = 0; i < d->numhttps_rrs; i++) {
# ifdef DEBUGBUILD
local_print_buf(data, "DoH HTTPS",
doh_print_buf(data, "DoH HTTPS",
d->https_rrs[i].val, d->https_rrs[i].len);
# else
infof(data, "DoH HTTPS RR: length %d", d->https_rrs[i].len);
@ -891,7 +885,7 @@ static void showdoh(struct Curl_easy *data,
}
}
#else
#define showdoh(x,y)
#define doh_show(x,y)
#endif
/*
@ -1011,7 +1005,7 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
}
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static const char *type2name(DNStype dnstype)
static const char *doh_type2name(DNStype dnstype)
{
switch(dnstype) {
case DNS_TYPE_A:
@ -1056,7 +1050,7 @@ UNITTEST void de_cleanup(struct dohentry *d)
* just after the end of the DNS name encoding on output. (And
* that is why it is an "unsigned char **" :-)
*/
static CURLcode local_decode_rdata_name(unsigned char **buf, size_t *remaining,
static CURLcode doh_decode_rdata_name(unsigned char **buf, size_t *remaining,
char **dnsname)
{
unsigned char *cp = NULL;
@ -1103,7 +1097,7 @@ static CURLcode local_decode_rdata_name(unsigned char **buf, size_t *remaining,
return CURLE_OK;
}
static CURLcode local_decode_rdata_alpn(unsigned char *rrval, size_t len,
static CURLcode doh_decode_rdata_alpn(unsigned char *rrval, size_t len,
char **alpns)
{
/*
@ -1160,7 +1154,7 @@ err:
}
#ifdef DEBUGBUILD
static CURLcode test_alpn_escapes(void)
static CURLcode doh_test_alpn_escapes(void)
{
/* we will use an example from draft-ietf-dnsop-svcb, figure 10 */
static unsigned char example[] = {
@ -1173,7 +1167,7 @@ static CURLcode test_alpn_escapes(void)
char *aval = NULL;
static const char *expected = "f\\\\oo\\,bar,h2";
if(local_decode_rdata_alpn(example, example_len, &aval) != CURLE_OK)
if(doh_decode_rdata_alpn(example, example_len, &aval) != CURLE_OK)
return CURLE_BAD_CONTENT_ENCODING;
if(strlen(aval) != strlen(expected))
return CURLE_BAD_CONTENT_ENCODING;
@ -1183,7 +1177,7 @@ static CURLcode test_alpn_escapes(void)
}
#endif
static CURLcode Curl_doh_decode_httpsrr(unsigned char *rrval, size_t len,
static CURLcode doh_resp_decode_httpsrr(unsigned char *rrval, size_t len,
struct Curl_https_rrinfo **hrr)
{
size_t remaining = len;
@ -1194,7 +1188,7 @@ static CURLcode Curl_doh_decode_httpsrr(unsigned char *rrval, size_t len,
#ifdef DEBUGBUILD
/* a few tests of escaping, should not be here but ok for now */
if(test_alpn_escapes() != CURLE_OK)
if(doh_test_alpn_escapes() != CURLE_OK)
return CURLE_OUT_OF_MEMORY;
#endif
lhrr = calloc(1, sizeof(struct Curl_https_rrinfo));
@ -1209,7 +1203,7 @@ static CURLcode Curl_doh_decode_httpsrr(unsigned char *rrval, size_t len,
lhrr->priority = (uint16_t)((cp[0] << 8) + cp[1]);
cp += 2;
remaining -= (uint16_t)2;
if(local_decode_rdata_name(&cp, &remaining, &dnsname) != CURLE_OK)
if(doh_decode_rdata_name(&cp, &remaining, &dnsname) != CURLE_OK)
goto err;
lhrr->target = dnsname;
while(remaining >= 4) {
@ -1219,7 +1213,7 @@ static CURLcode Curl_doh_decode_httpsrr(unsigned char *rrval, size_t len,
cp += 2;
remaining -= 4;
if(pcode == HTTPS_RR_CODE_ALPN) {
if(local_decode_rdata_alpn(cp, plen, &lhrr->alpns) != CURLE_OK)
if(doh_decode_rdata_alpn(cp, plen, &lhrr->alpns) != CURLE_OK)
goto err;
}
if(pcode == HTTPS_RR_CODE_NO_DEF_ALPN)
@ -1268,7 +1262,7 @@ err:
}
# ifdef DEBUGBUILD
static void local_print_httpsrr(struct Curl_easy *data,
static void doh_print_httpsrr(struct Curl_easy *data,
struct Curl_https_rrinfo *hrr)
{
DEBUGASSERT(hrr);
@ -1283,19 +1277,19 @@ static void local_print_httpsrr(struct Curl_easy *data,
else
infof(data, "HTTPS RR: no_def_alpn not set");
if(hrr->ipv4hints) {
local_print_buf(data, "HTTPS RR: ipv4hints",
doh_print_buf(data, "HTTPS RR: ipv4hints",
hrr->ipv4hints, hrr->ipv4hints_len);
}
else
infof(data, "HTTPS RR: no ipv4hints");
if(hrr->echconfiglist) {
local_print_buf(data, "HTTPS RR: ECHConfigList",
doh_print_buf(data, "HTTPS RR: ECHConfigList",
hrr->echconfiglist, hrr->echconfiglist_len);
}
else
infof(data, "HTTPS RR: no ECHConfigList");
if(hrr->ipv6hints) {
local_print_buf(data, "HTTPS RR: ipv6hint",
doh_print_buf(data, "HTTPS RR: ipv6hint",
hrr->ipv6hints, hrr->ipv6hints_len);
}
else
@ -1309,52 +1303,45 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dnsp)
{
CURLcode result;
struct dohdata *dohp = data->req.doh;
struct doh_probes *dohp = data->req.doh;
*dnsp = NULL; /* defaults to no response */
if(!dohp)
return CURLE_OUT_OF_MEMORY;
if(dohp->probe[DOH_PROBE_SLOT_IPADDR_V4].easy_mid < 0 &&
dohp->probe[DOH_PROBE_SLOT_IPADDR_V6].easy_mid < 0) {
if(dohp->probe[DOH_SLOT_IPV4].easy_mid < 0 &&
dohp->probe[DOH_SLOT_IPV6].easy_mid < 0) {
failf(data, "Could not DoH-resolve: %s", data->state.async.hostname);
return CONN_IS_PROXIED(data->conn)?CURLE_COULDNT_RESOLVE_PROXY:
CURLE_COULDNT_RESOLVE_HOST;
}
else if(!dohp->pending) {
#ifndef USE_HTTPSRR
DOHcode rc[DOH_PROBE_SLOTS] = {
DOH_OK, DOH_OK
};
#else
DOHcode rc[DOH_PROBE_SLOTS] = {
DOH_OK, DOH_OK, DOH_OK
};
#endif
DOHcode rc[DOH_SLOT_COUNT];
struct dohentry de;
int slot;
memset(rc, 0, sizeof(rc));
/* remove DoH handles from multi handle and close them */
Curl_doh_close(data);
/* parse the responses, create the struct and return it! */
de_init(&de);
for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
struct dnsprobe *p = &dohp->probe[slot];
for(slot = 0; slot < DOH_SLOT_COUNT; slot++) {
struct doh_probe *p = &dohp->probe[slot];
if(!p->dnstype)
continue;
rc[slot] = doh_decode(Curl_dyn_uptr(&p->serverdoh),
Curl_dyn_len(&p->serverdoh),
p->dnstype,
&de);
Curl_dyn_free(&p->serverdoh);
rc[slot] = doh_resp_decode(Curl_dyn_uptr(&p->resp_body),
Curl_dyn_len(&p->resp_body),
p->dnstype, &de);
Curl_dyn_free(&p->resp_body);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
if(rc[slot]) {
infof(data, "DoH: %s type %s for %s", doh_strerror(rc[slot]),
type2name(p->dnstype), dohp->host);
doh_type2name(p->dnstype), dohp->host);
}
#endif
} /* next slot */
result = CURLE_COULDNT_RESOLVE_HOST; /* until we know better */
if(!rc[DOH_PROBE_SLOT_IPADDR_V4] || !rc[DOH_PROBE_SLOT_IPADDR_V6]) {
if(!rc[DOH_SLOT_IPV4] || !rc[DOH_SLOT_IPV6]) {
/* we have an address, of one kind or other */
struct Curl_dns_entry *dns;
struct Curl_addrinfo *ai;
@ -1362,7 +1349,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc)) {
infof(data, "[DoH] hostname: %s", dohp->host);
showdoh(data, &de);
doh_show(data, &de);
}
result = doh2ai(&de, dohp->host, dohp->port, &ai);
@ -1395,7 +1382,7 @@ 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 = Curl_doh_decode_httpsrr(de.https_rrs->val, de.https_rrs->len,
result = doh_resp_decode_httpsrr(de.https_rrs->val, de.https_rrs->len,
&hrr);
if(result) {
infof(data, "Failed to decode HTTPS RR");
@ -1403,7 +1390,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
}
infof(data, "Some HTTPS RR to process");
# ifdef DEBUGBUILD
local_print_httpsrr(data, hrr);
doh_print_httpsrr(data, hrr);
# endif
(*dnsp)->hinfo = hrr;
}
@ -1411,7 +1398,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
/* All done */
de_cleanup(&de);
Curl_safefree(data->req.doh);
Curl_doh_cleanup(data);
return result;
} /* !dohp->pending */
@ -1422,12 +1409,12 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
void Curl_doh_close(struct Curl_easy *data)
{
struct dohdata *doh = data->req.doh;
struct doh_probes *doh = data->req.doh;
if(doh && data->multi) {
struct Curl_easy *probe_data;
curl_off_t mid;
size_t slot;
for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
for(slot = 0; slot < DOH_SLOT_COUNT; slot++) {
mid = doh->probe[slot].easy_mid;
if(mid < 0)
continue;
@ -1450,11 +1437,11 @@ void Curl_doh_close(struct Curl_easy *data)
void Curl_doh_cleanup(struct Curl_easy *data)
{
struct dohdata *doh = data->req.doh;
struct doh_probes *doh = data->req.doh;
if(doh) {
Curl_doh_close(data);
curl_slist_free_all(doh->headers);
data->req.doh->headers = NULL;
curl_slist_free_all(doh->req_hds);
data->req.doh->req_hds = NULL;
Curl_safefree(data->req.doh);
}
}

View File

@ -59,18 +59,39 @@ typedef enum {
} DNStype;
/* one of these for each DoH request */
struct dnsprobe {
struct doh_probe {
curl_off_t easy_mid; /* multi id of easy handle doing the lookup */
DNStype dnstype;
unsigned char dohbuffer[512];
size_t dohlen;
struct dynbuf serverdoh;
unsigned char req_body[512];
size_t req_body_len;
struct dynbuf resp_body;
};
struct dohdata {
struct curl_slist *headers;
struct dnsprobe probe[DOH_PROBE_SLOTS];
unsigned int pending; /* still outstanding requests */
enum doh_slot_num {
/* Explicit values for first two symbols so as to match hard-coded
* constants in existing code
*/
DOH_SLOT_IPV4 = 0, /* make 'V4' stand out for readability */
DOH_SLOT_IPV6 = 1, /* 'V6' likewise */
/* Space here for (possibly build-specific) additional slot definitions */
#ifdef USE_HTTPSRR
DOH_SLOT_HTTPS_RR = 2, /* for HTTPS RR */
#endif
/* for example */
/* #ifdef WANT_DOH_FOOBAR_TXT */
/* DOH_PROBE_SLOT_FOOBAR_TXT, */
/* #endif */
/* AFTER all slot definitions, establish how many we have */
DOH_SLOT_COUNT
};
struct doh_probes {
struct curl_slist *req_hds;
struct doh_probe probe[DOH_SLOT_COUNT];
unsigned int pending; /* still outstanding probes */
int port;
const char *host;
};
@ -144,12 +165,12 @@ void Curl_doh_close(struct Curl_easy *data);
void Curl_doh_cleanup(struct Curl_easy *data);
#ifdef UNITTESTS
UNITTEST DOHcode doh_encode(const char *host,
UNITTEST DOHcode doh_req_encode(const char *host,
DNStype dnstype,
unsigned char *dnsp, /* buffer */
size_t len, /* buffer size */
size_t *olen); /* output length */
UNITTEST DOHcode doh_decode(const unsigned char *doh,
UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
size_t dohlen,
DNStype dnstype,
struct dohentry *d);

View File

@ -32,6 +32,9 @@
/* forward declarations */
struct UserDefined;
#ifndef CURL_DISABLE_DOH
struct doh_probes;
#endif
enum expect100 {
EXP100_SEND_DATA, /* enough waiting, just send the body now */
@ -114,7 +117,7 @@ struct SingleRequest {
struct TELNET *telnet;
} p;
#ifndef CURL_DISABLE_DOH
struct dohdata *doh; /* DoH specific data for this request */
struct doh_probes *doh; /* DoH specific data for this request */
#endif
#ifndef CURL_DISABLE_COOKIES
unsigned char setcookies;

View File

@ -622,27 +622,6 @@ struct easy_pollset {
unsigned char actions[MAX_SOCKSPEREASYHANDLE];
};
enum doh_slots {
/* Explicit values for first two symbols so as to match hard-coded
* constants in existing code
*/
DOH_PROBE_SLOT_IPADDR_V4 = 0, /* make 'V4' stand out for readability */
DOH_PROBE_SLOT_IPADDR_V6 = 1, /* 'V6' likewise */
/* Space here for (possibly build-specific) additional slot definitions */
#ifdef USE_HTTPSRR
DOH_PROBE_SLOT_HTTPS = 2, /* for HTTPS RR */
#endif
/* for example */
/* #ifdef WANT_DOH_FOOBAR_TXT */
/* DOH_PROBE_SLOT_FOOBAR_TXT, */
/* #endif */
/* AFTER all slot definitions, establish how many we have */
DOH_PROBE_SLOTS
};
/*
* Specific protocol handler.
*/

View File

@ -17,7 +17,7 @@ unittest
DoH
</features>
<name>
unit test for doh_encode
unit test for doh_req_encode
</name>
</client>
</testcase>

View File

@ -161,7 +161,7 @@ UNITTEST_START
unsigned char *p;
for(i = 0; i < sizeof(req) / sizeof(req[0]); i++) {
DOHcode rc = doh_encode(req[i].name, req[i].type,
DOHcode rc = doh_req_encode(req[i].name, req[i].type,
buffer, sizeof(buffer), &size);
if(rc != req[i].rc) {
fprintf(stderr, "req %zu: Expected return code %d got %d\n", i,
@ -190,7 +190,7 @@ UNITTEST_START
size_t len;
int u;
de_init(&d);
rc = doh_decode((const unsigned char *)resp[i].packet, resp[i].size,
rc = doh_resp_decode((const unsigned char *)resp[i].packet, resp[i].size,
resp[i].type, &d);
if(rc != resp[i].rc) {
fprintf(stderr, "resp %zu: Expected return code %d got %d\n", i,
@ -245,7 +245,7 @@ UNITTEST_START
struct dohentry d;
DOHcode rc;
memset(&d, 0, sizeof(d));
rc = doh_decode((const unsigned char *)full49, i, DNS_TYPE_A, &d);
rc = doh_resp_decode((const unsigned char *)full49, i, DNS_TYPE_A, &d);
if(!rc) {
/* none of them should work */
fprintf(stderr, "%zu: %d\n", i, rc);
@ -258,7 +258,7 @@ UNITTEST_START
struct dohentry d;
DOHcode rc;
memset(&d, 0, sizeof(d));
rc = doh_decode((const unsigned char *)&full49[i], sizeof(full49)-i-1,
rc = doh_resp_decode((const unsigned char *)&full49[i], sizeof(full49)-i-1,
DNS_TYPE_A, &d);
if(!rc) {
/* none of them should work */
@ -272,7 +272,7 @@ UNITTEST_START
struct dohentry d;
struct dohaddr *a;
memset(&d, 0, sizeof(d));
rc = doh_decode((const unsigned char *)full49, sizeof(full49)-1,
rc = doh_resp_decode((const unsigned char *)full49, sizeof(full49)-1,
DNS_TYPE_A, &d);
fail_if(d.numaddr != 1, "missing address");
a = &d.addr[0];

View File

@ -108,7 +108,7 @@ do {
victim.canary1 = 87; /* magic numbers, arbitrarily picked */
victim.canary2 = 35;
victim.canary3 = 41;
d = doh_encode(name, DNS_TYPE_A, victim.dohbuffer,
d = doh_req_encode(name, DNS_TYPE_A, victim.dohbuffer,
sizeof(struct demo), /* allow room for overflow */
&olen);
@ -151,31 +151,31 @@ do {
DOHcode ret2;
size_t olen;
DOHcode ret = doh_encode(sunshine1, dnstype, buffer, buflen, &olen1);
DOHcode ret = doh_req_encode(sunshine1, dnstype, buffer, buflen, &olen1);
fail_unless(ret == DOH_OK, "sunshine case 1 should pass fine");
fail_if(olen1 == magic1, "olen has not been assigned properly");
fail_unless(olen1 > strlen(sunshine1), "bad out length");
/* with a trailing dot, the response should have the same length */
olen2 = magic1;
ret2 = doh_encode(dotshine1, dnstype, buffer, buflen, &olen2);
ret2 = doh_req_encode(dotshine1, dnstype, buffer, buflen, &olen2);
fail_unless(ret2 == DOH_OK, "dotshine case should pass fine");
fail_if(olen2 == magic1, "olen has not been assigned properly");
fail_unless(olen1 == olen2, "olen should not grow for a trailing dot");
/* add one letter, the response should be one longer */
olen2 = magic1;
ret2 = doh_encode(sunshine2, dnstype, buffer, buflen, &olen2);
ret2 = doh_req_encode(sunshine2, dnstype, buffer, buflen, &olen2);
fail_unless(ret2 == DOH_OK, "sunshine case 2 should pass fine");
fail_if(olen2 == magic1, "olen has not been assigned properly");
fail_unless(olen1 + 1 == olen2, "olen should grow with the hostname");
/* pass a short buffer, should fail */
ret = doh_encode(sunshine1, dnstype, buffer, olen1 - 1, &olen);
ret = doh_req_encode(sunshine1, dnstype, buffer, olen1 - 1, &olen);
fail_if(ret == DOH_OK, "short buffer should have been noticed");
/* pass a minimum buffer, should succeed */
ret = doh_encode(sunshine1, dnstype, buffer, olen1, &olen);
ret = doh_req_encode(sunshine1, dnstype, buffer, olen1, &olen);
fail_unless(ret == DOH_OK, "minimal length buffer should be long enough");
fail_unless(olen == olen1, "bad buffer length");
} while(0);