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:
parent
40017fb323
commit
435dd8aa6e
@ -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
215
lib/doh.c
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
41
lib/doh.h
41
lib/doh.h
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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];
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user