diff --git a/CHANGES b/CHANGES index 6c6f9d46a0..de454fddff 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,5 @@ +4217. [protocol] Add support for CSYNC. [RT #40532] + 4216. [cleanup] Silence static analysis warnings. [RT #40649] 4215. [bug] nsupdate: skip to next request on GSSTKEY create diff --git a/bin/tests/system/genzone.sh b/bin/tests/system/genzone.sh index cdf9447443..dcd0ba765e 100644 --- a/bin/tests/system/genzone.sh +++ b/bin/tests/system/genzone.sh @@ -288,6 +288,10 @@ openpgpkey OPENPGPKEY ( AQMFD5raczCJHViKtLYhWGz8hMY sENW91IOW4vqudngPZsY3GvQ/xVA8/7pyFj6b7Esg a60zyGW6LFe9r8n6paHrlG5ojqf0BaqHT+8= ) +;type 62 +csync01 CSYNC 0 0 A NS AAAA +csync02 CSYNC 0 0 + ; type 249 ; TKEY is a meta-type and should never occur in master files. ; The text representation is not specified in the draft. diff --git a/bin/tests/system/xfer/dig1.good b/bin/tests/system/xfer/dig1.good index 85fbe5c5eb..df27c3501d 100644 --- a/bin/tests/system/xfer/dig1.good +++ b/bin/tests/system/xfer/dig1.good @@ -18,6 +18,8 @@ cert01.example. 3600 IN CERT 65534 65535 PRIVATEOID MxFcby9k/yvedMfQgKzhH5er0Mu cname01.example. 3600 IN CNAME cname-target. cname02.example. 3600 IN CNAME cname-target.example. cname03.example. 3600 IN CNAME . +csync01.example. 3600 IN CSYNC 0 0 A NS AAAA +csync02.example. 3600 IN CSYNC 0 0 dlv.example. 3600 IN DLV 30795 1 1 310D27F4D82C1FC2400704EA9939FE6E1CEAA3B9 dname01.example. 3600 IN DNAME dname-target. dname02.example. 3600 IN DNAME dname-target.example. diff --git a/bin/tests/system/xfer/dig2.good b/bin/tests/system/xfer/dig2.good index 57633c9956..ffcaa38d2f 100644 --- a/bin/tests/system/xfer/dig2.good +++ b/bin/tests/system/xfer/dig2.good @@ -18,6 +18,8 @@ cert01.example. 3600 IN CERT 65534 65535 PRIVATEOID MxFcby9k/yvedMfQgKzhH5er0Mu cname01.example. 3600 IN CNAME cname-target. cname02.example. 3600 IN CNAME cname-target.example. cname03.example. 3600 IN CNAME . +csync01.example. 3600 IN CSYNC 0 0 A NS AAAA +csync02.example. 3600 IN CSYNC 0 0 dlv.example. 3600 IN DLV 30795 1 1 310D27F4D82C1FC2400704EA9939FE6E1CEAA3B9 dname01.example. 3600 IN DNAME dname-target. dname02.example. 3600 IN DNAME dname-target.example. diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 8b2ab82cc5..0f57428467 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -12634,6 +12634,19 @@ example.com. NS ns2.example.net. + + + + CSYNC + + + + + Child-to-Parent Synchronization in DNS as described + in RFC 7477. + + + diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml index 0ad180c1a5..db0dd43f28 100644 --- a/doc/arm/notes.xml +++ b/doc/arm/notes.xml @@ -133,8 +133,8 @@ - The following types have been implemented: NINFO, RKEY, SINK, TA, - TALINK. + The following types have been implemented: CSYNC, NINFO, RKEY, + SINK, TA, TALINK. diff --git a/doc/misc/rfc-compliance b/doc/misc/rfc-compliance index 18e6e8ba20..766cd23fac 100644 --- a/doc/misc/rfc-compliance +++ b/doc/misc/rfc-compliance @@ -85,7 +85,7 @@ or Best Current Practice (BCP) documents. RFC6891 RFC7043 RFC7314 - RFC7314 + RFC7477 The following DNS related RFC have been obsoleted diff --git a/doc/rfc/index b/doc/rfc/index index 20e7b72b45..4bfd9a0b4e 100644 --- a/doc/rfc/index +++ b/doc/rfc/index @@ -161,4 +161,5 @@ 7043: Resource Records for EUI-48 and EUI-64 Addresses in the DNS 7314: Extension Mechanisms for DNS (EDNS) EXPIRE Option 7534: AS112 Nameserver Operations +7477: Child-to-Parent Synchronization in DNS 7535: AS112 Redirection Using DNAME diff --git a/lib/dns/rdata.c b/lib/dns/rdata.c index e02357e31d..9a5a51def9 100644 --- a/lib/dns/rdata.c +++ b/lib/dns/rdata.c @@ -399,6 +399,138 @@ mem_maybedup(isc_mem_t *mctx, void *source, size_t length) { return (copy); } +static inline isc_result_t +typemap_fromtext(isc_lex_t *lexer, isc_buffer_t *target, + isc_boolean_t allow_empty) +{ + isc_token_t token; + unsigned char bm[8*1024]; /* 64k bits */ + dns_rdatatype_t covered; + int octet; + int window; + isc_boolean_t first = ISC_TRUE; + + memset(bm, 0, sizeof(bm)); + do { + RETERR(isc_lex_getmastertoken(lexer, &token, + isc_tokentype_string, ISC_TRUE)); + if (token.type != isc_tokentype_string) + break; + RETTOK(dns_rdatatype_fromtext(&covered, + &token.value.as_textregion)); + bm[covered/8] |= (0x80>>(covered%8)); + first = ISC_FALSE; + } while (1); + isc_lex_ungettoken(lexer, &token); + if (!allow_empty && first) + return (DNS_R_FORMERR); + + for (window = 0; window < 256 ; window++) { + /* + * Find if we have a type in this window. + */ + for (octet = 31; octet >= 0; octet--) + if (bm[window * 32 + octet] != 0) + break; + if (octet < 0) + continue; + RETERR(uint8_tobuffer(window, target)); + RETERR(uint8_tobuffer(octet + 1, target)); + RETERR(mem_tobuffer(target, &bm[window * 32], octet + 1)); + } + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +typemap_totext(isc_region_t *sr, dns_rdata_textctx_t *tctx, + isc_buffer_t *target) +{ + unsigned int i, j, k; + unsigned int window, len; + isc_boolean_t first = ISC_FALSE; + + for (i = 0; i < sr->length; i += len) { + if (tctx != NULL && + (tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { + RETERR(str_totext(tctx->linebreak, target)); + first = ISC_TRUE; + } + INSIST(i + 2 <= sr->length); + window = sr->base[i]; + len = sr->base[i + 1]; + INSIST(len > 0 && len <= 32); + i += 2; + INSIST(i + len <= sr->length); + for (j = 0; j < len; j++) { + dns_rdatatype_t t; + if (sr->base[i + j] == 0) + continue; + for (k = 0; k < 8; k++) { + if ((sr->base[i + j] & (0x80 >> k)) == 0) + continue; + t = window * 256 + j * 8 + k; + if (!first) + RETERR(str_totext(" ", target)); + first = ISC_FALSE; + if (dns_rdatatype_isknown(t)) { + RETERR(dns_rdatatype_totext(t, target)); + } else { + char buf[sizeof("TYPE65535")]; + sprintf(buf, "TYPE%u", t); + RETERR(str_totext(buf, target)); + } + } + } + } + return (ISC_R_SUCCESS); +} + +static isc_result_t +typemap_test(isc_region_t *sr, isc_boolean_t allow_empty) { + unsigned int window, lastwindow = 0; + unsigned int len; + isc_boolean_t first = ISC_TRUE; + unsigned int i; + + for (i = 0; i < sr->length; i += len) { + /* + * Check for overflow. + */ + if (i + 2 > sr->length) + RETERR(DNS_R_FORMERR); + window = sr->base[i]; + len = sr->base[i + 1]; + i += 2; + /* + * Check that bitmap windows are in the correct order. + */ + if (!first && window <= lastwindow) + RETERR(DNS_R_FORMERR); + /* + * Check for legal lengths. + */ + if (len < 1 || len > 32) + RETERR(DNS_R_FORMERR); + /* + * Check for overflow. + */ + if (i + len > sr->length) + RETERR(DNS_R_FORMERR); + /* + * The last octet of the bitmap must be non zero. + */ + if (sr->base[i + len - 1] == 0) + RETERR(DNS_R_FORMERR); + lastwindow = window; + first = ISC_FALSE; + } + if (i != sr->length) + return (DNS_R_EXTRADATA); + if (!allow_empty && first) + RETERR(DNS_R_FORMERR); + return (ISC_R_SUCCESS); +} + static const char hexdigits[] = "0123456789abcdef"; static const char decdigits[] = "0123456789"; diff --git a/lib/dns/rdata/generic/csync_62.c b/lib/dns/rdata/generic/csync_62.c new file mode 100644 index 0000000000..cd80195930 --- /dev/null +++ b/lib/dns/rdata/generic/csync_62.c @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* RFC 7477 */ + +#ifndef RDATA_GENERIC_CSYNC_62_C +#define RDATA_GENERIC_CSYNC_62_C + +#define RRTYPE_CSYNC_ATTRIBUTES 0 + +static inline isc_result_t +fromtext_csync(ARGS_FROMTEXT) { + isc_token_t token; + + REQUIRE(type == dns_rdatatype_csync); + + UNUSED(type); + UNUSED(rdclass); + UNUSED(origin); + UNUSED(options); + UNUSED(callbacks); + + /* Serial. */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, + ISC_FALSE)); + RETERR(uint32_tobuffer(token.value.as_ulong, target)); + + /* Flags. */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, + ISC_FALSE)); + if (token.value.as_ulong > 0xffffU) + RETTOK(ISC_R_RANGE); + RETERR(uint16_tobuffer(token.value.as_ulong, target)); + + /* Type Map */ + return (typemap_fromtext(lexer, target, ISC_TRUE)); +} + +static inline isc_result_t +totext_csync(ARGS_TOTEXT) { + unsigned long num; + char buf[sizeof("0123456789")]; /* Also TYPE65535 */ + isc_region_t sr; + + REQUIRE(rdata->type == dns_rdatatype_csync); + REQUIRE(rdata->length >= 6); + + UNUSED(tctx); + + dns_rdata_toregion(rdata, &sr); + + num = uint32_fromregion(&sr); + isc_region_consume(&sr, 4); + sprintf(buf, "%lu", num); + RETERR(str_totext(buf, target)); + + RETERR(str_totext(" ", target)); + + num = uint16_fromregion(&sr); + isc_region_consume(&sr, 2); + sprintf(buf, "%lu", num); + RETERR(str_totext(buf, target)); + + return (typemap_totext(&sr, NULL, target)); +} + +static /* inline */ isc_result_t +fromwire_csync(ARGS_FROMWIRE) { + isc_region_t sr; + + REQUIRE(type == dns_rdatatype_csync); + + UNUSED(type); + UNUSED(rdclass); + UNUSED(options); + UNUSED(dctx); + + /* + * Serial + Flags + */ + isc_buffer_activeregion(source, &sr); + if (sr.length < 6) + return (ISC_R_UNEXPECTEDEND); + + RETERR(mem_tobuffer(target, sr.base, 6)); + isc_buffer_forward(source, 6); + isc_region_consume(&sr, 6); + + RETERR(typemap_test(&sr, ISC_TRUE)); + + RETERR(mem_tobuffer(target, sr.base, sr.length)); + isc_buffer_forward(source, sr.length); + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +towire_csync(ARGS_TOWIRE) { + + REQUIRE(rdata->type == dns_rdatatype_csync); + REQUIRE(rdata->length >= 6); + + UNUSED(cctx); + + return (mem_tobuffer(target, rdata->data, rdata->length)); +} + +static inline int +compare_csync(ARGS_COMPARE) { + isc_region_t r1; + isc_region_t r2; + + REQUIRE(rdata1->type == rdata2->type); + REQUIRE(rdata1->rdclass == rdata2->rdclass); + REQUIRE(rdata1->type == dns_rdatatype_csync); + REQUIRE(rdata1->length >= 6); + REQUIRE(rdata2->length >= 6); + + dns_rdata_toregion(rdata1, &r1); + dns_rdata_toregion(rdata2, &r2); + return (isc_region_compare(&r1, &r2)); +} + +static inline isc_result_t +fromstruct_csync(ARGS_FROMSTRUCT) { + dns_rdata_csync_t *csync = source; + isc_region_t region; + + REQUIRE(type == dns_rdatatype_csync); + REQUIRE(source != NULL); + REQUIRE(csync->common.rdtype == type); + REQUIRE(csync->common.rdclass == rdclass); + REQUIRE(csync->typebits != NULL || csync->len == 0); + + UNUSED(type); + UNUSED(rdclass); + + RETERR(uint32_tobuffer(csync->serial, target)); + RETERR(uint16_tobuffer(csync->flags, target)); + + region.base = csync->typebits; + region.length = csync->len; + RETERR(typemap_test(®ion, ISC_TRUE)); + return (mem_tobuffer(target, csync->typebits, csync->len)); +} + +static inline isc_result_t +tostruct_csync(ARGS_TOSTRUCT) { + isc_region_t region; + dns_rdata_csync_t *csync = target; + + REQUIRE(rdata->type == dns_rdatatype_csync); + REQUIRE(target != NULL); + REQUIRE(rdata->length != 0); + + csync->common.rdclass = rdata->rdclass; + csync->common.rdtype = rdata->type; + ISC_LINK_INIT(&csync->common, link); + + dns_rdata_toregion(rdata, ®ion); + + csync->serial = uint32_fromregion(®ion); + isc_region_consume(®ion, 4); + + csync->flags = uint16_fromregion(®ion); + isc_region_consume(®ion, 2); + + csync->len = region.length; + csync->typebits = mem_maybedup(mctx, region.base, region.length); + if (csync->typebits == NULL) + goto cleanup; + + csync->mctx = mctx; + return (ISC_R_SUCCESS); + + cleanup: + return (ISC_R_NOMEMORY); +} + +static inline void +freestruct_csync(ARGS_FREESTRUCT) { + dns_rdata_csync_t *csync = source; + + REQUIRE(source != NULL); + REQUIRE(csync->common.rdtype == dns_rdatatype_csync); + + if (csync->mctx == NULL) + return; + + if (csync->typebits != NULL) + isc_mem_free(csync->mctx, csync->typebits); + csync->mctx = NULL; +} + +static inline isc_result_t +additionaldata_csync(ARGS_ADDLDATA) { + REQUIRE(rdata->type == dns_rdatatype_csync); + + UNUSED(rdata); + UNUSED(add); + UNUSED(arg); + + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +digest_csync(ARGS_DIGEST) { + isc_region_t r; + + REQUIRE(rdata->type == dns_rdatatype_csync); + + dns_rdata_toregion(rdata, &r); + return ((digest)(arg, &r)); +} + +static inline isc_boolean_t +checkowner_csync(ARGS_CHECKOWNER) { + + REQUIRE(type == dns_rdatatype_csync); + + UNUSED(name); + UNUSED(type); + UNUSED(rdclass); + UNUSED(wildcard); + + return (ISC_TRUE); +} + +static inline isc_boolean_t +checknames_csync(ARGS_CHECKNAMES) { + + REQUIRE(rdata->type == dns_rdatatype_csync); + + UNUSED(rdata); + UNUSED(owner); + UNUSED(bad); + + return (ISC_TRUE); +} + +static inline int +casecompare_csync(ARGS_COMPARE) { + isc_region_t region1; + isc_region_t region2; + + REQUIRE(rdata1->type == rdata2->type); + REQUIRE(rdata1->rdclass == rdata2->rdclass); + REQUIRE(rdata1->type == dns_rdatatype_csync); + REQUIRE(rdata1->length >= 6); + REQUIRE(rdata2->length >= 6); + + dns_rdata_toregion(rdata1, ®ion1); + dns_rdata_toregion(rdata2, ®ion2); + return (isc_region_compare(®ion1, ®ion2)); +} +#endif /* RDATA_GENERIC_CSYNC_62_C */ diff --git a/lib/dns/rdata/generic/csync_62.h b/lib/dns/rdata/generic/csync_62.h new file mode 100644 index 0000000000..1e4d3de428 --- /dev/null +++ b/lib/dns/rdata/generic/csync_62.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef GENERIC_CSYNC_62_H +#define GENERIC_CSYNC_62_H 1 + +/*! + * \brief Per RFC 7477 + */ + +typedef struct dns_rdata_csync { + dns_rdatacommon_t common; + isc_mem_t *mctx; + isc_uint32_t serial; + isc_uint16_t flags; + unsigned char *typebits; + isc_uint16_t len; +} dns_rdata_csync_t; + +#endif /* GENERIC_CSYNC_62_H */ diff --git a/lib/dns/rdata/generic/nsec3_50.c b/lib/dns/rdata/generic/nsec3_50.c index 2aec339c24..b8245a0417 100644 --- a/lib/dns/rdata/generic/nsec3_50.c +++ b/lib/dns/rdata/generic/nsec3_50.c @@ -45,13 +45,10 @@ static inline isc_result_t fromtext_nsec3(ARGS_FROMTEXT) { isc_token_t token; - unsigned char bm[8*1024]; /* 64k bits */ - dns_rdatatype_t covered; - int octet; - int window; unsigned int flags; unsigned char hashalg; isc_buffer_t b; + unsigned char buf[256]; REQUIRE(type == dns_rdatatype_nsec3); @@ -99,50 +96,24 @@ fromtext_nsec3(ARGS_FROMTEXT) { */ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, ISC_FALSE)); - isc_buffer_init(&b, bm, sizeof(bm)); + isc_buffer_init(&b, buf, sizeof(buf)); RETTOK(isc_base32hexnp_decodestring(DNS_AS_STR(token), &b)); if (isc_buffer_usedlength(&b) > 0xffU) RETTOK(ISC_R_RANGE); RETERR(uint8_tobuffer(isc_buffer_usedlength(&b), target)); - RETERR(mem_tobuffer(target, &bm, isc_buffer_usedlength(&b))); + RETERR(mem_tobuffer(target, &buf, isc_buffer_usedlength(&b))); - memset(bm, 0, sizeof(bm)); - do { - RETERR(isc_lex_getmastertoken(lexer, &token, - isc_tokentype_string, ISC_TRUE)); - if (token.type != isc_tokentype_string) - break; - RETTOK(dns_rdatatype_fromtext(&covered, - &token.value.as_textregion)); - bm[covered/8] |= (0x80>>(covered%8)); - } while (1); - isc_lex_ungettoken(lexer, &token); - for (window = 0; window < 256 ; window++) { - /* - * Find if we have a type in this window. - */ - for (octet = 31; octet >= 0; octet--) - if (bm[window * 32 + octet] != 0) - break; - if (octet < 0) - continue; - RETERR(uint8_tobuffer(window, target)); - RETERR(uint8_tobuffer(octet + 1, target)); - RETERR(mem_tobuffer(target, &bm[window * 32], octet + 1)); - } - return (ISC_R_SUCCESS); + return (typemap_fromtext(lexer, target, ISC_TRUE)); } static inline isc_result_t totext_nsec3(ARGS_TOTEXT) { isc_region_t sr; - unsigned int i, j, k; - unsigned int window, len; + unsigned int i, j; unsigned char hash; unsigned char flags; char buf[sizeof("TYPE65535")]; isc_uint32_t iterations; - isc_boolean_t first; REQUIRE(rdata->type == dns_rdatatype_nsec3); REQUIRE(rdata->length != 0); @@ -197,39 +168,7 @@ totext_nsec3(ARGS_TOTEXT) { if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) == 0) RETERR(str_totext(" ", target)); - /* Types covered */ - first = ISC_TRUE; - for (i = 0; i < sr.length; i += len) { - if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { - RETERR(str_totext(tctx->linebreak, target)); - first = ISC_TRUE; - } - INSIST(i + 2 <= sr.length); - window = sr.base[i]; - len = sr.base[i + 1]; - INSIST(len > 0 && len <= 32); - i += 2; - INSIST(i + len <= sr.length); - for (j = 0; j < len; j++) { - dns_rdatatype_t t; - if (sr.base[i + j] == 0) - continue; - for (k = 0; k < 8; k++) { - if ((sr.base[i + j] & (0x80 >> k)) == 0) - continue; - t = window * 256 + j * 8 + k; - if (!first) - RETERR(str_totext(" ", target)); - first = ISC_FALSE; - if (dns_rdatatype_isknown(t)) { - RETERR(dns_rdatatype_totext(t, target)); - } else { - sprintf(buf, "TYPE%u", t); - RETERR(str_totext(buf, target)); - } - } - } - } + RETERR(typemap_totext(&sr, tctx, target)); if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) RETERR(str_totext(" )", target)); @@ -240,11 +179,7 @@ totext_nsec3(ARGS_TOTEXT) { static inline isc_result_t fromwire_nsec3(ARGS_FROMWIRE) { isc_region_t sr, rr; - unsigned int window, lastwindow = 0; - unsigned int len; unsigned int saltlen, hashlen; - isc_boolean_t first = ISC_TRUE; - unsigned int i; REQUIRE(type == dns_rdatatype_nsec3); @@ -275,40 +210,8 @@ fromwire_nsec3(ARGS_FROMWIRE) { RETERR(DNS_R_FORMERR); isc_region_consume(&sr, hashlen); - for (i = 0; i < sr.length; i += len) { - /* - * Check for overflow. - */ - if (i + 2 > sr.length) - RETERR(DNS_R_FORMERR); - window = sr.base[i]; - len = sr.base[i + 1]; - i += 2; - /* - * Check that bitmap windows are in the correct order. - */ - if (!first && window <= lastwindow) - RETERR(DNS_R_FORMERR); - /* - * Check for legal lengths. - */ - if (len < 1 || len > 32) - RETERR(DNS_R_FORMERR); - /* - * Check for overflow. - */ - if (i + len > sr.length) - RETERR(DNS_R_FORMERR); - /* - * The last octet of the bitmap must be non zero. - */ - if (sr.base[i + len - 1] == 0) - RETERR(DNS_R_FORMERR); - lastwindow = window; - first = ISC_FALSE; - } - if (i != sr.length) - return (DNS_R_EXTRADATA); + RETERR(typemap_test(&sr, ISC_TRUE)); + RETERR(mem_tobuffer(target, rr.base, rr.length)); isc_buffer_forward(source, rr.length); return (ISC_R_SUCCESS); @@ -346,8 +249,7 @@ compare_nsec3(ARGS_COMPARE) { static inline isc_result_t fromstruct_nsec3(ARGS_FROMSTRUCT) { dns_rdata_nsec3_t *nsec3 = source; - unsigned int i, len, window, lastwindow = 0; - isc_boolean_t first = ISC_TRUE; + isc_region_t region; REQUIRE(type == dns_rdatatype_nsec3); REQUIRE(source != NULL); @@ -367,21 +269,9 @@ fromstruct_nsec3(ARGS_FROMSTRUCT) { RETERR(uint8_tobuffer(nsec3->next_length, target)); RETERR(mem_tobuffer(target, nsec3->next, nsec3->next_length)); - /* - * Perform sanity check. - */ - for (i = 0; i < nsec3->len ; i += len) { - INSIST(i + 2 <= nsec3->len); - window = nsec3->typebits[i]; - len = nsec3->typebits[i+1]; - i += 2; - INSIST(first || window > lastwindow); - INSIST(len > 0 && len <= 32); - INSIST(i + len <= nsec3->len); - INSIST(nsec3->typebits[i + len - 1] != 0); - lastwindow = window; - first = ISC_FALSE; - } + region.base = nsec3->typebits; + region.length = nsec3->len; + RETERR(typemap_test(®ion, ISC_TRUE)); return (mem_tobuffer(target, nsec3->typebits, nsec3->len)); } diff --git a/lib/dns/rdata/generic/nsec_47.c b/lib/dns/rdata/generic/nsec_47.c index a020fba0a3..3e80612a7b 100644 --- a/lib/dns/rdata/generic/nsec_47.c +++ b/lib/dns/rdata/generic/nsec_47.c @@ -35,10 +35,6 @@ fromtext_nsec(ARGS_FROMTEXT) { isc_token_t token; dns_name_t name; isc_buffer_t buffer; - unsigned char bm[8*1024]; /* 64k bits */ - dns_rdatatype_t covered; - int octet; - int window; REQUIRE(type == dns_rdatatype_nsec); @@ -57,39 +53,13 @@ fromtext_nsec(ARGS_FROMTEXT) { origin = dns_rootname; RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target)); - memset(bm, 0, sizeof(bm)); - do { - RETERR(isc_lex_getmastertoken(lexer, &token, - isc_tokentype_string, ISC_TRUE)); - if (token.type != isc_tokentype_string) - break; - RETTOK(dns_rdatatype_fromtext(&covered, - &token.value.as_textregion)); - bm[covered/8] |= (0x80>>(covered%8)); - } while (1); - isc_lex_ungettoken(lexer, &token); - for (window = 0; window < 256 ; window++) { - /* - * Find if we have a type in this window. - */ - for (octet = 31; octet >= 0; octet--) - if (bm[window * 32 + octet] != 0) - break; - if (octet < 0) - continue; - RETERR(uint8_tobuffer(window, target)); - RETERR(uint8_tobuffer(octet + 1, target)); - RETERR(mem_tobuffer(target, &bm[window * 32], octet + 1)); - } - return (ISC_R_SUCCESS); + return (typemap_fromtext(lexer, target, ISC_FALSE)); } static inline isc_result_t totext_nsec(ARGS_TOTEXT) { isc_region_t sr; - unsigned int i, j, k; dns_name_t name; - unsigned int window, len; REQUIRE(rdata->type == dns_rdatatype_nsec); REQUIRE(rdata->length != 0); @@ -101,45 +71,13 @@ totext_nsec(ARGS_TOTEXT) { dns_name_fromregion(&name, &sr); isc_region_consume(&sr, name_length(&name)); RETERR(dns_name_totext(&name, ISC_FALSE, target)); - - - for (i = 0; i < sr.length; i += len) { - INSIST(i + 2 <= sr.length); - window = sr.base[i]; - len = sr.base[i + 1]; - INSIST(len > 0 && len <= 32); - i += 2; - INSIST(i + len <= sr.length); - for (j = 0; j < len; j++) { - dns_rdatatype_t t; - if (sr.base[i + j] == 0) - continue; - for (k = 0; k < 8; k++) { - if ((sr.base[i + j] & (0x80 >> k)) == 0) - continue; - t = window * 256 + j * 8 + k; - RETERR(str_totext(" ", target)); - if (dns_rdatatype_isknown(t)) { - RETERR(dns_rdatatype_totext(t, target)); - } else { - char buf[sizeof("TYPE65535")]; - sprintf(buf, "TYPE%u", t); - RETERR(str_totext(buf, target)); - } - } - } - } - return (ISC_R_SUCCESS); + return (typemap_totext(&sr, NULL, target)); } static /* inline */ isc_result_t fromwire_nsec(ARGS_FROMWIRE) { isc_region_t sr; dns_name_t name; - unsigned int window, lastwindow = 0; - unsigned int len; - isc_boolean_t first = ISC_TRUE; - unsigned int i; REQUIRE(type == dns_rdatatype_nsec); @@ -152,42 +90,7 @@ fromwire_nsec(ARGS_FROMWIRE) { RETERR(dns_name_fromwire(&name, source, dctx, options, target)); isc_buffer_activeregion(source, &sr); - for (i = 0; i < sr.length; i += len) { - /* - * Check for overflow. - */ - if (i + 2 > sr.length) - RETERR(DNS_R_FORMERR); - window = sr.base[i]; - len = sr.base[i + 1]; - i += 2; - /* - * Check that bitmap windows are in the correct order. - */ - if (!first && window <= lastwindow) - RETERR(DNS_R_FORMERR); - /* - * Check for legal lengths. - */ - if (len < 1 || len > 32) - RETERR(DNS_R_FORMERR); - /* - * Check for overflow. - */ - if (i + len > sr.length) - RETERR(DNS_R_FORMERR); - /* - * The last octet of the bitmap must be non zero. - */ - if (sr.base[i + len - 1] == 0) - RETERR(DNS_R_FORMERR); - lastwindow = window; - first = ISC_FALSE; - } - if (i != sr.length) - return (DNS_R_EXTRADATA); - if (first) - RETERR(DNS_R_FORMERR); + RETERR(typemap_test(&sr, ISC_FALSE)); RETERR(mem_tobuffer(target, sr.base, sr.length)); isc_buffer_forward(source, sr.length); return (ISC_R_SUCCESS); @@ -232,8 +135,6 @@ static inline isc_result_t fromstruct_nsec(ARGS_FROMSTRUCT) { dns_rdata_nsec_t *nsec = source; isc_region_t region; - unsigned int i, len, window, lastwindow = 0; - isc_boolean_t first = ISC_TRUE; REQUIRE(type == dns_rdatatype_nsec); REQUIRE(source != NULL); @@ -246,22 +147,10 @@ fromstruct_nsec(ARGS_FROMSTRUCT) { dns_name_toregion(&nsec->next, ®ion); RETERR(isc_buffer_copyregion(target, ®ion)); - /* - * Perform sanity check. - */ - for (i = 0; i < nsec->len ; i += len) { - INSIST(i + 2 <= nsec->len); - window = nsec->typebits[i]; - len = nsec->typebits[i+1]; - i += 2; - INSIST(first || window > lastwindow); - INSIST(len > 0 && len <= 32); - INSIST(i + len <= nsec->len); - INSIST(nsec->typebits[i + len - 1] != 0); - lastwindow = window; - first = ISC_FALSE; - } - INSIST(!first); + + region.base = nsec->typebits; + region.length = nsec->len; + RETERR(typemap_test(®ion, ISC_FALSE)); return (mem_tobuffer(target, nsec->typebits, nsec->len)); } diff --git a/lib/dns/tests/Makefile.in b/lib/dns/tests/Makefile.in index 6b15953bb5..360ecce540 100644 --- a/lib/dns/tests/Makefile.in +++ b/lib/dns/tests/Makefile.in @@ -144,7 +144,8 @@ rdataset_test@EXEEXT@: rdataset_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} rdata_test@EXEEXT@: rdata_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ - rdata_test.@O@ ${DNSLIBS} ${ISCLIBS} ${LIBS} + rdata_test.@O@ dnstest.@O@ ${DNSLIBS} \ + ${ISCLIBS} ${LIBS} dispatch_test@EXEEXT@: dispatch_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ diff --git a/lib/dns/tests/rdata_test.c b/lib/dns/tests/rdata_test.c index 8bb2b8691b..a580019dcf 100644 --- a/lib/dns/tests/rdata_test.c +++ b/lib/dns/tests/rdata_test.c @@ -24,13 +24,14 @@ #include +#include #include +#include #include #include "dnstest.h" - /* * Individual unit tests */ @@ -201,7 +202,7 @@ ATF_TC_BODY(edns_client_subnet, tc) { } }; unsigned char buf[1024*1024]; - isc_buffer_t source, target; + isc_buffer_t source, target1; dns_rdata_t rdata; dns_decompress_t dctx; isc_result_t result; @@ -213,12 +214,12 @@ ATF_TC_BODY(edns_client_subnet, tc) { isc_buffer_init(&source, test_data[i].data, test_data[i].len); isc_buffer_add(&source, test_data[i].len); isc_buffer_setactive(&source, test_data[i].len); - isc_buffer_init(&target, buf, sizeof(buf)); + isc_buffer_init(&target1, buf, sizeof(buf)); dns_rdata_init(&rdata); dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY); result = dns_rdata_fromwire(&rdata, dns_rdataclass_in, dns_rdatatype_opt, &source, - &dctx, 0, &target); + &dctx, 0, &target1); dns_decompress_invalidate(&dctx); if (test_data[i].ok) ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); @@ -375,6 +376,238 @@ ATF_TC_BODY(isdn, tc) { } } +static void +error_callback(dns_rdatacallbacks_t *callbacks, const char *fmt, ...) { + UNUSED(callbacks); + UNUSED(fmt); +} + +static void +warn_callback(dns_rdatacallbacks_t *callbacks, const char *fmt, ...) { + UNUSED(callbacks); + UNUSED(fmt); +} + +ATF_TC(nsec); +ATF_TC_HEAD(nsec, tc) { + atf_tc_set_md_var(tc, "descr", "nsec to/from text/wire"); +} +ATF_TC_BODY(nsec, tc) { + struct { + const char *data; + isc_boolean_t ok; + } text_data[] = { + { "", ISC_FALSE }, + { ".", ISC_FALSE }, + { ". RRSIG", ISC_TRUE }, + { NULL, ISC_FALSE }, + }; + struct { + unsigned char data[64]; + size_t len; + isc_boolean_t ok; + } wire_data[] = { + { { 0x00 }, 0, ISC_FALSE }, + { { 0x00 }, 1, ISC_FALSE }, + { { 0x00, 0x00 }, 2, ISC_FALSE }, + { { 0x00, 0x00, 0x00 }, 3, ISC_FALSE }, + { { 0x00, 0x00, 0x01, 0x02 }, 4, ISC_TRUE } + }; + unsigned char buf1[1024], buf2[1024]; + isc_buffer_t source, target1, target2; + isc_result_t result; + size_t i; + dns_rdataclass_t rdclass = dns_rdataclass_in; + dns_rdatatype_t type = dns_rdatatype_nsec; + isc_lex_t *lex = NULL; + dns_rdatacallbacks_t callbacks; + dns_rdata_nsec_t nsec; + dns_decompress_t dctx; + + UNUSED(tc); + + result = dns_test_begin(NULL, ISC_FALSE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_lex_create(mctx, 64, &lex); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + dns_rdatacallbacks_init(&callbacks); + callbacks.error = error_callback; + callbacks.warn = warn_callback; + + for (i = 0; text_data[i].data != NULL; i++) { + size_t length = strlen(text_data[i].data); + isc_buffer_constinit(&source, text_data[i].data, length); + isc_buffer_add(&source, length); + result = isc_lex_openbuffer(lex, &source); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + isc_buffer_init(&target1, buf1, sizeof(buf1)); + + result = dns_rdata_fromtext(NULL, rdclass, type, lex, + dns_rootname, 0, NULL, &target1, + &callbacks); + if (text_data[i].ok) + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + else + ATF_CHECK(result != ISC_R_SUCCESS); + } + isc_lex_destroy(&lex); + + for (i = 0; i < sizeof(wire_data)/sizeof(wire_data[0]); i++) { + dns_rdata_t rdata = DNS_RDATA_INIT; + + isc_buffer_init(&source, wire_data[i].data, wire_data[i].len); + isc_buffer_add(&source, wire_data[i].len); + isc_buffer_setactive(&source, wire_data[i].len); + isc_buffer_init(&target1, buf1, sizeof(buf1)); + dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY); + result = dns_rdata_fromwire(&rdata, rdclass, type, &source, + &dctx, 0, &target1); + dns_decompress_invalidate(&dctx); + if (wire_data[i].ok) + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + else + ATF_REQUIRE(result != ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) + continue; + result = dns_rdata_tostruct(&rdata, &nsec, NULL); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + isc_buffer_init(&target2, buf2, sizeof(buf2)); + dns_rdata_reset(&rdata); + result = dns_rdata_fromstruct(&rdata, rdclass, type, + &nsec, &target2); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + ATF_REQUIRE_EQ(isc_buffer_usedlength(&target2), + wire_data[i].len); + ATF_REQUIRE_EQ(memcmp(buf2, wire_data[i].data, + wire_data[i].len), 0); + } +} + +ATF_TC(csync); +ATF_TC_HEAD(csync, tc) { + atf_tc_set_md_var(tc, "descr", "csync to/from struct"); +} +ATF_TC_BODY(csync, tc) { + struct { + const char *data; + isc_boolean_t ok; + } text_data[] = { + { "", ISC_FALSE }, + { "0", ISC_FALSE }, + { "0 0", ISC_TRUE }, + { "0 0 A", ISC_TRUE }, + { "0 0 NS", ISC_TRUE }, + { "0 0 AAAA", ISC_TRUE }, + { "0 0 A AAAA", ISC_TRUE }, + { "0 0 A NS AAAA", ISC_TRUE }, + { "0 0 A NS AAAA BOGUS", ISC_FALSE }, + { NULL, ISC_FALSE }, + }; + struct { + unsigned char data[64]; + size_t len; + isc_boolean_t ok; + } wire_data[] = { + /* short */ + { { 0x00 }, 0, ISC_FALSE }, + /* short */ + { { 0x00 }, 1, ISC_FALSE }, + /* short */ + { { 0x00, 0x00 }, 2, ISC_FALSE }, + /* short */ + { { 0x00, 0x00, 0x00 }, 3, ISC_FALSE }, + /* short */ + { { 0x00, 0x00, 0x00, 0x00 }, 4, ISC_FALSE }, + /* short */ + { { 0x00, 0x00, 0x00, 0x00, 0x00 }, 5, ISC_FALSE }, + /* serial + flags only */ + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 6, ISC_TRUE }, + /* bad type map */ + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 7, ISC_FALSE }, + /* bad type map */ + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + 8, ISC_FALSE }, + /* good type map */ + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02 }, + 9, ISC_TRUE } + }; + unsigned char buf1[1024]; + unsigned char buf2[1024]; + isc_buffer_t source, target1, target2; + isc_result_t result; + size_t i; + dns_rdataclass_t rdclass = dns_rdataclass_in; + dns_rdatatype_t type = dns_rdatatype_csync; + isc_lex_t *lex = NULL; + dns_rdatacallbacks_t callbacks; + dns_rdata_csync_t csync; + dns_decompress_t dctx; + + UNUSED(tc); + + result = dns_test_begin(NULL, ISC_FALSE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_lex_create(mctx, 64, &lex); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + dns_rdatacallbacks_init(&callbacks); + callbacks.error = error_callback; + callbacks.warn = warn_callback; + + for (i = 0; text_data[i].data != NULL; i++) { + size_t length = strlen(text_data[i].data); + isc_buffer_constinit(&source, text_data[i].data, length); + isc_buffer_add(&source, length); + result = isc_lex_openbuffer(lex, &source); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + isc_buffer_init(&target1, buf1, sizeof(buf1)); + + result = dns_rdata_fromtext(NULL, rdclass, type, lex, + dns_rootname, 0, NULL, &target1, + &callbacks); + if (text_data[i].ok) + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + else + ATF_CHECK(result != ISC_R_SUCCESS); + } + isc_lex_destroy(&lex); + + for (i = 0; i < sizeof(wire_data)/sizeof(wire_data[0]); i++) { + dns_rdata_t rdata = DNS_RDATA_INIT; + + isc_buffer_init(&source, wire_data[i].data, wire_data[i].len); + isc_buffer_add(&source, wire_data[i].len); + isc_buffer_setactive(&source, wire_data[i].len); + isc_buffer_init(&target1, buf1, sizeof(buf1)); + dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY); + result = dns_rdata_fromwire(&rdata, rdclass, type, &source, + &dctx, 0, &target1); + dns_decompress_invalidate(&dctx); + if (wire_data[i].ok) + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + else + ATF_REQUIRE(result != ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) + continue; + result = dns_rdata_tostruct(&rdata, &csync, NULL); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + isc_buffer_init(&target2, buf2, sizeof(buf2)); + dns_rdata_reset(&rdata); + result = dns_rdata_fromstruct(&rdata, rdclass, type, + &csync, &target2); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + ATF_REQUIRE_EQ(isc_buffer_usedlength(&target2), + wire_data[i].len); + ATF_REQUIRE_EQ(memcmp(buf2, wire_data[i].data, + wire_data[i].len), 0); + } +} + /* * Main */ @@ -383,7 +616,8 @@ ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, edns_client_subnet); ATF_TP_ADD_TC(tp, wks); ATF_TP_ADD_TC(tp, isdn); + ATF_TP_ADD_TC(tp, nsec); + ATF_TP_ADD_TC(tp, csync); return (atf_no_error()); } -