diff --git a/CHANGES b/CHANGES index ee65e38a7b..6b2ac4c97e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,5 @@ +4761. [protocol] Add support for DOA. [RT #45612] + 4759. [func] Add logging channel "trust-anchor-telementry" to record trust-anchor-telementry in incoming requests. Both _ta-XXXX./NULL and EDNS KEY-TAG options diff --git a/bin/tests/system/genzone.sh b/bin/tests/system/genzone.sh index 70f1e371c6..91e1921dd0 100644 --- a/bin/tests/system/genzone.sh +++ b/bin/tests/system/genzone.sh @@ -438,7 +438,17 @@ caa03 CAA 128 tbs "" ; type 258 avc AVC foo:bar -; type 259 -- 32767 (unassigned) +; type 259 +doa01 DOA ( 1234567890 1234567890 1 "image/gif" + R0lGODlhKAAZAOMCAGZmZgBmmf///zOZzMz//5nM/zNmmWbM/5nMzMzMzACZ//// + /////////////////yH5BAEKAA8ALAAAAAAoABkAAATH8IFJK5U2a4337F5ogRkp + noCJrly7PrCKyh8c3HgAhzT35MDbbtO7/IJIHbGiOiaTxVTpSVWWLqNq1UVyapNS + 1wd3OAxug0LhnCubcVhsxysQnOt4ATpvvzHlFzl1AwODhWeFAgRpen5/UhheAYMF + dUB4SFcpGEGGdQeCAqBBLTuSk30EeXd9pEsAbKGxjHqDSE0Sp6ixN4N1BJmbc7lI + hmsBich1awPAjkY1SZR8bJWrz382SGqIBQQFQd4IsUTaX+ceuudPEQA7 ) +doa02 DOA 0 1 2 "" aHR0cHM6Ly93d3cuaXNjLm9yZy8= + +; type 260 -- 32767 (unassigned) ; type 32768 ta TA 30795 1 1 ( diff --git a/bin/tests/system/rrchecker/typelist.good b/bin/tests/system/rrchecker/typelist.good index 33100ce604..89389944cd 100644 --- a/bin/tests/system/rrchecker/typelist.good +++ b/bin/tests/system/rrchecker/typelist.good @@ -72,5 +72,6 @@ EUI64 URI CAA AVC +DOA TA DLV diff --git a/bin/tests/system/xfer/dig1.good b/bin/tests/system/xfer/dig1.good index 7a2eff08b9..5af1e5928a 100644 --- a/bin/tests/system/xfer/dig1.good +++ b/bin/tests/system/xfer/dig1.good @@ -31,6 +31,8 @@ dlv.example. 3600 IN DLV 30795 1 1 310D27F4D82C1FC2400704EA9939FE6E1CEAA3B9 dname01.example. 3600 IN DNAME dname-target. dname02.example. 3600 IN DNAME dname-target.example. dname03.example. 3600 IN DNAME . +doa01.example. 3600 IN DOA 1234567890 1234567890 1 "image/gif" R0lGODlhKAAZAOMCAGZmZgBmmf///zOZzMz//5nM/zNmmWbM/5nMzMzMzACZ/////////////////////yH5BAEKAA8ALAAAAAAoABkAAATH8IFJK5U2a4337F5ogRkpnoCJrly7PrCKyh8c3HgAhzT35MDbbtO7/IJIHbGiOiaTxVTpSVWWLqNq1UVyapNS1wd3OAxug0LhnCubcVhsxysQnOt4ATpvvzHlFzl1AwODhWeFAgRpen5/UhheAYMFdUB4SFcpGEGGdQeCAqBBLTuSk30EeXd9pEsAbKGxjHqDSE0Sp6ixN4N1BJmbc7lIhmsBich1awPAjkY1SZR8bJWrz382SGqIBQQFQd4IsUTaX+ceuudPEQA7 +doa02.example. 3600 IN DOA 0 1 2 "" aHR0cHM6Ly93d3cuaXNjLm9yZy8= ds01.example. 3600 IN NS ns42.example. ds01.example. 3600 IN DS 12892 5 2 26584835CA80C81C91999F31CFAF2A0E89D4FF1C8FAFD0DDB31A85C7 19277C13 ds02.example. 3600 IN NS ns43.example. diff --git a/bin/tests/system/xfer/dig2.good b/bin/tests/system/xfer/dig2.good index 09b06b179a..e12ec118c5 100644 --- a/bin/tests/system/xfer/dig2.good +++ b/bin/tests/system/xfer/dig2.good @@ -31,6 +31,8 @@ dlv.example. 3600 IN DLV 30795 1 1 310D27F4D82C1FC2400704EA9939FE6E1CEAA3B9 dname01.example. 3600 IN DNAME dname-target. dname02.example. 3600 IN DNAME dname-target.example. dname03.example. 3600 IN DNAME . +doa01.example. 3600 IN DOA 1234567890 1234567890 1 "image/gif" R0lGODlhKAAZAOMCAGZmZgBmmf///zOZzMz//5nM/zNmmWbM/5nMzMzMzACZ/////////////////////yH5BAEKAA8ALAAAAAAoABkAAATH8IFJK5U2a4337F5ogRkpnoCJrly7PrCKyh8c3HgAhzT35MDbbtO7/IJIHbGiOiaTxVTpSVWWLqNq1UVyapNS1wd3OAxug0LhnCubcVhsxysQnOt4ATpvvzHlFzl1AwODhWeFAgRpen5/UhheAYMFdUB4SFcpGEGGdQeCAqBBLTuSk30EeXd9pEsAbKGxjHqDSE0Sp6ixN4N1BJmbc7lIhmsBich1awPAjkY1SZR8bJWrz382SGqIBQQFQd4IsUTaX+ceuudPEQA7 +doa02.example. 3600 IN DOA 0 1 2 "" aHR0cHM6Ly93d3cuaXNjLm9yZy8= ds01.example. 3600 IN NS ns42.example. ds01.example. 3600 IN DS 12892 5 2 26584835CA80C81C91999F31CFAF2A0E89D4FF1C8FAFD0DDB31A85C7 19277C13 ds02.example. 3600 IN NS ns43.example. diff --git a/lib/dns/rdata/generic/doa_259.c b/lib/dns/rdata/generic/doa_259.c new file mode 100644 index 0000000000..036a1fd593 --- /dev/null +++ b/lib/dns/rdata/generic/doa_259.c @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef RDATA_GENERIC_DOA_259_C +#define RDATA_GENERIC_DOA_259_C + +#define RRTYPE_DOA_ATTRIBUTES (0) + +static inline isc_result_t +fromtext_doa(ARGS_FROMTEXT) { + isc_token_t token; + + REQUIRE(type == dns_rdatatype_doa); + + UNUSED(rdclass); + UNUSED(origin); + UNUSED(options); + UNUSED(callbacks); + + /* + * DOA-ENTERPRISE + */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, + ISC_FALSE)); + RETERR(uint32_tobuffer(token.value.as_ulong, target)); + + /* + * DOA-TYPE + */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, + ISC_FALSE)); + RETERR(uint32_tobuffer(token.value.as_ulong, target)); + + /* + * DOA-LOCATION + */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, + ISC_FALSE)); + if (token.value.as_ulong > 0xffU) { + RETTOK(ISC_R_RANGE); + } + RETERR(uint8_tobuffer(token.value.as_ulong, target)); + + /* + * DOA-MEDIA-TYPE + */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring, + ISC_FALSE)); + RETTOK(txt_fromtext(&token.value.as_textregion, target)); + + /* + * DOA-DATA + */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + if (strcmp(DNS_AS_STR(token), "-") == 0) { + return (ISC_R_SUCCESS); + } else { + isc_lex_ungettoken(lexer, &token); + return (isc_base64_tobuffer(lexer, target, -1)); + } +} + +static inline isc_result_t +totext_doa(ARGS_TOTEXT) { + char buf[sizeof("4294967295 ")]; + isc_region_t region; + isc_uint32_t n; + + REQUIRE(rdata != NULL); + REQUIRE(rdata->type == dns_rdatatype_doa); + REQUIRE(rdata->length != 0); + + UNUSED(tctx); + + dns_rdata_toregion(rdata, ®ion); + + /* + * DOA-ENTERPRISE + */ + n = uint32_fromregion(®ion); + isc_region_consume(®ion, 4); + snprintf(buf, sizeof(buf), "%u ", n); + RETERR(str_totext(buf, target)); + + /* + * DOA-TYPE + */ + n = uint32_fromregion(®ion); + isc_region_consume(®ion, 4); + snprintf(buf, sizeof(buf), "%u ", n); + RETERR(str_totext(buf, target)); + + /* + * DOA-LOCATION + */ + n = uint8_fromregion(®ion); + isc_region_consume(®ion, 1); + snprintf(buf, sizeof(buf), "%u ", n); + RETERR(str_totext(buf, target)); + + /* + * DOA-MEDIA-TYPE + */ + RETERR(txt_totext(®ion, ISC_TRUE, target)); + RETERR(str_totext(" ", target)); + + /* + * DOA-DATA + */ + if (region.length == 0) { + return (str_totext("-", target)); + } else { + return (isc_base64_totext(®ion, 60, "", target)); + } +} + +static inline isc_result_t +fromwire_doa(ARGS_FROMWIRE) { + isc_region_t region; + + UNUSED(rdclass); + UNUSED(dctx); + UNUSED(options); + + REQUIRE(type == dns_rdatatype_doa); + + isc_buffer_activeregion(source, ®ion); + /* + * DOA-MEDIA-TYPE may be an empty (i.e., + * comprising of just the length octet) and DOA-DATA can have + * zero length. + */ + if (region.length < 4 + 4 + 1 + 1) { + return (ISC_R_UNEXPECTEDEND); + } + + /* + * Check whether DOA-MEDIA-TYPE length is not malformed. + */ + if (region.base[9] > region.length - 10) { + return (ISC_R_UNEXPECTEDEND); + } + + isc_buffer_forward(source, region.length); + return (mem_tobuffer(target, region.base, region.length)); +} + +static inline isc_result_t +towire_doa(ARGS_TOWIRE) { + isc_region_t region; + + UNUSED(cctx); + + REQUIRE(rdata != NULL); + REQUIRE(rdata->type == dns_rdatatype_doa); + REQUIRE(rdata->length != 0); + + dns_rdata_toregion(rdata, ®ion); + return (mem_tobuffer(target, region.base, region.length)); +} + +static inline int +compare_doa(ARGS_COMPARE) { + isc_region_t r1; + isc_region_t r2; + + REQUIRE(rdata1 != NULL); + REQUIRE(rdata2 != NULL); + REQUIRE(rdata1->type == rdata2->type); + REQUIRE(rdata1->type == dns_rdatatype_doa); + REQUIRE(rdata1->rdclass == rdata2->rdclass); + REQUIRE(rdata1->length != 0); + REQUIRE(rdata2->length != 0); + + dns_rdata_toregion(rdata1, &r1); + dns_rdata_toregion(rdata2, &r2); + return (isc_region_compare(&r1, &r2)); +} + +static inline isc_result_t +fromstruct_doa(ARGS_FROMSTRUCT) { + dns_rdata_doa_t *doa = source; + + REQUIRE(type == dns_rdatatype_doa); + REQUIRE(source != NULL); + REQUIRE(doa->common.rdtype == dns_rdatatype_doa); + REQUIRE(doa->common.rdclass == rdclass); + + RETERR(uint32_tobuffer(doa->enterprise, target)); + RETERR(uint32_tobuffer(doa->type, target)); + RETERR(uint8_tobuffer(doa->location, target)); + RETERR(uint8_tobuffer(doa->mediatype_len, target)); + RETERR(mem_tobuffer(target, doa->mediatype, doa->mediatype_len)); + return (mem_tobuffer(target, doa->data, doa->data_len)); +} + +static inline isc_result_t +tostruct_doa(ARGS_TOSTRUCT) { + dns_rdata_doa_t *doa = target; + isc_region_t region; + + REQUIRE(rdata != NULL); + REQUIRE(rdata->type == dns_rdatatype_doa); + REQUIRE(rdata->length != 0); + + doa->common.rdclass = rdata->rdclass; + doa->common.rdtype = rdata->type; + ISC_LINK_INIT(&doa->common, link); + + dns_rdata_toregion(rdata, ®ion); + + /* + * DOA-ENTERPRISE + */ + if (region.length < 4) { + return (ISC_R_UNEXPECTEDEND); + } + doa->enterprise = uint32_fromregion(®ion); + isc_region_consume(®ion, 4); + + /* + * DOA-TYPE + */ + if (region.length < 4) { + return (ISC_R_UNEXPECTEDEND); + } + doa->type = uint32_fromregion(®ion); + isc_region_consume(®ion, 4); + + /* + * DOA-LOCATION + */ + if (region.length < 1) { + return (ISC_R_UNEXPECTEDEND); + } + doa->location = uint8_fromregion(®ion); + isc_region_consume(®ion, 1); + + /* + * DOA-MEDIA-TYPE + */ + if (region.length < 1) { + return (ISC_R_UNEXPECTEDEND); + } + doa->mediatype_len = uint8_fromregion(®ion); + isc_region_consume(®ion, 1); + INSIST(doa->mediatype_len <= region.length); + doa->mediatype = mem_maybedup(mctx, region.base, doa->mediatype_len); + if (doa->mediatype == NULL) { + goto cleanup; + } + isc_region_consume(®ion, doa->mediatype_len); + + /* + * DOA-DATA + */ + doa->data_len = region.length; + doa->data = NULL; + if (doa->data_len > 0) { + doa->data = mem_maybedup(mctx, region.base, doa->data_len); + if (doa->data == NULL) { + goto cleanup; + } + isc_region_consume(®ion, doa->data_len); + } + + doa->mctx = mctx; + + return (ISC_R_SUCCESS); + +cleanup: + if (mctx != NULL && doa->mediatype != NULL) { + isc_mem_free(mctx, doa->mediatype); + } + return (ISC_R_NOMEMORY); +} + +static inline void +freestruct_doa(ARGS_FREESTRUCT) { + dns_rdata_doa_t *doa = source; + + REQUIRE(source != NULL); + REQUIRE(doa->common.rdtype == dns_rdatatype_doa); + + if (doa->mctx == NULL) { + return; + } + + if (doa->mediatype != NULL) { + isc_mem_free(doa->mctx, doa->mediatype); + } + if (doa->data != NULL) { + isc_mem_free(doa->mctx, doa->data); + } + + doa->mctx = NULL; +} + +static inline isc_result_t +additionaldata_doa(ARGS_ADDLDATA) { + UNUSED(rdata); + UNUSED(add); + UNUSED(arg); + + REQUIRE(rdata->type == dns_rdatatype_doa); + + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +digest_doa(ARGS_DIGEST) { + isc_region_t r; + + REQUIRE(rdata->type == dns_rdatatype_doa); + + dns_rdata_toregion(rdata, &r); + + return ((digest)(arg, &r)); +} + +static inline isc_boolean_t +checkowner_doa(ARGS_CHECKOWNER) { + UNUSED(name); + UNUSED(type); + UNUSED(rdclass); + UNUSED(wildcard); + + REQUIRE(type == dns_rdatatype_doa); + + return (ISC_TRUE); +} + +static inline isc_boolean_t +checknames_doa(ARGS_CHECKNAMES) { + UNUSED(rdata); + UNUSED(owner); + UNUSED(bad); + + REQUIRE(rdata->type == dns_rdatatype_doa); + + return (ISC_TRUE); +} + +static inline int +casecompare_doa(ARGS_COMPARE) { + return (compare_doa(rdata1, rdata2)); +} + +#endif /* RDATA_GENERIC_DOA_259_C */ diff --git a/lib/dns/rdata/generic/doa_259.h b/lib/dns/rdata/generic/doa_259.h new file mode 100644 index 0000000000..730ddeebae --- /dev/null +++ b/lib/dns/rdata/generic/doa_259.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef GENERIC_DOA_259_H +#define GENERIC_DOA_259_H 1 + +typedef struct dns_rdata_doa { + dns_rdatacommon_t common; + isc_mem_t * mctx; + unsigned char * mediatype; + unsigned char * data; + isc_uint32_t enterprise; + isc_uint32_t type; + isc_uint16_t data_len; + isc_uint8_t location; + isc_uint8_t mediatype_len; +} dns_rdata_doa_t; + +#endif /* GENERIC_DOA_259_H */ diff --git a/lib/dns/tests/rdata_test.c b/lib/dns/tests/rdata_test.c index 0d83642183..cedb6d06e1 100644 --- a/lib/dns/tests/rdata_test.c +++ b/lib/dns/tests/rdata_test.c @@ -39,9 +39,10 @@ * An array of these structures is passed to check_text_ok(). */ struct text_ok { - const char *data; /* RDATA in text format */ - isc_boolean_t ok; /* is this RDATA valid? */ - int lineno; /* source line in which RDATA is defined */ + const char *text_in; /* text passed to fromtext_*() */ + const char *text_out; /* text expected from totext_*(); + NULL indicates text_in is invalid */ + int lineno; /* source line defining this RDATA */ }; typedef struct text_ok text_ok_t; @@ -49,10 +50,10 @@ typedef struct text_ok text_ok_t; * An array of these structures is passed to check_wire_ok(). */ struct wire_ok { - unsigned char data[64]; /* RDATA in wire format */ - size_t len; /* octets of data to parse */ - isc_boolean_t ok; /* is this RDATA valid? */ - int lineno; /* source line in which RDATA is defined */ + unsigned char data[512]; /* RDATA in wire format */ + size_t len; /* octets of data to parse */ + isc_boolean_t ok; /* is this RDATA valid? */ + int lineno; /* source line defining this RDATA */ }; typedef struct wire_ok wire_ok_t; @@ -60,8 +61,10 @@ typedef struct wire_ok wire_ok_t; ***** Convenience macros for creating the above structures *****/ -#define TEXT_VALID(data) { data, ISC_TRUE, __LINE__ } -#define TEXT_INVALID(data) { data, ISC_FALSE, __LINE__ } +#define TEXT_VALID_CHANGED(data_in, data_out) \ + { data_in, data_out, __LINE__ } +#define TEXT_VALID(data) { data, data, __LINE__ } +#define TEXT_INVALID(data) { data, NULL, __LINE__ } #define TEXT_SENTINEL() TEXT_INVALID(NULL) #define VARGC(...) (sizeof((unsigned char[]){ __VA_ARGS__ })) @@ -138,14 +141,17 @@ check_struct_conversions(dns_rdata_t *rdata, size_t structsize, int lineno) { } /* - * Test whether supplied RDATA in text format is properly handled as having - * either valid or invalid syntax for an RR of given rdclass and type. + * Check whether converting supplied text form RDATA into uncompressed wire + * form succeeds (tests fromtext_*()). If so, try converting it back into text + * form and see if it results in the original text (tests totext_*()). */ static void check_text_ok_single(const text_ok_t *text_ok, dns_rdataclass_t rdclass, - dns_rdatatype_t type, size_t structsize) { + dns_rdatatype_t type, size_t structsize) +{ isc_buffer_t source, target; - unsigned char buf[1024]; + unsigned char buf_fromtext[1024]; + char buf_totext[1024] = { 0 }; isc_lex_t *lex = NULL; isc_result_t result; dns_rdata_t rdata; @@ -156,45 +162,76 @@ check_text_ok_single(const text_ok_t *text_ok, dns_rdataclass_t rdclass, */ result = isc_lex_create(mctx, 64, &lex); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); - length = strlen(text_ok->data); - isc_buffer_constinit(&source, text_ok->data, length); + length = strlen(text_ok->text_in); + isc_buffer_constinit(&source, text_ok->text_in, length); isc_buffer_add(&source, length); result = isc_lex_openbuffer(lex, &source); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); /* * Initialize target structures. */ - isc_buffer_init(&target, buf, sizeof(buf)); + isc_buffer_init(&target, buf_fromtext, sizeof(buf_fromtext)); dns_rdata_init(&rdata); /* - * Try converting RDATA text into uncompressed wire form. + * Try converting text form RDATA into uncompressed wire form. */ result = dns_rdata_fromtext(&rdata, rdclass, type, lex, dns_rootname, 0, NULL, &target, NULL); + /* + * Destroy lexer now to simplify error handling below. + */ + isc_lex_destroy(&lex); /* * Check whether result is as expected. */ - if (text_ok->ok) - ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); - else - ATF_REQUIRE(result != ISC_R_SUCCESS); + if (text_ok->text_out != NULL) { + ATF_REQUIRE_EQ_MSG(result, ISC_R_SUCCESS, + "line %d: '%s': " + "expected success, got failure", + text_ok->lineno, text_ok->text_in); + } else { + ATF_REQUIRE_MSG(result != ISC_R_SUCCESS, + "line %d: '%s': " + "expected failure, got success", + text_ok->lineno, text_ok->text_in); + } /* - * If text was parsed correctly, perform additional two-way - * rdata <-> type-specific struct conversion checks. + * If text form RDATA was not parsed correctly, performing any + * additional checks is pointless. */ - if (result == ISC_R_SUCCESS) - check_struct_conversions(&rdata, structsize, text_ok->lineno); - - isc_lex_destroy(&lex); + if (result != ISC_R_SUCCESS) { + return; + } + /* + * Try converting uncompressed wire form RDATA back into text form and + * check whether the resulting text is the same as the original one. + */ + isc_buffer_init(&target, buf_totext, sizeof(buf_totext)); + result = dns_rdata_totext(&rdata, NULL, &target); + ATF_REQUIRE_EQ_MSG(result, ISC_R_SUCCESS, + "line %d: '%s': " + "failed to convert rdata back to text form", + text_ok->lineno, text_ok->text_in); + ATF_REQUIRE_EQ_MSG(strcmp(buf_totext, text_ok->text_out), 0, + "line %d: '%s': " + "converts back to '%s', expected '%s'", + text_ok->lineno, text_ok->text_in, buf_totext, + text_ok->text_out); + /* + * Perform two-way conversion checks between uncompressed wire form and + * type-specific struct. + */ + check_struct_conversions(&rdata, structsize, text_ok->lineno); } /* - * Test whether supplied RDATA in wire format is properly handled as being - * either valid or invalid for an RR of given rdclass and type. + * Test whether supplied wire form RDATA is properly handled as being either + * valid or invalid for an RR of given rdclass and type. */ static void check_wire_ok_single(const wire_ok_t *wire_ok, dns_rdataclass_t rdclass, - dns_rdatatype_t type, size_t structsize) { + dns_rdatatype_t type, size_t structsize) +{ isc_buffer_t source, target; unsigned char buf[1024]; dns_decompress_t dctx; @@ -223,7 +260,7 @@ check_wire_ok_single(const wire_ok_t *wire_ok, dns_rdataclass_t rdclass, /* * Check whether result is as expected. */ - if (wire_ok->ok) + if (wire_ok->ok) { ATF_REQUIRE_EQ_MSG(result, ISC_R_SUCCESS, "line %d: %s (%lu): " "expected success, got failure", @@ -231,7 +268,7 @@ check_wire_ok_single(const wire_ok_t *wire_ok, dns_rdataclass_t rdclass, dns_test_tohex(wire_ok->data, wire_ok->len, hex, sizeof(hex)), wire_ok->len); - else + } else { ATF_REQUIRE_MSG(result != ISC_R_SUCCESS, "line %d: %s (%lu): " "expected failure, got success", @@ -239,30 +276,34 @@ check_wire_ok_single(const wire_ok_t *wire_ok, dns_rdataclass_t rdclass, dns_test_tohex(wire_ok->data, wire_ok->len, hex, sizeof(hex)), wire_ok->len); + } /* - * If data was parsed correctly, perform additional two-way - * rdata <-> type-specific struct conversion checks. + * If data was parsed correctly, perform two-way conversion checks + * between uncompressed wire form and type-specific struct. */ - if (result == ISC_R_SUCCESS) + if (result == ISC_R_SUCCESS) { check_struct_conversions(&rdata, structsize, wire_ok->lineno); + } } /* - * For each text RDATA in the supplied array, check whether it is properly - * handled as having either valid or invalid syntax for an RR of given rdclass - * and type. This checks whether the fromtext_*() routine for given RR class - * and type behaves as expected. + * Test fromtext_*() and totext_*() routines for given RR class and type for + * each text form RDATA in the supplied array. See the comment for + * check_text_ok_single() for an explanation of how exactly these routines are + * tested. */ static void check_text_ok(const text_ok_t *text_ok, dns_rdataclass_t rdclass, - dns_rdatatype_t type, size_t structsize) { + dns_rdatatype_t type, size_t structsize) +{ size_t i; /* * Check all entries in the supplied array. */ - for (i = 0; text_ok[i].data != NULL; i++) + for (i = 0; text_ok[i].text_in != NULL; i++) { check_text_ok_single(&text_ok[i], rdclass, type, structsize); + } } /* @@ -275,15 +316,17 @@ check_text_ok(const text_ok_t *text_ok, dns_rdataclass_t rdclass, static void check_wire_ok(const wire_ok_t *wire_ok, isc_boolean_t empty_ok, dns_rdataclass_t rdclass, dns_rdatatype_t type, - size_t structsize) { + size_t structsize) +{ wire_ok_t empty_wire = WIRE_TEST(empty_ok); size_t i; /* * Check all entries in the supplied array. */ - for (i = 0; wire_ok[i].len != 0; i++) + for (i = 0; wire_ok[i].len != 0; i++) { check_wire_ok_single(&wire_ok[i], rdclass, type, structsize); + } /* * Check empty wire data. @@ -292,30 +335,33 @@ check_wire_ok(const wire_ok_t *wire_ok, isc_boolean_t empty_ok, } /* - * Test whether supplied sets of RDATA in text and/or wire form are handled as - * expected. This is just a helper function which should be the only function - * called for a test case using it, due to the use of dns_test_begin() and - * dns_test_end(). + * Test whether supplied sets of text form and/or wire form RDATA are handled + * as expected. This is just a helper function which should be the only + * function called for a test case using it, due to the use of dns_test_begin() + * and dns_test_end(). * * The empty_ok argument denotes whether an attempt to parse a zero-length wire * data buffer should succeed or not (it is valid for some RR types). There is - * no point in performing a similar check for empty text RDATA, because + * no point in performing a similar check for empty text form RDATA, because * dns_rdata_fromtext() returns ISC_R_UNEXPECTEDEND before calling fromtext_*() * for the given RR class and type. */ static void check_rdata(const text_ok_t *text_ok, const wire_ok_t *wire_ok, isc_boolean_t empty_ok, dns_rdataclass_t rdclass, - dns_rdatatype_t type, size_t structsize) { + dns_rdatatype_t type, size_t structsize) +{ isc_result_t result; result = dns_test_begin(NULL, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); - if (text_ok != NULL) + if (text_ok != NULL) { check_text_ok(text_ok, rdclass, type, structsize); - if (wire_ok != NULL) + } + if (wire_ok != NULL) { check_wire_ok(wire_ok, empty_ok, rdclass, type, structsize); + } dns_test_end(); } @@ -455,6 +501,223 @@ ATF_TC_BODY(csync, tc) { dns_rdatatype_csync, sizeof(dns_rdata_csync_t)); } +/* + * DOA tests. + * + * draft-durand-doa-over-dns-03: + * + * 3.2. DOA RDATA Wire Format + * + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * 0: | | + * | DOA-ENTERPRISE | + * | | + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * 4: | | + * | DOA-TYPE | + * | | + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * 8: | DOA-LOCATION | DOA-MEDIA-TYPE / + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * 10: / / + * / DOA-MEDIA-TYPE (continued) / + * / / + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * / / + * / DOA-DATA / + * / / + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * + * DOA-ENTERPRISE: a 32-bit unsigned integer in network order. + * + * DOA-TYPE: a 32-bit unsigned integer in network order. + * + * DOA-LOCATION: an 8-bit unsigned integer. + * + * DOA-MEDIA-TYPE: A (see [RFC1035]). The first + * octet of the contains the number of characters to + * follow. + * + * DOA-DATA: A variable length blob of binary data. The length of the + * DOA-DATA is not contained within the wire format of the RR and has to + * be computed from the RDLENGTH of the entire RR once other fields have + * been taken into account. + * + * 3.3. DOA RDATA Presentation Format + * + * The DOA-ENTERPRISE field is presented as an unsigned 32-bit decimal + * integer with range 0 - 4,294,967,295. + * + * The DOA-TYPE field is presented as an unsigned 32-bit decimal integer + * with range 0 - 4,294,967,295. + * + * The DOA-LOCATION field is presented as an unsigned 8-bit decimal + * integer with range 0 - 255. + * + * The DOA-MEDIA-TYPE field is presented as a single . + * + * The DOA-DATA is presented as Base64 encoded data [RFC3548] unless the + * DOA-DATA is empty in which case it is presented as a single dash + * character ("-", ASCII 45). White space is permitted within Base64 data. + */ +ATF_TC(doa); +ATF_TC_HEAD(doa, tc) { + atf_tc_set_md_var(tc, "descr", "DOA RDATA manipulations"); +} +ATF_TC_BODY(doa, tc) { + text_ok_t text_ok[] = { + /* + * Valid, non-empty DOA-DATA. + */ + TEXT_VALID("0 0 1 \"text/plain\" Zm9v"), + /* + * Valid, non-empty DOA-DATA with whitespace in between. + */ + TEXT_VALID_CHANGED("0 0 1 \"text/plain\" Zm 9v", + "0 0 1 \"text/plain\" Zm9v"), + /* + * Valid, unquoted DOA-MEDIA-TYPE, non-empty DOA-DATA. + */ + TEXT_VALID_CHANGED("0 0 1 text/plain Zm9v", + "0 0 1 \"text/plain\" Zm9v"), + /* + * Invalid, quoted non-empty DOA-DATA. + */ + TEXT_INVALID("0 0 1 \"text/plain\" \"Zm9v\""), + /* + * Valid, empty DOA-DATA. + */ + TEXT_VALID("0 0 1 \"text/plain\" -"), + /* + * Invalid, quoted empty DOA-DATA. + */ + TEXT_INVALID("0 0 1 \"text/plain\" \"-\""), + /* + * Invalid, missing "-" in empty DOA-DATA. + */ + TEXT_INVALID("0 0 1 \"text/plain\""), + /* + * Valid, undefined DOA-LOCATION. + */ + TEXT_VALID("0 0 100 \"text/plain\" Zm9v"), + /* + * Invalid, DOA-LOCATION too big. + */ + TEXT_INVALID("0 0 256 \"text/plain\" ZM9v"), + /* + * Valid, empty DOA-MEDIA-TYPE, non-empty DOA-DATA. + */ + TEXT_VALID("0 0 2 \"\" aHR0cHM6Ly93d3cuaXNjLm9yZy8="), + /* + * Valid, empty DOA-MEDIA-TYPE, empty DOA-DATA. + */ + TEXT_VALID("0 0 1 \"\" -"), + /* + * Valid, DOA-MEDIA-TYPE with a space. + */ + TEXT_VALID("0 0 1 \"plain text\" Zm9v"), + /* + * Invalid, missing DOA-MEDIA-TYPE. + */ + TEXT_INVALID("1234567890 1234567890 1"), + /* + * Valid, DOA-DATA over 255 octets. + */ + TEXT_VALID("1234567890 1234567890 1 \"image/gif\" " + "R0lGODlhKAAZAOMCAGZmZgBmmf///zOZzMz//5nM/zNmmWbM" + "/5nMzMzMzACZ/////////////////////yH5BAEKAA8ALAAA" + "AAAoABkAAATH8IFJK5U2a4337F5ogRkpnoCJrly7PrCKyh8c" + "3HgAhzT35MDbbtO7/IJIHbGiOiaTxVTpSVWWLqNq1UVyapNS" + "1wd3OAxug0LhnCubcVhsxysQnOt4ATpvvzHlFzl1AwODhWeF" + "AgRpen5/UhheAYMFdUB4SFcpGEGGdQeCAqBBLTuSk30EeXd9" + "pEsAbKGxjHqDSE0Sp6ixN4N1BJmbc7lIhmsBich1awPAjkY1" + "SZR8bJWrz382SGqIBQQFQd4IsUTaX+ceuudPEQA7"), + /* + * Invalid, bad Base64 in DOA-DATA. + */ + TEXT_INVALID("1234567890 1234567890 1 \"image/gif\" R0lGODl"), + /* + * Sentinel. + */ + TEXT_SENTINEL() + }; + wire_ok_t wire_ok[] = { + /* + * Valid, empty DOA-MEDIA-TYPE, empty DOA-DATA. + */ + WIRE_VALID(0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, + 0x01, 0x00), + /* + * Invalid, missing DOA-MEDIA-TYPE. + */ + WIRE_INVALID(0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, + 0x01), + /* + * Invalid, malformed DOA-MEDIA-TYPE length. + */ + WIRE_INVALID(0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, + 0x01, 0xff), + /* + * Valid, empty DOA-DATA. + */ + WIRE_VALID(0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, + 0x01, 0x03, 0x66, 0x6f, 0x6f), + /* + * Valid, non-empty DOA-DATA. + */ + WIRE_VALID(0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, + 0x01, 0x03, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72), + /* + * Valid, DOA-DATA over 255 octets. + */ + WIRE_VALID(0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, + 0x01, 0x06, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, + 0x00, 0x66, 0x99, 0xff, 0xff, 0xff, 0x33, 0x99, + 0xcc, 0xcc, 0xff, 0xff, 0x99, 0xcc, 0xff, 0x33, + 0x66, 0x99, 0x66, 0xcc, 0xff, 0x99, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0x00, 0x99, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x21, 0xf9, 0x04, + 0x01, 0x0a, 0x00, 0x0f, 0x00, 0x2c, 0x00, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x19, 0x00, 0x00, 0x04, + 0xc7, 0xf0, 0x81, 0x49, 0x2b, 0x95, 0x36, 0x6b, + 0x8d, 0xf7, 0xec, 0x5e, 0x68, 0x81, 0x19, 0x29, + 0x9e, 0x80, 0x89, 0xae, 0x5c, 0xbb, 0x3e, 0xb0, + 0x8a, 0xca, 0x1f, 0x1c, 0xdc, 0x78, 0x00, 0x87, + 0x34, 0xf7, 0xe4, 0xc0, 0xdb, 0x6e, 0xd3, 0xbb, + 0xfc, 0x82, 0x48, 0x1d, 0xb1, 0xa2, 0x3a, 0x26, + 0x93, 0xc5, 0x54, 0xe9, 0x49, 0x55, 0x96, 0x2e, + 0xa3, 0x6a, 0xd5, 0x45, 0x72, 0x6a, 0x93, 0x52, + 0xd7, 0x07, 0x77, 0x38, 0x0c, 0x6e, 0x83, 0x42, + 0xe1, 0x9c, 0x2b, 0x9b, 0x71, 0x58, 0x6c, 0xc7, + 0x2b, 0x10, 0x9c, 0xeb, 0x78, 0x01, 0x3a, 0x6f, + 0xbf, 0x31, 0xe5, 0x17, 0x39, 0x75, 0x03, 0x03, + 0x83, 0x85, 0x67, 0x85, 0x02, 0x04, 0x69, 0x7a, + 0x7e, 0x7f, 0x52, 0x18, 0x5e, 0x01, 0x83, 0x05, + 0x75, 0x40, 0x78, 0x48, 0x57, 0x29, 0x18, 0x41, + 0x86, 0x75, 0x07, 0x82, 0x02, 0xa0, 0x41, 0x2d, + 0x3b, 0x92, 0x93, 0x7d, 0x04, 0x79, 0x77, 0x7d, + 0xa4, 0x4b, 0x00, 0x6c, 0xa1, 0xb1, 0x8c, 0x7a, + 0x83, 0x48, 0x4d, 0x12, 0xa7, 0xa8, 0xb1, 0x37, + 0x83, 0x75, 0x04, 0x99, 0x9b, 0x73, 0xb9, 0x48, + 0x86, 0x6b, 0x01, 0x89, 0xc8, 0x75, 0x6b, 0x03, + 0xc0, 0x8e, 0x46, 0x35, 0x49, 0x94, 0x7c, 0x6c, + 0x95, 0xab, 0xcf, 0x7f, 0x36, 0x48, 0x6a, 0x88, + 0x05, 0x04, 0x05, 0x41, 0xde, 0x08, 0xb1, 0x44, + 0xda, 0x5f, 0xe7, 0x1e, 0xba, 0xe7, 0x4f, 0x11, + 0x00, 0x3b), + /* + * Sentinel. + */ + WIRE_SENTINEL() + }; + + UNUSED(tc); + + check_rdata(text_ok, wire_ok, ISC_FALSE, dns_rdataclass_in, + dns_rdatatype_doa, sizeof(dns_rdata_doa_t)); +} + /* * EDNS Client Subnet tests. * @@ -933,6 +1196,7 @@ ATF_TC_BODY(wks, tc) { ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, csync); + ATF_TP_ADD_TC(tp, doa); ATF_TP_ADD_TC(tp, edns_client_subnet); ATF_TP_ADD_TC(tp, hip); ATF_TP_ADD_TC(tp, isdn);