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

View File

@ -59,18 +59,39 @@ typedef enum {
} DNStype; } DNStype;
/* one of these for each DoH request */ /* 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 */ curl_off_t easy_mid; /* multi id of easy handle doing the lookup */
DNStype dnstype; DNStype dnstype;
unsigned char dohbuffer[512]; unsigned char req_body[512];
size_t dohlen; size_t req_body_len;
struct dynbuf serverdoh; struct dynbuf resp_body;
}; };
struct dohdata { enum doh_slot_num {
struct curl_slist *headers; /* Explicit values for first two symbols so as to match hard-coded
struct dnsprobe probe[DOH_PROBE_SLOTS]; * constants in existing code
unsigned int pending; /* still outstanding requests */ */
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; int port;
const char *host; const char *host;
}; };
@ -144,12 +165,12 @@ void Curl_doh_close(struct Curl_easy *data);
void Curl_doh_cleanup(struct Curl_easy *data); void Curl_doh_cleanup(struct Curl_easy *data);
#ifdef UNITTESTS #ifdef UNITTESTS
UNITTEST DOHcode doh_encode(const char *host, UNITTEST DOHcode doh_req_encode(const char *host,
DNStype dnstype, DNStype dnstype,
unsigned char *dnsp, /* buffer */ unsigned char *dnsp, /* buffer */
size_t len, /* buffer size */ size_t len, /* buffer size */
size_t *olen); /* output length */ 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, size_t dohlen,
DNStype dnstype, DNStype dnstype,
struct dohentry *d); struct dohentry *d);

View File

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

View File

@ -622,27 +622,6 @@ struct easy_pollset {
unsigned char actions[MAX_SOCKSPEREASYHANDLE]; 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. * Specific protocol handler.
*/ */

View File

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

View File

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

View File

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