Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SVCB dohpath support #739

Merged
merged 12 commits into from
Jul 3, 2023
66 changes: 54 additions & 12 deletions sldns/str2wire.c
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ rrinternal_get_delims(sldns_rdf_type rdftype, size_t r_cnt, size_t r_max)
break;
default : break;
}
return "\n\t ";
return "\n\t ";
}

/* Syntactic sugar for sldns_rr_new_frm_str_internal */
Expand Down Expand Up @@ -448,7 +448,7 @@ rrinternal_parse_unknown(sldns_buffer* strbuf, char* token, size_t token_len,
sldns_buffer_position(strbuf));
}
hex_data_size = (size_t)atoi(token);
if(hex_data_size > LDNS_MAX_RDFLEN ||
if(hex_data_size > LDNS_MAX_RDFLEN ||
*rr_cur_len + hex_data_size > *rr_len) {
return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
sldns_buffer_position(strbuf));
Expand Down Expand Up @@ -567,7 +567,7 @@ sldns_parse_rdf_token(sldns_buffer* strbuf, char* token, size_t token_len,
/* check if not quoted yet, and we have encountered quotes */
if(!*quoted && sldns_rdf_type_maybe_quoted(rdftype) &&
slen >= 2 &&
(token[0] == '"' || token[0] == '\'') &&
(token[0] == '"' || token[0] == '\'') &&
(token[slen-1] == '"' || token[slen-1] == '\'')) {
/* move token two smaller (quotes) with endnull */
memmove(token, token+1, slen-2);
Expand Down Expand Up @@ -698,7 +698,7 @@ static int sldns_str2wire_check_svcbparams(uint8_t* rdata, uint16_t rdata_len)
mandatory = svcparams[i];
}

/* 4. verify that all the SvcParamKeys in mandatory are present */
/* Verify that all the SvcParamKeys in mandatory are present */
if(mandatory) {
/* Divide by sizeof(uint16_t)*/
uint16_t mandatory_nkeys = sldns_read_uint16(mandatory + 2) / sizeof(uint16_t);
Expand Down Expand Up @@ -785,7 +785,7 @@ rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len,
token[2]=='\t')) {
was_unknown_rr_format = 1;
if((status=rrinternal_parse_unknown(strbuf, token,
token_len, rr, rr_len, &rr_cur_len,
token_len, rr, rr_len, &rr_cur_len,
pre_data_pos)) != 0)
return status;
} else if(token_strlen > 0 || quoted) {
Expand Down Expand Up @@ -844,7 +844,7 @@ rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len,
if (rr_type == LDNS_RR_TYPE_SVCB || rr_type == LDNS_RR_TYPE_HTTPS) {
size_t rdata_len = rr_cur_len - dname_len - 10;
uint8_t *rdata = rr+dname_len + 10;

/* skip 1st rdata field SvcPriority (uint16_t) */
if (rdata_len < sizeof(uint16_t))
return LDNS_WIREPARSE_ERR_OK;
Expand Down Expand Up @@ -1150,6 +1150,11 @@ sldns_str2wire_svcparam_key_lookup(const char *key, size_t key_len)
return SVCB_KEY_IPV6HINT;
break;

case sizeof("dohpath")-1:
if (!strncmp(key, "dohpath", sizeof("dohpath")-1))
return SVCB_KEY_DOHPATH;
break;

case sizeof("ech")-1:
if (!strncmp(key, "ech", sizeof("ech")-1))
return SVCB_KEY_ECH;
Expand Down Expand Up @@ -1477,7 +1482,7 @@ sldns_str2wire_svcbparam_alpn_value(const char* val,
size_t str_len;
size_t dst_len;
size_t val_len;

val_len = strlen(val);

if (val_len > sizeof(unescaped_dst)) {
Expand Down Expand Up @@ -1511,7 +1516,41 @@ sldns_str2wire_svcbparam_alpn_value(const char* val,
sldns_write_uint16(rd + 2, dst_len);
memcpy(rd + 4, unescaped_dst, dst_len);
*rd_len = 4 + dst_len;


return LDNS_WIREPARSE_ERR_OK;
}

static int
sldns_str2wire_svcbparam_dohpath_value(const char* val,
uint8_t* rd, size_t* rd_len)
{
size_t val_len;

/* RFC6570#section-2.1
* "The characters outside of expressions in a URI Template string are
* intended to be copied literally"
* Practically this means we do not have to look for "double escapes"
* like in the alpn value list.
*/

val_len = strlen(val);

if (*rd_len < 4 + val_len) {
return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
}

/* draft-ietf-add-svcb-dns-06#section-5.1
* The URI Template MUST contain a "dns" variable
*/
if (!(strstr(val, "?dns"))) {
TCY16 marked this conversation as resolved.
Show resolved Hide resolved
return LDNS_WIREPARSE_ERR_SVCB_NO_DNS_VAR_IN_DOHPATH;
}

sldns_write_uint16(rd, SVCB_KEY_DOHPATH);
sldns_write_uint16(rd + 2, val_len);
memcpy(rd + 4, val, val_len);
*rd_len = 4 + val_len;

return LDNS_WIREPARSE_ERR_OK;
}

Expand All @@ -1535,6 +1574,7 @@ sldns_str2wire_svcparam_value(const char *key, size_t key_len,
case SVCB_KEY_PORT:
case SVCB_KEY_IPV4HINT:
case SVCB_KEY_IPV6HINT:
case SVCB_KEY_DOHPATH:
return LDNS_WIREPARSE_ERR_SVCB_MISSING_PARAM;
#endif
default:
Expand Down Expand Up @@ -1566,6 +1606,8 @@ sldns_str2wire_svcparam_value(const char *key, size_t key_len,
return sldns_str2wire_svcbparam_ech_value(val, rd, rd_len);
case SVCB_KEY_ALPN:
return sldns_str2wire_svcbparam_alpn_value(val, rd, rd_len);
case SVCB_KEY_DOHPATH:
return sldns_str2wire_svcbparam_dohpath_value(val, rd, rd_len);
default:
str_len = strlen(val);
if (*rd_len < 4 + str_len)
Expand Down Expand Up @@ -1593,7 +1635,7 @@ static int sldns_str2wire_svcparam_buf(const char* str, uint8_t* rd, size_t* rd_
/* case: key=value */
if (eq_pos != NULL && eq_pos[1]) {
val_in = eq_pos + 1;

/* unescape characters and "" blocks */
if (*val_in == '"') {
val_in++;
Expand All @@ -1610,11 +1652,11 @@ static int sldns_str2wire_svcparam_buf(const char* str, uint8_t* rd, size_t* rd_
}
*val_out = 0;

return sldns_str2wire_svcparam_value(str, eq_pos - str,
unescaped_val[0] ? unescaped_val : NULL, rd, rd_len);
return sldns_str2wire_svcparam_value(str, eq_pos - str,
unescaped_val[0] ? unescaped_val : NULL, rd, rd_len);
}
/* case: key= */
else if (eq_pos != NULL && !(eq_pos[1])) {
else if (eq_pos != NULL && !(eq_pos[1])) {
return sldns_str2wire_svcparam_value(str, eq_pos - str, NULL, rd, rd_len);
}
/* case: key */
Expand Down
7 changes: 5 additions & 2 deletions sldns/str2wire.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ struct sldns_struct_lookup_table;
#define SVCB_KEY_IPV4HINT 4
#define SVCB_KEY_ECH 5
#define SVCB_KEY_IPV6HINT 6
#define SVCPARAMKEY_COUNT 7
#define SVCB_KEY_DOHPATH 7
#define SVCPARAMKEY_COUNT 8

#define MAX_NUMBER_OF_SVCPARAMS 64

Expand Down Expand Up @@ -234,7 +235,9 @@ uint8_t* sldns_wirerr_get_rdatawl(uint8_t* rr, size_t len, size_t dname_len);
#define LDNS_WIREPARSE_ERR_SVCB_IPV6_TOO_MANY_ADDRESSES 383
#define LDNS_WIREPARSE_ERR_SVCB_ALPN_KEY_TOO_LARGE 384
#define LDNS_WIREPARSE_ERR_SVCB_NO_DEFAULT_ALPN_VALUE 385
#define LDNS_WIREPARSE_ERR_SVCPARAM_BROKEN_RDATA 386
#define LDNS_WIREPARSE_ERR_SVCB_NO_DNS_VAR_IN_DOHPATH 386
#define LDNS_WIREPARSE_ERR_SVCPARAM_BROKEN_RDATA 387


/**
* Get reference to a constant string for the (parse) error.
Expand Down
48 changes: 40 additions & 8 deletions sldns/wire2str.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ static sldns_lookup_table sldns_wireparse_errors_data[] = {
"Mandatory SvcParamKey is missing"},
{ LDNS_WIREPARSE_ERR_SVCB_MANDATORY_DUPLICATE_KEY,
"Keys in SvcParam mandatory MUST be unique" },
{ LDNS_WIREPARSE_ERR_SVCB_MANDATORY_IN_MANDATORY,
{ LDNS_WIREPARSE_ERR_SVCB_MANDATORY_IN_MANDATORY,
"mandatory MUST not be included as mandatory parameter" },
{ LDNS_WIREPARSE_ERR_SVCB_PORT_VALUE_SYNTAX,
"Could not parse port SvcParamValue" },
Expand All @@ -171,6 +171,8 @@ static sldns_lookup_table sldns_wireparse_errors_data[] = {
"Alpn strings need to be smaller than 255 chars"},
{ LDNS_WIREPARSE_ERR_SVCB_NO_DEFAULT_ALPN_VALUE,
"No-default-alpn should not have a value" },
{ LDNS_WIREPARSE_ERR_SVCB_NO_DNS_VAR_IN_DOHPATH,
"Dohpath must have '?dns' in the URI template variable" },
{ LDNS_WIREPARSE_ERR_SVCPARAM_BROKEN_RDATA,
"General SVCParam error" },
{ 0, NULL }
Expand Down Expand Up @@ -224,7 +226,7 @@ sldns_lookup_table* sldns_tsig_errors = sldns_tsig_errors_data;
/* draft-ietf-dnsop-svcb-https-06: 6. Initial SvcParamKeys */
const char *svcparamkey_strs[] = {
"mandatory", "alpn", "no-default-alpn", "port",
"ipv4hint", "ech", "ipv6hint"
"ipv4hint", "ech", "ipv6hint", "dohpath"
};

char* sldns_wire2str_pkt(uint8_t* data, size_t len)
Expand Down Expand Up @@ -487,7 +489,7 @@ int sldns_wire2str_rr_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
uint8_t* rr = *d;
size_t rrlen = *dlen, dname_off, rdlen, ordlen;
uint16_t rrtype = 0;

if(*dlen >= 3 && (*d)[0]==0 &&
sldns_read_uint16((*d)+1)==LDNS_RR_TYPE_OPT) {
/* perform EDNS OPT processing */
Expand Down Expand Up @@ -1119,7 +1121,7 @@ static int sldns_wire2str_svcparam_alpn2str(char** s,
w += sldns_str_print(s, slen, "%s", ",");
}
w += sldns_str_print(s, slen, "\"");

return w;
}

Expand All @@ -1139,11 +1141,37 @@ static int sldns_wire2str_svcparam_ech2str(char** s,
(*s) += size;
(*slen) -= size;

w += sldns_str_print(s, slen, "\"");
w += sldns_str_print(s, slen, "\"");

return w + size;
}

static int sldns_wire2str_svcparam_dohpath2str(char** s,
size_t* slen, uint16_t data_len, uint8_t* data)
{
int w = 0;
uint16_t i;

assert(data_len > 0); /* Guaranteed by sldns_wire2str_svcparam_scan */

w += sldns_str_print(s, slen, "=\"");

/* RC6570#section-2.1 specifies that the '\' (and other non-letter
* characters in the URI) are "intended to be copied literally" (as
* opposed to the alpn printing) */
for (i = 0; i < data_len; i++) {
if (!isprint(data[i])) {
w += sldns_str_print(s, slen, "\\%03u", (unsigned) data[i]);
} else {
w += sldns_str_print(s, slen, "%c", data[i]);
}
}

w += sldns_str_print(s, slen, "\"");

return w;
}

TCY16 marked this conversation as resolved.
Show resolved Hide resolved
int sldns_wire2str_svcparam_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
{
uint8_t ch;
Expand All @@ -1162,7 +1190,7 @@ int sldns_wire2str_svcparam_scan(uint8_t** d, size_t* dlen, char** s, size_t* sl

/* verify that we have data_len data */
if (data_len > *dlen)
return -1;
return -1;

written_chars += sldns_print_svcparamkey(s, slen, svcparamkey);
if (!data_len) {
Expand All @@ -1174,6 +1202,7 @@ int sldns_wire2str_svcparam_scan(uint8_t** d, size_t* dlen, char** s, size_t* sl
case SVCB_KEY_IPV4HINT:
case SVCB_KEY_IPV6HINT:
case SVCB_KEY_MANDATORY:
case SVCB_KEY_DOHPATH:
return -1;
default:
return written_chars;
Expand Down Expand Up @@ -1201,6 +1230,9 @@ int sldns_wire2str_svcparam_scan(uint8_t** d, size_t* dlen, char** s, size_t* sl
case SVCB_KEY_ECH:
r = sldns_wire2str_svcparam_ech2str(s, slen, data_len, *d);
break;
case SVCB_KEY_DOHPATH:
r = sldns_wire2str_svcparam_dohpath2str(s, slen, data_len, *d);
break;
TCY16 marked this conversation as resolved.
Show resolved Hide resolved
default:
r = sldns_str_print(s, slen, "=\"");

Expand All @@ -1222,7 +1254,7 @@ int sldns_wire2str_svcparam_scan(uint8_t** d, size_t* dlen, char** s, size_t* sl
}
if (r <= 0)
return -1; /* wireformat error */

written_chars += r;
*d += data_len;
*dlen -= data_len;
Expand Down Expand Up @@ -1551,7 +1583,7 @@ int sldns_wire2str_nsec_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
unsigned i, bit, window, block_len;
uint16_t t;
int w = 0;

/* check for errors */
while(pl) {
if(pl < 2) return -1;
Expand Down
2 changes: 1 addition & 1 deletion testdata/svcb.tdir/svcb.failure-cases-01
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ $TTL 3600

@ SOA primary admin 0 0 0 0 0

; Here there are multiple instances of the same SvcParamKey in the mandatory list
; These cases should be bnase64 encoded but aren't

f21 HTTPS 1 foo.example.com. ech="123"
f21 HTTPS 1 foo.example.com. echconfig="123"
5 changes: 5 additions & 0 deletions testdata/svcb.tdir/svcb.success-cases.zone
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,8 @@ s08 HTTPS 0 . ( key11=a key12=a key13=a key14=a key15=a key16=a key17=a ke
; maximum alpn size allowed (255 characters)

s09 HTTPS 0 . ( alpn="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" )

; dohpath can be (non-)quoted and MUST contain "?dns"

_dns.doh.example. 7200 IN SVCB 1 doh.example. alpn=h2 dohpath="/dns-query{?dns}"
_dns.doh.example. 7200 IN SVCB 1 doh.example. alpn=h2 dohpath=/dns-query{?dns}
2 changes: 2 additions & 0 deletions testdata/svcb.tdir/svcb.success-cases.zone.cmp
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ s06.success-cases. 3600 IN HTTPS 0 . ech="aGVsbG93b3JsZCE="
s07.success-cases. 3600 IN HTTPS 0 . ech="aGVsbG93b3JsZCE="
s08.success-cases. 3600 IN HTTPS 0 . key11="a" key12="a" key13="a" key14="a" key15="a" key16="a" key17="a" key18="a" key19="a" key110="a" key111="a" key112="a" key113="a" key114="a" key115="a" key116="a" key117="a" key118="a" key119="a" key120="a" key121="a" key122="a" key123="a" key124="a" key125="a" key126="a" key127="a" key128="a" key129="a" key130="a" key131="a" key132="a" key133="a" key134="a" key135="a" key136="a" key137="a" key138="a" key139="a" key140="a" key141="a" key142="a" key143="a" key144="a" key145="a" key146="a" key147="a" key148="a" key149="a" key150="a" key151="a" key152="a" key153="a" key154="a" key155="a" key156="a" key157="a" key158="a" key159="a" key160="a" key161="a" key162="a" key163="a"
s09.success-cases. 3600 IN HTTPS 0 . alpn="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
_dns.doh.example. 7200 IN SVCB 1 doh.example. alpn="h2" dohpath="/dns-query{?dns}"
_dns.doh.example. 7200 IN SVCB 1 doh.example. alpn="h2" dohpath="/dns-query{?dns}"
TCY16 marked this conversation as resolved.
Show resolved Hide resolved