diff --git a/CHANGES b/CHANGES index e985cea2c9..43f595c0b6 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,5 @@ +5280. [protocol] Add support for displaying EDNS option LLQ. [GL #1201] + 5279. [bug] When loading, reject zones containing CDS or CDNSKEY RRsets at the zone apex if they would cause DNSSEC validation failures if published in the parent zone diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index d9ee70bcf1..91a18d3770 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -1383,6 +1383,7 @@ typedef struct dig_ednsoptname { } dig_ednsoptname_t; dig_ednsoptname_t optnames[] = { + { 1, "LLQ" }, /* draft-sekar-dns-llq */ { 3, "NSID" }, /* RFC 5001 */ { 5, "DAU" }, /* RFC 6975 */ { 6, "DHU" }, /* RFC 6975 */ diff --git a/bin/tests/system/digdelv/tests.sh b/bin/tests/system/digdelv/tests.sh index 9178f4ae4b..f87ece2598 100644 --- a/bin/tests/system/digdelv/tests.sh +++ b/bin/tests/system/digdelv/tests.sh @@ -519,6 +519,14 @@ if [ -x "$DIG" ] ; then if [ $ret -ne 0 ]; then echo_i "failed"; fi status=$((status+ret)) + n=$((n+1)) + echo_i "checking ednsopt LLQ prints as expected ($n)" + ret=0 + dig_with_opts @10.53.0.3 +ednsopt=llq:0001000200001234567812345678fefefefe +qr a.example > dig.out.test$n 2>&1 || ret=1 + grep 'LLQ: Version: 1, Opcode: 2, Error: 0, Identifier: 1311768465173141112, Lifetime: 4278124286$' dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + n=$((n+1)) echo_i "checking that dig warns about .local queries ($n)" ret=0 diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index af6af7d1c7..e0f0aa365a 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -99,6 +99,7 @@ #define DNS_MESSAGEEXTFLAG_DO 0x8000U /*%< EDNS0 extended OPT codes */ +#define DNS_OPT_LLQ 1 /*%< LLQ opt code */ #define DNS_OPT_NSID 3 /*%< NSID opt code */ #define DNS_OPT_CLIENT_SUBNET 8 /*%< client subnet opt code */ #define DNS_OPT_EXPIRE 9 /*%< EXPIRE opt code */ diff --git a/lib/dns/message.c b/lib/dns/message.c index a3e8189a23..3dac389011 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -3427,6 +3427,42 @@ render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) { return (result); } +static isc_result_t +render_llq(isc_buffer_t *optbuf, isc_buffer_t *target) { + char buf[sizeof("18446744073709551615")]; /* 2^64-1 */ + isc_result_t result = ISC_R_SUCCESS; + uint32_t u; + uint64_t q; + + u = isc_buffer_getuint16(optbuf); + ADD_STRING(target, " Version: "); + snprintf(buf, sizeof(buf), "%u", u); + ADD_STRING(target, buf); + + u = isc_buffer_getuint16(optbuf); + ADD_STRING(target, ", Opcode: "); + snprintf(buf, sizeof(buf), "%u", u); + ADD_STRING(target, buf); + + u = isc_buffer_getuint16(optbuf); + ADD_STRING(target, ", Error: "); + snprintf(buf, sizeof(buf), "%u", u); + ADD_STRING(target, buf); + + q = isc_buffer_getuint32(optbuf); + q <<= 32; + q |= isc_buffer_getuint32(optbuf); + ADD_STRING(target, ", Identifier: "); + snprintf(buf, sizeof(buf), "%" PRIu64, q); + ADD_STRING(target, buf); + + u = isc_buffer_getuint32(optbuf); + ADD_STRING(target, ", Lifetime: "); + snprintf(buf, sizeof(buf), "%u", u); + ADD_STRING(target, buf); + cleanup: + return (result); +} static isc_result_t dns_message_pseudosectiontoyaml(dns_message_t *msg, @@ -3513,7 +3549,19 @@ dns_message_pseudosectiontoyaml(dns_message_t *msg, optlen = isc_buffer_getuint16(&optbuf); INSIST(isc_buffer_remaininglength(&optbuf) >= optlen); - if (optcode == DNS_OPT_NSID) { + if (optcode == DNS_OPT_LLQ) { + INDENT(style); + if (optlen == 18U) { + ADD_STRING(target, "LLQ: "); + result = render_llq(&optbuf, target); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + ADD_STRING(target, "\n"); + continue; + } + ADD_STRING(target, "LLQ"); + } else if (optcode == DNS_OPT_NSID) { INDENT(style); ADD_STRING(target, "NSID"); } else if (optcode == DNS_OPT_COOKIE) { @@ -3795,7 +3843,18 @@ dns_message_pseudosectiontotext(dns_message_t *msg, INDENT(style); - if (optcode == DNS_OPT_NSID) { + if (optcode == DNS_OPT_LLQ) { + if (optlen == 18U) { + ADD_STRING(target, "; LLQ:"); + result = render_llq(&optbuf, target); + if (result != ISC_R_SUCCESS) { + return (result); + } + ADD_STRING(target, "\n"); + continue; + } + ADD_STRING(target, "; LLQ"); + } else if (optcode == DNS_OPT_NSID) { ADD_STRING(target, "; NSID"); } else if (optcode == DNS_OPT_COOKIE) { ADD_STRING(target, "; COOKIE"); diff --git a/lib/dns/rdata/generic/opt_41.c b/lib/dns/rdata/generic/opt_41.c index b8b7f53656..0fe7243f64 100644 --- a/lib/dns/rdata/generic/opt_41.c +++ b/lib/dns/rdata/generic/opt_41.c @@ -116,6 +116,12 @@ fromwire_opt(ARGS_FROMWIRE) { return (ISC_R_UNEXPECTEDEND); } switch (opt) { + case DNS_OPT_LLQ: + if (length != 18U) { + return (DNS_R_OPTERR); + } + isc_region_consume(&sregion, length); + break; case DNS_OPT_CLIENT_SUBNET: { uint16_t family; uint8_t addrlen;