2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 14:07:59 +00:00

Add support for 'dohpath' to SVCB (and HTTPS)

dohpath is specfied in draft-ietf-add-svcb-dns and has a value
of 7.  It must be a relative path (start with a /), be encoded
as UTF8 and contain the variable dns ({?dns}).

(cherry picked from commit 6d561d38864d2cc21a4e9528527bceac389b173e)
This commit is contained in:
Mark Andrews 2022-09-15 16:04:43 +10:00
parent c179933c09
commit 10d9c040e7
3 changed files with 67 additions and 18 deletions

View File

@ -24,3 +24,4 @@ svcb6 SVCB 6 . mandatory=port,alpn port=60 alpn=h3
svcb7 SVCB 7 . mandatory=port,alpn port=60 alpn=h1,h3 svcb7 SVCB 7 . mandatory=port,alpn port=60 alpn=h1,h3
svcb8 SVCB 8 . mandatory=port,alpn port=60 alpn="h1\\,h2,h3" svcb8 SVCB 8 . mandatory=port,alpn port=60 alpn="h1\\,h2,h3"
svcb9 SVCB 0 44._svbc.example.net. svcb9 SVCB 0 44._svbc.example.net.
svcb10 SVCB 7 . alpn="h2,h3" dohpath=/{?dns}

View File

@ -34,13 +34,14 @@ enum encoding {
sbpr_base64, sbpr_base64,
sbpr_empty, sbpr_empty,
sbpr_alpn, sbpr_alpn,
sbpr_keylist sbpr_keylist,
sbpr_dohpath
}; };
static const struct { static const struct {
const char *name; /* Restricted to lowercase LDH by registry. */ const char *name; /* Restricted to lowercase LDH by registry. */
unsigned int value; unsigned int value;
enum encoding encoding; enum encoding encoding;
bool initial; bool initial; /* Part of the first defined set of encodings. */
} sbpr[] = { } sbpr[] = {
{ "mandatory", 0, sbpr_keylist, true }, { "mandatory", 0, sbpr_keylist, true },
{ "alpn", 1, sbpr_alpn, true }, { "alpn", 1, sbpr_alpn, true },
@ -49,6 +50,7 @@ static const struct {
{ "ipv4hint", 4, sbpr_ipv4s, true }, { "ipv4hint", 4, sbpr_ipv4s, true },
{ "ech", 5, sbpr_base64, true }, { "ech", 5, sbpr_base64, true },
{ "ipv6hint", 6, sbpr_ipv6s, true }, { "ipv6hint", 6, sbpr_ipv6s, true },
{ "dohpath", 7, sbpr_dohpath, false },
}; };
static isc_result_t static isc_result_t
@ -147,6 +149,30 @@ svcb_validate(uint16_t key, isc_region_t *region) {
case sbpr_text: case sbpr_text:
case sbpr_base64: case sbpr_base64:
break; break;
case sbpr_dohpath:
/*
* Minimum valid dohpath is "/{?dns}" as
* it MUST be relative (leading "/") and
* MUST contain "{?dns}".
*/
if (region->length < 7) {
return (DNS_R_FORMERR);
}
/* MUST be relative */
if (region->base[0] != '/') {
return (DNS_R_FORMERR);
}
/* MUST be UTF8 */
if (!isc_utf8_valid(region->base,
region->length)) {
return (DNS_R_FORMERR);
}
/* MUST contain "{?dns}" */
if (strnstr((char *)region->base, "{?dns}",
region->length) == NULL) {
return (DNS_R_FORMERR);
}
break;
case sbpr_empty: case sbpr_empty:
if (region->length != 0) { if (region->length != 0) {
return (DNS_R_FORMERR); return (DNS_R_FORMERR);
@ -252,6 +278,7 @@ svc_fromtext(isc_textregion_t *region, isc_buffer_t *target) {
switch (sbpr[i].encoding) { switch (sbpr[i].encoding) {
case sbpr_text: case sbpr_text:
case sbpr_dohpath:
RETERR(multitxt_fromtext(region, target)); RETERR(multitxt_fromtext(region, target));
break; break;
case sbpr_alpn: case sbpr_alpn:
@ -328,6 +355,19 @@ svc_fromtext(isc_textregion_t *region, isc_buffer_t *target) {
len = isc_buffer_usedlength(target) - len = isc_buffer_usedlength(target) -
isc_buffer_usedlength(&sb) - 2; isc_buffer_usedlength(&sb) - 2;
RETERR(uint16_tobuffer(len, &sb)); /* length */ RETERR(uint16_tobuffer(len, &sb)); /* length */
switch (sbpr[i].encoding) {
case sbpr_dohpath:
/*
* Apply constraints not applied by multitxt_fromtext.
*/
keyregion.base = isc_buffer_used(&sb);
keyregion.length = isc_buffer_usedlength(target) -
isc_buffer_usedlength(&sb);
RETERR(svcb_validate(sbpr[i].value, &keyregion));
break;
default:
break;
}
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
} }

View File

@ -2463,7 +2463,7 @@ ISC_RUN_TEST_IMPL(wks) {
ISC_RUN_TEST_IMPL(https_svcb) { ISC_RUN_TEST_IMPL(https_svcb) {
/* /*
* Known keys: mandatory, apln, no-default-alpn, port, * Known keys: mandatory, apln, no-default-alpn, port,
* ipv4hint, port, ipv6hint. * ipv4hint, port, ipv6hint, dohpath.
*/ */
text_ok_t text_ok[] = { text_ok_t text_ok[] = {
/* unknown key invalid */ /* unknown key invalid */
@ -2482,9 +2482,9 @@ ISC_RUN_TEST_IMPL(https_svcb) {
TEXT_INVALID("2 svc.example.net. key=\"2222\""), TEXT_INVALID("2 svc.example.net. key=\"2222\""),
/* zero pad invalid */ /* zero pad invalid */
TEXT_INVALID("2 svc.example.net. key07=\"2222\""), TEXT_INVALID("2 svc.example.net. key07=\"2222\""),
TEXT_VALID_LOOP(1, "2 svc.example.net. key7=\"2222\""), TEXT_VALID_LOOP(1, "2 svc.example.net. key8=\"2222\""),
TEXT_VALID_LOOPCHG(1, "2 svc.example.net. key7=2222", TEXT_VALID_LOOPCHG(1, "2 svc.example.net. key8=2222",
"2 svc.example.net. key7=\"2222\""), "2 svc.example.net. key8=\"2222\""),
TEXT_VALID_LOOPCHG(1, "2 svc.example.net. alpn=h2", TEXT_VALID_LOOPCHG(1, "2 svc.example.net. alpn=h2",
"2 svc.example.net. alpn=\"h2\""), "2 svc.example.net. alpn=\"h2\""),
TEXT_VALID_LOOPCHG(1, "2 svc.example.net. alpn=h3", TEXT_VALID_LOOPCHG(1, "2 svc.example.net. alpn=h3",
@ -2512,12 +2512,12 @@ ISC_RUN_TEST_IMPL(https_svcb) {
TEXT_VALID_LOOP(1, "2 svc.example.net. ech=abcdefghijkl"), TEXT_VALID_LOOP(1, "2 svc.example.net. ech=abcdefghijkl"),
/* bad base64 */ /* bad base64 */
TEXT_INVALID("2 svc.example.net. ech=abcdefghijklm"), TEXT_INVALID("2 svc.example.net. ech=abcdefghijklm"),
TEXT_VALID_LOOP(1, "2 svc.example.net. key7=\"2222\""), TEXT_VALID_LOOP(1, "2 svc.example.net. key8=\"2222\""),
/* Out of key order on input (alpn == key1). */ /* Out of key order on input (alpn == key1). */
TEXT_VALID_LOOPCHG(2, TEXT_VALID_LOOPCHG(2,
"2 svc.example.net. key7=\"2222\" alpn=h2", "2 svc.example.net. key8=\"2222\" alpn=h2",
"2 svc.example.net. alpn=\"h2\" " "2 svc.example.net. alpn=\"h2\" "
"key7=\"2222\""), "key8=\"2222\""),
TEXT_VALID_LOOP(1, "2 svc.example.net. key65535=\"2222\""), TEXT_VALID_LOOP(1, "2 svc.example.net. key65535=\"2222\""),
TEXT_INVALID("2 svc.example.net. key65536=\"2222\""), TEXT_INVALID("2 svc.example.net. key65536=\"2222\""),
TEXT_VALID_LOOP(1, "2 svc.example.net. key10"), TEXT_VALID_LOOP(1, "2 svc.example.net. key10"),
@ -2548,18 +2548,18 @@ ISC_RUN_TEST_IMPL(https_svcb) {
TEXT_INVALID("2 svc.example.net. " TEXT_INVALID("2 svc.example.net. "
"mandatory=alpn,,port alpn=h2 port=433"), "mandatory=alpn,,port alpn=h2 port=433"),
/* mandatory w/ unknown key values */ /* mandatory w/ unknown key values */
TEXT_VALID_LOOP(2, "2 svc.example.net. mandatory=key7 key7"), TEXT_VALID_LOOP(2, "2 svc.example.net. mandatory=key8 key8"),
TEXT_VALID_LOOP(3, "2 svc.example.net. mandatory=key7,key8 " TEXT_VALID_LOOP(3, "2 svc.example.net. mandatory=key8,key9 "
"key7 key8"), "key8 key9"),
TEXT_VALID_LOOPCHG( TEXT_VALID_LOOPCHG(
3, "2 svc.example.net. mandatory=key8,key7 key7 key8", 3, "2 svc.example.net. mandatory=key9,key8 key8 key9",
"2 svc.example.net. mandatory=key7,key8 key7 key8"), "2 svc.example.net. mandatory=key8,key9 key8 key9"),
TEXT_INVALID("2 svc.example.net. " TEXT_INVALID("2 svc.example.net. "
"mandatory=key7,key7"), "mandatory=key8,key8"),
TEXT_INVALID("2 svc.example.net. mandatory=,key7"), TEXT_INVALID("2 svc.example.net. mandatory=,key8"),
TEXT_INVALID("2 svc.example.net. mandatory=key7,"), TEXT_INVALID("2 svc.example.net. mandatory=key8,"),
TEXT_INVALID("2 svc.example.net. " TEXT_INVALID("2 svc.example.net. "
"mandatory=key7,,key7"), "mandatory=key8,,key8"),
/* Invalid test vectors */ /* Invalid test vectors */
TEXT_INVALID("1 foo.example.com. ( key123=abc key123=def )"), TEXT_INVALID("1 foo.example.com. ( key123=abc key123=def )"),
TEXT_INVALID("1 foo.example.com. mandatory"), TEXT_INVALID("1 foo.example.com. mandatory"),
@ -2572,6 +2572,14 @@ ISC_RUN_TEST_IMPL(https_svcb) {
TEXT_INVALID("1 foo.example.com. mandatory=mandatory"), TEXT_INVALID("1 foo.example.com. mandatory=mandatory"),
TEXT_INVALID("1 foo.example.com. ( mandatory=key123,key123 " TEXT_INVALID("1 foo.example.com. ( mandatory=key123,key123 "
"key123=abc)"), "key123=abc)"),
/* dohpath tests */
TEXT_VALID_LOOPCHG(1, "1 example.net. dohpath=/{?dns}",
"1 example.net. key7=\"/{?dns}\""),
TEXT_VALID_LOOPCHG(1, "1 example.net. dohpath=/some/path{?dns}",
"1 example.net. key7=\"/some/path{?dns}\""),
TEXT_INVALID("1 example.com. dohpath=no-slash"),
TEXT_INVALID("1 example.com. dohpath=/{?notdns}"),
TEXT_INVALID("1 example.com. dohpath=/notvariable"),
TEXT_SENTINEL() TEXT_SENTINEL()
}; };