Skip to content

Commit 44e39bf

Browse files
The oots SvcParam (draft-johani-dnsop-svcb-oots-00) (#264)
* The oots SvcParam (draft-johani-dnsop-svcb-oots-00) * Improvements from github tests * Apply suggestions from code review Co-authored-by: Wouter Wijngaards <wcawijngaards@users.noreply.github.com> --------- Co-authored-by: Wouter Wijngaards <wcawijngaards@users.noreply.github.com>
1 parent 388c669 commit 44e39bf

3 files changed

Lines changed: 160 additions & 10 deletions

File tree

include/zone.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ extern "C" {
263263
#define ZONE_SVC_PARAM_KEY_DOCPATH (10u)
264264
/** PvD configuration is available at the well-known path @draft{ietf, intarea-proxy-config} */
265265
#define ZONE_SVC_PARAM_KEY_PVD (11u)
266+
/** Per-transport operator confidence in serving the nameserver's query load over that transport, as a percentage @draft{johani, dnsop-svcb-oots} */
267+
#define ZONE_SVC_PARAM_KEY_OOTS (12u)
266268
/** Reserved ("invalid key") @rfc{9460} */
267269
#define ZONE_SVC_PARAM_KEY_INVALID_KEY (65535u)
268270
/** @} */

src/generic/svcb.h

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,76 @@ static int32_t parse_docpath(
432432
return parse_alpn(parser, type, field, key, param, rdata, token);
433433
}
434434

435+
nonnull_all
436+
static int32_t parse_oots(
437+
parser_t *parser,
438+
const type_info_t *type,
439+
const rdata_info_t *field,
440+
uint16_t key,
441+
const svc_param_info_t *param,
442+
rdata_t *rdata,
443+
const token_t *token)
444+
{
445+
const char *t = token->data, *te = token->data + token->length;
446+
const uint8_t *rdata_start = rdata->octets;
447+
448+
(void)field;
449+
(void)key;
450+
(void)param;
451+
452+
while (t < te) {
453+
const char *transport = t;
454+
const uint8_t *transport_out = rdata->octets;
455+
const char *colon = memchr(t, ':', (size_t)(te - t));
456+
457+
if (!colon)
458+
SYNTAX_ERROR(parser, "No colon found in oots DNS transport in %s", NAME(type));
459+
460+
if(colon == t)
461+
SYNTAX_ERROR(parser, "DNS transport name must have at least 1 character in %s", NAME(type));
462+
463+
if (rdata->octets + (colon - t) + 2 > rdata->limit)
464+
SYNTAX_ERROR(parser, "No space for oots DNS transport in %s", NAME(type));
465+
466+
if (colon - t > 255)
467+
SYNTAX_ERROR(parser, "DNS transport name too large in %s", NAME(type));
468+
469+
*rdata->octets++ = (uint8_t)(colon - t);
470+
memcpy(rdata->octets, transport, (size_t)(colon - t));
471+
rdata->octets += (colon - t);
472+
473+
t = colon + 1;
474+
uint64_t number = 0;
475+
for (;; t++) {
476+
const uint64_t digit = (uint8_t)*t - '0';
477+
if (digit > 9)
478+
break;
479+
number = number * 10 + digit;
480+
}
481+
if(t == colon +1)
482+
SYNTAX_ERROR(parser, "Oots percentage missing in %s", NAME(type));
483+
if (number > 100)
484+
SYNTAX_ERROR(parser, "Invalid oots percentage in %s", NAME(type));
485+
486+
*rdata->octets++ = (uint8_t)number;
487+
488+
const uint8_t *g;
489+
for (g = rdata_start; g < transport_out; g += ((size_t)(*g)) + 2) {
490+
if (memcmp(g, transport_out, ((size_t)(*transport_out)) + 1) == 0)
491+
SEMANTIC_ERROR(parser, "Duplicate DNS transport in oots in %s", NAME(type));
492+
}
493+
if (*t != ',')
494+
break;
495+
else
496+
t++;
497+
}
498+
499+
if (t != te || rdata->octets > rdata->limit)
500+
SYNTAX_ERROR(parser, "Invalid oots in %s", NAME(type));
501+
return 0;
502+
}
503+
504+
435505
nonnull_all
436506
static int32_t parse_mandatory_lax(
437507
parser_t *parser,
@@ -498,6 +568,8 @@ static const svc_param_info_t svc_params[] = {
498568
SVC_PARAM("docpath", 10u, OPTIONAL_VALUE, parse_docpath, parse_docpath),
499569
// draft-ietf-intarea-proxy-config-13 section 2.1:
500570
SVC_PARAM("pvd", 11u, NO_VALUE, parse_unknown, parse_unknown),
571+
// draft-johani-dnsop-svcb-oots
572+
SVC_PARAM("oots", 12u, MANDATORY_VALUE, parse_oots, parse_oots),
501573
};
502574

503575
static const svc_param_info_t unknown_svc_param =
@@ -559,14 +631,16 @@ static really_inline size_t scan_svc_param(
559631
return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_IPV6HINT)]), 8;
560632
else if (memcmp(data, "dohpath", 7) == 0)
561633
return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_DOHPATH)]), 7;
562-
else if (memcmp(data, "docpath", 7) == 0)
563-
return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_DOCPATH)]), 7;
564634
else if (memcmp(data, "ohttp", 5) == 0)
565635
return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_OHTTP)]), 5;
566636
else if (memcmp(data, "tls-supported-groups", 20) == 0)
567637
return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_TLS_SUPPORTED_GROUPS)]), 20;
638+
else if (memcmp(data, "docpath", 7) == 0)
639+
return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_DOCPATH)]), 7;
568640
else if (memcmp(data, "pvd", 3) == 0)
569641
return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_PVD)]), 3;
642+
else if (memcmp(data, "oots", 4) == 0)
643+
return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_OOTS)]), 4;
570644
else if (memcmp(data, "key", 3) == 0)
571645
return scan_unknown_svc_param_key(data, key, param);
572646
else

tests/svcb.c

Lines changed: 82 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ static const rdata_t docpath_s4_rdata =
812812

813813
// From the draft-ietf-intarea-proxy-config-13 Section-2.1 Discovery via HTTPS/SVCB Records:
814814
static const char pvd_s1_text[] =
815-
PAD("pvd-s1. 3600 IN HTTPS 1 . alpn=\"h3,h2\" pvd");
815+
PAD("pvd-s1 3600 IN HTTPS 1 . alpn=\"h3,h2\" pvd");
816816
static const rdata_t pvd_s1_rdata =
817817
RDATA(
818818
0x00, 0x01, // priority
@@ -822,7 +822,58 @@ static const rdata_t pvd_s1_rdata =
822822
);
823823

824824
static const char pvd_f1_text[] =
825-
PAD("pvd-f1. 3600 IN HTTPS 1 . alpn=\"h3,h2\" pvd=\"something\"");
825+
PAD("pvd-f1 3600 IN HTTPS 1 . alpn=\"h3,h2\" pvd=\"something\"");
826+
827+
static const char oots_s1_text[] =
828+
PAD("oots-s1 300 IN SVCB 1 . oots=\"do53:100,dot:10\"");
829+
830+
static const rdata_t oots_s1_rdata =
831+
RDATA(
832+
0x00, 0x01, // priority
833+
0x00, // target
834+
0x00, 0x0c, 0x00, 0x0b, 0x04, 'd', 'o', '5', '3', 100, 0x03, 'd', 'o', 't', 10 // outs="do53:100,dot:10"
835+
);
836+
837+
static const char oots_s2_text[] =
838+
PAD("oots-s2 300 IN SVCB 1 . oots=\"do53:100,dot:5,doq:5\"");
839+
840+
static const rdata_t oots_s2_rdata =
841+
RDATA(
842+
0x00, 0x01, // priority
843+
0x00, // target
844+
0x00, 0x0c, 0x00, 0x10, 0x04, 'd', 'o', '5', '3', 100, 0x03, 'd', 'o', 't', 5, 0x03, 'd', 'o', 'q', 5 // outs="do53:100,dot:5,doq:5"
845+
);
846+
847+
static const char oots_s3_text[] =
848+
PAD("oots-s3 300 IN SVCB 1 . oots=\"do53:100,dot:25,doh:10,doq:10\"");
849+
850+
static const rdata_t oots_s3_rdata =
851+
RDATA(
852+
0x00, 0x01, // priority
853+
0x00, // target
854+
0x00, 0x0c, 0x00, 0x15, 0x04, 'd', 'o', '5', '3', 100, 0x03, 'd', 'o', 't', 25, 0x03, 'd', 'o', 'h', 10, 0x03, 'd', 'o', 'q', 10// outs="do53:100,dot:25,doh:10,doq:10"
855+
);
856+
857+
// Missing percentage
858+
static const char oots_f1_text[] =
859+
PAD("oots-f1 300 IN SVCB 1 . oots=\"do53:100,dot\"");
860+
861+
// Missing transport
862+
static const char oots_f2_text[] =
863+
PAD("oots-f2 300 IN SVCB 1 . oots=\"do53:100,:25\"");
864+
865+
// Invalid percentage
866+
static const char oots_f3_text[] =
867+
PAD("oots-f3 300 IN SVCB 1 . oots=\"do53:100,dot:101\"");
868+
869+
// Invalid percentage
870+
static const char oots_f4_text[] =
871+
PAD("oots-f4 300 IN SVCB 1 . oots=\"do53:100,dot:25%\"");
872+
873+
// Duplicate transport
874+
static const char oots_f5_text[] =
875+
PAD("oots-f5 300 IN SVCB 1 . oots=\"do53:100,dot:25,dot:10\"");
876+
826877

827878
// FIXME: make a test that verifies correct behavior for no-default-alpn="some value"
828879

@@ -924,7 +975,15 @@ static const test_t tests[] = {
924975
{ false, ZONE_TYPE_SVCB, 0, docpath_s3_text, &docpath_s3_rdata },
925976
{ false, ZONE_TYPE_SVCB, 0, docpath_s4_text, &docpath_s4_rdata },
926977
{ false, ZONE_TYPE_HTTPS, 0, pvd_s1_text, &pvd_s1_rdata },
927-
{ false, ZONE_TYPE_HTTPS, ZONE_SEMANTIC_ERROR, pvd_f1_text, NULL }
978+
{ false, ZONE_TYPE_HTTPS, ZONE_SEMANTIC_ERROR, pvd_f1_text, NULL },
979+
{ false, ZONE_TYPE_SVCB, 0, oots_s1_text, &oots_s1_rdata },
980+
{ false, ZONE_TYPE_SVCB, 0, oots_s2_text, &oots_s2_rdata },
981+
{ false, ZONE_TYPE_SVCB, 0, oots_s3_text, &oots_s3_rdata },
982+
{ false, ZONE_TYPE_SVCB, ZONE_SYNTAX_ERROR, oots_f1_text, NULL },
983+
{ false, ZONE_TYPE_SVCB, ZONE_SYNTAX_ERROR, oots_f2_text, NULL },
984+
{ false, ZONE_TYPE_SVCB, ZONE_SYNTAX_ERROR, oots_f3_text, NULL },
985+
{ false, ZONE_TYPE_SVCB, ZONE_SYNTAX_ERROR, oots_f4_text, NULL },
986+
{ false, ZONE_TYPE_SVCB, ZONE_SEMANTIC_ERROR, oots_f5_text, NULL }
928987
};
929988

930989
static int32_t add_rr(
@@ -942,15 +1001,30 @@ static int32_t add_rr(
9421001
(void)owner;
9431002
(void)class;
9441003
(void)ttl;
945-
if (type != test->type)
1004+
if (type != test->type) {
1005+
fprintf(stderr, "type mismatch\n");
9461006
return ZONE_SYNTAX_ERROR;
1007+
}
9471008
if (test->code != ZONE_SUCCESS)
9481009
return ZONE_SUCCESS;
9491010
if (rdlength != test->rdata->length || !test->rdata->octets)
950-
return ZONE_SYNTAX_ERROR;
951-
if (memcmp(rdata, test->rdata->octets, rdlength) != 0)
952-
return ZONE_SYNTAX_ERROR;
953-
return ZONE_SUCCESS;
1011+
fprintf( stderr, "rdata length did not match %d != %d"
1012+
, (int)rdlength, (int)test->rdata->length);
1013+
else if (memcmp(rdata, test->rdata->octets, rdlength) != 0)
1014+
fprintf(stderr, "rdata bytes did not match");
1015+
else
1016+
return ZONE_SUCCESS;
1017+
1018+
size_t i;
1019+
for (i = 0; i < rdlength; i++) {
1020+
if (i % 16 == 0)
1021+
fprintf(stderr, "\n");
1022+
else if (i % 8 == 0)
1023+
fprintf(stderr, " ");
1024+
fprintf(stderr, " %.2x", rdata[i]);
1025+
}
1026+
fprintf(stderr, "\n");
1027+
return ZONE_SYNTAX_ERROR;
9541028
}
9551029

9561030
static uint8_t origin[] =

0 commit comments

Comments
 (0)