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 connectdata *conn = data->conn;
|
||||
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;
|
||||
(void)hostname;
|
||||
(void)port;
|
||||
@ -463,28 +457,27 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
|
||||
|
||||
#ifdef USE_HTTPSRR
|
||||
/*
|
||||
* TODO: Figure out the conditions under which we want to make
|
||||
* a request for an HTTPS RR when we are not doing ECH. For now,
|
||||
* making this request breaks a bunch of DoH tests, e.g. test2100,
|
||||
* where the additional request does not match the pre-cooked data
|
||||
* files, so there is a bit of work attached to making the request
|
||||
* in a non-ECH use-case. For the present, we will only make the
|
||||
* request when ECH is enabled in the build and is being used for
|
||||
* the curl operation.
|
||||
* TODO: Figure out the conditions under which we want to make a request for
|
||||
* an HTTPS RR when we are not doing ECH. For now, making this request
|
||||
* breaks a bunch of DoH tests, e.g. test2100, where the additional request
|
||||
* does not match the pre-cooked data files, so there is a bit of work
|
||||
* attached to making the request in a non-ECH use-case. For the present, we
|
||||
* will only make the request when ECH is enabled in the build and is being
|
||||
* used for the curl operation.
|
||||
*/
|
||||
# ifdef USE_ECH
|
||||
if(data->set.tls_ech & CURLECH_ENABLE
|
||||
|| data->set.tls_ech & CURLECH_HARD) {
|
||||
if(port == 443)
|
||||
qname = strdup(hostname);
|
||||
else
|
||||
if(data->set.tls_ech & (CURLECH_ENABLE|CURLECH_HARD)) {
|
||||
char *qname = NULL;
|
||||
if(port != PORT_HTTPS) {
|
||||
qname = aprintf("_%d._https.%s", port, hostname);
|
||||
if(!qname)
|
||||
goto error;
|
||||
if(!qname)
|
||||
goto error;
|
||||
}
|
||||
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);
|
||||
Curl_safefree(qname);
|
||||
free(qname);
|
||||
if(result)
|
||||
goto error;
|
||||
dohp->pending++;
|
||||
@ -1081,12 +1074,12 @@ static CURLcode doh_decode_rdata_name(unsigned char **buf, size_t *remaining,
|
||||
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)
|
||||
{
|
||||
/*
|
||||
* spec here is as per draft-ietf-dnsop-svcb-https, section-7.1.1
|
||||
* encoding is catenated list of strings each preceded by a one
|
||||
* spec here is as per RFC 9460, section-7.1.1
|
||||
* encoding is a concatenated list of strings each preceded by a one
|
||||
* octet length
|
||||
* output is comma-sep list of the strings
|
||||
* 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
|
||||
* we need to use two backslashes in strings when we mean one;-)
|
||||
*/
|
||||
int remaining = (int) len;
|
||||
char *oval;
|
||||
size_t i;
|
||||
unsigned char *cp = rrval;
|
||||
struct dynbuf dval;
|
||||
|
||||
if(!alpns)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
Curl_dyn_init(&dval, DYN_DOH_RESPONSE);
|
||||
remaining = (int)len;
|
||||
cp = rrval;
|
||||
while(remaining > 0) {
|
||||
while(len > 0) {
|
||||
size_t tlen = (size_t) *cp++;
|
||||
size_t i;
|
||||
|
||||
/* 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;
|
||||
remaining--;
|
||||
if(tlen > (size_t)remaining)
|
||||
len--;
|
||||
if(tlen > len)
|
||||
goto err;
|
||||
/* add escape char if needed, clunky but easier to read */
|
||||
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))
|
||||
goto err;
|
||||
}
|
||||
remaining -= (int)tlen;
|
||||
len -= tlen;
|
||||
}
|
||||
/* this string is always null terminated */
|
||||
oval = Curl_dyn_ptr(&dval);
|
||||
@ -1161,11 +1150,9 @@ static CURLcode doh_test_alpn_escapes(void)
|
||||
}
|
||||
#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)
|
||||
{
|
||||
size_t remaining = len;
|
||||
unsigned char *cp = rrval;
|
||||
uint16_t pcode = 0, plen = 0;
|
||||
struct Curl_https_rrinfo *lhrr = 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)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
#endif
|
||||
if(len <= 2)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
lhrr = calloc(1, sizeof(struct Curl_https_rrinfo));
|
||||
if(!lhrr)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
lhrr->val = Curl_memdup(rrval, len);
|
||||
if(!lhrr->val)
|
||||
goto err;
|
||||
lhrr->len = len;
|
||||
if(remaining <= 2)
|
||||
goto err;
|
||||
lhrr->priority = (uint16_t)((cp[0] << 8) + cp[1]);
|
||||
lhrr->priority = doh_get16bit(cp, 0);
|
||||
cp += 2;
|
||||
remaining -= (uint16_t)2;
|
||||
if(doh_decode_rdata_name(&cp, &remaining, &dnsname) != CURLE_OK)
|
||||
len -= 2;
|
||||
if(doh_decode_rdata_name(&cp, &len, &dnsname) != CURLE_OK)
|
||||
goto err;
|
||||
lhrr->target = dnsname;
|
||||
while(remaining >= 4) {
|
||||
pcode = (uint16_t)((*cp << 8) + (*(cp + 1)));
|
||||
cp += 2;
|
||||
plen = (uint16_t)((*cp << 8) + (*(cp + 1)));
|
||||
cp += 2;
|
||||
remaining -= 4;
|
||||
if(pcode == HTTPS_RR_CODE_ALPN) {
|
||||
lhrr->port = -1; /* until set */
|
||||
while(len >= 4) {
|
||||
pcode = doh_get16bit(cp, 0);
|
||||
plen = doh_get16bit(cp, 2);
|
||||
cp += 4;
|
||||
len -= 4;
|
||||
switch(pcode) {
|
||||
case HTTPS_RR_CODE_ALPN:
|
||||
if(doh_decode_rdata_alpn(cp, plen, &lhrr->alpns) != CURLE_OK)
|
||||
goto err;
|
||||
}
|
||||
if(pcode == HTTPS_RR_CODE_NO_DEF_ALPN)
|
||||
break;
|
||||
case HTTPS_RR_CODE_NO_DEF_ALPN:
|
||||
lhrr->no_def_alpn = TRUE;
|
||||
else if(pcode == HTTPS_RR_CODE_IPV4) {
|
||||
break;
|
||||
case HTTPS_RR_CODE_IPV4:
|
||||
if(!plen)
|
||||
goto err;
|
||||
lhrr->ipv4hints = Curl_memdup(cp, plen);
|
||||
if(!lhrr->ipv4hints)
|
||||
goto err;
|
||||
lhrr->ipv4hints_len = (size_t)plen;
|
||||
}
|
||||
else if(pcode == HTTPS_RR_CODE_ECH) {
|
||||
break;
|
||||
case HTTPS_RR_CODE_ECH:
|
||||
if(!plen)
|
||||
goto err;
|
||||
lhrr->echconfiglist = Curl_memdup(cp, plen);
|
||||
if(!lhrr->echconfiglist)
|
||||
goto err;
|
||||
lhrr->echconfiglist_len = (size_t)plen;
|
||||
}
|
||||
else if(pcode == HTTPS_RR_CODE_IPV6) {
|
||||
break;
|
||||
case HTTPS_RR_CODE_IPV6:
|
||||
if(!plen)
|
||||
goto err;
|
||||
lhrr->ipv6hints = Curl_memdup(cp, plen);
|
||||
if(!lhrr->ipv6hints)
|
||||
goto err;
|
||||
lhrr->ipv6hints_len = (size_t)plen;
|
||||
break;
|
||||
case HTTPS_RR_CODE_PORT:
|
||||
lhrr->port = doh_get16bit(cp, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(plen > 0 && plen <= remaining) {
|
||||
if(plen > 0 && plen <= len) {
|
||||
cp += plen;
|
||||
remaining -= plen;
|
||||
len -= plen;
|
||||
}
|
||||
}
|
||||
DEBUGASSERT(!remaining);
|
||||
DEBUGASSERT(!len);
|
||||
*hrr = lhrr;
|
||||
return CURLE_OK;
|
||||
err:
|
||||
if(lhrr) {
|
||||
Curl_safefree(lhrr->target);
|
||||
Curl_safefree(lhrr->echconfiglist);
|
||||
Curl_safefree(lhrr->val);
|
||||
Curl_safefree(lhrr->alpns);
|
||||
Curl_safefree(lhrr);
|
||||
}
|
||||
Curl_safefree(lhrr->target);
|
||||
Curl_safefree(lhrr->echconfiglist);
|
||||
Curl_safefree(lhrr->alpns);
|
||||
Curl_safefree(lhrr);
|
||||
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);
|
||||
#ifdef USE_HTTPSRR
|
||||
if(dns->hinfo) {
|
||||
if(dns->hinfo->target)
|
||||
free(dns->hinfo->target);
|
||||
if(dns->hinfo->alpns)
|
||||
free(dns->hinfo->alpns);
|
||||
if(dns->hinfo->ipv4hints)
|
||||
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->target);
|
||||
free(dns->hinfo->alpns);
|
||||
free(dns->hinfo->ipv4hints);
|
||||
free(dns->hinfo->echconfiglist);
|
||||
free(dns->hinfo->ipv6hints);
|
||||
free(dns->hinfo);
|
||||
}
|
||||
#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
|
||||
|
||||
struct Curl_https_rrinfo {
|
||||
size_t len; /* raw encoded length */
|
||||
unsigned char *val; /* raw encoded octets */
|
||||
/*
|
||||
* fields from HTTPS RR, with the mandatory fields
|
||||
* first (priority, target), then the others in the
|
||||
* order of the keytag numbers defined at
|
||||
* https://datatracker.ietf.org/doc/html/rfc9460#section-14.3.2
|
||||
* Fields from HTTPS RR. The only mandatory fields are priority and target.
|
||||
* See https://datatracker.ietf.org/doc/html/rfc9460#section-14.3.2
|
||||
*/
|
||||
uint16_t priority;
|
||||
char *target;
|
||||
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 */
|
||||
size_t ipv4hints_len;
|
||||
unsigned char *echconfiglist; /* keytag = 5 */
|
||||
size_t echconfiglist_len;
|
||||
unsigned char *ipv6hints; /* keytag = 6 */
|
||||
size_t ipv6hints_len;
|
||||
int port; /* -1 means not set */
|
||||
uint16_t priority;
|
||||
bool no_def_alpn; /* keytag = 2 */
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user