[9.20] fix: dev: Correct locator decoding for NID, L64, and L32 records

NID, L64, and L32 records were decoded incorrectly when converted into their
parsed structures, because the preference field was not skipped before the
locator.

Closes #6097

Backport of MR !12348

Merge branch 'backport-6097-nid-l64-l32-tostruct-consume-9.20' into 'bind-9.20'

See merge request isc-projects/bind9!12349
This commit is contained in:
Ondřej Surý 2026-07-02 13:31:51 +02:00
commit 8a8cc34a50
4 changed files with 106 additions and 0 deletions

View file

@ -156,6 +156,8 @@ tostruct_l32(ARGS_TOSTRUCT) {
dns_rdata_toregion(rdata, &region);
l32->pref = uint16_fromregion(&region);
isc_region_consume(&region, 2);
INSIST(region.length == sizeof(l32->l32));
n = uint32_fromregion(&region);
l32->l32.s_addr = htonl(n);
return ISC_R_SUCCESS;

View file

@ -151,6 +151,8 @@ tostruct_l64(ARGS_TOSTRUCT) {
dns_rdata_toregion(rdata, &region);
l64->pref = uint16_fromregion(&region);
isc_region_consume(&region, 2);
INSIST(region.length == sizeof(l64->l64));
memmove(l64->l64, region.base, region.length);
return ISC_R_SUCCESS;
}

View file

@ -151,6 +151,8 @@ tostruct_nid(ARGS_TOSTRUCT) {
dns_rdata_toregion(rdata, &region);
nid->pref = uint16_fromregion(&region);
isc_region_consume(&region, 2);
INSIST(region.length == sizeof(nid->nid));
memmove(nid->nid, region.base, region.length);
return ISC_R_SUCCESS;
}

View file

@ -2278,6 +2278,70 @@ ISC_RUN_TEST_IMPL(key) {
dns_rdatatype_key, sizeof(dns_rdata_key_t));
}
/*
* L32 tests (RFC 6742): a 16-bit Preference followed by a 32-bit Locator32.
* The wire form is a fixed six octets. The struct round-trip guards against
* the Preference being folded back into the locator.
*/
ISC_RUN_TEST_IMPL(l32) {
text_ok_t text_ok[] = {
/* RFC 6742 section 4.2 examples. */
TEXT_VALID("10 10.1.2.0"),
TEXT_VALID("20 10.1.4.0"),
/* Preference out of range. */
TEXT_INVALID("65536 10.1.2.0"),
/* Locator32 is not a dotted quad. */
TEXT_INVALID("10 2001:db8::1"),
TEXT_SENTINEL(),
};
wire_ok_t wire_ok[] = {
/* Preference + 32-bit Locator32 == 6 octets. */
WIRE_VALID(0x00, 0x0a, 0x0a, 0x01, 0x02, 0x00),
/* Too short. */
WIRE_INVALID(0x00, 0x0a, 0x0a, 0x01, 0x02),
/* Too long. */
WIRE_INVALID(0x00, 0x0a, 0x0a, 0x01, 0x02, 0x00, 0x00),
WIRE_SENTINEL(),
};
check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
dns_rdatatype_l32, sizeof(dns_rdata_l32_t));
}
/*
* L64 tests (RFC 6742): a 16-bit Preference followed by a 64-bit Locator64.
* The wire form is a fixed ten octets.
*/
ISC_RUN_TEST_IMPL(l64) {
text_ok_t text_ok[] = {
/* RFC 6742 section 4.3 example. */
TEXT_VALID("10 2001:db8:1140:1000"),
/* Leading zeroes in a group are dropped on output. */
TEXT_VALID_CHANGED("20 2001:0db8:2140:2000",
"20 2001:db8:2140:2000"),
/* Preference out of range. */
TEXT_INVALID("65536 2001:db8:1140:1000"),
/* Wrong number of groups. */
TEXT_INVALID("10 2001:db8:1140"),
TEXT_SENTINEL(),
};
wire_ok_t wire_ok[] = {
/* Preference + 64-bit Locator64 == 10 octets. */
WIRE_VALID(0x00, 0x0a, 0x20, 0x01, 0x0d, 0xb8, 0x11, 0x40, 0x10,
0x00),
/* Too short. */
WIRE_INVALID(0x00, 0x0a, 0x20, 0x01, 0x0d, 0xb8, 0x11, 0x40,
0x10),
/* Too long. */
WIRE_INVALID(0x00, 0x0a, 0x20, 0x01, 0x0d, 0xb8, 0x11, 0x40,
0x10, 0x00, 0x00),
WIRE_SENTINEL(),
};
check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
dns_rdatatype_l64, sizeof(dns_rdata_l64_t));
}
/*
* LOC tests.
*/
@ -2340,6 +2404,39 @@ ISC_RUN_TEST_IMPL(loc) {
dns_rdatatype_loc, sizeof(dns_rdata_loc_t));
}
/*
* NID tests (RFC 6742): a 16-bit Preference followed by a 64-bit Node ID.
* The wire form is a fixed ten octets.
*/
ISC_RUN_TEST_IMPL(nid) {
text_ok_t text_ok[] = {
/* RFC 6742 section 4.1 examples. */
TEXT_VALID("10 14:4fff:ff20:ee64"),
TEXT_VALID_CHANGED("20 0015:5fff:ff21:ee65",
"20 15:5fff:ff21:ee65"),
/* Preference out of range. */
TEXT_INVALID("65536 14:4fff:ff20:ee64"),
/* Wrong number of groups. */
TEXT_INVALID("10 14:4fff:ff20"),
TEXT_SENTINEL(),
};
wire_ok_t wire_ok[] = {
/* Preference + 64-bit Node ID == 10 octets. */
WIRE_VALID(0x00, 0x0a, 0x00, 0x14, 0x4f, 0xff, 0xff, 0x20, 0xee,
0x64),
/* Too short. */
WIRE_INVALID(0x00, 0x0a, 0x00, 0x14, 0x4f, 0xff, 0xff, 0x20,
0xee),
/* Too long. */
WIRE_INVALID(0x00, 0x0a, 0x00, 0x14, 0x4f, 0xff, 0xff, 0x20,
0xee, 0x64, 0x00),
WIRE_SENTINEL(),
};
check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
dns_rdatatype_nid, sizeof(dns_rdata_nid_t));
}
/*
* http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt
*
@ -3406,7 +3503,10 @@ ISC_TEST_ENTRY(hip)
ISC_TEST_ENTRY(https_svcb)
ISC_TEST_ENTRY(isdn)
ISC_TEST_ENTRY(key)
ISC_TEST_ENTRY(l32)
ISC_TEST_ENTRY(l64)
ISC_TEST_ENTRY(loc)
ISC_TEST_ENTRY(nid)
ISC_TEST_ENTRY(nimloc)
ISC_TEST_ENTRY(nsec)
ISC_TEST_ENTRY(nsec3)