doh: cleanups and extended HTTPS RR code
In preparation for using HTTPS outside of ECH, the parser now also extracts the port number. Plus other minor cleanups. Closes #16007
This commit is contained in:
parent
f739a6867b
commit
5d70a5c5a4
132
lib/doh.c
132
lib/doh.c
@ -410,12 +410,6 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
|
|||||||
struct doh_probes *dohp;
|
struct doh_probes *dohp;
|
||||||
struct connectdata *conn = data->conn;
|
struct connectdata *conn = data->conn;
|
||||||
size_t i;
|
size_t i;
|
||||||
#ifdef USE_HTTPSRR
|
|
||||||
/* for now, this is only used when ECH is enabled */
|
|
||||||
# ifdef USE_ECH
|
|
||||||
char *qname = NULL;
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
*waitp = FALSE;
|
*waitp = FALSE;
|
||||||
(void)hostname;
|
(void)hostname;
|
||||||
(void)port;
|
(void)port;
|
||||||
@ -463,28 +457,27 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
|
|||||||
|
|
||||||
#ifdef USE_HTTPSRR
|
#ifdef USE_HTTPSRR
|
||||||
/*
|
/*
|
||||||
* TODO: Figure out the conditions under which we want to make
|
* TODO: Figure out the conditions under which we want to make a request for
|
||||||
* a request for an HTTPS RR when we are not doing ECH. For now,
|
* an HTTPS RR when we are not doing ECH. For now, making this request
|
||||||
* making this request breaks a bunch of DoH tests, e.g. test2100,
|
* breaks a bunch of DoH tests, e.g. test2100, where the additional request
|
||||||
* where the additional request does not match the pre-cooked data
|
* does not match the pre-cooked data files, so there is a bit of work
|
||||||
* files, so there is a bit of work attached to making the request
|
* attached to making the request in a non-ECH use-case. For the present, we
|
||||||
* in a non-ECH use-case. For the present, we will only make the
|
* will only make the request when ECH is enabled in the build and is being
|
||||||
* request when ECH is enabled in the build and is being used for
|
* used for the curl operation.
|
||||||
* the curl operation.
|
|
||||||
*/
|
*/
|
||||||
# ifdef USE_ECH
|
# ifdef USE_ECH
|
||||||
if(data->set.tls_ech & CURLECH_ENABLE
|
if(data->set.tls_ech & (CURLECH_ENABLE|CURLECH_HARD)) {
|
||||||
|| data->set.tls_ech & CURLECH_HARD) {
|
char *qname = NULL;
|
||||||
if(port == 443)
|
if(port != PORT_HTTPS) {
|
||||||
qname = strdup(hostname);
|
|
||||||
else
|
|
||||||
qname = aprintf("_%d._https.%s", port, hostname);
|
qname = aprintf("_%d._https.%s", port, hostname);
|
||||||
if(!qname)
|
if(!qname)
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
result = doh_run_probe(data, &dohp->probe[DOH_SLOT_HTTPS_RR],
|
result = doh_run_probe(data, &dohp->probe[DOH_SLOT_HTTPS_RR],
|
||||||
DNS_TYPE_HTTPS, qname, data->set.str[STRING_DOH],
|
DNS_TYPE_HTTPS,
|
||||||
|
qname ? qname : hostname, data->set.str[STRING_DOH],
|
||||||
data->multi, dohp->req_hds);
|
data->multi, dohp->req_hds);
|
||||||
Curl_safefree(qname);
|
free(qname);
|
||||||
if(result)
|
if(result)
|
||||||
goto error;
|
goto error;
|
||||||
dohp->pending++;
|
dohp->pending++;
|
||||||
@ -1081,12 +1074,12 @@ static CURLcode doh_decode_rdata_name(unsigned char **buf, size_t *remaining,
|
|||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode doh_decode_rdata_alpn(unsigned char *rrval, size_t len,
|
static CURLcode doh_decode_rdata_alpn(unsigned char *cp, size_t len,
|
||||||
char **alpns)
|
char **alpns)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* spec here is as per draft-ietf-dnsop-svcb-https, section-7.1.1
|
* spec here is as per RFC 9460, section-7.1.1
|
||||||
* encoding is catenated list of strings each preceded by a one
|
* encoding is a concatenated list of strings each preceded by a one
|
||||||
* octet length
|
* octet length
|
||||||
* output is comma-sep list of the strings
|
* output is comma-sep list of the strings
|
||||||
* implementations may or may not handle quoting of comma within
|
* implementations may or may not handle quoting of comma within
|
||||||
@ -1095,25 +1088,21 @@ static CURLcode doh_decode_rdata_alpn(unsigned char *rrval, size_t len,
|
|||||||
* backslash - same goes for a backslash character, and of course
|
* backslash - same goes for a backslash character, and of course
|
||||||
* we need to use two backslashes in strings when we mean one;-)
|
* we need to use two backslashes in strings when we mean one;-)
|
||||||
*/
|
*/
|
||||||
int remaining = (int) len;
|
|
||||||
char *oval;
|
char *oval;
|
||||||
size_t i;
|
|
||||||
unsigned char *cp = rrval;
|
|
||||||
struct dynbuf dval;
|
struct dynbuf dval;
|
||||||
|
|
||||||
if(!alpns)
|
if(!alpns)
|
||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
Curl_dyn_init(&dval, DYN_DOH_RESPONSE);
|
Curl_dyn_init(&dval, DYN_DOH_RESPONSE);
|
||||||
remaining = (int)len;
|
while(len > 0) {
|
||||||
cp = rrval;
|
|
||||||
while(remaining > 0) {
|
|
||||||
size_t tlen = (size_t) *cp++;
|
size_t tlen = (size_t) *cp++;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
/* if not 1st time, add comma */
|
/* if not 1st time, add comma */
|
||||||
if(remaining != (int)len && Curl_dyn_addn(&dval, ",", 1))
|
if(Curl_dyn_len(&dval) && Curl_dyn_addn(&dval, ",", 1))
|
||||||
goto err;
|
goto err;
|
||||||
remaining--;
|
len--;
|
||||||
if(tlen > (size_t)remaining)
|
if(tlen > len)
|
||||||
goto err;
|
goto err;
|
||||||
/* add escape char if needed, clunky but easier to read */
|
/* add escape char if needed, clunky but easier to read */
|
||||||
for(i = 0; i != tlen; i++) {
|
for(i = 0; i != tlen; i++) {
|
||||||
@ -1124,7 +1113,7 @@ static CURLcode doh_decode_rdata_alpn(unsigned char *rrval, size_t len,
|
|||||||
if(Curl_dyn_addn(&dval, cp++, 1))
|
if(Curl_dyn_addn(&dval, cp++, 1))
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
remaining -= (int)tlen;
|
len -= tlen;
|
||||||
}
|
}
|
||||||
/* this string is always null terminated */
|
/* this string is always null terminated */
|
||||||
oval = Curl_dyn_ptr(&dval);
|
oval = Curl_dyn_ptr(&dval);
|
||||||
@ -1161,11 +1150,9 @@ static CURLcode doh_test_alpn_escapes(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static CURLcode doh_resp_decode_httpsrr(unsigned char *rrval, size_t len,
|
static CURLcode doh_resp_decode_httpsrr(unsigned char *cp, size_t len,
|
||||||
struct Curl_https_rrinfo **hrr)
|
struct Curl_https_rrinfo **hrr)
|
||||||
{
|
{
|
||||||
size_t remaining = len;
|
|
||||||
unsigned char *cp = rrval;
|
|
||||||
uint16_t pcode = 0, plen = 0;
|
uint16_t pcode = 0, plen = 0;
|
||||||
struct Curl_https_rrinfo *lhrr = NULL;
|
struct Curl_https_rrinfo *lhrr = NULL;
|
||||||
char *dnsname = NULL;
|
char *dnsname = NULL;
|
||||||
@ -1175,73 +1162,74 @@ static CURLcode doh_resp_decode_httpsrr(unsigned char *rrval, size_t len,
|
|||||||
if(doh_test_alpn_escapes() != CURLE_OK)
|
if(doh_test_alpn_escapes() != CURLE_OK)
|
||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
#endif
|
#endif
|
||||||
|
if(len <= 2)
|
||||||
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||||
lhrr = calloc(1, sizeof(struct Curl_https_rrinfo));
|
lhrr = calloc(1, sizeof(struct Curl_https_rrinfo));
|
||||||
if(!lhrr)
|
if(!lhrr)
|
||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
lhrr->val = Curl_memdup(rrval, len);
|
lhrr->priority = doh_get16bit(cp, 0);
|
||||||
if(!lhrr->val)
|
|
||||||
goto err;
|
|
||||||
lhrr->len = len;
|
|
||||||
if(remaining <= 2)
|
|
||||||
goto err;
|
|
||||||
lhrr->priority = (uint16_t)((cp[0] << 8) + cp[1]);
|
|
||||||
cp += 2;
|
cp += 2;
|
||||||
remaining -= (uint16_t)2;
|
len -= 2;
|
||||||
if(doh_decode_rdata_name(&cp, &remaining, &dnsname) != CURLE_OK)
|
if(doh_decode_rdata_name(&cp, &len, &dnsname) != CURLE_OK)
|
||||||
goto err;
|
goto err;
|
||||||
lhrr->target = dnsname;
|
lhrr->target = dnsname;
|
||||||
while(remaining >= 4) {
|
lhrr->port = -1; /* until set */
|
||||||
pcode = (uint16_t)((*cp << 8) + (*(cp + 1)));
|
while(len >= 4) {
|
||||||
cp += 2;
|
pcode = doh_get16bit(cp, 0);
|
||||||
plen = (uint16_t)((*cp << 8) + (*(cp + 1)));
|
plen = doh_get16bit(cp, 2);
|
||||||
cp += 2;
|
cp += 4;
|
||||||
remaining -= 4;
|
len -= 4;
|
||||||
if(pcode == HTTPS_RR_CODE_ALPN) {
|
switch(pcode) {
|
||||||
|
case HTTPS_RR_CODE_ALPN:
|
||||||
if(doh_decode_rdata_alpn(cp, plen, &lhrr->alpns) != CURLE_OK)
|
if(doh_decode_rdata_alpn(cp, plen, &lhrr->alpns) != CURLE_OK)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
break;
|
||||||
if(pcode == HTTPS_RR_CODE_NO_DEF_ALPN)
|
case HTTPS_RR_CODE_NO_DEF_ALPN:
|
||||||
lhrr->no_def_alpn = TRUE;
|
lhrr->no_def_alpn = TRUE;
|
||||||
else if(pcode == HTTPS_RR_CODE_IPV4) {
|
break;
|
||||||
|
case HTTPS_RR_CODE_IPV4:
|
||||||
if(!plen)
|
if(!plen)
|
||||||
goto err;
|
goto err;
|
||||||
lhrr->ipv4hints = Curl_memdup(cp, plen);
|
lhrr->ipv4hints = Curl_memdup(cp, plen);
|
||||||
if(!lhrr->ipv4hints)
|
if(!lhrr->ipv4hints)
|
||||||
goto err;
|
goto err;
|
||||||
lhrr->ipv4hints_len = (size_t)plen;
|
lhrr->ipv4hints_len = (size_t)plen;
|
||||||
}
|
break;
|
||||||
else if(pcode == HTTPS_RR_CODE_ECH) {
|
case HTTPS_RR_CODE_ECH:
|
||||||
if(!plen)
|
if(!plen)
|
||||||
goto err;
|
goto err;
|
||||||
lhrr->echconfiglist = Curl_memdup(cp, plen);
|
lhrr->echconfiglist = Curl_memdup(cp, plen);
|
||||||
if(!lhrr->echconfiglist)
|
if(!lhrr->echconfiglist)
|
||||||
goto err;
|
goto err;
|
||||||
lhrr->echconfiglist_len = (size_t)plen;
|
lhrr->echconfiglist_len = (size_t)plen;
|
||||||
}
|
break;
|
||||||
else if(pcode == HTTPS_RR_CODE_IPV6) {
|
case HTTPS_RR_CODE_IPV6:
|
||||||
if(!plen)
|
if(!plen)
|
||||||
goto err;
|
goto err;
|
||||||
lhrr->ipv6hints = Curl_memdup(cp, plen);
|
lhrr->ipv6hints = Curl_memdup(cp, plen);
|
||||||
if(!lhrr->ipv6hints)
|
if(!lhrr->ipv6hints)
|
||||||
goto err;
|
goto err;
|
||||||
lhrr->ipv6hints_len = (size_t)plen;
|
lhrr->ipv6hints_len = (size_t)plen;
|
||||||
|
break;
|
||||||
|
case HTTPS_RR_CODE_PORT:
|
||||||
|
lhrr->port = doh_get16bit(cp, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if(plen > 0 && plen <= remaining) {
|
if(plen > 0 && plen <= len) {
|
||||||
cp += plen;
|
cp += plen;
|
||||||
remaining -= plen;
|
len -= plen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DEBUGASSERT(!remaining);
|
DEBUGASSERT(!len);
|
||||||
*hrr = lhrr;
|
*hrr = lhrr;
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
err:
|
err:
|
||||||
if(lhrr) {
|
Curl_safefree(lhrr->target);
|
||||||
Curl_safefree(lhrr->target);
|
Curl_safefree(lhrr->echconfiglist);
|
||||||
Curl_safefree(lhrr->echconfiglist);
|
Curl_safefree(lhrr->alpns);
|
||||||
Curl_safefree(lhrr->val);
|
Curl_safefree(lhrr);
|
||||||
Curl_safefree(lhrr->alpns);
|
|
||||||
Curl_safefree(lhrr);
|
|
||||||
}
|
|
||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
17
lib/hostip.c
17
lib/hostip.c
@ -1079,18 +1079,11 @@ static void hostcache_unlink_entry(void *entry)
|
|||||||
Curl_freeaddrinfo(dns->addr);
|
Curl_freeaddrinfo(dns->addr);
|
||||||
#ifdef USE_HTTPSRR
|
#ifdef USE_HTTPSRR
|
||||||
if(dns->hinfo) {
|
if(dns->hinfo) {
|
||||||
if(dns->hinfo->target)
|
free(dns->hinfo->target);
|
||||||
free(dns->hinfo->target);
|
free(dns->hinfo->alpns);
|
||||||
if(dns->hinfo->alpns)
|
free(dns->hinfo->ipv4hints);
|
||||||
free(dns->hinfo->alpns);
|
free(dns->hinfo->echconfiglist);
|
||||||
if(dns->hinfo->ipv4hints)
|
free(dns->hinfo->ipv6hints);
|
||||||
free(dns->hinfo->ipv4hints);
|
|
||||||
if(dns->hinfo->echconfiglist)
|
|
||||||
free(dns->hinfo->echconfiglist);
|
|
||||||
if(dns->hinfo->ipv6hints)
|
|
||||||
free(dns->hinfo->ipv6hints);
|
|
||||||
if(dns->hinfo->val)
|
|
||||||
free(dns->hinfo->val);
|
|
||||||
free(dns->hinfo);
|
free(dns->hinfo);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
17
lib/hostip.h
17
lib/hostip.h
@ -67,28 +67,21 @@ struct Curl_hash *Curl_global_host_cache_init(void);
|
|||||||
#define CURL_MAXLEN_host_name 253
|
#define CURL_MAXLEN_host_name 253
|
||||||
|
|
||||||
struct Curl_https_rrinfo {
|
struct Curl_https_rrinfo {
|
||||||
size_t len; /* raw encoded length */
|
|
||||||
unsigned char *val; /* raw encoded octets */
|
|
||||||
/*
|
/*
|
||||||
* fields from HTTPS RR, with the mandatory fields
|
* Fields from HTTPS RR. The only mandatory fields are priority and target.
|
||||||
* first (priority, target), then the others in the
|
* See https://datatracker.ietf.org/doc/html/rfc9460#section-14.3.2
|
||||||
* order of the keytag numbers defined at
|
|
||||||
* https://datatracker.ietf.org/doc/html/rfc9460#section-14.3.2
|
|
||||||
*/
|
*/
|
||||||
uint16_t priority;
|
|
||||||
char *target;
|
char *target;
|
||||||
char *alpns; /* keytag = 1 */
|
char *alpns; /* keytag = 1 */
|
||||||
bool no_def_alpn; /* keytag = 2 */
|
|
||||||
/*
|
|
||||||
* we do not support ports (keytag = 3) as we do not support
|
|
||||||
* port-switching yet
|
|
||||||
*/
|
|
||||||
unsigned char *ipv4hints; /* keytag = 4 */
|
unsigned char *ipv4hints; /* keytag = 4 */
|
||||||
size_t ipv4hints_len;
|
size_t ipv4hints_len;
|
||||||
unsigned char *echconfiglist; /* keytag = 5 */
|
unsigned char *echconfiglist; /* keytag = 5 */
|
||||||
size_t echconfiglist_len;
|
size_t echconfiglist_len;
|
||||||
unsigned char *ipv6hints; /* keytag = 6 */
|
unsigned char *ipv6hints; /* keytag = 6 */
|
||||||
size_t ipv6hints_len;
|
size_t ipv6hints_len;
|
||||||
|
int port; /* -1 means not set */
|
||||||
|
uint16_t priority;
|
||||||
|
bool no_def_alpn; /* keytag = 2 */
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user