Merge branch '4419-add-the-ability-to-add-the-ul-edns-option-to-update-messages' into 'main'

Resolve "Add the ability to add the UL EDNS option to UPDATE messages"

Closes #4419

See merge request isc-projects/bind9!8469
This commit is contained in:
Mark Andrews 2024-01-23 01:17:02 +00:00
commit 5ce1ff5214
8 changed files with 200 additions and 4 deletions

View file

@ -1,3 +1,6 @@
6327. [func] Nsupdate can now set the UL EDNS option when sending
UPDATE requests. [GL #4419]
6326. [func] Add workaround to enforce dynamic linker to pull
jemalloc earlier than libc to ensure all memory
allocations are done via jemalloc. [GL #4404]

View file

@ -1388,6 +1388,7 @@ typedef struct dig_ednsoptname {
dig_ednsoptname_t optnames[] = {
{ 1, "LLQ" }, /* draft-sekar-dns-llq */
{ 2, "UL" }, /* draft-ietf-dnssd-update-lease */
{ 3, "NSID" }, /* RFC 5001 */
{ 5, "DAU" }, /* RFC 6975 */
{ 6, "DHU" }, /* RFC 6975 */

View file

@ -102,6 +102,8 @@
#define DNSDEFAULTPORT 53
#define DEFAULT_EDNS_BUFSIZE 1232
/* Number of addresses to request from isc_getaddresses() */
#define MAX_SERVERADDRS 4
@ -175,6 +177,8 @@ static isc_mutex_t answer_lock;
static dns_message_t *answer = NULL;
static uint32_t default_ttl = 0;
static bool default_ttl_set = false;
static uint32_t lease = 0, keylease = 0;
static bool lease_set = false, keylease_set = false;
static bool checknames = true;
static bool checksvcb = true;
static const char *resolvconf = RESOLV_CONF;
@ -1518,6 +1522,90 @@ evaluate_prereq(char *cmdline) {
return (make_prereq(cmdline, ispositive, isrrset));
}
static void
updateopt(void) {
isc_result_t result;
dns_ednsopt_t ednsopts[1];
unsigned char ul[8];
unsigned int count = 0;
if (lease_set) {
isc_buffer_t b;
INSIST(count < ARRAY_SIZE(ednsopts));
ednsopts[count++] = (dns_ednsopt_t){ .code = DNS_OPT_UL,
.length = keylease_set ? 8
: 4,
.value = ul };
isc_buffer_init(&b, ul, sizeof(ul));
isc_buffer_putuint32(&b, lease);
isc_buffer_putuint32(&b, keylease);
}
if (count != 0) {
dns_rdataset_t *opt = NULL;
result = dns_message_buildopt(updatemsg, &opt, 0,
DEFAULT_EDNS_BUFSIZE, 0, ednsopts,
count);
check_result(result, "dns_message_buildopt");
result = dns_message_setopt(updatemsg, opt);
check_result(result, "dns_message_setopt");
} else {
result = dns_message_setopt(updatemsg, NULL);
check_result(result, "dns_message_setopt");
}
}
static uint16_t
evaluate_lease(char *cmdline) {
char *word;
isc_result_t result;
uint32_t value1, value2;
word = nsu_strsep(&cmdline, " \t\r\n");
if (word == NULL || *word == 0) {
fprintf(stderr, "could not read ttl\n");
return (STATUS_SYNTAX);
}
if (!strcasecmp(word, "none")) {
lease = 0;
lease_set = false;
keylease = 0;
keylease_set = false;
updateopt();
return (STATUS_MORE);
}
result = isc_parse_uint32(&value1, word, 10);
if (result != ISC_R_SUCCESS) {
return (STATUS_SYNTAX);
}
word = nsu_strsep(&cmdline, " \t\r\n");
if (word == NULL || *word == 0) {
lease = value1;
lease_set = true;
keylease = 0;
keylease_set = false;
updateopt();
return (STATUS_MORE);
}
result = isc_parse_uint32(&value2, word, 10);
if (result != ISC_R_SUCCESS) {
return (STATUS_SYNTAX);
}
lease = value1;
lease_set = true;
keylease = value2;
keylease_set = true;
updateopt();
return (STATUS_MORE);
}
static uint16_t
evaluate_server(char *cmdline) {
char *word, *server;
@ -2222,6 +2310,9 @@ do_next_command(char *cmdline) {
if (strcasecmp(word, "add") == 0) {
return (update_addordelete(cmdline, false));
}
if (strcasecmp(word, "lease") == 0) {
return (evaluate_lease(cmdline));
}
if (strcasecmp(word, "server") == 0) {
return (evaluate_server(cmdline));
}

View file

@ -323,6 +323,11 @@ The command formats and their meanings are as follows:
By default check-svcb processing is on. If check-svcb processing
fails, the record is not added to the UPDATE message.
``lease time [keytime]``
Set the EDNS Update Lease (UL) option to value to ``time`` and
optionally also set the key lease time to ``keytime`` in seconds.
If ``time`` is ``none`` the lease times are cleared.
``prereq nxdomain domain-name``
This command requires that no resource record of any type exist with the name
``domain-name``.

View file

@ -562,6 +562,25 @@ if [ -x "$DIG" ]; then
status=$((status + ret))
n=$((n + 1))
echo_i "checking ednsopt UL prints as expected (single lease) ($n)"
ret=0
dig_with_opts @10.53.0.3 +ednsopt=UL:00000e10 +qr a.example >dig.out.test$n 2>&1 || ret=1
pat='UL: 3600 (1 hour)'
grep "$pat" dig.out.test$n >/dev/null || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
n=$((n + 1))
echo_i "checking ednsopt UL prints as expected (split lease) ($n)"
ret=0
dig_with_opts @10.53.0.3 +ednsopt=UL:00000e1000127500 +qr a.example >dig.out.test$n 2>&1 || ret=1
pat='UL: 3600/1209600 (1 hour/2 weeks)'
grep "$pat" 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 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

View file

@ -103,6 +103,7 @@
/*%< EDNS0 extended OPT codes */
#define DNS_OPT_LLQ 1 /*%< LLQ opt code */
#define DNS_OPT_UL 2 /*%< UL 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 */
@ -1113,14 +1114,14 @@ dns_message_getopt(dns_message_t *msg);
isc_result_t
dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt);
/*%<
* Set the OPT record for 'msg'.
* Set/clear the OPT record for 'msg'.
*
* Requires:
*
*\li 'msg' is a valid message with rendering intent
* and no sections have been rendered.
*
*\li 'opt' is a valid OPT record.
*\li 'opt' is a valid OPT record or NULL.
*
* Ensures:
*

View file

@ -2707,12 +2707,17 @@ dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
*/
REQUIRE(DNS_MESSAGE_VALID(msg));
REQUIRE(opt->type == dns_rdatatype_opt);
REQUIRE(opt == NULL || DNS_RDATASET_VALID(opt));
REQUIRE(opt == NULL || opt->type == dns_rdatatype_opt);
REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
REQUIRE(msg->state == DNS_SECTION_ANY);
msgresetopt(msg);
if (opt == NULL) {
return (ISC_R_SUCCESS);
}
result = dns_rdataset_first(opt);
if (result != ISC_R_SUCCESS) {
goto cleanup;
@ -3428,7 +3433,7 @@ dns_message_pseudosectiontoyaml(dns_message_t *msg, dns_pseudosection_t section,
dns_rdataset_t *ps = NULL;
const dns_name_t *name = NULL;
isc_result_t result = ISC_R_SUCCESS;
char buf[sizeof("1234567890")];
char buf[sizeof("/1234567890")];
uint32_t mbz;
dns_rdata_t rdata;
isc_buffer_t optbuf;
@ -3520,6 +3525,39 @@ dns_message_pseudosectiontoyaml(dns_message_t *msg, dns_pseudosection_t section,
ADD_STRING(target, "\n");
continue;
}
} else if (optcode == DNS_OPT_UL) {
INDENT(style);
ADD_STRING(target, "UL:");
if (optlen == 4U || optlen == 8U) {
uint32_t secs, key = 0;
secs = isc_buffer_getuint32(&optbuf);
snprintf(buf, sizeof(buf), " %u", secs);
ADD_STRING(target, buf);
if (optlen == 8U) {
key = isc_buffer_getuint32(
&optbuf);
snprintf(buf, sizeof(buf),
"/%u", key);
ADD_STRING(target, buf);
}
ADD_STRING(target, " (");
result = dns_ttl_totext(secs, true,
true, target);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
if (optlen == 8U) {
ADD_STRING(target, "/");
result = dns_ttl_totext(
key, true, true,
target);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
}
ADD_STRING(target, ")\n");
continue;
}
} else if (optcode == DNS_OPT_NSID) {
INDENT(style);
ADD_STRING(target, "NSID:");
@ -3880,6 +3918,38 @@ dns_message_pseudosectiontotext(dns_message_t *msg, dns_pseudosection_t section,
ADD_STRING(target, "\n");
continue;
}
} else if (optcode == DNS_OPT_UL) {
ADD_STRING(target, "; UL:");
if (optlen == 4U || optlen == 8U) {
uint32_t secs, key = 0;
secs = isc_buffer_getuint32(&optbuf);
snprintf(buf, sizeof(buf), " %u", secs);
ADD_STRING(target, buf);
if (optlen == 8U) {
key = isc_buffer_getuint32(
&optbuf);
snprintf(buf, sizeof(buf),
"/%u", key);
ADD_STRING(target, buf);
}
ADD_STRING(target, " (");
result = dns_ttl_totext(secs, true,
true, target);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
if (optlen == 8U) {
ADD_STRING(target, "/");
result = dns_ttl_totext(
key, true, true,
target);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
}
ADD_STRING(target, ")\n");
continue;
}
} else if (optcode == DNS_OPT_NSID) {
ADD_STRING(target, "; NSID:");
} else if (optcode == DNS_OPT_COOKIE) {

View file

@ -129,6 +129,12 @@ fromwire_opt(ARGS_FROMWIRE) {
}
isc_region_consume(&sregion, length);
break;
case DNS_OPT_UL:
if (length != 4U && length != 8U) {
return (DNS_R_OPTERR);
}
isc_region_consume(&sregion, length);
break;
case DNS_OPT_CLIENT_SUBNET: {
uint16_t family;
uint8_t addrlen;