From f0265b8fa691c41975e395dfd58dc41699adb902 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Wed, 24 Mar 2021 10:58:09 +1100 Subject: [PATCH 01/12] Make whether to follow additional data records generic Adds dns_rdatatype_followadditional() and DNS_RDATATYPEATTR_FOLLOWADDITIONAL --- lib/dns/include/dns/rdata.h | 17 +++++++++++++++++ lib/dns/rdata.c | 9 +++++++++ lib/dns/rdata/in_1/srv_33.c | 2 +- lib/ns/query.c | 19 ++++--------------- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/lib/dns/include/dns/rdata.h b/lib/dns/include/dns/rdata.h index 359f69d674..476ef5f9c7 100644 --- a/lib/dns/include/dns/rdata.h +++ b/lib/dns/include/dns/rdata.h @@ -695,6 +695,21 @@ dns_rdatatype_atcname(dns_rdatatype_t type); * */ +bool +dns_rdatatype_followadditional(dns_rdatatype_t type); +/*%< + * Return true if adding a record of type 'type' to the ADDITIONAL section + * of a message can itself trigger the addition of still more data to the + * additional section. + * + * (For example: adding SRV to the ADDITIONAL section may trigger + * the addition of address records associated with that SRV.) + * + * Requires: + * \li 'type' is a valid rdata type. + * + */ + unsigned int dns_rdatatype_attributes(dns_rdatatype_t rdtype); /*%< @@ -729,6 +744,8 @@ dns_rdatatype_attributes(dns_rdatatype_t rdtype); #define DNS_RDATATYPEATTR_ATPARENT 0x00000200U /*% Can exist along side a CNAME */ #define DNS_RDATATYPEATTR_ATCNAME 0x00000400U +/*% Follow additional */ +#define DNS_RDATATYPEATTR_FOLLOWADDITIONAL 0x00000800U dns_rdatatype_t dns_rdata_covers(dns_rdata_t *rdata); diff --git a/lib/dns/rdata.c b/lib/dns/rdata.c index 6fb7bc3d22..c8d684a38c 100644 --- a/lib/dns/rdata.c +++ b/lib/dns/rdata.c @@ -2131,6 +2131,15 @@ dns_rdatatype_atparent(dns_rdatatype_t type) { return (false); } +bool +dns_rdatatype_followadditional(dns_rdatatype_t type) { + if ((dns_rdatatype_attributes(type) & + DNS_RDATATYPEATTR_FOLLOWADDITIONAL) != 0) { + return (true); + } + return (false); +} + bool dns_rdataclass_ismeta(dns_rdataclass_t rdclass) { if (rdclass == dns_rdataclass_reserved0 || diff --git a/lib/dns/rdata/in_1/srv_33.c b/lib/dns/rdata/in_1/srv_33.c index 268c0e9385..80dd1d637c 100644 --- a/lib/dns/rdata/in_1/srv_33.c +++ b/lib/dns/rdata/in_1/srv_33.c @@ -14,7 +14,7 @@ #ifndef RDATA_IN_1_SRV_33_C #define RDATA_IN_1_SRV_33_C -#define RRTYPE_SRV_ATTRIBUTES (0) +#define RRTYPE_SRV_ATTRIBUTES (DNS_RDATATYPEATTR_FOLLOWADDITIONAL) static inline isc_result_t fromtext_in_srv(ARGS_FROMTEXT) { diff --git a/lib/ns/query.c b/lib/ns/query.c index a9b1cd9dbb..81ff6abfe7 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -2041,22 +2041,11 @@ addname: fname = NULL; /* - * In a few cases, we want to add additional data for additional - * data. It's simpler to just deal with special cases here than - * to try to create a general purpose mechanism and allow the - * rdata implementations to do it themselves. - * - * This involves recursion, but the depth is limited. The - * most complex case is adding a SRV rdataset, which involves - * recursing to add address records, which in turn can cause - * recursion to add KEYs. + * In some cases, a record that has been added as additional + * data may *also* trigger the addition of additional data. + * This cannot go more than MAX_RESTARTS levels deep. */ - if (type == dns_rdatatype_srv && trdataset != NULL) { - /* - * If we're adding SRV records to the additional data - * section, it's helpful if we add the SRV additional data - * as well. - */ + if (trdataset != NULL && dns_rdatatype_followadditional(type)) { eresult = dns_rdataset_additionaldata( trdataset, query_additional_cb, qctx); } From 42c22670b3970c0418acfbdc7645bf0e0368a750 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Wed, 25 Sep 2019 18:02:38 +1000 Subject: [PATCH 02/12] Add support for parsing [=] where may be a quoted string. Previously quoted string only supported opening quotes at the start of the string. --- lib/isc/include/isc/lex.h | 30 ++++++++++++--------- lib/isc/lex.c | 56 +++++++++++++++++++++++++++++++++++---- 2 files changed, 68 insertions(+), 18 deletions(-) diff --git a/lib/isc/include/isc/lex.h b/lib/isc/include/isc/lex.h index fdbe10b92a..84d4f42486 100644 --- a/lib/isc/include/isc/lex.h +++ b/lib/isc/include/isc/lex.h @@ -61,11 +61,11 @@ ISC_LANG_BEGINDECLS * Various options for isc_lex_gettoken(). */ -#define ISC_LEXOPT_EOL 0x01 /*%< Want end-of-line token. */ -#define ISC_LEXOPT_EOF 0x02 /*%< Want end-of-file token. */ -#define ISC_LEXOPT_INITIALWS 0x04 /*%< Want initial whitespace. */ -#define ISC_LEXOPT_NUMBER 0x08 /*%< Recognize numbers. */ -#define ISC_LEXOPT_QSTRING 0x10 /*%< Recognize qstrings. */ +#define ISC_LEXOPT_EOL 0x0001 /*%< Want end-of-line token. */ +#define ISC_LEXOPT_EOF 0x0002 /*%< Want end-of-file token. */ +#define ISC_LEXOPT_INITIALWS 0x0004 /*%< Want initial whitespace. */ +#define ISC_LEXOPT_NUMBER 0x0008 /*%< Recognize numbers. */ +#define ISC_LEXOPT_QSTRING 0x0010 /*%< Recognize qstrings. */ /*@}*/ /*@{*/ @@ -76,14 +76,16 @@ ISC_LANG_BEGINDECLS * the paren count is > 0. To use this option, '(' and ')' must be special * characters. */ -#define ISC_LEXOPT_DNSMULTILINE 0x20 /*%< Handle '(' and ')'. */ -#define ISC_LEXOPT_NOMORE 0x40 /*%< Want "no more" token. */ +#define ISC_LEXOPT_DNSMULTILINE 0x0020 /*%< Handle '(' and ')'. */ +#define ISC_LEXOPT_NOMORE 0x0040 /*%< Want "no more" token. */ -#define ISC_LEXOPT_CNUMBER 0x80 /*%< Recognize octal and hex. */ -#define ISC_LEXOPT_ESCAPE 0x100 /*%< Recognize escapes. */ -#define ISC_LEXOPT_QSTRINGMULTILINE 0x200 /*%< Allow multiline "" strings */ -#define ISC_LEXOPT_OCTAL 0x400 /*%< Expect a octal number. */ -#define ISC_LEXOPT_BTEXT 0x800 /*%< Bracketed text. */ +#define ISC_LEXOPT_CNUMBER 0x0080 /*%< Recognize octal and hex. */ +#define ISC_LEXOPT_ESCAPE 0x0100 /*%< Recognize escapes. */ +#define ISC_LEXOPT_QSTRINGMULTILINE 0x0200 /*%< Allow multiline "" strings */ +#define ISC_LEXOPT_OCTAL 0x0400 /*%< Expect a octal number. */ +#define ISC_LEXOPT_BTEXT 0x0800 /*%< Bracketed text. */ +#define ISC_LEXOPT_VPAIR 0x1000 /*%< Recognize value pair. */ +#define ISC_LEXOPT_QVPAIR 0x2000 /*%< Recognize quoted value pair. */ /*@}*/ /*@{*/ /*! @@ -117,7 +119,9 @@ typedef enum { isc_tokentype_initialws = 6, isc_tokentype_special = 7, isc_tokentype_nomore = 8, - isc_tokentype_btext = 8 + isc_tokentype_btext = 9, + isc_tokentype_vpair = 10, + isc_tokentype_qvpair = 11, } isc_tokentype_t; typedef union { diff --git a/lib/isc/lex.c b/lib/isc/lex.c index 3aef691694..8ab3682873 100644 --- a/lib/isc/lex.c +++ b/lib/isc/lex.c @@ -293,7 +293,10 @@ typedef enum { lexstate_ccommentend, lexstate_eatline, lexstate_qstring, - lexstate_btext + lexstate_btext, + lexstate_vpair, + lexstate_vpairstart, + lexstate_qvpair, } lexstate; #define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL) @@ -663,6 +666,29 @@ isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) { remaining--; break; case lexstate_string: + if (!escaped && c == '=' && + (options & ISC_LEXOPT_VPAIR) != 0) { + INSIST(remaining > 0U); + *curr++ = c; + *curr = '\0'; + remaining--; + state = lexstate_vpairstart; + break; + } + /* FALLTHROUGH */ + case lexstate_vpairstart: + if (state == lexstate_vpairstart) { + if (c == '"' && + (options & ISC_LEXOPT_QVPAIR) != 0) { + INSIST(remaining > 0U); + no_comments = true; + state = lexstate_qvpair; + break; + } + state = lexstate_vpair; + } + /* FALLTHROUGH */ + case lexstate_vpair: /* * EOF needs to be checked before lex->specials[c] * as lex->specials[EOF] is not a good idea. @@ -676,7 +702,13 @@ isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) { result = source->result; goto done; } - tokenp->type = isc_tokentype_string; + if (escaped && c == EOF) { + result = ISC_R_UNEXPECTEDEND; + goto done; + } + tokenp->type = (state == lexstate_string) + ? isc_tokentype_string + : isc_tokentype_vpair; tokenp->value.as_textregion.base = lex->data; tokenp->value.as_textregion.length = (unsigned int)(lex->max_token - @@ -753,6 +785,7 @@ isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) { } break; case lexstate_qstring: + case lexstate_qvpair: if (c == EOF) { result = ISC_R_UNEXPECTEDEND; goto done; @@ -766,7 +799,10 @@ isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) { INSIST(prev != NULL); *prev = '"'; } else { - tokenp->type = isc_tokentype_qstring; + tokenp->type = + (state == lexstate_qstring) + ? isc_tokentype_qstring + : isc_tokentype_qvpair; tokenp->value.as_textregion.base = lex->data; tokenp->value.as_textregion.length = @@ -876,7 +912,12 @@ isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token, ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE; isc_result_t result; - if (expect == isc_tokentype_qstring) { + if (expect == isc_tokentype_vpair) { + options |= ISC_LEXOPT_VPAIR; + } else if (expect == isc_tokentype_qvpair) { + options |= ISC_LEXOPT_VPAIR; + options |= ISC_LEXOPT_QVPAIR; + } else if (expect == isc_tokentype_qstring) { options |= ISC_LEXOPT_QSTRING; } else if (expect == isc_tokentype_number) { options |= ISC_LEXOPT_NUMBER; @@ -895,7 +936,12 @@ isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token, return (ISC_R_SUCCESS); } if (token->type == isc_tokentype_string && - expect == isc_tokentype_qstring) { + (expect == isc_tokentype_qstring || expect == isc_tokentype_qvpair)) + { + return (ISC_R_SUCCESS); + } + if (token->type == isc_tokentype_vpair && + expect == isc_tokentype_qvpair) { return (ISC_R_SUCCESS); } if (token->type != expect) { From 36f34a3e79d6228078794defc2c626dad031993f Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Thu, 5 Nov 2020 17:22:52 +1100 Subject: [PATCH 03/12] Parse and print HTTPS and SVCB records --- .../checkzone/zones/bad-svcb-mandatory.db | 15 + bin/tests/system/checkzone/zones/bad-svcb.db | 15 + bin/tests/system/checkzone/zones/good-svcb.db | 23 + bin/tests/system/doth/example.axfr.good | 4 + bin/tests/system/genzone.sh | 6 + bin/tests/system/rrchecker/typelist.good | 2 + bin/tests/system/xfer/dig1.good | 4 + bin/tests/system/xfer/dig2.good | 4 + lib/dns/include/dns/result.h | 3 +- lib/dns/rdata.c | 132 +- lib/dns/rdata/in_1/https_65.c | 184 +++ lib/dns/rdata/in_1/https_65.h | 33 + lib/dns/rdata/in_1/svcb_64.c | 1217 +++++++++++++++++ lib/dns/rdata/in_1/svcb_64.h | 38 + lib/dns/result.c | 2 + lib/dns/tests/rdata_test.c | 254 +++- util/copyrights | 4 + 17 files changed, 1913 insertions(+), 27 deletions(-) create mode 100644 bin/tests/system/checkzone/zones/bad-svcb-mandatory.db create mode 100644 bin/tests/system/checkzone/zones/bad-svcb.db create mode 100644 bin/tests/system/checkzone/zones/good-svcb.db create mode 100644 lib/dns/rdata/in_1/https_65.c create mode 100644 lib/dns/rdata/in_1/https_65.h create mode 100644 lib/dns/rdata/in_1/svcb_64.c create mode 100644 lib/dns/rdata/in_1/svcb_64.h diff --git a/bin/tests/system/checkzone/zones/bad-svcb-mandatory.db b/bin/tests/system/checkzone/zones/bad-svcb-mandatory.db new file mode 100644 index 0000000000..d7048798e9 --- /dev/null +++ b/bin/tests/system/checkzone/zones/bad-svcb-mandatory.db @@ -0,0 +1,15 @@ +; Copyright (C) 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/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 + +svcb SVCB 0 . mandatory=alpn diff --git a/bin/tests/system/checkzone/zones/bad-svcb.db b/bin/tests/system/checkzone/zones/bad-svcb.db new file mode 100644 index 0000000000..d40e8db980 --- /dev/null +++ b/bin/tests/system/checkzone/zones/bad-svcb.db @@ -0,0 +1,15 @@ +; Copyright (C) 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/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 + +svcb SVCB 0 . unknown=wha diff --git a/bin/tests/system/checkzone/zones/good-svcb.db b/bin/tests/system/checkzone/zones/good-svcb.db new file mode 100644 index 0000000000..e94916402c --- /dev/null +++ b/bin/tests/system/checkzone/zones/good-svcb.db @@ -0,0 +1,23 @@ +; Copyright (C) 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/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 + +svcb0 SVCB 0 example.net. +svcb1 SVCB 1 . port=60 alpn=h3 ech="ZWFzdGVyIGVnZyE=" +svcb2 SVCB 2 . no-default-alpn alpn=alpn +svcb3 SVCB 3 . ipv4hint="10.10.10.10" +svcb4 SVCB 4 . ipv6hint="feed:a::bee" +svcb5 SVCB 5 . key9999="something" +svcb6 SVCB 6 . mandatory=port,alpn port=60 alpn=h3 +svcb7 SVCB 7 . mandatory=port,alpn port=60 alpn=h1,h3 +svcb8 SVCB 8 . mandatory=port,alpn port=60 alpn="h1\\,h2,h3" diff --git a/bin/tests/system/doth/example.axfr.good b/bin/tests/system/doth/example.axfr.good index 01e15fa9a2..653fb46bda 100644 --- a/bin/tests/system/doth/example.axfr.good +++ b/bin/tests/system/doth/example.axfr.good @@ -2558,6 +2558,8 @@ hinfo01.example. 3600 IN HINFO "Generic PC clone" "NetBSD-1.4" hinfo02.example. 3600 IN HINFO "PC" "NetBSD" hip1.example. 3600 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D hip2.example. 3600 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs.example.com. +https0.example. 3600 IN HTTPS 0 example.net. +https1.example. 3600 IN HTTPS 1 . port=60 ipseckey01.example. 3600 IN IPSECKEY 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== ipseckey02.example. 3600 IN IPSECKEY 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== ipseckey03.example. 3600 IN IPSECKEY 10 1 2 192.0.2.3 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== @@ -2634,6 +2636,8 @@ srv01.example. 3600 IN SRV 0 0 0 . srv02.example. 3600 IN SRV 65535 65535 65535 old-slow-box.example. sshfp01.example. 3600 IN SSHFP 4 2 C76D8329954DA2835751E371544E963EFDA099080D6C58DD2BFD9A31 6E162C83 sshfp02.example. 3600 IN SSHFP 1 2 BF29468C83AC58CCF8C85AB7B3BEB054ECF1E38512B8353AB36471FA 88961DCC +svcb0.example. 3600 IN SVCB 0 example.net. +svcb1.example. 3600 IN SVCB 1 . port=60 ta.example. 3600 IN TA 30795 1 1 310D27F4D82C1FC2400704EA9939FE6E1CEAA3B9 talink0.example. 3600 IN TALINK . talink1.example. talink1.example. 3600 IN TALINK talink0.example. talink2.example. diff --git a/bin/tests/system/genzone.sh b/bin/tests/system/genzone.sh index 2f8882b401..88ae7f04e9 100644 --- a/bin/tests/system/genzone.sh +++ b/bin/tests/system/genzone.sh @@ -493,6 +493,12 @@ dlv DLV 30795 1 1 ( ; type 65280-65534 (private use) +https0 HTTPS 0 example.net. +https1 HTTPS 1 . port=60 + +svcb0 SVCB 0 example.net. +svcb1 SVCB 1 . port=60 + ; keydata (internal type used for managed keys) keydata TYPE65533 \# 0 keydata TYPE65533 \# 6 010203040506 diff --git a/bin/tests/system/rrchecker/typelist.good b/bin/tests/system/rrchecker/typelist.good index c843fc7b51..3c3e5cd384 100644 --- a/bin/tests/system/rrchecker/typelist.good +++ b/bin/tests/system/rrchecker/typelist.good @@ -59,6 +59,8 @@ CDNSKEY OPENPGPKEY CSYNC ZONEMD +SVCB +HTTPS SPF UINFO UID diff --git a/bin/tests/system/xfer/dig1.good b/bin/tests/system/xfer/dig1.good index 0f8fad0f31..9fa5437d38 100644 --- a/bin/tests/system/xfer/dig1.good +++ b/bin/tests/system/xfer/dig1.good @@ -59,6 +59,8 @@ hinfo01.example. 3600 IN HINFO "Generic PC clone" "NetBSD-1.4" hinfo02.example. 3600 IN HINFO "PC" "NetBSD" hip1.example. 3600 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D hip2.example. 3600 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs.example.com. +https0.example. 3600 IN HTTPS 0 example.net. +https1.example. 3600 IN HTTPS 1 . port=60 ipseckey01.example. 3600 IN IPSECKEY 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== ipseckey02.example. 3600 IN IPSECKEY 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== ipseckey03.example. 3600 IN IPSECKEY 10 1 2 192.0.2.3 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== @@ -137,6 +139,8 @@ sink02.example. 3600 IN SINK 8 0 2 l4ik smimea.example. 3600 IN SMIMEA 1 1 2 92003BA34942DC74152E2F2C408D29ECA5A520E7F2E06BB944F4DCA3 46BAF63C1B177615D466F6C4B71C216A50292BD58C9EBDD2F74E38FE 51FFD48C43326CBC srv01.example. 3600 IN SRV 0 0 0 . srv02.example. 3600 IN SRV 65535 65535 65535 old-slow-box.example. +svcb0.example. 3600 IN SVCB 0 example.net. +svcb1.example. 3600 IN SVCB 1 . port=60 ta.example. 3600 IN TA 30795 1 1 310D27F4D82C1FC2400704EA9939FE6E1CEAA3B9 talink0.example. 3600 IN TALINK . talink1.example. talink1.example. 3600 IN TALINK talink0.example. talink2.example. diff --git a/bin/tests/system/xfer/dig2.good b/bin/tests/system/xfer/dig2.good index fed8926817..2229f9ce7a 100644 --- a/bin/tests/system/xfer/dig2.good +++ b/bin/tests/system/xfer/dig2.good @@ -69,6 +69,8 @@ isdn04.example. 3600 IN ISDN "isdn-address" "subaddress" hip1.example. 3600 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D hip2.example. 3600 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs.example.com. dnskey01.example. 3600 IN DNSKEY 512 255 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aRyzWZriO6i2od GWWQVucZqKVsENW91IOW4vqudngPZsY3GvQ/xVA8/7pyFj6b7Esga60z yGW6LFe9r8n6paHrlG5ojqf0BaqHT+8= +https0.example. 3600 IN HTTPS 0 example.net. +https1.example. 3600 IN HTTPS 1 . port=60 keydata.example. 3600 IN TYPE65533 \# 0 keydata.example. 3600 IN TYPE65533 \# 6 010203040506 keydata.example. 3600 IN TYPE65533 \# 18 010203040506010203040506010203040506 @@ -137,6 +139,8 @@ srv01.example. 3600 IN SRV 0 0 0 . srv02.example. 3600 IN SRV 65535 65535 65535 old-slow-box.example. sshfp01.example. 3600 IN SSHFP 4 2 C76D8329954DA2835751E371544E963EFDA099080D6C58DD2BFD9A31 6E162C83 sshfp02.example. 3600 IN SSHFP 1 2 BF29468C83AC58CCF8C85AB7B3BEB054ECF1E38512B8353AB36471FA 88961DCC +svcb0.example. 3600 IN SVCB 0 example.net. +svcb1.example. 3600 IN SVCB 1 . port=60 ta.example. 3600 IN TA 30795 1 1 310D27F4D82C1FC2400704EA9939FE6E1CEAA3B9 talink0.example. 3600 IN TALINK . talink1.example. talink1.example. 3600 IN TALINK talink0.example. talink2.example. diff --git a/lib/dns/include/dns/result.h b/lib/dns/include/dns/result.h index 58e7426b3f..22a75b5d24 100644 --- a/lib/dns/include/dns/result.h +++ b/lib/dns/include/dns/result.h @@ -162,8 +162,9 @@ #define DNS_R_NSEC3SALTRANGE (ISC_RESULTCLASS_DNS + 124) #define DNS_R_NSEC3BADALG (ISC_RESULTCLASS_DNS + 125) #define DNS_R_NSEC3RESALT (ISC_RESULTCLASS_DNS + 126) +#define DNS_R_INCONSISTENTRR (ISC_RESULTCLASS_DNS + 127) -#define DNS_R_NRESULTS 127 /*%< Number of results */ +#define DNS_R_NRESULTS 128 /*%< Number of results */ /* * DNS wire format rcodes. diff --git a/lib/dns/rdata.c b/lib/dns/rdata.c index c8d684a38c..29e472c266 100644 --- a/lib/dns/rdata.c +++ b/lib/dns/rdata.c @@ -159,6 +159,13 @@ txt_fromtext(isc_textregion_t *source, isc_buffer_t *target); static isc_result_t txt_fromwire(isc_buffer_t *source, isc_buffer_t *target); +static isc_result_t +commatxt_fromtext(isc_textregion_t *source, bool comma, isc_buffer_t *target); + +static isc_result_t +commatxt_totext(isc_region_t *source, bool quote, bool comma, + isc_buffer_t *target); + static isc_result_t multitxt_totext(isc_region_t *source, isc_buffer_t *target); @@ -302,6 +309,22 @@ static isc_result_t generic_tostruct_tlsa(ARGS_TOSTRUCT); static void generic_freestruct_tlsa(ARGS_FREESTRUCT); +static isc_result_t generic_fromtext_in_svcb(ARGS_FROMTEXT); +static isc_result_t generic_totext_in_svcb(ARGS_TOTEXT); +static isc_result_t generic_fromwire_in_svcb(ARGS_FROMWIRE); +static isc_result_t generic_towire_in_svcb(ARGS_TOWIRE); +static isc_result_t generic_fromstruct_in_svcb(ARGS_FROMSTRUCT); +static isc_result_t generic_tostruct_in_svcb(ARGS_TOSTRUCT); +static void generic_freestruct_in_svcb(ARGS_FREESTRUCT); +static isc_result_t generic_additionaldata_in_svcb(ARGS_ADDLDATA); +static bool generic_checknames_in_svcb(ARGS_CHECKNAMES); +static isc_result_t +generic_rdata_in_svcb_first(dns_rdata_in_svcb_t *); +static isc_result_t +generic_rdata_in_svcb_next(dns_rdata_in_svcb_t *); +static void +generic_rdata_in_svcb_current(dns_rdata_in_svcb_t *, isc_region_t *); + /*% INT16 Size */ #define NS_INT16SZ 2 /*% IPv6 Address Size */ @@ -1415,7 +1438,8 @@ name_length(const dns_name_t *name) { } static isc_result_t -txt_totext(isc_region_t *source, bool quote, isc_buffer_t *target) { +commatxt_totext(isc_region_t *source, bool quote, bool comma, + isc_buffer_t *target) { unsigned int tl; unsigned int n; unsigned char *sp; @@ -1445,30 +1469,48 @@ txt_totext(isc_region_t *source, bool quote, isc_buffer_t *target) { /* * \DDD space (0x20) if not quoting. */ - if (*sp < (quote ? 0x20 : 0x21) || *sp >= 0x7f) { + if (*sp < (quote ? ' ' : '!') || *sp >= 0x7f) { if (tl < 4) { return (ISC_R_NOSPACE); } - *tp++ = 0x5c; - *tp++ = 0x30 + ((*sp / 100) % 10); - *tp++ = 0x30 + ((*sp / 10) % 10); - *tp++ = 0x30 + (*sp % 10); + *tp++ = '\\'; + *tp++ = '0' + ((*sp / 100) % 10); + *tp++ = '0' + ((*sp / 10) % 10); + *tp++ = '0' + (*sp % 10); sp++; tl -= 4; continue; } /* * Escape double quote and backslash. If we are not - * enclosing the string in double quotes also escape - * at sign and semicolon. + * enclosing the string in double quotes, also escape + * at sign (@) and semicolon (;) unless comma is set. + * If comma is set, then only escape commas (,). */ - if (*sp == 0x22 || *sp == 0x5c || - (!quote && (*sp == 0x40 || *sp == 0x3b))) { + if (*sp == '"' || *sp == '\\' || (comma && *sp == ',') || + (!comma && !quote && (*sp == '@' || *sp == ';'))) + { if (tl < 2) { return (ISC_R_NOSPACE); } *tp++ = '\\'; tl--; + /* + * Perform comma escape processing. + * ',' => '\\,' + * '\' => '\\\\' + */ + if (comma && (*sp == ',' || *sp == '\\')) { + if (tl < ((*sp == '\\') ? 3 : 2)) { + return (ISC_R_NOSPACE); + } + *tp++ = '\\'; + tl--; + if (*sp == '\\') { + *tp++ = '\\'; + tl--; + } + } } if (tl < 1) { return (ISC_R_NOSPACE); @@ -1490,9 +1532,14 @@ txt_totext(isc_region_t *source, bool quote, isc_buffer_t *target) { } static isc_result_t -txt_fromtext(isc_textregion_t *source, isc_buffer_t *target) { +txt_totext(isc_region_t *source, bool quote, isc_buffer_t *target) { + return (commatxt_totext(source, quote, false, target)); +} + +static isc_result_t +commatxt_fromtext(isc_textregion_t *source, bool comma, isc_buffer_t *target) { isc_region_t tregion; - bool escape; + bool escape = false, comma_escape = false, seen_comma = false; unsigned int n, nrem; char *s; unsigned char *t; @@ -1504,7 +1551,6 @@ txt_fromtext(isc_textregion_t *source, isc_buffer_t *target) { n = source->length; t = tregion.base; nrem = tregion.length; - escape = false; if (nrem < 1) { return (ISC_R_NOSPACE); } @@ -1549,6 +1595,25 @@ txt_fromtext(isc_textregion_t *source, isc_buffer_t *target) { continue; } escape = false; + /* + * Level 1 escape processing complete. + * If comma is set perform comma escape processing. + * + * Level 1 Level 2 ALPN's + * h1\,h2 => h1,h2 => h1 and h2 + * h1\\,h2 => h1\,h2 => h1,h2 + * h1\\h2 => h1\h2 => h1h2 + * h1\\\\h2 => h1\\h2 => h1\h2 + */ + if (comma && !comma_escape && c == ',') { + seen_comma = true; + break; + } + if (comma && !comma_escape && c == '\\') { + comma_escape = true; + continue; + } + comma_escape = false; if (nrem == 0) { return ((tregion.length <= 256U) ? ISC_R_NOSPACE : DNS_R_SYNTAX); @@ -1556,14 +1621,41 @@ txt_fromtext(isc_textregion_t *source, isc_buffer_t *target) { *t++ = c; nrem--; } - if (escape) { + + /* + * Incomplete escape processing? + */ + if (escape || (comma && comma_escape)) { return (DNS_R_SYNTAX); } + + if (comma) { + /* + * Disallow empty ALPN at start (",h1") or in the + * middle ("h1,,h2"). + */ + if (s == source->base || (seen_comma && s == source->base + 1)) + { + return (DNS_R_SYNTAX); + } + isc_textregion_consume(source, s - source->base); + /* + * Disallow empty ALPN at end ("h1,"). + */ + if (seen_comma && source->length == 0) { + return (DNS_R_SYNTAX); + } + } *tregion.base = (unsigned char)(t - tregion.base - 1); isc_buffer_add(target, *tregion.base + 1); return (ISC_R_SUCCESS); } +static isc_result_t +txt_fromtext(isc_textregion_t *source, isc_buffer_t *target) { + return (commatxt_fromtext(source, false, target)); +} + static isc_result_t txt_fromwire(isc_buffer_t *source, isc_buffer_t *target) { unsigned int n; @@ -1618,20 +1710,20 @@ multitxt_totext(isc_region_t *source, isc_buffer_t *target) { n0 = source->length - 1; while (n--) { - if (*sp < 0x20 || *sp >= 0x7f) { + if (*sp < ' ' || *sp >= 0x7f) { if (tl < 4) { return (ISC_R_NOSPACE); } - *tp++ = 0x5c; - *tp++ = 0x30 + ((*sp / 100) % 10); - *tp++ = 0x30 + ((*sp / 10) % 10); - *tp++ = 0x30 + (*sp % 10); + *tp++ = '\\'; + *tp++ = '0' + ((*sp / 100) % 10); + *tp++ = '0' + ((*sp / 10) % 10); + *tp++ = '0' + (*sp % 10); sp++; tl -= 4; continue; } /* double quote, backslash */ - if (*sp == 0x22 || *sp == 0x5c) { + if (*sp == '"' || *sp == '\\') { if (tl < 2) { return (ISC_R_NOSPACE); } diff --git a/lib/dns/rdata/in_1/https_65.c b/lib/dns/rdata/in_1/https_65.c new file mode 100644 index 0000000000..464b58337d --- /dev/null +++ b/lib/dns/rdata/in_1/https_65.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 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 https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* draft-ietf-dnsop-svcb-https-02 */ + +#ifndef RDATA_IN_1_HTTPS_65_C +#define RDATA_IN_1_HTTPS_65_C + +#define RRTYPE_HTTPS_ATTRIBUTES 0 + +/* + * Most of these functions refer to equivalent functions for SVCB, + * since wire and presentation formats are identical. + */ + +static inline isc_result_t +fromtext_in_https(ARGS_FROMTEXT) { + REQUIRE(type == dns_rdatatype_https); + REQUIRE(rdclass == dns_rdataclass_in); + + return (generic_fromtext_in_svcb(CALL_FROMTEXT)); +} + +static inline isc_result_t +totext_in_https(ARGS_TOTEXT) { + REQUIRE(rdata->type == dns_rdatatype_https); + REQUIRE(rdata->rdclass == dns_rdataclass_in); + REQUIRE(rdata->length != 0); + + return (generic_totext_in_svcb(CALL_TOTEXT)); +} + +static inline isc_result_t +fromwire_in_https(ARGS_FROMWIRE) { + REQUIRE(type == dns_rdatatype_https); + REQUIRE(rdclass == dns_rdataclass_in); + + return (generic_fromwire_in_svcb(CALL_FROMWIRE)); +} + +static inline isc_result_t +towire_in_https(ARGS_TOWIRE) { + REQUIRE(rdata->type == dns_rdatatype_https); + REQUIRE(rdata->length != 0); + + return (generic_towire_in_svcb(CALL_TOWIRE)); +} + +static inline int +compare_in_https(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_https); + REQUIRE(rdata1->rdclass == dns_rdataclass_in); + REQUIRE(rdata1->length != 0); + REQUIRE(rdata2->length != 0); + + dns_rdata_toregion(rdata1, ®ion1); + dns_rdata_toregion(rdata2, ®ion2); + + return (isc_region_compare(®ion1, ®ion2)); +} + +static inline isc_result_t +fromstruct_in_https(ARGS_FROMSTRUCT) { + dns_rdata_in_https_t *https = source; + + REQUIRE(type == dns_rdatatype_https); + REQUIRE(rdclass == dns_rdataclass_in); + REQUIRE(https != NULL); + REQUIRE(https->common.rdtype == type); + REQUIRE(https->common.rdclass == rdclass); + + return (generic_fromstruct_in_svcb(CALL_FROMSTRUCT)); +} + +static inline isc_result_t +tostruct_in_https(ARGS_TOSTRUCT) { + dns_rdata_in_https_t *https = target; + + REQUIRE(rdata->rdclass == dns_rdataclass_in); + REQUIRE(rdata->type == dns_rdatatype_https); + REQUIRE(https != NULL); + REQUIRE(rdata->length != 0); + + return (generic_tostruct_in_svcb(CALL_TOSTRUCT)); +} + +static inline void +freestruct_in_https(ARGS_FREESTRUCT) { + dns_rdata_in_https_t *https = source; + + REQUIRE(https != NULL); + REQUIRE(https->common.rdclass == dns_rdataclass_in); + REQUIRE(https->common.rdtype == dns_rdatatype_https); + + generic_freestruct_in_svcb(CALL_FREESTRUCT); +} + +static inline isc_result_t +additionaldata_in_https(ARGS_ADDLDATA) { + REQUIRE(rdata->type == dns_rdatatype_https); + REQUIRE(rdata->rdclass == dns_rdataclass_in); + + return (generic_additionaldata_in_svcb(CALL_ADDLDATA)); +} + +static inline isc_result_t +digest_in_https(ARGS_DIGEST) { + isc_region_t region1; + + REQUIRE(rdata->type == dns_rdatatype_https); + REQUIRE(rdata->rdclass == dns_rdataclass_in); + + dns_rdata_toregion(rdata, ®ion1); + return ((digest)(arg, ®ion1)); +} + +static inline bool +checkowner_in_https(ARGS_CHECKOWNER) { + REQUIRE(type == dns_rdatatype_https); + REQUIRE(rdclass == dns_rdataclass_in); + + UNUSED(name); + UNUSED(type); + UNUSED(rdclass); + UNUSED(wildcard); + + return (true); +} + +static inline bool +checknames_in_https(ARGS_CHECKNAMES) { + REQUIRE(rdata->type == dns_rdatatype_https); + REQUIRE(rdata->rdclass == dns_rdataclass_in); + + return (generic_checknames_in_svcb(CALL_CHECKNAMES)); +} + +static inline int +casecompare_in_https(ARGS_COMPARE) { + return (compare_in_https(rdata1, rdata2)); +} + +isc_result_t +dns_rdata_in_https_first(dns_rdata_in_https_t *https) { + REQUIRE(https != NULL); + REQUIRE(https->common.rdtype == dns_rdatatype_https); + REQUIRE(https->common.rdclass == dns_rdataclass_in); + + return (generic_rdata_in_svcb_first(https)); +} + +isc_result_t +dns_rdata_in_https_next(dns_rdata_in_https_t *https) { + REQUIRE(https != NULL); + REQUIRE(https->common.rdtype == dns_rdatatype_https); + REQUIRE(https->common.rdclass == dns_rdataclass_in); + + return (generic_rdata_in_svcb_next(https)); +} + +void +dns_rdata_in_https_current(dns_rdata_in_https_t *https, isc_region_t *region) { + REQUIRE(https != NULL); + REQUIRE(https->common.rdtype == dns_rdatatype_https); + REQUIRE(https->common.rdclass == dns_rdataclass_in); + REQUIRE(region != NULL); + + generic_rdata_in_svcb_current(https, region); +} + +#endif /* RDATA_IN_1_HTTPS_65_C */ diff --git a/lib/dns/rdata/in_1/https_65.h b/lib/dns/rdata/in_1/https_65.h new file mode 100644 index 0000000000..2469a35962 --- /dev/null +++ b/lib/dns/rdata/in_1/https_65.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 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 https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef IN_1_HTTPS_65_H +#define IN_1_HTTPS_65_H 1 + +/*! + * \brief Per draft-ietf-dnsop-svcb-https-02 + */ + +/* + * Wire and presentation formats for HTTPS are identical to SVCB. + */ +typedef struct dns_rdata_in_svcb dns_rdata_in_https_t; + +isc_result_t +dns_rdata_in_https_first(dns_rdata_in_https_t *); + +isc_result_t +dns_rdata_in_https_next(dns_rdata_in_https_t *); + +void +dns_rdata_in_https_current(dns_rdata_in_https_t *, isc_region_t *); + +#endif /* IN_1_HTTPS_65_H */ diff --git a/lib/dns/rdata/in_1/svcb_64.c b/lib/dns/rdata/in_1/svcb_64.c new file mode 100644 index 0000000000..8987094aa3 --- /dev/null +++ b/lib/dns/rdata/in_1/svcb_64.c @@ -0,0 +1,1217 @@ +/* + * Copyright (C) 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 https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* draft-ietf-dnsop-svcb-https-02 */ + +#ifndef RDATA_IN_1_SVCB_64_C +#define RDATA_IN_1_SVCB_64_C + +#define RRTYPE_SVCB_ATTRIBUTES 0 + +#define SVCB_MAN_KEY 0 +#define SVCB_ALPN_KEY 1 +#define SVCB_NO_DEFAULT_ALPN_KEY 2 + +/* + * Service Binding Parameter Registry + */ +enum encoding { + sbpr_text, + sbpr_port, + sbpr_ipv4s, + sbpr_ipv6s, + sbpr_base64, + sbpr_empty, + sbpr_alpn, + sbpr_keylist +}; +static const struct { + const char *name; /* Restricted to lowercase LDH by registry. */ + unsigned int value; + enum encoding encoding; + bool initial; +} sbpr[] = { + { "mandatory", 0, sbpr_keylist, true }, + { "alpn", 1, sbpr_alpn, true }, + { "no-default-alpn", 2, sbpr_empty, true }, + { "port", 3, sbpr_port, true }, + { "ipv4hint", 4, sbpr_ipv4s, true }, + { "ech", 5, sbpr_base64, true }, + { "ipv6hint", 6, sbpr_ipv6s, true }, +}; + +static isc_result_t +alpn_fromtxt(isc_textregion_t *source, isc_buffer_t *target) { + isc_textregion_t source0 = *source; + do { + RETERR(commatxt_fromtext(&source0, true, target)); + } while (source0.length != 0); + return (ISC_R_SUCCESS); +} + +static int +svckeycmp(const void *a1, const void *a2) { + const unsigned char *u1 = a1, *u2 = a2; + if (*u1 != *u2) { + return (*u1 - *u2); + } + return (*(++u1) - *(++u2)); +} + +static isc_result_t +svcsortkeylist(isc_buffer_t *target, unsigned int used) { + isc_region_t region; + + isc_buffer_usedregion(target, ®ion); + isc_region_consume(®ion, used); + INSIST(region.length > 0U); + qsort(region.base, region.length / 2, 2, svckeycmp); + /* Reject duplicates. */ + while (region.length >= 4) { + if (region.base[0] == region.base[2] && + region.base[1] == region.base[3]) { + return (DNS_R_SYNTAX); + } + isc_region_consume(®ion, 2); + } + return (ISC_R_SUCCESS); +} + +static isc_result_t +svcb_validate(uint16_t key, isc_region_t *region) { + size_t i; + +#ifndef ARRAYSIZE +/* defined in winnt.h */ +#define ARRAYSIZE(x) (sizeof(x) / sizeof(*x)) +#endif + + for (i = 0; i < ARRAYSIZE(sbpr); i++) { + if (sbpr[i].value == key) { + switch (sbpr[i].encoding) { + case sbpr_port: + if (region->length != 2) { + return (DNS_R_FORMERR); + } + break; + case sbpr_ipv4s: + if ((region->length % 4) != 0 || + region->length == 0) { + return (DNS_R_FORMERR); + } + break; + case sbpr_ipv6s: + if ((region->length % 16) != 0 || + region->length == 0) { + return (DNS_R_FORMERR); + } + break; + case sbpr_alpn: { + if (region->length == 0) { + return (DNS_R_FORMERR); + } + while (region->length != 0) { + size_t l = *region->base + 1; + if (l > region->length) { + return (DNS_R_FORMERR); + } + isc_region_consume(region, l); + } + break; + } + case sbpr_keylist: { + if ((region->length % 2) != 0 || + region->length == 0) { + return (DNS_R_FORMERR); + } + /* In order? */ + while (region->length >= 4) { + if (region->base[0] > region->base[2] || + (region->base[0] == + region->base[2] && + region->base[1] >= + region->base[3])) + { + return (DNS_R_FORMERR); + } + isc_region_consume(region, 2); + } + break; + } + case sbpr_text: + case sbpr_base64: + break; + case sbpr_empty: + if (region->length != 0) { + return (DNS_R_FORMERR); + } + break; + } + } + } + return (ISC_R_SUCCESS); +} + +/* + * Parse keyname from region. + */ +static isc_result_t +svc_keyfromregion(isc_textregion_t *region, char sep, uint16_t *value, + isc_buffer_t *target) { + char *e = NULL; + size_t i; + unsigned long ul; + + /* Look for known key names. */ + for (i = 0; i < ARRAYSIZE(sbpr); i++) { + size_t len = strlen(sbpr[i].name); + if (strncasecmp(region->base, sbpr[i].name, len) != 0 || + (region->base[len] != 0 && region->base[len] != sep)) + { + continue; + } + isc_textregion_consume(region, len); + ul = sbpr[i].value; + goto finish; + } + /* Handle keyXXXXX form. */ + if (strncmp(region->base, "key", 3) != 0) { + return (DNS_R_SYNTAX); + } + isc_textregion_consume(region, 3); + /* Disallow [+-]XXXXX which is allowed by strtoul. */ + if (region->length == 0 || *region->base == '-' || *region->base == '+') + { + return (DNS_R_SYNTAX); + } + /* No zero padding. */ + if (region->length > 1 && *region->base == '0' && + region->base[1] != sep) { + return (DNS_R_SYNTAX); + } + ul = strtoul(region->base, &e, 10); + /* Valid number? */ + if (e == region->base || (*e != sep && *e != 0)) { + return (DNS_R_SYNTAX); + } + if (ul > 0xffff) { + return (ISC_R_RANGE); + } + isc_textregion_consume(region, e - region->base); +finish: + if (sep == ',' && region->length == 1) { + return (DNS_R_SYNTAX); + } + /* Consume separator. */ + if (region->length != 0) { + isc_textregion_consume(region, 1); + } + RETERR(uint16_tobuffer(ul, target)); + if (value != NULL) { + *value = ul; + } + return (ISC_R_SUCCESS); +} + +static isc_result_t +svc_fromtext(isc_textregion_t *region, isc_buffer_t *target) { + char *e = NULL; + char abuf[16]; + char tbuf[sizeof("aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:255.255.255.255,")]; + isc_buffer_t sb; + isc_region_t keyregion; + size_t len; + uint16_t key; + unsigned int i; + unsigned int used; + unsigned long ul; + + for (i = 0; i < ARRAYSIZE(sbpr); i++) { + len = strlen(sbpr[i].name); + if (strncmp(region->base, sbpr[i].name, len) != 0 || + (region->base[len] != 0 && region->base[len] != '=')) + { + continue; + } + + if (region->base[len] == '=') { + len++; + } + + RETERR(uint16_tobuffer(sbpr[i].value, target)); + isc_textregion_consume(region, len); + + sb = *target; + RETERR(uint16_tobuffer(0, target)); /* length */ + + switch (sbpr[i].encoding) { + case sbpr_text: + RETERR(multitxt_fromtext(region, target)); + break; + case sbpr_alpn: + RETERR(alpn_fromtxt(region, target)); + break; + case sbpr_port: + if (!isdigit(*region->base)) { + return (DNS_R_SYNTAX); + } + ul = strtoul(region->base, &e, 10); + if (*e != '\0') { + return (DNS_R_SYNTAX); + } + if (ul > 0xffff) { + return (ISC_R_RANGE); + } + RETERR(uint16_tobuffer(ul, target)); + break; + case sbpr_ipv4s: + do { + snprintf(tbuf, sizeof(tbuf), "%*s", + (int)(region->length), region->base); + e = strchr(tbuf, ','); + if (e != NULL) { + *e++ = 0; + isc_textregion_consume(region, + e - tbuf); + } + if (inet_pton(AF_INET, tbuf, abuf) != 1) { + return (DNS_R_SYNTAX); + } + mem_tobuffer(target, abuf, 4); + } while (e != NULL); + break; + case sbpr_ipv6s: + do { + snprintf(tbuf, sizeof(tbuf), "%*s", + (int)(region->length), region->base); + e = strchr(tbuf, ','); + if (e != NULL) { + *e++ = 0; + isc_textregion_consume(region, + e - tbuf); + } + if (inet_pton(AF_INET6, tbuf, abuf) != 1) { + return (DNS_R_SYNTAX); + } + mem_tobuffer(target, abuf, 16); + } while (e != NULL); + break; + case sbpr_base64: + RETERR(isc_base64_decodestring(region->base, target)); + break; + case sbpr_empty: + if (region->length != 0) { + return (DNS_R_SYNTAX); + } + break; + case sbpr_keylist: + if (region->length == 0) { + return (DNS_R_SYNTAX); + } + used = isc_buffer_usedlength(target); + while (region->length != 0) { + RETERR(svc_keyfromregion(region, ',', NULL, + target)); + } + RETERR(svcsortkeylist(target, used)); + break; + default: + INSIST(0); + ISC_UNREACHABLE(); + } + + len = isc_buffer_usedlength(target) - + isc_buffer_usedlength(&sb) - 2; + RETERR(uint16_tobuffer(len, &sb)); /* length */ + return (ISC_R_SUCCESS); + } + + RETERR(svc_keyfromregion(region, '=', &key, target)); + if (region->length == 0) { + RETERR(uint16_tobuffer(0, target)); /* length */ + /* Sanity check keyXXXXX form. */ + keyregion.base = isc_buffer_used(target); + keyregion.length = 0; + return (svcb_validate(key, &keyregion)); + } + sb = *target; + RETERR(uint16_tobuffer(0, target)); /* dummy length */ + RETERR(multitxt_fromtext(region, target)); + len = isc_buffer_usedlength(target) - isc_buffer_usedlength(&sb) - 2; + RETERR(uint16_tobuffer(len, &sb)); /* length */ + /* Sanity check keyXXXXX form. */ + keyregion.base = isc_buffer_used(&sb); + keyregion.length = len; + return (svcb_validate(key, &keyregion)); +} + +static const char * +svcparamkey(unsigned short value, enum encoding *encoding, char *buf, + size_t len) { + size_t i; + int n; + + for (i = 0; i < ARRAYSIZE(sbpr); i++) { + if (sbpr[i].value == value && sbpr[i].initial) { + *encoding = sbpr[i].encoding; + return (sbpr[i].name); + } + } + n = snprintf(buf, len, "key%u", value); + INSIST(n > 0 && (unsigned)n < len); + *encoding = sbpr_text; + return (buf); +} + +static isc_result_t +svcsortkeys(isc_buffer_t *target, unsigned int used) { + isc_region_t r1, r2, man = { .base = NULL, .length = 0 }; + unsigned char buf[1024]; + uint16_t mankey = 0; + bool have_alpn = false; + + if (isc_buffer_usedlength(target) == used) { + return (ISC_R_SUCCESS); + } + + /* + * Get the parameters into r1. + */ + isc_buffer_usedregion(target, &r1); + isc_region_consume(&r1, used); + + while (1) { + uint16_t key1, len1, key2, len2; + unsigned char *base1, *base2; + + r2 = r1; + + /* + * Get the first parameter. + */ + base1 = r1.base; + key1 = uint16_fromregion(&r1); + isc_region_consume(&r1, 2); + len1 = uint16_fromregion(&r1); + isc_region_consume(&r1, 2); + isc_region_consume(&r1, len1); + + /* + * Was there only one key left? + */ + if (r1.length == 0) { + if (mankey != 0) { + /* Is this the last mandatory key? */ + if (key1 != mankey || man.length != 0) { + return (DNS_R_INCONSISTENTRR); + } + } else if (key1 == SVCB_MAN_KEY) { + /* Lone mandatory field. */ + return (DNS_R_DISALLOWED); + } else if (key1 == SVCB_NO_DEFAULT_ALPN_KEY && + !have_alpn) { + /* Missing required ALPN field. */ + return (DNS_R_DISALLOWED); + } + return (ISC_R_SUCCESS); + } + + /* + * Find the smallest parameter. + */ + while (r1.length != 0) { + base2 = r1.base; + key2 = uint16_fromregion(&r1); + isc_region_consume(&r1, 2); + len2 = uint16_fromregion(&r1); + isc_region_consume(&r1, 2); + isc_region_consume(&r1, len2); + if (key2 == key1) { + return (DNS_R_DUPLICATE); + } + if (key2 < key1) { + base1 = base2; + key1 = key2; + len1 = len2; + } + } + + /* + * Do we need to move the smallest parameter to the start? + */ + if (base1 != r2.base) { + size_t offset = 0; + size_t bytes = len1 + 4; + size_t length = base1 - r2.base; + + /* + * Move the smallest parameter to the start. + */ + while (bytes > 0) { + size_t count; + + if (bytes > sizeof(buf)) { + count = sizeof(buf); + } else { + count = bytes; + } + memmove(buf, base1, count); + memmove(r2.base + offset + count, + r2.base + offset, length); + memmove(r2.base + offset, buf, count); + base1 += count; + bytes -= count; + offset += count; + } + } + + /* + * Check ALPN is present when NO-DEFAULT-ALPN is set. + */ + if (key1 == SVCB_ALPN_KEY) { + have_alpn = true; + } else if (key1 == SVCB_NO_DEFAULT_ALPN_KEY && !have_alpn) { + /* Missing required ALPN field. */ + return (DNS_R_DISALLOWED); + } + + /* + * Check key against mandatory key list. + */ + if (mankey != 0) { + if (key1 > mankey) { + return (DNS_R_INCONSISTENTRR); + } + if (key1 == mankey) { + if (man.length >= 2) { + mankey = uint16_fromregion(&man); + isc_region_consume(&man, 2); + } else { + mankey = 0; + } + } + } + + /* + * Is this the mandatory key? + */ + if (key1 == SVCB_MAN_KEY) { + man = r2; + man.length = len1 + 4; + isc_region_consume(&man, 4); + if (man.length >= 2) { + mankey = uint16_fromregion(&man); + isc_region_consume(&man, 2); + if (mankey == SVCB_MAN_KEY) { + return (DNS_R_DISALLOWED); + } + } else { + return (DNS_R_SYNTAX); + } + } + + /* + * Consume the smallest parameter. + */ + isc_region_consume(&r2, len1 + 4); + r1 = r2; + } +} + +static inline isc_result_t +generic_fromtext_in_svcb(ARGS_FROMTEXT) { + isc_token_t token; + dns_name_t name; + isc_buffer_t buffer; + bool alias; +#if 0 + bool ok = true; +#endif + unsigned int used; + + UNUSED(type); + UNUSED(rdclass); + UNUSED(callbacks); + + /* + * SvcPriority. + */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, + false)); + if (token.value.as_ulong > 0xffffU) { + RETTOK(ISC_R_RANGE); + } + RETERR(uint16_tobuffer(token.value.as_ulong, target)); + + alias = token.value.as_ulong == 0; + + /* + * TargetName. + */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring, + false)); + dns_name_init(&name, NULL); + buffer_fromregion(&buffer, &token.value.as_region); + if (origin == NULL) { + origin = dns_rootname; + } + RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target)); +#if 0 + if (!alias && (options & DNS_RDATA_CHECKNAMES) != 0) { + ok = dns_name_ishostname(&name, false); + } + if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0) { + RETTOK(DNS_R_BADNAME); + } + if (!ok && callbacks != NULL) { + warn_badname(&name, lexer, callbacks); + } +#endif + + if (alias) { + return (ISC_R_SUCCESS); + } + + /* + * SvcParams + */ + used = isc_buffer_usedlength(target); + while (1) { + RETERR(isc_lex_getmastertoken(lexer, &token, + isc_tokentype_qvpair, true)); + if (token.type == isc_tokentype_eol || + token.type == isc_tokentype_eof) { + isc_lex_ungettoken(lexer, &token); + return (svcsortkeys(target, used)); + } + + if (token.type != isc_tokentype_string && /* key only */ + token.type != isc_tokentype_qvpair && + token.type != isc_tokentype_vpair) + { + RETTOK(DNS_R_SYNTAX); + } + RETTOK(svc_fromtext(&token.value.as_textregion, target)); + } +} + +static inline isc_result_t +fromtext_in_svcb(ARGS_FROMTEXT) { + REQUIRE(type == dns_rdatatype_svcb); + REQUIRE(rdclass == dns_rdataclass_in); + UNUSED(type); + UNUSED(rdclass); + UNUSED(callbacks); + + return (generic_fromtext_in_svcb(CALL_FROMTEXT)); +} + +static inline isc_result_t +generic_totext_in_svcb(ARGS_TOTEXT) { + isc_region_t region; + dns_name_t name; + dns_name_t prefix; + bool sub; + char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")]; + unsigned short num; + int n; + + REQUIRE(rdata->length != 0); + + dns_name_init(&name, NULL); + dns_name_init(&prefix, NULL); + + dns_rdata_toregion(rdata, ®ion); + + /* + * SvcPriority. + */ + num = uint16_fromregion(®ion); + isc_region_consume(®ion, 2); + n = snprintf(buf, sizeof(buf), "%u ", num); + INSIST(n > 0 && (unsigned)n < sizeof(buf)); + RETERR(str_totext(buf, target)); + + /* + * TargetName. + */ + dns_name_fromregion(&name, ®ion); + isc_region_consume(®ion, name_length(&name)); + sub = name_prefix(&name, tctx->origin, &prefix); + RETERR(dns_name_totext(&prefix, sub, target)); + + while (region.length > 0) { + isc_region_t r; + enum encoding encoding; + + RETERR(str_totext(" ", target)); + + INSIST(region.length >= 2); + num = uint16_fromregion(®ion); + isc_region_consume(®ion, 2); + RETERR(str_totext(svcparamkey(num, &encoding, buf, sizeof(buf)), + target)); + + INSIST(region.length >= 2); + num = uint16_fromregion(®ion); + isc_region_consume(®ion, 2); + + INSIST(region.length >= num); + r = region; + r.length = num; + isc_region_consume(®ion, num); + if (num == 0) { + continue; + } + if (encoding != sbpr_empty) { + RETERR(str_totext("=", target)); + } + switch (encoding) { + case sbpr_text: + RETERR(multitxt_totext(&r, target)); + break; + case sbpr_port: + num = uint16_fromregion(&r); + isc_region_consume(&r, 2); + n = snprintf(buf, sizeof(buf), "%u", num); + INSIST(n > 0 && (unsigned)n < sizeof(buf)); + RETERR(str_totext(buf, target)); + INSIST(r.length == 0U); + break; + case sbpr_ipv4s: + while (r.length > 0U) { + INSIST(r.length >= 4U); + inet_ntop(AF_INET, r.base, buf, sizeof(buf)); + RETERR(str_totext(buf, target)); + isc_region_consume(&r, 4); + if (r.length != 0U) { + RETERR(str_totext(",", target)); + } + } + break; + case sbpr_ipv6s: + while (r.length > 0U) { + INSIST(r.length >= 16U); + inet_ntop(AF_INET6, r.base, buf, sizeof(buf)); + RETERR(str_totext(buf, target)); + isc_region_consume(&r, 16); + if (r.length != 0U) { + RETERR(str_totext(",", target)); + } + } + break; + case sbpr_base64: + RETERR(isc_base64_totext(&r, 0, "", target)); + break; + case sbpr_alpn: + INSIST(r.length != 0U); + RETERR(str_totext("\"", target)); + while (r.length != 0) { + commatxt_totext(&r, false, true, target); + if (r.length != 0) { + RETERR(str_totext(",", target)); + } + } + RETERR(str_totext("\"", target)); + break; + case sbpr_empty: + INSIST(r.length == 0U); + break; + case sbpr_keylist: + while (r.length > 0) { + num = uint16_fromregion(&r); + isc_region_consume(&r, 2); + RETERR(str_totext(svcparamkey(num, &encoding, + buf, sizeof(buf)), + target)); + if (r.length != 0) { + RETERR(str_totext(",", target)); + } + } + break; + default: + INSIST(0); + ISC_UNREACHABLE(); + } + } + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +totext_in_svcb(ARGS_TOTEXT) { + REQUIRE(rdata->type == dns_rdatatype_svcb); + REQUIRE(rdata->rdclass == dns_rdataclass_in); + REQUIRE(rdata->length != 0); + + return (generic_totext_in_svcb(CALL_TOTEXT)); +} + +static inline isc_result_t +generic_fromwire_in_svcb(ARGS_FROMWIRE) { + dns_name_t name; + isc_region_t region, man = { .base = NULL, .length = 0 }; + bool alias, first = true; + uint16_t lastkey = 0, mankey = 0; + + UNUSED(type); + UNUSED(rdclass); + + dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); + + dns_name_init(&name, NULL); + + /* + * SvcPriority. + */ + isc_buffer_activeregion(source, ®ion); + if (region.length < 2) { + return (ISC_R_UNEXPECTEDEND); + } + RETERR(mem_tobuffer(target, region.base, 2)); + alias = uint16_fromregion(®ion) == 0; + isc_buffer_forward(source, 2); + + /* + * TargetName. + */ + RETERR(dns_name_fromwire(&name, source, dctx, options, target)); + + if (alias) { + return (ISC_R_SUCCESS); + } + + /* + * SvcParams. + */ + isc_buffer_activeregion(source, ®ion); + while (region.length > 0U) { + isc_region_t keyregion; + uint16_t key, len; + + /* + * SvcParamKey + */ + if (region.length < 2U) { + return (ISC_R_UNEXPECTEDEND); + } + RETERR(mem_tobuffer(target, region.base, 2)); + key = uint16_fromregion(®ion); + isc_region_consume(®ion, 2); + + /* + * Keys must be unique and in order. + */ + if (!first && key <= lastkey) { + return (DNS_R_FORMERR); + } + + /* + * Check mandatory keys. + */ + if (mankey != 0) { + /* Missing mandatory key? */ + if (key > mankey) { + return (DNS_R_FORMERR); + } + if (key == mankey) { + /* Get next mandatory key. */ + if (man.length >= 2) { + mankey = uint16_fromregion(&man); + isc_region_consume(&man, 2); + } else { + mankey = 0; + } + } + } + + first = false; + lastkey = key; + + /* + * SvcParamValue length. + */ + if (region.length < 2U) { + return (ISC_R_UNEXPECTEDEND); + } + RETERR(mem_tobuffer(target, region.base, 2)); + len = uint16_fromregion(®ion); + isc_region_consume(®ion, 2); + + /* + * SvcParamValue. + */ + if (region.length < len) { + return (ISC_R_UNEXPECTEDEND); + } + + /* + * Remember manatory key. + */ + if (key == SVCB_MAN_KEY) { + man = region; + man.length = len; + /* Get first mandatory key */ + if (man.length >= 2) { + mankey = uint16_fromregion(&man); + isc_region_consume(&man, 2); + if (mankey == SVCB_MAN_KEY) { + return (DNS_R_FORMERR); + } + } else { + return (DNS_R_FORMERR); + } + } + keyregion = region; + keyregion.length = len; + RETERR(svcb_validate(key, &keyregion)); + RETERR(mem_tobuffer(target, region.base, len)); + isc_region_consume(®ion, len); + isc_buffer_forward(source, len + 4); + } + + /* + * Do we have an outstanding mandatory key? + */ + if (mankey != 0) { + return (DNS_R_FORMERR); + } + + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +fromwire_in_svcb(ARGS_FROMWIRE) { + REQUIRE(type == dns_rdatatype_svcb); + REQUIRE(rdclass == dns_rdataclass_in); + + return (generic_fromwire_in_svcb(CALL_FROMWIRE)); +} + +static inline isc_result_t +generic_towire_in_svcb(ARGS_TOWIRE) { + dns_name_t name; + dns_offsets_t offsets; + isc_region_t region; + + REQUIRE(rdata->length != 0); + + dns_compress_setmethods(cctx, DNS_COMPRESS_NONE); + + /* + * SvcPriority. + */ + dns_rdata_toregion(rdata, ®ion); + RETERR(mem_tobuffer(target, region.base, 2)); + isc_region_consume(®ion, 2); + + /* + * TargetName. + */ + dns_name_init(&name, offsets); + dns_name_fromregion(&name, ®ion); + RETERR(dns_name_towire(&name, cctx, target)); + isc_region_consume(®ion, name_length(&name)); + + /* + * SvcParams. + */ + return (mem_tobuffer(target, region.base, region.length)); +} + +static inline isc_result_t +towire_in_svcb(ARGS_TOWIRE) { + REQUIRE(rdata->type == dns_rdatatype_svcb); + REQUIRE(rdata->length != 0); + + return (generic_towire_in_svcb(CALL_TOWIRE)); +} + +static inline int +compare_in_svcb(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_svcb); + REQUIRE(rdata1->rdclass == dns_rdataclass_in); + REQUIRE(rdata1->length != 0); + REQUIRE(rdata2->length != 0); + + dns_rdata_toregion(rdata1, ®ion1); + dns_rdata_toregion(rdata2, ®ion2); + + return (isc_region_compare(®ion1, ®ion2)); +} + +static inline isc_result_t +generic_fromstruct_in_svcb(ARGS_FROMSTRUCT) { + dns_rdata_in_svcb_t *svcb = source; + isc_region_t region; + + REQUIRE(svcb != NULL); + REQUIRE(svcb->common.rdtype == type); + REQUIRE(svcb->common.rdclass == rdclass); + + UNUSED(type); + UNUSED(rdclass); + + RETERR(uint16_tobuffer(svcb->priority, target)); + dns_name_toregion(&svcb->svcdomain, ®ion); + RETERR(isc_buffer_copyregion(target, ®ion)); + + return (mem_tobuffer(target, svcb->svc, svcb->svclen)); +} + +static inline isc_result_t +fromstruct_in_svcb(ARGS_FROMSTRUCT) { + dns_rdata_in_svcb_t *svcb = source; + + REQUIRE(type == dns_rdatatype_svcb); + REQUIRE(rdclass == dns_rdataclass_in); + REQUIRE(svcb != NULL); + REQUIRE(svcb->common.rdtype == type); + REQUIRE(svcb->common.rdclass == rdclass); + + return (generic_fromstruct_in_svcb(CALL_FROMSTRUCT)); +} + +static inline isc_result_t +generic_tostruct_in_svcb(ARGS_TOSTRUCT) { + isc_region_t region; + dns_rdata_in_svcb_t *svcb = target; + dns_name_t name; + + REQUIRE(svcb != NULL); + REQUIRE(rdata->length != 0); + + svcb->common.rdclass = rdata->rdclass; + svcb->common.rdtype = rdata->type; + ISC_LINK_INIT(&svcb->common, link); + + dns_rdata_toregion(rdata, ®ion); + + svcb->priority = uint16_fromregion(®ion); + isc_region_consume(®ion, 2); + + dns_name_init(&svcb->svcdomain, NULL); + dns_name_init(&name, NULL); + dns_name_fromregion(&name, ®ion); + isc_region_consume(®ion, name_length(&name)); + + RETERR(name_duporclone(&name, mctx, &svcb->svcdomain)); + svcb->svclen = region.length; + svcb->svc = mem_maybedup(mctx, region.base, region.length); + + if (svcb->svc == NULL) { + if (mctx != NULL) { + dns_name_free(&svcb->svcdomain, svcb->mctx); + } + return (ISC_R_NOMEMORY); + } + + svcb->offset = 0; + svcb->mctx = mctx; + + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +tostruct_in_svcb(ARGS_TOSTRUCT) { + dns_rdata_in_svcb_t *svcb = target; + + REQUIRE(rdata->rdclass == dns_rdataclass_in); + REQUIRE(rdata->type == dns_rdatatype_svcb); + REQUIRE(svcb != NULL); + REQUIRE(rdata->length != 0); + + return (generic_tostruct_in_svcb(CALL_TOSTRUCT)); +} + +static inline void +generic_freestruct_in_svcb(ARGS_FREESTRUCT) { + dns_rdata_in_svcb_t *svcb = source; + + REQUIRE(svcb != NULL); + + if (svcb->mctx == NULL) { + return; + } + + dns_name_free(&svcb->svcdomain, svcb->mctx); + isc_mem_free(svcb->mctx, svcb->svc); + svcb->mctx = NULL; +} + +static inline void +freestruct_in_svcb(ARGS_FREESTRUCT) { + dns_rdata_in_svcb_t *svcb = source; + + REQUIRE(svcb != NULL); + REQUIRE(svcb->common.rdclass == dns_rdataclass_in); + REQUIRE(svcb->common.rdtype == dns_rdatatype_svcb); + + generic_freestruct_in_svcb(CALL_FREESTRUCT); +} + +static inline isc_result_t +generic_additionaldata_in_svcb(ARGS_ADDLDATA) { + UNUSED(rdata); + UNUSED(add); + UNUSED(arg); + + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +additionaldata_in_svcb(ARGS_ADDLDATA) { + REQUIRE(rdata->type == dns_rdatatype_svcb); + REQUIRE(rdata->rdclass == dns_rdataclass_in); + + return (generic_additionaldata_in_svcb(CALL_ADDLDATA)); +} + +static inline isc_result_t +digest_in_svcb(ARGS_DIGEST) { + isc_region_t region1; + + REQUIRE(rdata->type == dns_rdatatype_svcb); + REQUIRE(rdata->rdclass == dns_rdataclass_in); + + dns_rdata_toregion(rdata, ®ion1); + return ((digest)(arg, ®ion1)); +} + +static inline bool +checkowner_in_svcb(ARGS_CHECKOWNER) { + REQUIRE(type == dns_rdatatype_svcb); + REQUIRE(rdclass == dns_rdataclass_in); + + UNUSED(name); + UNUSED(type); + UNUSED(rdclass); + UNUSED(wildcard); + + return (true); +} + +static inline bool +generic_checknames_in_svcb(ARGS_CHECKNAMES) { +#if 0 + isc_region_t region; + dns_name_t name; +#endif + + UNUSED(rdata); + UNUSED(bad); + UNUSED(owner); + +#if 0 + dns_rdata_toregion(rdata, ®ion); + isc_region_consume(®ion, 2); + dns_name_init(&name, NULL); + dns_name_fromregion(&name, ®ion); + if (!dns_name_ishostname(&name, false)) { + if (bad != NULL) { + dns_name_clone(&name, bad); + } + return (false); + } +#endif + return (true); +} + +static inline bool +checknames_in_svcb(ARGS_CHECKNAMES) { + REQUIRE(rdata->type == dns_rdatatype_svcb); + REQUIRE(rdata->rdclass == dns_rdataclass_in); + + return (generic_checknames_in_svcb(CALL_CHECKNAMES)); +} + +static inline int +casecompare_in_svcb(ARGS_COMPARE) { + return (compare_in_svcb(rdata1, rdata2)); +} + +static isc_result_t +generic_rdata_in_svcb_first(dns_rdata_in_svcb_t *svcb) { + if (svcb->svclen == 0) { + return (ISC_R_NOMORE); + } + svcb->offset = 0; + return (ISC_R_SUCCESS); +} + +static isc_result_t +generic_rdata_in_svcb_next(dns_rdata_in_svcb_t *svcb) { + isc_region_t region; + size_t len; + + if (svcb->offset >= svcb->svclen) { + return (ISC_R_NOMORE); + } + + region.base = svcb->svc + svcb->offset; + region.length = svcb->svclen - svcb->offset; + INSIST(region.length >= 4); + isc_region_consume(®ion, 2); + len = uint16_fromregion(®ion); + INSIST(region.length >= len + 2); + svcb->offset += len + 4; + return (svcb->offset >= svcb->svclen ? ISC_R_NOMORE : ISC_R_SUCCESS); +} + +static void +generic_rdata_in_svcb_current(dns_rdata_in_svcb_t *svcb, isc_region_t *region) { + size_t len; + + INSIST(svcb->offset <= svcb->svclen); + + region->base = svcb->svc + svcb->offset; + region->length = svcb->svclen - svcb->offset; + INSIST(region->length >= 4); + isc_region_consume(region, 2); + len = uint16_fromregion(region); + INSIST(region->length >= len + 2); + region->base = svcb->svc + svcb->offset; + region->length = len + 4; +} + +isc_result_t +dns_rdata_in_svcb_first(dns_rdata_in_svcb_t *svcb) { + REQUIRE(svcb != NULL); + REQUIRE(svcb->common.rdtype == dns_rdatatype_svcb); + REQUIRE(svcb->common.rdclass == dns_rdataclass_in); + + return (generic_rdata_in_svcb_first(svcb)); +} + +isc_result_t +dns_rdata_in_svcb_next(dns_rdata_in_svcb_t *svcb) { + REQUIRE(svcb != NULL); + REQUIRE(svcb->common.rdtype == dns_rdatatype_svcb); + REQUIRE(svcb->common.rdclass == dns_rdataclass_in); + + return (generic_rdata_in_svcb_next(svcb)); +} + +void +dns_rdata_in_svcb_current(dns_rdata_in_svcb_t *svcb, isc_region_t *region) { + REQUIRE(svcb != NULL); + REQUIRE(svcb->common.rdtype == dns_rdatatype_svcb); + REQUIRE(svcb->common.rdclass == dns_rdataclass_in); + REQUIRE(region != NULL); + + generic_rdata_in_svcb_current(svcb, region); +} + +#endif /* RDATA_IN_1_SVCB_64_C */ diff --git a/lib/dns/rdata/in_1/svcb_64.h b/lib/dns/rdata/in_1/svcb_64.h new file mode 100644 index 0000000000..750b6820da --- /dev/null +++ b/lib/dns/rdata/in_1/svcb_64.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 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 https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef IN_1_SVCB_64_H +#define IN_1_SVCB_64_H 1 + +/*! + * \brief Per draft-ietf-dnsop-svcb-https-02 + */ + +typedef struct dns_rdata_in_svcb { + dns_rdatacommon_t common; + isc_mem_t *mctx; + uint16_t priority; + dns_name_t svcdomain; + unsigned char *svc; + uint16_t svclen; + uint16_t offset; +} dns_rdata_in_svcb_t; + +isc_result_t +dns_rdata_in_svcb_first(dns_rdata_in_svcb_t *); + +isc_result_t +dns_rdata_in_svcb_next(dns_rdata_in_svcb_t *); + +void +dns_rdata_in_svcb_current(dns_rdata_in_svcb_t *, isc_region_t *); + +#endif /* IN_1_SVCB_64_H */ diff --git a/lib/dns/result.c b/lib/dns/result.c index 1c8641227b..01ce2b4e85 100644 --- a/lib/dns/result.c +++ b/lib/dns/result.c @@ -174,6 +174,7 @@ static const char *text[DNS_R_NRESULTS] = { "cannot use NSEC3 with key algorithm", /*%< 125 DNS_R_NSEC3BADALG */ "NSEC3 resalt", /*%< 126 DNS_R_NSEC3RESALT */ + "inconsistent resource record", /*%< 127 DNS_R_INCONSISTENTRR */ }; static const char *ids[DNS_R_NRESULTS] = { @@ -308,6 +309,7 @@ static const char *ids[DNS_R_NRESULTS] = { "DNS_R_NSEC3SALTRANGE", "DNS_R_NSEC3BADALG", "DNS_R_NSEC3RESALT", + "DNS_R_INCONSISTENTRR", }; static const char *rcode_text[DNS_R_NRCODERESULTS] = { diff --git a/lib/dns/tests/rdata_test.c b/lib/dns/tests/rdata_test.c index 131f7804a7..d520cdbb91 100644 --- a/lib/dns/tests/rdata_test.c +++ b/lib/dns/tests/rdata_test.c @@ -299,7 +299,8 @@ check_struct_conversions(dns_rdata_t *rdata, size_t structsize, assert_memory_equal(buf, rdata->data, rdata->length); /* - * Check that one can walk hip rendezvous servers. + * Check that one can walk hip rendezvous servers and + * https/svcb parameters. */ switch (type) { case dns_rdatatype_hip: { @@ -319,6 +320,38 @@ check_struct_conversions(dns_rdata_t *rdata, size_t structsize, assert_int_equal(count, loop); break; } + case dns_rdatatype_https: { + dns_rdata_in_https_t *https = rdata_struct; + + for (result = dns_rdata_in_https_first(https); + result == ISC_R_SUCCESS; + result = dns_rdata_in_https_next(https)) + { + isc_region_t region; + dns_rdata_in_https_current(https, ®ion); + assert_true(region.length >= 4); + count++; + } + assert_int_equal(result, ISC_R_NOMORE); + assert_int_equal(count, loop); + break; + } + case dns_rdatatype_svcb: { + dns_rdata_in_svcb_t *svcb = rdata_struct; + + for (result = dns_rdata_in_svcb_first(svcb); + result == ISC_R_SUCCESS; + result = dns_rdata_in_svcb_next(svcb)) + { + isc_region_t region; + dns_rdata_in_svcb_current(svcb, ®ion); + assert_true(region.length >= 4); + count++; + } + assert_int_equal(result, ISC_R_NOMORE); + assert_int_equal(count, loop); + break; + } } isc_mem_free(dt_mctx, rdata_struct); @@ -339,6 +372,10 @@ check_text_ok_single(const text_ok_t *text_ok, dns_rdataclass_t rdclass, isc_result_t result; size_t length = 0; + if (debug) { + fprintf(stdout, "#check_text_ok_single(%s)\n", + text_ok->text_in); + } /* * Try converting text form RDATA into uncompressed wire form. */ @@ -350,7 +387,9 @@ check_text_ok_single(const text_ok_t *text_ok, dns_rdataclass_t rdclass, */ if (text_ok->text_out != NULL) { if (debug && result != ISC_R_SUCCESS) { - fprintf(stdout, "#'%s'\n", text_ok->text_in); + fprintf(stdout, "# '%s'\n", text_ok->text_in); + fprintf(stdout, "# result=%s\n", + dns_result_totext(result)); } assert_int_equal(result, ISC_R_SUCCESS); } else { @@ -374,6 +413,18 @@ check_text_ok_single(const text_ok_t *text_ok, dns_rdataclass_t rdclass, */ isc_buffer_init(&target, buf_totext, sizeof(buf_totext)); result = dns_rdata_totext(&rdata, NULL, &target); + if (result != ISC_R_SUCCESS && debug) { + size_t i; + fprintf(stdout, "# dns_rdata_totext -> %s", + dns_result_totext(result)); + for (i = 0; i < rdata.length; i++) { + if ((i % 16) == 0) { + fprintf(stdout, "\n#"); + } + fprintf(stdout, " %02x", rdata.data[i]); + } + fprintf(stdout, "\n"); + } assert_int_equal(result, ISC_R_SUCCESS); /* * Ensure buf_totext is properly NUL terminated as dns_rdata_totext() @@ -387,6 +438,10 @@ check_text_ok_single(const text_ok_t *text_ok, dns_rdataclass_t rdclass, } assert_string_equal(buf_totext, text_ok->text_out); + if (debug) { + fprintf(stdout, "#dns_rdata_totext -> '%s'\n", buf_totext); + } + /* * Ensure that fromtext_*() output is valid input for fromwire_*(). */ @@ -463,6 +518,10 @@ check_text_conversions(dns_rdata_t *rdata) { result = dns_test_rdatafromstring(&rdata2, rdata->rdclass, rdata->type, buf_fromtext, sizeof(buf_fromtext), buf_totext, false); + if (debug && result != ISC_R_SUCCESS) { + fprintf(stdout, "# result = %s\n", dns_result_totext(result)); + fprintf(stdout, "# '%s'\n", buf_fromtext); + } assert_int_equal(result, ISC_R_SUCCESS); assert_int_equal(rdata2.length, rdata->length); assert_memory_equal(buf_fromtext, rdata->data, rdata->length); @@ -2412,6 +2471,186 @@ wks(void **state) { dns_rdatatype_wks, sizeof(dns_rdata_in_wks_t)); } +static void +https_svcb(void **state) { + /* + * Known keys: mandatory, apln, no-default-alpn, port, + * ipv4hint, port, ipv6hint. + */ + text_ok_t text_ok[] = { + /* unknown key invalid */ + TEXT_INVALID("1 . unknown="), + /* no domain */ + TEXT_INVALID("0"), + /* minimal record */ + TEXT_VALID_LOOP(0, "0 ."), + /* Alias form requires SvcFieldValue to be empty */ + TEXT_INVALID("0 . alpn=\"h2\""), + /* no "key" prefix */ + TEXT_INVALID("2 svc.example.net. 0=\"2222\""), + /* no key value */ + TEXT_INVALID("2 svc.example.net. key"), + /* no key value */ + TEXT_INVALID("2 svc.example.net. key=\"2222\""), + /* zero pad invalid */ + TEXT_INVALID("2 svc.example.net. key07=\"2222\""), + TEXT_VALID_LOOP(1, "2 svc.example.net. key7=\"2222\""), + TEXT_VALID_LOOPCHG(1, "2 svc.example.net. key7=2222", + "2 svc.example.net. key7=\"2222\""), + TEXT_VALID_LOOPCHG(1, "2 svc.example.net. alpn=h2", + "2 svc.example.net. alpn=\"h2\""), + TEXT_VALID_LOOPCHG(1, "2 svc.example.net. alpn=h3", + "2 svc.example.net. alpn=\"h3\""), + /* alpn has 2 sub field "h2" and "h3" */ + TEXT_VALID_LOOPCHG(1, "2 svc.example.net. alpn=h2,h3", + "2 svc.example.net. alpn=\"h2,h3\""), + /* apln has 2 sub fields "h1,h2" and "h3" (comma escaped) */ + TEXT_VALID_LOOPCHG(1, "2 svc.example.net. alpn=h1\\\\,h2,h3", + "2 svc.example.net. alpn=\"h1\\\\,h2,h3\""), + TEXT_VALID_LOOP(1, "2 svc.example.net. port=50"), + /* no-default-alpn, alpn is required */ + TEXT_INVALID("2 svc.example.net. no-default-alpn"), + /* no-default-alpn with alpn present */ + TEXT_VALID_LOOPCHG( + 2, "2 svc.example.net. no-default-alpn alpn=h2", + "2 svc.example.net. alpn=\"h2\" no-default-alpn"), + /* empty hint */ + TEXT_INVALID("2 svc.example.net. ipv4hint="), + TEXT_VALID_LOOP(1, "2 svc.example.net. " + "ipv4hint=10.50.0.1,10.50.0.2"), + /* empty hint */ + TEXT_INVALID("2 svc.example.net. ipv6hint="), + TEXT_VALID_LOOP(1, "2 svc.example.net. ipv6hint=::1,2002::1"), + TEXT_VALID_LOOP(1, "2 svc.example.net. ech=abcdefghijkl"), + /* bad base64 */ + TEXT_INVALID("2 svc.example.net. ech=abcdefghijklm"), + TEXT_VALID_LOOP(1, "2 svc.example.net. key7=\"2222\""), + /* Out of key order on input (alpn == key1). */ + TEXT_VALID_LOOPCHG(2, + "2 svc.example.net. key7=\"2222\" alpn=h2", + "2 svc.example.net. alpn=\"h2\" " + "key7=\"2222\""), + TEXT_VALID_LOOP(1, "2 svc.example.net. key65535=\"2222\""), + TEXT_INVALID("2 svc.example.net. key65536=\"2222\""), + TEXT_VALID_LOOP(1, "2 svc.example.net. key10"), + TEXT_VALID_LOOPCHG(1, "2 svc.example.net. key11=", + "2 svc.example.net. key11"), + TEXT_VALID_LOOPCHG(1, "2 svc.example.net. key12=\"\"", + "2 svc.example.net. key12"), + /* empty alpn-id sub fields */ + TEXT_INVALID("2 svc.example.net. alpn"), + TEXT_INVALID("2 svc.example.net. alpn="), + TEXT_INVALID("2 svc.example.net. alpn=,h1"), + TEXT_INVALID("2 svc.example.net. alpn=h1,"), + TEXT_INVALID("2 svc.example.net. alpn=h1,,h2"), + /* mandatory */ + TEXT_VALID_LOOP(2, "2 svc.example.net. mandatory=alpn " + "alpn=\"h2\""), + TEXT_VALID_LOOP(3, "2 svc.example.net. mandatory=alpn,port " + "alpn=\"h2\" port=443"), + TEXT_VALID_LOOPCHG(3, + "2 svc.example.net. mandatory=port,alpn " + "alpn=\"h2\" port=443", + "2 svc.example.net. mandatory=alpn,port " + "alpn=\"h2\" port=443"), + TEXT_INVALID("2 svc.example.net. mandatory=mandatory"), + TEXT_INVALID("2 svc.example.net. mandatory=port"), + TEXT_INVALID("2 svc.example.net. mandatory=,port port=433"), + TEXT_INVALID("2 svc.example.net. mandatory=port, port=433"), + TEXT_INVALID("2 svc.example.net. " + "mandatory=alpn,,port alpn=h2 port=433"), + /* mandatory w/ unknown key values */ + TEXT_VALID_LOOP(2, "2 svc.example.net. mandatory=key7 key7"), + TEXT_VALID_LOOP(3, "2 svc.example.net. mandatory=key7,key8 " + "key7 key8"), + TEXT_VALID_LOOPCHG( + 3, "2 svc.example.net. mandatory=key8,key7 key7 key8", + "2 svc.example.net. mandatory=key7,key8 key7 key8"), + TEXT_INVALID("2 svc.example.net. " + "mandatory=key7,key7"), + TEXT_INVALID("2 svc.example.net. mandatory=,key7"), + TEXT_INVALID("2 svc.example.net. mandatory=key7,"), + TEXT_INVALID("2 svc.example.net. " + "mandatory=key7,,key7"), + TEXT_SENTINEL() + + }; + wire_ok_t wire_ok[] = { + /* + * Too short + */ + WIRE_INVALID(0x00, 0x00), + /* + * Minimal length record. + */ + WIRE_VALID(0x00, 0x00, 0x00), + /* + * Alias with non-empty SvcFieldValue (key7=""). + */ + WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00), + /* + * Bad key7= length (longer than rdata). + */ + WIRE_INVALID(0x00, 0x01, 0x00, 0x00, 0x07, 0x00, 0x01), + /* + * Port (0x03) too small (zero and one octets). + */ + WIRE_INVALID(0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00), + WIRE_INVALID(0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00), + /* Valid port */ + WIRE_VALID_LOOP(1, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x02, + 0x00, 0x00), + /* + * Port (0x03) too big (three octets). + */ + WIRE_INVALID(0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, + 0x00, 0x00), + /* + * Duplicate keys. + */ + WIRE_INVALID(0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00), + /* + * Out of order keys. + */ + WIRE_INVALID(0x01, 0x01, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00), + /* + * Empty of mandatory key list. + */ + WIRE_INVALID(0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00), + /* + * "mandatory=mandatory" is invalid + */ + WIRE_INVALID(0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00), + /* + * Out of order mandatory key list. + */ + WIRE_INVALID(0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x80, 0x00, 0x71, 0x00, 0x71, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00), + /* + * Alpn(0x00 0x01) (length 0x00 0x09) "h1,h2" + "h3" + */ + WIRE_VALID_LOOP(0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x09, + 5, 'h', '1', ',', 'h', '2', 2, 'h', '3'), + /* + * Alpn(0x00 0x01) (length 0x00 0x09) "h1\h2" + "h3" + */ + WIRE_VALID_LOOP(0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x09, + 5, 'h', '1', '\\', 'h', '2', 2, 'h', '3'), + WIRE_SENTINEL() + }; + + UNUSED(state); + + check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in, + dns_rdatatype_svcb, sizeof(dns_rdata_in_svcb_t)); + check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in, + dns_rdatatype_https, sizeof(dns_rdata_in_https_t)); +} + /* * ZONEMD tests. * @@ -2755,18 +2994,18 @@ iszonecutauth(void **state) { int main(int argc, char **argv) { const struct CMUnitTest tests[] = { + /* types */ cmocka_unit_test_setup_teardown(amtrelay, _setup, _teardown), cmocka_unit_test_setup_teardown(apl, _setup, _teardown), cmocka_unit_test_setup_teardown(atma, _setup, _teardown), cmocka_unit_test_setup_teardown(cdnskey, _setup, _teardown), cmocka_unit_test_setup_teardown(csync, _setup, _teardown), - cmocka_unit_test_setup_teardown(doa, _setup, _teardown), cmocka_unit_test_setup_teardown(dnskey, _setup, _teardown), + cmocka_unit_test_setup_teardown(doa, _setup, _teardown), cmocka_unit_test_setup_teardown(ds, _setup, _teardown), cmocka_unit_test_setup_teardown(eid, _setup, _teardown), - cmocka_unit_test_setup_teardown(edns_client_subnet, _setup, - _teardown), cmocka_unit_test_setup_teardown(hip, _setup, _teardown), + cmocka_unit_test_setup_teardown(https_svcb, _setup, _teardown), cmocka_unit_test_setup_teardown(isdn, _setup, _teardown), cmocka_unit_test_setup_teardown(key, _setup, _teardown), cmocka_unit_test_setup_teardown(loc, _setup, _teardown), @@ -2774,10 +3013,13 @@ main(int argc, char **argv) { cmocka_unit_test_setup_teardown(nsec, _setup, _teardown), cmocka_unit_test_setup_teardown(nsec3, _setup, _teardown), cmocka_unit_test_setup_teardown(nxt, _setup, _teardown), + cmocka_unit_test_setup_teardown(rkey, _setup, _teardown), cmocka_unit_test_setup_teardown(sshfp, _setup, _teardown), cmocka_unit_test_setup_teardown(wks, _setup, _teardown), - cmocka_unit_test_setup_teardown(rkey, _setup, _teardown), cmocka_unit_test_setup_teardown(zonemd, _setup, _teardown), + /* other tests */ + cmocka_unit_test_setup_teardown(edns_client_subnet, _setup, + _teardown), cmocka_unit_test_setup_teardown(atcname, NULL, NULL), cmocka_unit_test_setup_teardown(atparent, NULL, NULL), cmocka_unit_test_setup_teardown(iszonecutauth, NULL, NULL), diff --git a/util/copyrights b/util/copyrights index 931e52ee9f..0f4dab432d 100644 --- a/util/copyrights +++ b/util/copyrights @@ -1497,6 +1497,8 @@ ./lib/dns/rdata/in_1/dhcid_49.h C 2006,2007,2016,2018,2019,2020,2021 ./lib/dns/rdata/in_1/eid_31.c C 2018,2019,2020,2021 ./lib/dns/rdata/in_1/eid_31.h C 2018,2019,2020,2021 +./lib/dns/rdata/in_1/https_65.c C 2019,2020,2021 +./lib/dns/rdata/in_1/https_65.h C 2019,2020,2021 ./lib/dns/rdata/in_1/kx_36.c C 1999,2000,2001,2003,2004,2005,2007,2009,2015,2016,2017,2018,2019,2020,2021 ./lib/dns/rdata/in_1/kx_36.h C 1999,2000,2001,2004,2005,2007,2016,2018,2019,2020,2021 ./lib/dns/rdata/in_1/nimloc_32.c C 2018,2019,2020,2021 @@ -1509,6 +1511,8 @@ ./lib/dns/rdata/in_1/px_26.h C 1999,2000,2001,2004,2005,2007,2016,2018,2019,2020,2021 ./lib/dns/rdata/in_1/srv_33.c C 1999,2000,2001,2003,2004,2005,2007,2009,2015,2016,2018,2019,2020,2021 ./lib/dns/rdata/in_1/srv_33.h C 1999,2000,2001,2004,2005,2007,2016,2018,2019,2020,2021 +./lib/dns/rdata/in_1/svcb_64.c C 2019,2020,2021 +./lib/dns/rdata/in_1/svcb_64.h C 2019,2020,2021 ./lib/dns/rdata/in_1/wks_11.c C 1999,2000,2001,2002,2004,2007,2009,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021 ./lib/dns/rdata/in_1/wks_11.h C 1999,2000,2001,2004,2007,2016,2018,2019,2020,2021 ./lib/dns/rdata/rdatastructpre.h C 1999,2000,2001,2004,2007,2016,2018,2019,2020,2021 From 3e459b4808572a17297f10d4ee585816f1f4948f Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Thu, 25 Mar 2021 16:41:33 +1100 Subject: [PATCH 04/12] add text vs unknown test vectors --- lib/dns/tests/rdata_test.c | 121 +++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/lib/dns/tests/rdata_test.c b/lib/dns/tests/rdata_test.c index d520cdbb91..a3a7b2043a 100644 --- a/lib/dns/tests/rdata_test.c +++ b/lib/dns/tests/rdata_test.c @@ -48,6 +48,12 @@ struct compare_ok { }; typedef struct compare_ok compare_ok_t; +struct textvsunknown { + const char *text1; + const char *text2; +}; +typedef struct textvsunknown textvsunknown_t; + static int _setup(void **state) { isc_result_t result; @@ -785,6 +791,64 @@ check_rdata(const text_ok_t *text_ok, const wire_ok_t *wire_ok, } } +/* + * Check presentation vs unknown format of the record. + */ +static void +check_textvsunknown_single(const textvsunknown_t *textvsunknown, + dns_rdataclass_t rdclass, dns_rdatatype_t type) { + dns_rdata_t rdata1 = DNS_RDATA_INIT, rdata2 = DNS_RDATA_INIT; + unsigned char buf1[1024], buf2[1024]; + isc_result_t result; + + result = dns_test_rdatafromstring(&rdata1, rdclass, type, buf1, + sizeof(buf1), textvsunknown->text1, + false); + if (debug && result != ISC_R_SUCCESS) { + fprintf(stdout, "# '%s'\n", textvsunknown->text1); + fprintf(stdout, "# result=%s\n", dns_result_totext(result)); + } + assert_int_equal(result, ISC_R_SUCCESS); + result = dns_test_rdatafromstring(&rdata2, rdclass, type, buf2, + sizeof(buf2), textvsunknown->text2, + false); + if (debug && result != ISC_R_SUCCESS) { + fprintf(stdout, "# '%s'\n", textvsunknown->text2); + fprintf(stdout, "# result=%s\n", dns_result_totext(result)); + } + assert_int_equal(result, ISC_R_SUCCESS); + if (debug && rdata1.length != rdata2.length) { + fprintf(stdout, "# '%s'\n", textvsunknown->text1); + fprintf(stdout, "# rdata1.length (%u) != rdata2.length (%u)\n", + rdata1.length, rdata2.length); + } + assert_int_equal(rdata1.length, rdata2.length); + if (debug && memcmp(rdata1.data, rdata2.data, rdata1.length) != 0) { + unsigned int i; + fprintf(stdout, "# '%s'\n", textvsunknown->text1); + for (i = 0; i < rdata1.length; i++) { + if (rdata1.data[i] != rdata2.data[i]) { + fprintf(stderr, "# %u: %02x != %02x\n", i, + rdata1.data[i], rdata2.data[i]); + } + } + } + assert_memory_equal(rdata1.data, rdata2.data, rdata1.length); +} + +static void +check_textvsunknown(const textvsunknown_t *textvsunknown, + dns_rdataclass_t rdclass, dns_rdatatype_t type) { + size_t i; + + /* + * Check all entries in the supplied array. + */ + for (i = 0; textvsunknown[i].text1 != NULL; i++) { + check_textvsunknown_single(&textvsunknown[i], rdclass, type); + } +} + /* * Common tests for RR types based on KEY that require key data: * @@ -2642,6 +2706,58 @@ https_svcb(void **state) { 5, 'h', '1', '\\', 'h', '2', 2, 'h', '3'), WIRE_SENTINEL() }; + /* Test vectors from RFCXXXX */ + textvsunknown_t textvsunknown[] = { + /* AliasForm */ + { "0 foo.example.com", "\\# 19 ( 00 00 03 66 6f 6f 07 65 78 61 " + "6d 70 6c 65 03 63 6f 6d 00)" }, + /* ServiceForm */ + { "1 .", "\\# 3 ( 00 01 00)" }, + /* Port example */ + { "16 foo.example.com port=53", + "\\# 25 ( 00 10 03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f " + "6d 00 00 03 00 02 00 35 )" }, + /* Unregistered keys with unquoted value. */ + { "1 foo.example.com key667=hello", + "\\# 28 ( 00 01 03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f " + "6d 00 02 9b 00 05 68 65 6c 6c 6f )" }, + /* + * Quoted decimal-escaped character. + * 1 foo.example.com key667="hello\210qoo" + */ + { "1 foo.example.com key667=\"hello\\210qoo\"", + "\\# 32 ( 00 01 03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f " + "6d 00 02 9b 00 09 68 65 6c 6c 6f d2 71 6f 6f )" }, + /* + * IPv6 hints example, quoted. + * 1 foo.example.com ipv6hint="2001:db8::1,2001:db8::53:1" + */ + { "1 foo.example.com ipv6hint=\"2001:db8::1,2001:db8::53:1\"", + "\\# 55 ( 00 01 03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f " + "6d 00 00 06 00 20 20 01 0d b8 00 00 00 00 00 00 00 00 00 00 " + "00 01 20 01 0d b8 00 00 00 00 00 00 00 00 00 53 00 01 )" }, + /* SvcParamValues and mandatory out of order. */ + { "16 foo.example.org alpn=h2,h3-19 mandatory=ipv4hint,alpn " + "ipv4hint=192.0.2.1", + "\\# 48 ( 00 10 03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 6f 72 " + "67 00 00 00 00 04 00 01 00 04 00 01 00 09 02 68 32 05 68 33 " + "2d 31 39 00 04 00 04 c0 00 02 01 )" }, + /* + * Quoted ALPN with escaped comma and backslash. + * 16 foo.example.org alpn="f\\\\oo\\,bar,h2" + */ + { "16 foo.example.org alpn=\"f\\\\\\\\oo\\\\,bar,h2\"", + "\\# 35 ( 00 10 03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 6f 72 " + "67 00 00 01 00 0c 08 66 5c 6f 6f 2c 62 61 72 02 68 32 )" }, + /* + * Unquoted ALPN with escaped comma and backslash. + * 16 foo.example.org alpn=f\\\092oo\092,bar,h2 + */ + { "16 foo.example.org alpn=f\\\\\\092oo\\092,bar,h2", + "\\# 35 ( 00 10 03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 6f 72 " + "67 00 00 01 00 0c 08 66 5c 6f 6f 2c 62 61 72 02 68 32 )" }, + { NULL, NULL } + }; UNUSED(state); @@ -2649,6 +2765,11 @@ https_svcb(void **state) { dns_rdatatype_svcb, sizeof(dns_rdata_in_svcb_t)); check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in, dns_rdatatype_https, sizeof(dns_rdata_in_https_t)); + + check_textvsunknown(textvsunknown, dns_rdataclass_in, + dns_rdatatype_svcb); + check_textvsunknown(textvsunknown, dns_rdataclass_in, + dns_rdatatype_https); } /* From bc210154381afed3eeaf68df9fe6277d0b9b7229 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Thu, 22 Apr 2021 16:18:46 +1000 Subject: [PATCH 05/12] Add invalid test vectors --- lib/dns/tests/rdata_test.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/dns/tests/rdata_test.c b/lib/dns/tests/rdata_test.c index a3a7b2043a..f283c362ba 100644 --- a/lib/dns/tests/rdata_test.c +++ b/lib/dns/tests/rdata_test.c @@ -2636,6 +2636,18 @@ https_svcb(void **state) { TEXT_INVALID("2 svc.example.net. mandatory=key7,"), TEXT_INVALID("2 svc.example.net. " "mandatory=key7,,key7"), + /* Invalid test vectors */ + TEXT_INVALID("1 foo.example.com. ( key123=abc key123=def )"), + TEXT_INVALID("1 foo.example.com. mandatory"), + TEXT_INVALID("1 foo.example.com. alpn"), + TEXT_INVALID("1 foo.example.com. port"), + TEXT_INVALID("1 foo.example.com. ipv4hint"), + TEXT_INVALID("1 foo.example.com. ipv6hint"), + TEXT_INVALID("1 foo.example.com. no-default-alpn=abc"), + TEXT_INVALID("1 foo.example.com. mandatory=key123"), + TEXT_INVALID("1 foo.example.com. mandatory=mandatory"), + TEXT_INVALID("1 foo.example.com. ( mandatory=key123,key123 " + "key123=abc)"), TEXT_SENTINEL() }; From baaa5492eedc8f51efe35ed899e03a389a215fbb Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Mon, 3 Aug 2020 13:27:51 +1000 Subject: [PATCH 06/12] add svcb fuzzing seed --- fuzz/dns_rdata_fromwire_text.in/svcb | Bin 0 -> 39 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 fuzz/dns_rdata_fromwire_text.in/svcb diff --git a/fuzz/dns_rdata_fromwire_text.in/svcb b/fuzz/dns_rdata_fromwire_text.in/svcb new file mode 100644 index 0000000000000000000000000000000000000000..800a616701ec9d143c5a40198a5d33da28d3bed8 GIT binary patch literal 39 pcmZQzVlFOAW>2k1%q_@CWzI`2VE_Ua21W*EAZE%i0@6&38v&=K2I~L- literal 0 HcmV?d00001 From cd985d96e324c5be6300ac84322a8b48f5ede506 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Fri, 5 Jul 2019 16:20:20 +1000 Subject: [PATCH 07/12] Add additional processing to HTTPS and SVBC records The additional processing method has been expanded to take the owner name of the record, as HTTPS and SVBC need it to process "." in service form. The additional section callback can now return the RRset that was added. We use this when adding CNAMEs. Previously, the recursion would stop if it detected that a record you added already exists. With CNAMEs this rule doesn't work, as you ultimately care about the RRset at the target of the CNAME and not the presence of the CNAME itself. Returning the record allows the caller to restart with the target name. As CNAMEs can form loops, loop protection was added. As HTTPS and SVBC can produce infinite chains, we prevent this by tracking recursion depth and stopping if we go too deep. --- .../system/resolver/ns6/example.net.db.in | 11 +++ bin/tests/system/resolver/ns6/named.conf.in | 1 + bin/tests/system/resolver/ns7/named1.conf.in | 1 + bin/tests/system/resolver/ns7/named2.conf.in | 1 + bin/tests/system/resolver/tests.sh | 44 ++++++++++ lib/dns/gen.c | 2 +- lib/dns/include/dns/rdata.h | 4 +- lib/dns/include/dns/rdataset.h | 1 + lib/dns/include/dns/types.h | 3 +- lib/dns/rbtdb.c | 8 +- lib/dns/rdata.c | 13 +-- lib/dns/rdata/any_255/tsig_250.c | 1 + lib/dns/rdata/ch_3/a_1.c | 1 + lib/dns/rdata/generic/afsdb_18.c | 4 +- lib/dns/rdata/generic/amtrelay_260.c | 1 + lib/dns/rdata/generic/avc_258.c | 1 + lib/dns/rdata/generic/caa_257.c | 1 + lib/dns/rdata/generic/cdnskey_60.c | 1 + lib/dns/rdata/generic/cds_59.c | 1 + lib/dns/rdata/generic/cert_37.c | 1 + lib/dns/rdata/generic/cname_5.c | 1 + lib/dns/rdata/generic/csync_62.c | 1 + lib/dns/rdata/generic/dlv_32769.c | 1 + lib/dns/rdata/generic/dname_39.c | 5 +- lib/dns/rdata/generic/dnskey_48.c | 1 + lib/dns/rdata/generic/doa_259.c | 5 +- lib/dns/rdata/generic/ds_43.c | 1 + lib/dns/rdata/generic/eui48_108.c | 1 + lib/dns/rdata/generic/eui64_109.c | 1 + lib/dns/rdata/generic/gpos_27.c | 1 + lib/dns/rdata/generic/hinfo_13.c | 3 +- lib/dns/rdata/generic/hip_55.c | 5 +- lib/dns/rdata/generic/ipseckey_45.c | 1 + lib/dns/rdata/generic/isdn_20.c | 1 + lib/dns/rdata/generic/key_25.c | 1 + lib/dns/rdata/generic/keydata_65533.c | 1 + lib/dns/rdata/generic/l32_105.c | 1 + lib/dns/rdata/generic/l64_106.c | 1 + lib/dns/rdata/generic/loc_29.c | 1 + lib/dns/rdata/generic/lp_107.c | 6 +- lib/dns/rdata/generic/mb_7.c | 4 +- lib/dns/rdata/generic/md_3.c | 4 +- lib/dns/rdata/generic/mf_4.c | 4 +- lib/dns/rdata/generic/mg_8.c | 1 + lib/dns/rdata/generic/minfo_14.c | 1 + lib/dns/rdata/generic/mr_9.c | 1 + lib/dns/rdata/generic/mx_15.c | 7 +- lib/dns/rdata/generic/naptr_35.c | 4 +- lib/dns/rdata/generic/nid_104.c | 1 + lib/dns/rdata/generic/ninfo_56.c | 1 + lib/dns/rdata/generic/ns_2.c | 4 +- lib/dns/rdata/generic/nsec3_50.c | 1 + lib/dns/rdata/generic/nsec3param_51.c | 1 + lib/dns/rdata/generic/nsec_47.c | 1 + lib/dns/rdata/generic/null_10.c | 5 +- lib/dns/rdata/generic/nxt_30.c | 1 + lib/dns/rdata/generic/openpgpkey_61.c | 1 + lib/dns/rdata/generic/opt_41.c | 1 + lib/dns/rdata/generic/proforma.c | 5 +- lib/dns/rdata/generic/ptr_12.c | 1 + lib/dns/rdata/generic/rkey_57.c | 1 + lib/dns/rdata/generic/rp_17.c | 1 + lib/dns/rdata/generic/rrsig_46.c | 1 + lib/dns/rdata/generic/rt_21.c | 8 +- lib/dns/rdata/generic/sig_24.c | 1 + lib/dns/rdata/generic/sink_40.c | 1 + lib/dns/rdata/generic/smimea_53.c | 1 + lib/dns/rdata/generic/soa_6.c | 5 +- lib/dns/rdata/generic/spf_99.c | 1 + lib/dns/rdata/generic/sshfp_44.c | 1 + lib/dns/rdata/generic/ta_32768.c | 1 + lib/dns/rdata/generic/talink_58.c | 5 +- lib/dns/rdata/generic/tkey_249.c | 5 +- lib/dns/rdata/generic/tlsa_52.c | 1 + lib/dns/rdata/generic/txt_16.c | 1 + lib/dns/rdata/generic/uri_256.c | 1 + lib/dns/rdata/generic/x25_19.c | 1 + lib/dns/rdata/generic/zonemd_63.c | 1 + lib/dns/rdata/hs_4/a_1.c | 1 + lib/dns/rdata/in_1/a6_38.c | 1 + lib/dns/rdata/in_1/a_1.c | 1 + lib/dns/rdata/in_1/aaaa_28.c | 1 + lib/dns/rdata/in_1/apl_42.c | 6 +- lib/dns/rdata/in_1/atma_34.c | 1 + lib/dns/rdata/in_1/dhcid_49.c | 1 + lib/dns/rdata/in_1/eid_31.c | 1 + lib/dns/rdata/in_1/https_65.c | 2 +- lib/dns/rdata/in_1/kx_36.c | 4 +- lib/dns/rdata/in_1/nimloc_32.c | 1 + lib/dns/rdata/in_1/nsap-ptr_23.c | 1 + lib/dns/rdata/in_1/nsap_22.c | 1 + lib/dns/rdata/in_1/px_26.c | 1 + lib/dns/rdata/in_1/srv_33.c | 7 +- lib/dns/rdata/in_1/svcb_64.c | 85 +++++++++++++++++-- lib/dns/rdata/in_1/wks_11.c | 9 +- lib/dns/rdataset.c | 3 +- lib/dns/resolver.c | 36 +++++--- lib/dns/tests/rdata_test.c | 7 +- lib/ns/client.c | 1 + lib/ns/include/ns/client.h | 1 + lib/ns/query.c | 31 +++++-- 101 files changed, 349 insertions(+), 80 deletions(-) diff --git a/bin/tests/system/resolver/ns6/example.net.db.in b/bin/tests/system/resolver/ns6/example.net.db.in index eab3267b79..e3699c1889 100644 --- a/bin/tests/system/resolver/ns6/example.net.db.in +++ b/bin/tests/system/resolver/ns6/example.net.db.in @@ -13,6 +13,17 @@ $TTL 600 @ IN MX 0 mail ns IN A 10.53.0.6 mail IN A 10.53.0.6 +www IN HTTPS 0 http-server +http-server IN A 10.53.0.6 +https-loop IN HTTPS 0 https-next +https-loop IN A 10.53.0.6 +https-next IN HTTPS 0 https-loop +https-next IN A 10.53.0.7 +https-cname IN HTTPS 0 cname-server +cname-server IN CNAME cname-next +cname-next IN CNAME http-server +https-cname-loop IN HTTPS 0 https-cname-loop0 +https-cname-loop0 IN CNAME https-cname-loop0 fetch 10 IN TXT A short ttl non-zero 10 IN TXT A short ttl zero 0 IN TXT A zero ttl diff --git a/bin/tests/system/resolver/ns6/named.conf.in b/bin/tests/system/resolver/ns6/named.conf.in index 1726d5fa5b..5c631ae111 100644 --- a/bin/tests/system/resolver/ns6/named.conf.in +++ b/bin/tests/system/resolver/ns6/named.conf.in @@ -28,6 +28,7 @@ options { * has a exclude list. */ root-delegation-only exclude { "a"; }; + max-udp-size 4096; }; zone "." { diff --git a/bin/tests/system/resolver/ns7/named1.conf.in b/bin/tests/system/resolver/ns7/named1.conf.in index 47ce301e86..ec4ade0c51 100644 --- a/bin/tests/system/resolver/ns7/named1.conf.in +++ b/bin/tests/system/resolver/ns7/named1.conf.in @@ -29,6 +29,7 @@ options { */ prefetch 0; querylog yes; + edns-udp-size 4096; }; key rndc_key { diff --git a/bin/tests/system/resolver/ns7/named2.conf.in b/bin/tests/system/resolver/ns7/named2.conf.in index 47ce301e86..ec4ade0c51 100644 --- a/bin/tests/system/resolver/ns7/named2.conf.in +++ b/bin/tests/system/resolver/ns7/named2.conf.in @@ -29,6 +29,7 @@ options { */ prefetch 0; querylog yes; + edns-udp-size 4096; }; key rndc_key { diff --git a/bin/tests/system/resolver/tests.sh b/bin/tests/system/resolver/tests.sh index 435501c2a4..165b196b70 100755 --- a/bin/tests/system/resolver/tests.sh +++ b/bin/tests/system/resolver/tests.sh @@ -845,5 +845,49 @@ grep "status: NXDOMAIN" dig.ns1.out.${n} > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` +n=`expr $n + 1` +echo_i "check that the addition section for HTTPS is populated on initial query to a recursive server ($n)" +ret=0 +$DIG $DIGOPTS @10.53.0.7 www.example.net https > dig.out.ns7.${n} || ret=1 +grep "status: NOERROR" dig.out.ns7.${n} > /dev/null || ret=1 +grep "flags:[^;]* ra[ ;]" dig.out.ns7.${n} > /dev/null || ret=1 +grep "ADDITIONAL: 2" dig.out.ns7.${n} > /dev/null || ret=1 +grep "ANSWER: 1," dig.out.ns7.${n} > /dev/null || ret=1 +grep "http-server\.example\.net\..*A.*10\.53\.0\.6" dig.out.ns7.${n} > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "check HTTPS loop is handled properly ($n)" +ret=0 +$DIG $DIGOPTS @10.53.0.7 https-loop.example.net https > dig.out.ns7.${n} || ret=1 +grep "status: NOERROR" dig.out.ns7.${n} > /dev/null || ret=1 +grep "ANSWER: 1," dig.out.ns7.${n} > /dev/null || ret=1 +grep "ADDITIONAL: 2" dig.out.ns7.${n} > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "check HTTPS -> CNAME loop is handled properly ($n)" +ret=0 +$DIG $DIGOPTS @10.53.0.7 https-cname-loop.example.net https > dig.out.ns7.${n} || ret=1 +grep "status: NOERROR" dig.out.ns7.${n} > /dev/null || ret=1 +grep "ADDITIONAL: 2" dig.out.ns7.${n} > /dev/null || ret=1 +grep "ANSWER: 1," dig.out.ns7.${n} > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "check HTTPS cname chains are followed ($n)" +ret=0 +$DIG $DIGOPTS @10.53.0.7 https-cname.example.net https > dig.out.ns7.${n} || ret=1 +grep "status: NOERROR" dig.out.ns7.${n} > /dev/null || ret=1 +grep "ADDITIONAL: 4" dig.out.ns7.${n} > /dev/null || ret=1 +grep 'http-server\.example\.net\..*A.10\.53\.0\.6' dig.out.ns7.${n} > /dev/null || ret=1 +grep 'cname-server\.example\.net\..*CNAME.cname-next\.example\.net\.' dig.out.ns7.${n} > /dev/null || ret=1 +grep 'cname-next\.example\.net\..*CNAME.http-server\.example\.net\.' dig.out.ns7.${n} > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + echo_i "exit status: $status" [ $status -eq 0 ] || exit 1 diff --git a/lib/dns/gen.c b/lib/dns/gen.c index 2939c175e7..09b877e6ff 100644 --- a/lib/dns/gen.c +++ b/lib/dns/gen.c @@ -78,7 +78,7 @@ #define COMPARETYPE "rdata1->type" #define COMPAREDEF "use_default = true" -#define ADDITIONALDATAARGS "rdata, add, arg" +#define ADDITIONALDATAARGS "rdata, owner, add, arg" #define ADDITIONALDATACLASS "rdata->rdclass" #define ADDITIONALDATATYPE "rdata->type" #define ADDITIONALDATADEF "use_default = true" diff --git a/lib/dns/include/dns/rdata.h b/lib/dns/include/dns/rdata.h index 476ef5f9c7..245b69b29c 100644 --- a/lib/dns/include/dns/rdata.h +++ b/lib/dns/include/dns/rdata.h @@ -594,8 +594,8 @@ dns_rdatatype_isknown(dns_rdatatype_t type); */ isc_result_t -dns_rdata_additionaldata(dns_rdata_t *rdata, dns_additionaldatafunc_t add, - void *arg); +dns_rdata_additionaldata(dns_rdata_t *rdata, const dns_name_t *owner, + dns_additionaldatafunc_t add, void *arg); /*%< * Call 'add' for each name and type from 'rdata' which is subject to * additional section processing. diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h index 2569e40d23..f5a4f2be35 100644 --- a/lib/dns/include/dns/rdataset.h +++ b/lib/dns/include/dns/rdataset.h @@ -439,6 +439,7 @@ dns_rdataset_towirepartial(dns_rdataset_t * rdataset, isc_result_t dns_rdataset_additionaldata(dns_rdataset_t * rdataset, + const dns_name_t * owner_name, dns_additionaldatafunc_t add, void *arg); /*%< * For each rdata in rdataset, call 'add' for each name and type in the diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index 21ced9e4e6..f42bd80cd7 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -396,7 +396,8 @@ typedef isc_result_t (*dns_addrdatasetfunc_t)(void *, const dns_name_t *, dns_rdataset_t *); typedef isc_result_t (*dns_additionaldatafunc_t)(void *, const dns_name_t *, - dns_rdatatype_t); + dns_rdatatype_t, + dns_rdataset_t *); typedef isc_result_t (*dns_digestfunc_t)(void *, isc_region_t *); diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 32355c1398..3b5035ea34 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -10084,7 +10084,8 @@ maybe_rehash_gluetable(rbtdb_version_t *version) { } static isc_result_t -glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { +glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, + dns_rdataset_t *unused) { rbtdb_glue_additionaldata_ctx_t *ctx; isc_result_t result; dns_fixedname_t fixedname_a; @@ -10098,6 +10099,8 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { rbtdb_glue_t *glue = NULL; dns_name_t *gluename = NULL; + UNUSED(unused); + /* * NS records want addresses in additional records. */ @@ -10397,7 +10400,8 @@ no_glue: maybe_rehash_gluetable(rbtversion); idx = hash_32(hash, rbtversion->glue_table_bits); - (void)dns_rdataset_additionaldata(rdataset, glue_nsdname_cb, &ctx); + (void)dns_rdataset_additionaldata(rdataset, dns_rootname, + glue_nsdname_cb, &ctx); cur = isc_mem_get(rbtdb->common.mctx, sizeof(*cur)); diff --git a/lib/dns/rdata.c b/lib/dns/rdata.c index 29e472c266..a655233204 100644 --- a/lib/dns/rdata.c +++ b/lib/dns/rdata.c @@ -29,12 +29,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -118,10 +120,11 @@ #define CALL_FREESTRUCT source -#define ARGS_ADDLDATA \ - dns_rdata_t *rdata, dns_additionaldatafunc_t add, void *arg +#define ARGS_ADDLDATA \ + dns_rdata_t *rdata, const dns_name_t *owner, \ + dns_additionaldatafunc_t add, void *arg -#define CALL_ADDLDATA rdata, add, arg +#define CALL_ADDLDATA rdata, owner, add, arg #define ARGS_DIGEST dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg @@ -1265,8 +1268,8 @@ dns_rdata_freestruct(void *source) { } isc_result_t -dns_rdata_additionaldata(dns_rdata_t *rdata, dns_additionaldatafunc_t add, - void *arg) { +dns_rdata_additionaldata(dns_rdata_t *rdata, const dns_name_t *owner, + dns_additionaldatafunc_t add, void *arg) { isc_result_t result = ISC_R_NOTIMPLEMENTED; bool use_default = false; diff --git a/lib/dns/rdata/any_255/tsig_250.c b/lib/dns/rdata/any_255/tsig_250.c index 0fb1211d13..083bde3345 100644 --- a/lib/dns/rdata/any_255/tsig_250.c +++ b/lib/dns/rdata/any_255/tsig_250.c @@ -567,6 +567,7 @@ additionaldata_any_tsig(ARGS_ADDLDATA) { REQUIRE(rdata->rdclass == dns_rdataclass_any); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/ch_3/a_1.c b/lib/dns/rdata/ch_3/a_1.c index 23163a0e50..0df83160cb 100644 --- a/lib/dns/rdata/ch_3/a_1.c +++ b/lib/dns/rdata/ch_3/a_1.c @@ -261,6 +261,7 @@ additionaldata_ch_a(ARGS_ADDLDATA) { REQUIRE(rdata->rdclass == dns_rdataclass_ch); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/afsdb_18.c b/lib/dns/rdata/generic/afsdb_18.c index 7fe396c7c5..d2b84b7273 100644 --- a/lib/dns/rdata/generic/afsdb_18.c +++ b/lib/dns/rdata/generic/afsdb_18.c @@ -247,12 +247,14 @@ additionaldata_afsdb(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_afsdb); + UNUSED(owner); + dns_name_init(&name, offsets); dns_rdata_toregion(rdata, ®ion); isc_region_consume(®ion, 2); dns_name_fromregion(&name, ®ion); - return ((add)(arg, &name, dns_rdatatype_a)); + return ((add)(arg, &name, dns_rdatatype_a, NULL)); } static inline isc_result_t diff --git a/lib/dns/rdata/generic/amtrelay_260.c b/lib/dns/rdata/generic/amtrelay_260.c index 4e200049de..1cd8d1dd92 100644 --- a/lib/dns/rdata/generic/amtrelay_260.c +++ b/lib/dns/rdata/generic/amtrelay_260.c @@ -395,6 +395,7 @@ additionaldata_amtrelay(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_amtrelay); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/avc_258.c b/lib/dns/rdata/generic/avc_258.c index c269f01e4f..5f3de214be 100644 --- a/lib/dns/rdata/generic/avc_258.c +++ b/lib/dns/rdata/generic/avc_258.c @@ -95,6 +95,7 @@ additionaldata_avc(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_avc); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/caa_257.c b/lib/dns/rdata/generic/caa_257.c index 60c95a5a81..b443aa7d13 100644 --- a/lib/dns/rdata/generic/caa_257.c +++ b/lib/dns/rdata/generic/caa_257.c @@ -572,6 +572,7 @@ additionaldata_caa(ARGS_ADDLDATA) { REQUIRE(rdata->length >= 3U); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/cdnskey_60.c b/lib/dns/rdata/generic/cdnskey_60.c index 2fb006a31a..9eea7d6b8c 100644 --- a/lib/dns/rdata/generic/cdnskey_60.c +++ b/lib/dns/rdata/generic/cdnskey_60.c @@ -108,6 +108,7 @@ additionaldata_cdnskey(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_cdnskey); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/cds_59.c b/lib/dns/rdata/generic/cds_59.c index 56a847be59..26cc70d427 100644 --- a/lib/dns/rdata/generic/cds_59.c +++ b/lib/dns/rdata/generic/cds_59.c @@ -116,6 +116,7 @@ additionaldata_cds(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_cds); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/cert_37.c b/lib/dns/rdata/generic/cert_37.c index 8a171f8a4f..34f5ef7c9f 100644 --- a/lib/dns/rdata/generic/cert_37.c +++ b/lib/dns/rdata/generic/cert_37.c @@ -235,6 +235,7 @@ additionaldata_cert(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_cert); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/cname_5.c b/lib/dns/rdata/generic/cname_5.c index 69c28902fc..aa45ad3713 100644 --- a/lib/dns/rdata/generic/cname_5.c +++ b/lib/dns/rdata/generic/cname_5.c @@ -175,6 +175,7 @@ freestruct_cname(ARGS_FREESTRUCT) { static inline isc_result_t additionaldata_cname(ARGS_ADDLDATA) { UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/csync_62.c b/lib/dns/rdata/generic/csync_62.c index 66c37a6f16..eb41bcb640 100644 --- a/lib/dns/rdata/generic/csync_62.c +++ b/lib/dns/rdata/generic/csync_62.c @@ -214,6 +214,7 @@ additionaldata_csync(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_csync); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/dlv_32769.c b/lib/dns/rdata/generic/dlv_32769.c index 3b996adb1b..21ae76df86 100644 --- a/lib/dns/rdata/generic/dlv_32769.c +++ b/lib/dns/rdata/generic/dlv_32769.c @@ -112,6 +112,7 @@ additionaldata_dlv(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_dlv); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/dname_39.c b/lib/dns/rdata/generic/dname_39.c index 468a6e8a60..6964249b2e 100644 --- a/lib/dns/rdata/generic/dname_39.c +++ b/lib/dns/rdata/generic/dname_39.c @@ -175,12 +175,13 @@ freestruct_dname(ARGS_FREESTRUCT) { static inline isc_result_t additionaldata_dname(ARGS_ADDLDATA) { + REQUIRE(rdata->type == dns_rdatatype_dname); + UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); - REQUIRE(rdata->type == dns_rdatatype_dname); - return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/dnskey_48.c b/lib/dns/rdata/generic/dnskey_48.c index 1aa3f532e4..ca557bf59d 100644 --- a/lib/dns/rdata/generic/dnskey_48.c +++ b/lib/dns/rdata/generic/dnskey_48.c @@ -109,6 +109,7 @@ additionaldata_dnskey(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_dnskey); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/doa_259.c b/lib/dns/rdata/generic/doa_259.c index c8a735b180..5de79296c0 100644 --- a/lib/dns/rdata/generic/doa_259.c +++ b/lib/dns/rdata/generic/doa_259.c @@ -308,12 +308,13 @@ freestruct_doa(ARGS_FREESTRUCT) { static inline isc_result_t additionaldata_doa(ARGS_ADDLDATA) { + REQUIRE(rdata->type == dns_rdatatype_doa); + UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); - REQUIRE(rdata->type == dns_rdatatype_doa); - return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/ds_43.c b/lib/dns/rdata/generic/ds_43.c index bbfd136a68..0b91301c31 100644 --- a/lib/dns/rdata/generic/ds_43.c +++ b/lib/dns/rdata/generic/ds_43.c @@ -335,6 +335,7 @@ additionaldata_ds(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_ds); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/eui48_108.c b/lib/dns/rdata/generic/eui48_108.c index 7be59c2c69..1a9820bbee 100644 --- a/lib/dns/rdata/generic/eui48_108.c +++ b/lib/dns/rdata/generic/eui48_108.c @@ -159,6 +159,7 @@ additionaldata_eui48(ARGS_ADDLDATA) { REQUIRE(rdata->length == 6); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/eui64_109.c b/lib/dns/rdata/generic/eui64_109.c index 381b87bbb8..50220c5199 100644 --- a/lib/dns/rdata/generic/eui64_109.c +++ b/lib/dns/rdata/generic/eui64_109.c @@ -162,6 +162,7 @@ additionaldata_eui64(ARGS_ADDLDATA) { REQUIRE(rdata->length == 8); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/gpos_27.c b/lib/dns/rdata/generic/gpos_27.c index d719fcc5e1..8bdfbdaae1 100644 --- a/lib/dns/rdata/generic/gpos_27.c +++ b/lib/dns/rdata/generic/gpos_27.c @@ -205,6 +205,7 @@ additionaldata_gpos(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_gpos); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/hinfo_13.c b/lib/dns/rdata/generic/hinfo_13.c index 2d5ed3e338..2e8a032bde 100644 --- a/lib/dns/rdata/generic/hinfo_13.c +++ b/lib/dns/rdata/generic/hinfo_13.c @@ -169,9 +169,10 @@ static inline isc_result_t additionaldata_hinfo(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_hinfo); + UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); - UNUSED(rdata); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/hip_55.c b/lib/dns/rdata/generic/hip_55.c index 9ead94ed4b..77d774e37b 100644 --- a/lib/dns/rdata/generic/hip_55.c +++ b/lib/dns/rdata/generic/hip_55.c @@ -379,12 +379,13 @@ freestruct_hip(ARGS_FREESTRUCT) { static inline isc_result_t additionaldata_hip(ARGS_ADDLDATA) { + REQUIRE(rdata->type == dns_rdatatype_hip); + UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); - REQUIRE(rdata->type == dns_rdatatype_hip); - return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/ipseckey_45.c b/lib/dns/rdata/generic/ipseckey_45.c index d93f3e4ab9..5404039216 100644 --- a/lib/dns/rdata/generic/ipseckey_45.c +++ b/lib/dns/rdata/generic/ipseckey_45.c @@ -440,6 +440,7 @@ additionaldata_ipseckey(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_ipseckey); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/isdn_20.c b/lib/dns/rdata/generic/isdn_20.c index 264c7a0724..3054590d7c 100644 --- a/lib/dns/rdata/generic/isdn_20.c +++ b/lib/dns/rdata/generic/isdn_20.c @@ -196,6 +196,7 @@ additionaldata_isdn(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_isdn); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/key_25.c b/lib/dns/rdata/generic/key_25.c index 5867beee35..1351bfdd23 100644 --- a/lib/dns/rdata/generic/key_25.c +++ b/lib/dns/rdata/generic/key_25.c @@ -415,6 +415,7 @@ additionaldata_key(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_key); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/keydata_65533.c b/lib/dns/rdata/generic/keydata_65533.c index 6c78c98a1f..ae8d438e2e 100644 --- a/lib/dns/rdata/generic/keydata_65533.c +++ b/lib/dns/rdata/generic/keydata_65533.c @@ -412,6 +412,7 @@ additionaldata_keydata(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_keydata); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/l32_105.c b/lib/dns/rdata/generic/l32_105.c index b887285eb5..b2f02df646 100644 --- a/lib/dns/rdata/generic/l32_105.c +++ b/lib/dns/rdata/generic/l32_105.c @@ -178,6 +178,7 @@ additionaldata_l32(ARGS_ADDLDATA) { REQUIRE(rdata->length == 6); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/l64_106.c b/lib/dns/rdata/generic/l64_106.c index c225b0f6ef..6ff8fa83bd 100644 --- a/lib/dns/rdata/generic/l64_106.c +++ b/lib/dns/rdata/generic/l64_106.c @@ -172,6 +172,7 @@ additionaldata_l64(ARGS_ADDLDATA) { REQUIRE(rdata->length == 10); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/loc_29.c b/lib/dns/rdata/generic/loc_29.c index 478723ae6c..8c8afc374c 100644 --- a/lib/dns/rdata/generic/loc_29.c +++ b/lib/dns/rdata/generic/loc_29.c @@ -785,6 +785,7 @@ additionaldata_loc(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_loc); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/lp_107.c b/lib/dns/rdata/generic/lp_107.c index ed4cd199e3..7164394aac 100644 --- a/lib/dns/rdata/generic/lp_107.c +++ b/lib/dns/rdata/generic/lp_107.c @@ -193,16 +193,18 @@ additionaldata_lp(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_lp); + UNUSED(owner); + dns_name_init(&name, offsets); dns_rdata_toregion(rdata, ®ion); isc_region_consume(®ion, 2); dns_name_fromregion(&name, ®ion); - result = (add)(arg, &name, dns_rdatatype_l32); + result = (add)(arg, &name, dns_rdatatype_l32, NULL); if (result != ISC_R_SUCCESS) { return (result); } - return ((add)(arg, &name, dns_rdatatype_l64)); + return ((add)(arg, &name, dns_rdatatype_l64, NULL)); } static inline isc_result_t diff --git a/lib/dns/rdata/generic/mb_7.c b/lib/dns/rdata/generic/mb_7.c index 9a037cc7ba..0702fbe490 100644 --- a/lib/dns/rdata/generic/mb_7.c +++ b/lib/dns/rdata/generic/mb_7.c @@ -179,11 +179,13 @@ additionaldata_mb(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_mb); + UNUSED(owner); + dns_name_init(&name, offsets); dns_rdata_toregion(rdata, ®ion); dns_name_fromregion(&name, ®ion); - return ((add)(arg, &name, dns_rdatatype_a)); + return ((add)(arg, &name, dns_rdatatype_a, NULL)); } static inline isc_result_t diff --git a/lib/dns/rdata/generic/md_3.c b/lib/dns/rdata/generic/md_3.c index 78c36f92ef..cff5e91c3c 100644 --- a/lib/dns/rdata/generic/md_3.c +++ b/lib/dns/rdata/generic/md_3.c @@ -180,11 +180,13 @@ additionaldata_md(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_md); + UNUSED(owner); + dns_name_init(&name, offsets); dns_rdata_toregion(rdata, ®ion); dns_name_fromregion(&name, ®ion); - return ((add)(arg, &name, dns_rdatatype_a)); + return ((add)(arg, &name, dns_rdatatype_a, NULL)); } static inline isc_result_t diff --git a/lib/dns/rdata/generic/mf_4.c b/lib/dns/rdata/generic/mf_4.c index 8d2c2b8482..13b63561fe 100644 --- a/lib/dns/rdata/generic/mf_4.c +++ b/lib/dns/rdata/generic/mf_4.c @@ -179,11 +179,13 @@ additionaldata_mf(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_mf); + UNUSED(owner); + dns_name_init(&name, offsets); dns_rdata_toregion(rdata, ®ion); dns_name_fromregion(&name, ®ion); - return ((add)(arg, &name, dns_rdatatype_a)); + return ((add)(arg, &name, dns_rdatatype_a, NULL)); } static inline isc_result_t diff --git a/lib/dns/rdata/generic/mg_8.c b/lib/dns/rdata/generic/mg_8.c index 0b60c90951..efaa0a34be 100644 --- a/lib/dns/rdata/generic/mg_8.c +++ b/lib/dns/rdata/generic/mg_8.c @@ -178,6 +178,7 @@ additionaldata_mg(ARGS_ADDLDATA) { UNUSED(add); UNUSED(arg); UNUSED(rdata); + UNUSED(owner); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/minfo_14.c b/lib/dns/rdata/generic/minfo_14.c index 7394e3f292..62b5897bc6 100644 --- a/lib/dns/rdata/generic/minfo_14.c +++ b/lib/dns/rdata/generic/minfo_14.c @@ -253,6 +253,7 @@ additionaldata_minfo(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_minfo); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/mr_9.c b/lib/dns/rdata/generic/mr_9.c index 295cf6ed1a..6205358313 100644 --- a/lib/dns/rdata/generic/mr_9.c +++ b/lib/dns/rdata/generic/mr_9.c @@ -176,6 +176,7 @@ additionaldata_mr(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_mr); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/mx_15.c b/lib/dns/rdata/generic/mx_15.c index 9bddb45ee0..2b5fe03f54 100644 --- a/lib/dns/rdata/generic/mx_15.c +++ b/lib/dns/rdata/generic/mx_15.c @@ -273,6 +273,8 @@ additionaldata_mx(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_mx); + UNUSED(owner); + dns_name_init(&name, offsets); dns_rdata_toregion(rdata, ®ion); isc_region_consume(®ion, 2); @@ -282,7 +284,7 @@ additionaldata_mx(ARGS_ADDLDATA) { return (ISC_R_SUCCESS); } - result = (add)(arg, &name, dns_rdatatype_a); + result = (add)(arg, &name, dns_rdatatype_a, NULL); if (result != ISC_R_SUCCESS) { return (result); } @@ -294,7 +296,8 @@ additionaldata_mx(ARGS_ADDLDATA) { return (ISC_R_SUCCESS); } - return ((add)(arg, dns_fixedname_name(&fixed), dns_rdatatype_tlsa)); + return ((add)(arg, dns_fixedname_name(&fixed), dns_rdatatype_tlsa, + NULL)); } static inline isc_result_t diff --git a/lib/dns/rdata/generic/naptr_35.c b/lib/dns/rdata/generic/naptr_35.c index 04bb8e05a8..d8de8e9def 100644 --- a/lib/dns/rdata/generic/naptr_35.c +++ b/lib/dns/rdata/generic/naptr_35.c @@ -601,6 +601,8 @@ additionaldata_naptr(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_naptr); + UNUSED(owner); + /* * Order, preference. */ @@ -642,7 +644,7 @@ additionaldata_naptr(ARGS_ADDLDATA) { dns_name_fromregion(&name, &sr); if (atype != 0) { - return ((add)(arg, &name, atype)); + return ((add)(arg, &name, atype, NULL)); } return (ISC_R_SUCCESS); diff --git a/lib/dns/rdata/generic/nid_104.c b/lib/dns/rdata/generic/nid_104.c index d05a42ca30..d8f9afa815 100644 --- a/lib/dns/rdata/generic/nid_104.c +++ b/lib/dns/rdata/generic/nid_104.c @@ -172,6 +172,7 @@ additionaldata_nid(ARGS_ADDLDATA) { REQUIRE(rdata->length == 10); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/ninfo_56.c b/lib/dns/rdata/generic/ninfo_56.c index 0e74d522f0..a14356c0c7 100644 --- a/lib/dns/rdata/generic/ninfo_56.c +++ b/lib/dns/rdata/generic/ninfo_56.c @@ -95,6 +95,7 @@ additionaldata_ninfo(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_ninfo); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/ns_2.c b/lib/dns/rdata/generic/ns_2.c index 45a760c616..21ed02349e 100644 --- a/lib/dns/rdata/generic/ns_2.c +++ b/lib/dns/rdata/generic/ns_2.c @@ -190,11 +190,13 @@ additionaldata_ns(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_ns); + UNUSED(owner); + dns_name_init(&name, offsets); dns_rdata_toregion(rdata, ®ion); dns_name_fromregion(&name, ®ion); - return ((add)(arg, &name, dns_rdatatype_a)); + return ((add)(arg, &name, dns_rdatatype_a, NULL)); } static inline isc_result_t diff --git a/lib/dns/rdata/generic/nsec3_50.c b/lib/dns/rdata/generic/nsec3_50.c index e1eab66d5a..8f62a61533 100644 --- a/lib/dns/rdata/generic/nsec3_50.c +++ b/lib/dns/rdata/generic/nsec3_50.c @@ -362,6 +362,7 @@ additionaldata_nsec3(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_nsec3); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/nsec3param_51.c b/lib/dns/rdata/generic/nsec3param_51.c index 1cc56e5ae2..db3a97413c 100644 --- a/lib/dns/rdata/generic/nsec3param_51.c +++ b/lib/dns/rdata/generic/nsec3param_51.c @@ -272,6 +272,7 @@ additionaldata_nsec3param(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_nsec3param); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/nsec_47.c b/lib/dns/rdata/generic/nsec_47.c index 004d163089..f7e4693c33 100644 --- a/lib/dns/rdata/generic/nsec_47.c +++ b/lib/dns/rdata/generic/nsec_47.c @@ -213,6 +213,7 @@ additionaldata_nsec(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_nsec); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/null_10.c b/lib/dns/rdata/generic/null_10.c index f495d56a72..f13d052e24 100644 --- a/lib/dns/rdata/generic/null_10.c +++ b/lib/dns/rdata/generic/null_10.c @@ -133,12 +133,13 @@ freestruct_null(ARGS_FREESTRUCT) { static inline isc_result_t additionaldata_null(ARGS_ADDLDATA) { + REQUIRE(rdata->type == dns_rdatatype_null); + UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); - REQUIRE(rdata->type == dns_rdatatype_null); - return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/nxt_30.c b/lib/dns/rdata/generic/nxt_30.c index 4065204fe1..d713f0192a 100644 --- a/lib/dns/rdata/generic/nxt_30.c +++ b/lib/dns/rdata/generic/nxt_30.c @@ -292,6 +292,7 @@ additionaldata_nxt(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_nxt); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/openpgpkey_61.c b/lib/dns/rdata/generic/openpgpkey_61.c index 7077eac71d..8c4bec53e4 100644 --- a/lib/dns/rdata/generic/openpgpkey_61.c +++ b/lib/dns/rdata/generic/openpgpkey_61.c @@ -187,6 +187,7 @@ additionaldata_openpgpkey(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_openpgpkey); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/opt_41.c b/lib/dns/rdata/generic/opt_41.c index 7dbb370386..6d6a127eaf 100644 --- a/lib/dns/rdata/generic/opt_41.c +++ b/lib/dns/rdata/generic/opt_41.c @@ -359,6 +359,7 @@ additionaldata_opt(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_opt); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/proforma.c b/lib/dns/rdata/generic/proforma.c index 7913d66162..1db5d9e469 100644 --- a/lib/dns/rdata/generic/proforma.c +++ b/lib/dns/rdata/generic/proforma.c @@ -103,8 +103,9 @@ static inline isc_result_t additionaldata_ #(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_proforma.c #); REQUIRE(rdata->rdclass == #); - (void)add; - (void)arg; + UNUSED(owner); + UNUSED(add); + UNUSED(arg); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/ptr_12.c b/lib/dns/rdata/generic/ptr_12.c index 188676a660..bf689eb7c0 100644 --- a/lib/dns/rdata/generic/ptr_12.c +++ b/lib/dns/rdata/generic/ptr_12.c @@ -190,6 +190,7 @@ additionaldata_ptr(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_ptr); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/rkey_57.c b/lib/dns/rdata/generic/rkey_57.c index 7dd11a29e4..afa294daae 100644 --- a/lib/dns/rdata/generic/rkey_57.c +++ b/lib/dns/rdata/generic/rkey_57.c @@ -105,6 +105,7 @@ additionaldata_rkey(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_rkey); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/rp_17.c b/lib/dns/rdata/generic/rp_17.c index 70c3204d23..a44a2321ed 100644 --- a/lib/dns/rdata/generic/rp_17.c +++ b/lib/dns/rdata/generic/rp_17.c @@ -252,6 +252,7 @@ additionaldata_rp(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_rp); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/rrsig_46.c b/lib/dns/rdata/generic/rrsig_46.c index 40506d7ed6..e6ef8725d1 100644 --- a/lib/dns/rdata/generic/rrsig_46.c +++ b/lib/dns/rdata/generic/rrsig_46.c @@ -536,6 +536,7 @@ additionaldata_rrsig(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_rrsig); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/rt_21.c b/lib/dns/rdata/generic/rt_21.c index e54d02970a..08fb097bf3 100644 --- a/lib/dns/rdata/generic/rt_21.c +++ b/lib/dns/rdata/generic/rt_21.c @@ -241,20 +241,22 @@ additionaldata_rt(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_rt); + UNUSED(owner); + dns_name_init(&name, offsets); dns_rdata_toregion(rdata, ®ion); isc_region_consume(®ion, 2); dns_name_fromregion(&name, ®ion); - result = (add)(arg, &name, dns_rdatatype_x25); + result = (add)(arg, &name, dns_rdatatype_x25, NULL); if (result != ISC_R_SUCCESS) { return (result); } - result = (add)(arg, &name, dns_rdatatype_isdn); + result = (add)(arg, &name, dns_rdatatype_isdn, NULL); if (result != ISC_R_SUCCESS) { return (result); } - return ((add)(arg, &name, dns_rdatatype_a)); + return ((add)(arg, &name, dns_rdatatype_a, NULL)); } static inline isc_result_t diff --git a/lib/dns/rdata/generic/sig_24.c b/lib/dns/rdata/generic/sig_24.c index bfff78c663..fc9279eebe 100644 --- a/lib/dns/rdata/generic/sig_24.c +++ b/lib/dns/rdata/generic/sig_24.c @@ -528,6 +528,7 @@ additionaldata_sig(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_sig); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/sink_40.c b/lib/dns/rdata/generic/sink_40.c index 09bb04fab4..5d85652d9c 100644 --- a/lib/dns/rdata/generic/sink_40.c +++ b/lib/dns/rdata/generic/sink_40.c @@ -242,6 +242,7 @@ additionaldata_sink(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_sink); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/smimea_53.c b/lib/dns/rdata/generic/smimea_53.c index 8871369d9e..dd3894b30d 100644 --- a/lib/dns/rdata/generic/smimea_53.c +++ b/lib/dns/rdata/generic/smimea_53.c @@ -102,6 +102,7 @@ additionaldata_smimea(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_smimea); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/soa_6.c b/lib/dns/rdata/generic/soa_6.c index c30b079b58..c9fbc10afe 100644 --- a/lib/dns/rdata/generic/soa_6.c +++ b/lib/dns/rdata/generic/soa_6.c @@ -370,12 +370,13 @@ freestruct_soa(ARGS_FREESTRUCT) { static inline isc_result_t additionaldata_soa(ARGS_ADDLDATA) { + REQUIRE(rdata->type == dns_rdatatype_soa); + UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); - REQUIRE(rdata->type == dns_rdatatype_soa); - return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/spf_99.c b/lib/dns/rdata/generic/spf_99.c index 4687324e30..29d5c54fa5 100644 --- a/lib/dns/rdata/generic/spf_99.c +++ b/lib/dns/rdata/generic/spf_99.c @@ -96,6 +96,7 @@ additionaldata_spf(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_spf); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/sshfp_44.c b/lib/dns/rdata/generic/sshfp_44.c index 9c604c1380..8c91d8fbcc 100644 --- a/lib/dns/rdata/generic/sshfp_44.c +++ b/lib/dns/rdata/generic/sshfp_44.c @@ -246,6 +246,7 @@ additionaldata_sshfp(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_sshfp); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/ta_32768.c b/lib/dns/rdata/generic/ta_32768.c index 93e095d4ac..69875c36ab 100644 --- a/lib/dns/rdata/generic/ta_32768.c +++ b/lib/dns/rdata/generic/ta_32768.c @@ -112,6 +112,7 @@ additionaldata_ta(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_ta); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/talink_58.c b/lib/dns/rdata/generic/talink_58.c index bf001bc160..1682facae2 100644 --- a/lib/dns/rdata/generic/talink_58.c +++ b/lib/dns/rdata/generic/talink_58.c @@ -216,12 +216,13 @@ freestruct_talink(ARGS_FREESTRUCT) { static inline isc_result_t additionaldata_talink(ARGS_ADDLDATA) { + REQUIRE(rdata->type == dns_rdatatype_talink); + UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); - REQUIRE(rdata->type == dns_rdatatype_talink); - return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/tkey_249.c b/lib/dns/rdata/generic/tkey_249.c index 4eae9d9094..6ba242789d 100644 --- a/lib/dns/rdata/generic/tkey_249.c +++ b/lib/dns/rdata/generic/tkey_249.c @@ -527,12 +527,13 @@ freestruct_tkey(ARGS_FREESTRUCT) { static inline isc_result_t additionaldata_tkey(ARGS_ADDLDATA) { + REQUIRE(rdata->type == dns_rdatatype_tkey); + UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); - REQUIRE(rdata->type == dns_rdatatype_tkey); - return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/tlsa_52.c b/lib/dns/rdata/generic/tlsa_52.c index 97ea972cbc..7ec2aaaa67 100644 --- a/lib/dns/rdata/generic/tlsa_52.c +++ b/lib/dns/rdata/generic/tlsa_52.c @@ -289,6 +289,7 @@ additionaldata_tlsa(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_tlsa); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/txt_16.c b/lib/dns/rdata/generic/txt_16.c index 643fb3dbd7..b0f1c0c9aa 100644 --- a/lib/dns/rdata/generic/txt_16.c +++ b/lib/dns/rdata/generic/txt_16.c @@ -231,6 +231,7 @@ additionaldata_txt(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_txt); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/uri_256.c b/lib/dns/rdata/generic/uri_256.c index ae53d85c4b..b66b583423 100644 --- a/lib/dns/rdata/generic/uri_256.c +++ b/lib/dns/rdata/generic/uri_256.c @@ -268,6 +268,7 @@ additionaldata_uri(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_uri); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/x25_19.c b/lib/dns/rdata/generic/x25_19.c index 0ba32d582f..ec27cecae6 100644 --- a/lib/dns/rdata/generic/x25_19.c +++ b/lib/dns/rdata/generic/x25_19.c @@ -182,6 +182,7 @@ additionaldata_x25(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_x25); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/generic/zonemd_63.c b/lib/dns/rdata/generic/zonemd_63.c index 8bb2478e35..e4dae5548e 100644 --- a/lib/dns/rdata/generic/zonemd_63.c +++ b/lib/dns/rdata/generic/zonemd_63.c @@ -300,6 +300,7 @@ additionaldata_zonemd(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_zonemd); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/hs_4/a_1.c b/lib/dns/rdata/hs_4/a_1.c index 6a4c1a53bf..1df54fc6f6 100644 --- a/lib/dns/rdata/hs_4/a_1.c +++ b/lib/dns/rdata/hs_4/a_1.c @@ -182,6 +182,7 @@ additionaldata_hs_a(ARGS_ADDLDATA) { REQUIRE(rdata->rdclass == dns_rdataclass_hs); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/in_1/a6_38.c b/lib/dns/rdata/in_1/a6_38.c index 377c4ec82f..5828ddb39c 100644 --- a/lib/dns/rdata/in_1/a6_38.c +++ b/lib/dns/rdata/in_1/a6_38.c @@ -401,6 +401,7 @@ additionaldata_in_a6(ARGS_ADDLDATA) { REQUIRE(rdata->rdclass == dns_rdataclass_in); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/in_1/a_1.c b/lib/dns/rdata/in_1/a_1.c index 24e303f257..cf544f0279 100644 --- a/lib/dns/rdata/in_1/a_1.c +++ b/lib/dns/rdata/in_1/a_1.c @@ -186,6 +186,7 @@ additionaldata_in_a(ARGS_ADDLDATA) { REQUIRE(rdata->rdclass == dns_rdataclass_in); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/in_1/aaaa_28.c b/lib/dns/rdata/in_1/aaaa_28.c index d7427a1757..5ac6d649db 100644 --- a/lib/dns/rdata/in_1/aaaa_28.c +++ b/lib/dns/rdata/in_1/aaaa_28.c @@ -198,6 +198,7 @@ additionaldata_in_aaaa(ARGS_ADDLDATA) { REQUIRE(rdata->rdclass == dns_rdataclass_in); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/in_1/apl_42.c b/lib/dns/rdata/in_1/apl_42.c index 50b784c15d..5ba4527b83 100644 --- a/lib/dns/rdata/in_1/apl_42.c +++ b/lib/dns/rdata/in_1/apl_42.c @@ -428,8 +428,10 @@ additionaldata_in_apl(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_apl); REQUIRE(rdata->rdclass == dns_rdataclass_in); - (void)add; - (void)arg; + UNUSED(rdata); + UNUSED(owner); + UNUSED(add); + UNUSED(arg); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/in_1/atma_34.c b/lib/dns/rdata/in_1/atma_34.c index 07a9198e53..11fb203267 100644 --- a/lib/dns/rdata/in_1/atma_34.c +++ b/lib/dns/rdata/in_1/atma_34.c @@ -264,6 +264,7 @@ additionaldata_in_atma(ARGS_ADDLDATA) { REQUIRE(rdata->rdclass == dns_rdataclass_in); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/in_1/dhcid_49.c b/lib/dns/rdata/in_1/dhcid_49.c index 454bf58292..8353e69f10 100644 --- a/lib/dns/rdata/in_1/dhcid_49.c +++ b/lib/dns/rdata/in_1/dhcid_49.c @@ -182,6 +182,7 @@ additionaldata_in_dhcid(ARGS_ADDLDATA) { REQUIRE(rdata->rdclass == dns_rdataclass_in); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/in_1/eid_31.c b/lib/dns/rdata/in_1/eid_31.c index fdab429e50..454ad2d570 100644 --- a/lib/dns/rdata/in_1/eid_31.c +++ b/lib/dns/rdata/in_1/eid_31.c @@ -171,6 +171,7 @@ additionaldata_in_eid(ARGS_ADDLDATA) { REQUIRE(rdata->rdclass == dns_rdataclass_in); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/in_1/https_65.c b/lib/dns/rdata/in_1/https_65.c index 464b58337d..ff562bec6d 100644 --- a/lib/dns/rdata/in_1/https_65.c +++ b/lib/dns/rdata/in_1/https_65.c @@ -14,7 +14,7 @@ #ifndef RDATA_IN_1_HTTPS_65_C #define RDATA_IN_1_HTTPS_65_C -#define RRTYPE_HTTPS_ATTRIBUTES 0 +#define RRTYPE_HTTPS_ATTRIBUTES (DNS_RDATATYPEATTR_FOLLOWADDITIONAL) /* * Most of these functions refer to equivalent functions for SVCB, diff --git a/lib/dns/rdata/in_1/kx_36.c b/lib/dns/rdata/in_1/kx_36.c index 2b47aa919f..bfa8d71771 100644 --- a/lib/dns/rdata/in_1/kx_36.c +++ b/lib/dns/rdata/in_1/kx_36.c @@ -228,12 +228,14 @@ additionaldata_in_kx(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_kx); REQUIRE(rdata->rdclass == dns_rdataclass_in); + UNUSED(owner); + dns_name_init(&name, offsets); dns_rdata_toregion(rdata, ®ion); isc_region_consume(®ion, 2); dns_name_fromregion(&name, ®ion); - return ((add)(arg, &name, dns_rdatatype_a)); + return ((add)(arg, &name, dns_rdatatype_a, NULL)); } static inline isc_result_t diff --git a/lib/dns/rdata/in_1/nimloc_32.c b/lib/dns/rdata/in_1/nimloc_32.c index 751e5a8918..ce4cc5f2af 100644 --- a/lib/dns/rdata/in_1/nimloc_32.c +++ b/lib/dns/rdata/in_1/nimloc_32.c @@ -171,6 +171,7 @@ additionaldata_in_nimloc(ARGS_ADDLDATA) { REQUIRE(rdata->rdclass == dns_rdataclass_in); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/in_1/nsap-ptr_23.c b/lib/dns/rdata/in_1/nsap-ptr_23.c index ea7bd3b6ae..9960ce818c 100644 --- a/lib/dns/rdata/in_1/nsap-ptr_23.c +++ b/lib/dns/rdata/in_1/nsap-ptr_23.c @@ -187,6 +187,7 @@ additionaldata_in_nsap_ptr(ARGS_ADDLDATA) { REQUIRE(rdata->rdclass == dns_rdataclass_in); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/in_1/nsap_22.c b/lib/dns/rdata/in_1/nsap_22.c index fe3361ce51..fa2d3d6d3b 100644 --- a/lib/dns/rdata/in_1/nsap_22.c +++ b/lib/dns/rdata/in_1/nsap_22.c @@ -206,6 +206,7 @@ additionaldata_in_nsap(ARGS_ADDLDATA) { REQUIRE(rdata->rdclass == dns_rdataclass_in); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/in_1/px_26.c b/lib/dns/rdata/in_1/px_26.c index 73d595355e..02faa728bc 100644 --- a/lib/dns/rdata/in_1/px_26.c +++ b/lib/dns/rdata/in_1/px_26.c @@ -308,6 +308,7 @@ additionaldata_in_px(ARGS_ADDLDATA) { REQUIRE(rdata->rdclass == dns_rdataclass_in); UNUSED(rdata); + UNUSED(owner); UNUSED(add); UNUSED(arg); diff --git a/lib/dns/rdata/in_1/srv_33.c b/lib/dns/rdata/in_1/srv_33.c index 80dd1d637c..2a299cedf7 100644 --- a/lib/dns/rdata/in_1/srv_33.c +++ b/lib/dns/rdata/in_1/srv_33.c @@ -313,6 +313,8 @@ additionaldata_in_srv(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_srv); REQUIRE(rdata->rdclass == dns_rdataclass_in); + UNUSED(owner); + dns_name_init(&name, offsets); dns_rdata_toregion(rdata, ®ion); isc_region_consume(®ion, 4); @@ -324,7 +326,7 @@ additionaldata_in_srv(ARGS_ADDLDATA) { return (ISC_R_SUCCESS); } - result = (add)(arg, &name, dns_rdatatype_a); + result = (add)(arg, &name, dns_rdatatype_a, NULL); if (result != ISC_R_SUCCESS) { return (result); } @@ -343,7 +345,8 @@ additionaldata_in_srv(ARGS_ADDLDATA) { return (ISC_R_SUCCESS); } - return ((add)(arg, dns_fixedname_name(&fixed), dns_rdatatype_tlsa)); + return ((add)(arg, dns_fixedname_name(&fixed), dns_rdatatype_tlsa, + NULL)); } static inline isc_result_t diff --git a/lib/dns/rdata/in_1/svcb_64.c b/lib/dns/rdata/in_1/svcb_64.c index 8987094aa3..94679f07ae 100644 --- a/lib/dns/rdata/in_1/svcb_64.c +++ b/lib/dns/rdata/in_1/svcb_64.c @@ -14,11 +14,12 @@ #ifndef RDATA_IN_1_SVCB_64_C #define RDATA_IN_1_SVCB_64_C -#define RRTYPE_SVCB_ATTRIBUTES 0 +#define RRTYPE_SVCB_ATTRIBUTES (DNS_RDATATYPEATTR_FOLLOWADDITIONAL) #define SVCB_MAN_KEY 0 #define SVCB_ALPN_KEY 1 #define SVCB_NO_DEFAULT_ALPN_KEY 2 +#define MAX_CNAMES 16 /* See ns/query.c MAX_RESTARTS */ /* * Service Binding Parameter Registry @@ -1064,11 +1065,85 @@ freestruct_in_svcb(ARGS_FREESTRUCT) { static inline isc_result_t generic_additionaldata_in_svcb(ARGS_ADDLDATA) { - UNUSED(rdata); - UNUSED(add); - UNUSED(arg); + bool alias, done = false; + dns_fixedname_t fixed; + dns_name_t name, *fname = NULL; + dns_offsets_t offsets; + dns_rdataset_t rdataset; + isc_region_t region; + unsigned int cnames = 0; - return (ISC_R_SUCCESS); + dns_name_init(&name, offsets); + dns_rdata_toregion(rdata, ®ion); + alias = uint16_fromregion(®ion) == 0; + isc_region_consume(®ion, 2); + + dns_name_fromregion(&name, ®ion); + + if (dns_name_equal(&name, dns_rootname)) { + /* + * "." only means owner name in service form. + */ + if (alias || dns_name_equal(owner, dns_rootname) || + !dns_name_ishostname(owner, false)) + { + return (ISC_R_SUCCESS); + } + /* Only lookup address records */ + return ((add)(arg, owner, dns_rdatatype_a, NULL)); + } + + /* + * Follow CNAME chains when processing HTTPS and SVCB records. + */ + dns_rdataset_init(&rdataset); + fname = dns_fixedname_initname(&fixed); + do { + RETERR((add)(arg, &name, dns_rdatatype_cname, &rdataset)); + if (dns_rdataset_isassociated(&rdataset)) { + isc_result_t result; + result = dns_rdataset_first(&rdataset); + if (result == ISC_R_SUCCESS) { + dns_rdata_t current = DNS_RDATA_INIT; + dns_rdata_cname_t cname; + + dns_rdataset_current(&rdataset, ¤t); + + result = dns_rdata_tostruct(¤t, &cname, + NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + dns_name_copy(&cname.cname, fname); + dns_name_clone(fname, &name); + } else { + done = true; + } + dns_rdataset_disassociate(&rdataset); + } else { + done = true; + } + /* + * Stop following a potentially infinite CNAME chain. + */ + if (!done && cnames++ > MAX_CNAMES) { + return (ISC_R_SUCCESS); + } + } while (!done); + + /* + * Look up HTTPS/SVCB records when processing the alias form. + */ + if (alias) { + RETERR((add)(arg, &name, rdata->type, &rdataset)); + /* + * Don't return A or AAAA if this is not the last element + * in the HTTP / SVCB chain. + */ + if (dns_rdataset_isassociated(&rdataset)) { + dns_rdataset_disassociate(&rdataset); + return (ISC_R_SUCCESS); + } + } + return ((add)(arg, &name, dns_rdatatype_a, NULL)); } static inline isc_result_t diff --git a/lib/dns/rdata/in_1/wks_11.c b/lib/dns/rdata/in_1/wks_11.c index caa3892b64..b837c55920 100644 --- a/lib/dns/rdata/in_1/wks_11.c +++ b/lib/dns/rdata/in_1/wks_11.c @@ -360,13 +360,14 @@ freestruct_in_wks(ARGS_FREESTRUCT) { static inline isc_result_t additionaldata_in_wks(ARGS_ADDLDATA) { - UNUSED(rdata); - UNUSED(add); - UNUSED(arg); - REQUIRE(rdata->type == dns_rdatatype_wks); REQUIRE(rdata->rdclass == dns_rdataclass_in); + UNUSED(rdata); + UNUSED(owner); + UNUSED(add); + UNUSED(arg); + return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c index 87fda079f9..c51916e7dd 100644 --- a/lib/dns/rdataset.c +++ b/lib/dns/rdataset.c @@ -576,6 +576,7 @@ dns_rdataset_towire(dns_rdataset_t *rdataset, const dns_name_t *owner_name, isc_result_t dns_rdataset_additionaldata(dns_rdataset_t *rdataset, + const dns_name_t *owner_name, dns_additionaldatafunc_t add, void *arg) { dns_rdata_t rdata = DNS_RDATA_INIT; isc_result_t result; @@ -595,7 +596,7 @@ dns_rdataset_additionaldata(dns_rdataset_t *rdataset, do { dns_rdataset_current(rdataset, &rdata); - result = dns_rdata_additionaldata(&rdata, add, arg); + result = dns_rdata_additionaldata(&rdata, owner_name, add, arg); if (result == ISC_R_SUCCESS) { result = dns_rdataset_next(rdataset); } diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index f8b9c4d9a9..0358241d95 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -7026,7 +7026,7 @@ mark_related(dns_name_t *name, dns_rdataset_t *rdataset, bool external, static isc_result_t check_section(void *arg, const dns_name_t *addname, dns_rdatatype_t type, - dns_section_t section) { + dns_rdataset_t *found, dns_section_t section) { respctx_t *rctx = arg; fetchctx_t *fctx = rctx->fctx; isc_result_t result; @@ -7071,6 +7071,9 @@ check_section(void *arg, const dns_name_t *addname, dns_rdatatype_t type, result = dns_message_findtype(name, type, 0, &rdataset); if (result == ISC_R_SUCCESS) { mark_related(name, rdataset, external, gluing); + if (found != NULL) { + dns_rdataset_clone(rdataset, found); + } /* * Do we have its SIG too? */ @@ -7090,8 +7093,10 @@ check_section(void *arg, const dns_name_t *addname, dns_rdatatype_t type, } static isc_result_t -check_related(void *arg, const dns_name_t *addname, dns_rdatatype_t type) { - return (check_section(arg, addname, type, DNS_SECTION_ADDITIONAL)); +check_related(void *arg, const dns_name_t *addname, dns_rdatatype_t type, + dns_rdataset_t *found) { + return (check_section(arg, addname, type, found, + DNS_SECTION_ADDITIONAL)); } #ifndef CHECK_FOR_GLUE_IN_ANSWER @@ -7100,8 +7105,9 @@ check_related(void *arg, const dns_name_t *addname, dns_rdatatype_t type) { #if CHECK_FOR_GLUE_IN_ANSWER static isc_result_t -check_answer(void *arg, const dns_name_t *addname, dns_rdatatype_t type) { - return (check_section(arg, addname, type, DNS_SECTION_ANSWER)); +check_answer(void *arg, const dns_name_t *addname, dns_rdatatype_t type, + dns_rdataset_t *found) { + return (check_section(arg, addname, type, found, DNS_SECTION_ANSWER)); } #endif /* if CHECK_FOR_GLUE_IN_ANSWER */ @@ -8774,8 +8780,8 @@ rctx_answer_any(respctx_t *rctx) { rdataset->attributes |= DNS_RDATASETATTR_CACHE; rdataset->trust = rctx->trust; - (void)dns_rdataset_additionaldata(rdataset, check_related, - rctx); + (void)dns_rdataset_additionaldata(rdataset, rctx->aname, + check_related, rctx); } return (ISC_R_SUCCESS); @@ -8822,7 +8828,8 @@ rctx_answer_match(respctx_t *rctx) { rctx->ardataset->attributes |= DNS_RDATASETATTR_ANSWER; rctx->ardataset->attributes |= DNS_RDATASETATTR_CACHE; rctx->ardataset->trust = rctx->trust; - (void)dns_rdataset_additionaldata(rctx->ardataset, check_related, rctx); + (void)dns_rdataset_additionaldata(rctx->ardataset, rctx->aname, + check_related, rctx); for (sigrdataset = ISC_LIST_HEAD(rctx->aname->list); sigrdataset != NULL; @@ -9030,7 +9037,8 @@ rctx_authority_positive(respctx_t *rctx) { * to this rdataset. */ (void)dns_rdataset_additionaldata( - rdataset, check_related, rctx); + rdataset, name, check_related, + rctx); done = true; } } @@ -9531,8 +9539,8 @@ rctx_referral(respctx_t *rctx) { */ INSIST(rctx->ns_rdataset != NULL); FCTX_ATTR_SET(fctx, FCTX_ATTR_GLUING); - (void)dns_rdataset_additionaldata(rctx->ns_rdataset, check_related, - rctx); + (void)dns_rdataset_additionaldata(rctx->ns_rdataset, rctx->ns_name, + check_related, rctx); #if CHECK_FOR_GLUE_IN_ANSWER /* * Look in the answer section for "glue" that is incorrectly @@ -9544,8 +9552,8 @@ rctx_referral(respctx_t *rctx) { if (rctx->glue_in_answer && (fctx->type == dns_rdatatype_aaaa || fctx->type == dns_rdatatype_a)) { - (void)dns_rdataset_additionaldata(rctx->ns_rdataset, - check_answer, fctx); + (void)dns_rdataset_additionaldata( + rctx->ns_rdataset, rctx->ns_name, check_answer, fctx); } #endif /* if CHECK_FOR_GLUE_IN_ANSWER */ FCTX_ATTR_CLR(fctx, FCTX_ATTR_GLUING); @@ -9655,7 +9663,7 @@ again: if (CHASE(rdataset)) { rdataset->attributes &= ~DNS_RDATASETATTR_CHASE; (void)dns_rdataset_additionaldata( - rdataset, check_related, rctx); + rdataset, name, check_related, rctx); rescan = true; } } diff --git a/lib/dns/tests/rdata_test.c b/lib/dns/tests/rdata_test.c index f283c362ba..5d0fc9cb07 100644 --- a/lib/dns/tests/rdata_test.c +++ b/lib/dns/tests/rdata_test.c @@ -207,10 +207,12 @@ rdata_towire(dns_rdata_t *rdata, unsigned char *dst, size_t dstlen, } static isc_result_t -additionaldata_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { +additionaldata_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, + dns_rdataset_t *found) { UNUSED(arg); UNUSED(name); UNUSED(qtype); + UNUSED(found); return (ISC_R_SUCCESS); } @@ -219,7 +221,8 @@ additionaldata_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { */ static isc_result_t rdata_additionadata(dns_rdata_t *rdata) { - return (dns_rdata_additionaldata(rdata, additionaldata_cb, NULL)); + return (dns_rdata_additionaldata(rdata, dns_rootname, additionaldata_cb, + NULL)); } /* diff --git a/lib/ns/client.c b/lib/ns/client.c index 097733474f..9ba1c89992 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -203,6 +203,7 @@ ns_client_endrequest(ns_client_t *client) { client->udpsize = 512; client->extflags = 0; client->ednsversion = -1; + client->additionaldepth = 0; dns_ecs_init(&client->ecs); dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE); diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h index 974e80dc1b..a99835bd4e 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -195,6 +195,7 @@ struct ns_client { uint16_t udpsize; uint16_t extflags; int16_t ednsversion; /* -1 noedns */ + uint16_t additionaldepth; void (*cleanup)(ns_client_t *); void (*shutdown)(void *arg, isc_result_t result); void * shutdown_arg; diff --git a/lib/ns/query.c b/lib/ns/query.c index 81ff6abfe7..f369c48134 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -1649,7 +1649,8 @@ query_additionalauth(query_ctx_t *qctx, const dns_name_t *name, } static isc_result_t -query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { +query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, + dns_rdataset_t *found) { query_ctx_t *qctx = arg; ns_client_t *client = qctx->client; isc_result_t result, eresult = ISC_R_SUCCESS; @@ -1833,6 +1834,13 @@ found: */ ns_client_keepname(client, fname, dbuf); + /* + * Does the caller want the found rdataset? + */ + if (found != NULL && dns_rdataset_isassociated(rdataset)) { + dns_rdataset_clone(rdataset, found); + } + /* * If we have an rdataset, add it to the additional data * section. @@ -2038,7 +2046,6 @@ addname: dns_message_addname(client->message, fname, DNS_SECTION_ADDITIONAL); } - fname = NULL; /* * In some cases, a record that has been added as additional @@ -2046,10 +2053,18 @@ addname: * This cannot go more than MAX_RESTARTS levels deep. */ if (trdataset != NULL && dns_rdatatype_followadditional(type)) { - eresult = dns_rdataset_additionaldata( - trdataset, query_additional_cb, qctx); + if (client->additionaldepth++ < MAX_RESTARTS) { + eresult = dns_rdataset_additionaldata( + trdataset, fname, query_additional_cb, qctx); + } + client->additionaldepth--; } + /* + * Don't release fname. + */ + fname = NULL; + cleanup: CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: cleanup"); ns_client_putrdataset(client, &rdataset); @@ -2101,7 +2116,8 @@ query_setorder(query_ctx_t *qctx, dns_name_t *name, dns_rdataset_t *rdataset) { * Handle glue and fetch any other needed additional data for 'rdataset'. */ static void -query_additional(query_ctx_t *qctx, dns_rdataset_t *rdataset) { +query_additional(query_ctx_t *qctx, dns_name_t *name, + dns_rdataset_t *rdataset) { ns_client_t *client = qctx->client; isc_result_t result; @@ -2138,7 +2154,8 @@ regular: * Add other additional data if needed. * We don't care if dns_rdataset_additionaldata() fails. */ - (void)dns_rdataset_additionaldata(rdataset, query_additional_cb, qctx); + (void)dns_rdataset_additionaldata(rdataset, name, query_additional_cb, + qctx); CTRACE(ISC_LOG_DEBUG(3), "query_additional: done"); } @@ -2219,7 +2236,7 @@ query_addrrset(query_ctx_t *qctx, dns_name_t **namep, */ query_addtoname(mname, rdataset); query_setorder(qctx, mname, rdataset); - query_additional(qctx, rdataset); + query_additional(qctx, mname, rdataset); /* * Note: we only add SIGs if we've added the type they cover, so From a6357d8b5cad6777b4f887ff85691e87fa7ee470 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Sat, 1 Aug 2020 01:25:37 +1000 Subject: [PATCH 08/12] Add unit test for keypair --- lib/isc/tests/lex_test.c | 112 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/lib/isc/tests/lex_test.c b/lib/isc/tests/lex_test.c index 059d323bf0..a4b27606e5 100644 --- a/lib/isc/tests/lex_test.c +++ b/lib/isc/tests/lex_test.c @@ -29,6 +29,8 @@ #include "isctest.h" +static bool debug = false; + static int _setup(void **state) { isc_result_t result; @@ -119,13 +121,121 @@ lex_setline(void **state) { isc_lex_destroy(&lex); } +/*% + * keypair is =. This has implications double quotes + * in key names. + */ +static void +lex_keypair(void **state) { + isc_buffer_t buf; + isc_lex_t *lex = NULL; + isc_result_t result; + isc_token_t token; + size_t i; + + struct { + const char *text; + const char *value; + isc_result_t result; + isc_tokentype_t type; + } tests[] = { + { "", "", ISC_R_SUCCESS, isc_tokentype_eof }, + { "1234", "1234", ISC_R_SUCCESS, isc_tokentype_string }, + { "1234=", "1234=", ISC_R_SUCCESS, isc_tokentype_vpair }, + { "1234=foo", "1234=foo", ISC_R_SUCCESS, isc_tokentype_vpair }, + { "1234=\"foo", NULL, ISC_R_UNEXPECTEDEND, 0 }, + { "1234=\"foo\"", "1234=foo", ISC_R_SUCCESS, + isc_tokentype_qvpair }, + { "key", "key", ISC_R_SUCCESS, isc_tokentype_string }, + { "\"key=", "\"key=", ISC_R_SUCCESS, isc_tokentype_vpair }, + { "\"key=\"", NULL, ISC_R_UNEXPECTEDEND, 0 }, + { "key=\"\"", "key=", ISC_R_SUCCESS, isc_tokentype_qvpair }, + { "key=\"a b\"", "key=a b", ISC_R_SUCCESS, + isc_tokentype_qvpair }, + { "key=\"a\tb\"", "key=a\tb", ISC_R_SUCCESS, + isc_tokentype_qvpair }, + /* double quote not immediately after '=' is not special. */ + { "key=c\"a b\"", "key=c\"a", ISC_R_SUCCESS, + isc_tokentype_vpair }, + /* remove special meaning for '=' by escaping */ + { "key\\=", "key\\=", ISC_R_SUCCESS, isc_tokentype_string }, + { "key\\=\"a\"", "key\\=\"a\"", ISC_R_SUCCESS, + isc_tokentype_string }, + { "key\\=\"a \"", "key\\=\"a", ISC_R_SUCCESS, + isc_tokentype_string }, + /* vpair with a key of 'key\=' (would need to be deescaped) */ + { "key\\==", "key\\==", ISC_R_SUCCESS, isc_tokentype_vpair }, + /* qvpair with a key of 'key\=' (would need to be deescaped) */ + { "key\\==\"\"", "key\\==", ISC_R_SUCCESS, + isc_tokentype_qvpair }, + }; + + UNUSED(state); + + for (i = 0; i < ARRAY_SIZE(tests); i++) { + result = isc_lex_create(test_mctx, 1024, &lex); + assert_int_equal(result, ISC_R_SUCCESS); + + isc_buffer_constinit(&buf, tests[i].text, + strlen(tests[i].text)); + isc_buffer_add(&buf, strlen(tests[i].text)); + + result = isc_lex_openbuffer(lex, &buf); + assert_int_equal(result, ISC_R_SUCCESS); + + result = isc_lex_setsourceline(lex, 100); + assert_int_equal(result, ISC_R_SUCCESS); + + memset(&token, 0, sizeof(token)); + result = isc_lex_getmastertoken(lex, &token, + isc_tokentype_qvpair, true); + if (debug) { + fprintf(stdout, "# '%s' -> result=%s/%s, type=%u/%u\n", + tests[i].text, isc_result_toid(result), + isc_result_toid(tests[i].result), token.type, + tests[i].type); + } + + assert_int_equal(result, tests[i].result); + if (result == ISC_R_SUCCESS) { + switch (token.type) { + case isc_tokentype_string: + case isc_tokentype_qstring: + case isc_tokentype_vpair: + case isc_tokentype_qvpair: + if (debug) { +#define AS_STR(x) (x).value.as_textregion.base + fprintf(stdout, "# value='%s'\n", + AS_STR(token)); + } + assert_int_equal(token.type, tests[i].type); + assert_string_equal(AS_STR(token), + tests[i].value); + break; + default: + assert_int_equal(token.type, tests[i].type); + break; + } + } + + isc_lex_destroy(&lex); + } +} + int -main(void) { +main(int argc, char *argv[]) { const struct CMUnitTest tests[] = { cmocka_unit_test(lex_0xff), + cmocka_unit_test(lex_keypair), cmocka_unit_test(lex_setline), }; + UNUSED(argv); + + if (argc > 1) { + debug = true; + } + return (cmocka_run_group_tests(tests, _setup, _teardown)); } From 26b22a1445918a46f65467942cd0945dc3f8cdec Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Tue, 4 Aug 2020 00:16:50 +1000 Subject: [PATCH 09/12] add tests for string and qstring --- lib/isc/tests/lex_test.c | 284 +++++++++++++++++++++++++++++++-------- 1 file changed, 231 insertions(+), 53 deletions(-) diff --git a/lib/isc/tests/lex_test.c b/lib/isc/tests/lex_test.c index a4b27606e5..f712d7e276 100644 --- a/lib/isc/tests/lex_test.c +++ b/lib/isc/tests/lex_test.c @@ -29,6 +29,8 @@ #include "isctest.h" +#define AS_STR(x) (x).value.as_textregion.base + static bool debug = false; static int @@ -121,6 +123,217 @@ lex_setline(void **state) { isc_lex_destroy(&lex); } +static struct { + const char *text; + const char *string_value; + isc_result_t string_result; + isc_tokentype_t string_type; + const char *qstring_value; + isc_result_t qstring_result; + isc_tokentype_t qstring_type; + const char *qvpair_value; + isc_result_t qvpair_result; + isc_tokentype_t qvpair_type; +} parse_tests[] = { + { "", "", ISC_R_SUCCESS, isc_tokentype_eof, "", ISC_R_SUCCESS, + isc_tokentype_eof, "", ISC_R_SUCCESS, isc_tokentype_eof }, + { "1234", "1234", ISC_R_SUCCESS, isc_tokentype_string, "1234", + ISC_R_SUCCESS, isc_tokentype_string, "1234", ISC_R_SUCCESS, + isc_tokentype_string }, + { "1234=", "1234=", ISC_R_SUCCESS, isc_tokentype_string, + "1234=", ISC_R_SUCCESS, isc_tokentype_string, "1234=", ISC_R_SUCCESS, + isc_tokentype_vpair }, + { "1234=foo", "1234=foo", ISC_R_SUCCESS, isc_tokentype_string, + "1234=foo", ISC_R_SUCCESS, isc_tokentype_string, "1234=foo", + ISC_R_SUCCESS, isc_tokentype_vpair }, + { "1234=\"foo", "1234=\"foo", ISC_R_SUCCESS, isc_tokentype_string, + "1234=\"foo", ISC_R_SUCCESS, isc_tokentype_string, NULL, + ISC_R_UNEXPECTEDEND, 0 }, + { "1234=\"foo\"", "1234=\"foo\"", ISC_R_SUCCESS, isc_tokentype_string, + "1234=\"foo\"", ISC_R_SUCCESS, isc_tokentype_string, "1234=foo", + ISC_R_SUCCESS, isc_tokentype_qvpair }, + { "key", "key", ISC_R_SUCCESS, isc_tokentype_string, "key", + ISC_R_SUCCESS, isc_tokentype_string, "key", ISC_R_SUCCESS, + isc_tokentype_string }, + { "\"key=", "\"key=", ISC_R_SUCCESS, isc_tokentype_string, NULL, + ISC_R_UNEXPECTEDEND, 0, "\"key=", ISC_R_SUCCESS, + isc_tokentype_vpair }, + { "\"key=\"", "\"key=\"", ISC_R_SUCCESS, isc_tokentype_string, "key=", + ISC_R_SUCCESS, isc_tokentype_qstring, NULL, ISC_R_UNEXPECTEDEND, 0 }, + { "key=\"\"", "key=\"\"", ISC_R_SUCCESS, isc_tokentype_string, + "key=\"\"", ISC_R_SUCCESS, isc_tokentype_string, + "key=", ISC_R_SUCCESS, isc_tokentype_qvpair }, + { "key=\"a b\"", "key=\"a", ISC_R_SUCCESS, isc_tokentype_string, + "key=\"a", ISC_R_SUCCESS, isc_tokentype_string, "key=a b", + ISC_R_SUCCESS, isc_tokentype_qvpair }, + { "key=\"a\tb\"", "key=\"a", ISC_R_SUCCESS, isc_tokentype_string, + "key=\"a", ISC_R_SUCCESS, isc_tokentype_string, "key=a\tb", + ISC_R_SUCCESS, isc_tokentype_qvpair }, + /* double quote not immediately after '=' is not special. */ + { "key=c\"a b\"", "key=c\"a", ISC_R_SUCCESS, isc_tokentype_string, + "key=c\"a", ISC_R_SUCCESS, isc_tokentype_string, "key=c\"a", + ISC_R_SUCCESS, isc_tokentype_vpair }, + /* remove special meaning for '=' by escaping */ + { "key\\=", "key\\=", ISC_R_SUCCESS, isc_tokentype_string, + "key\\=", ISC_R_SUCCESS, isc_tokentype_string, + "key\\=", ISC_R_SUCCESS, isc_tokentype_string }, + { "key\\=\"a\"", "key\\=\"a\"", ISC_R_SUCCESS, isc_tokentype_string, + "key\\=\"a\"", ISC_R_SUCCESS, isc_tokentype_string, "key\\=\"a\"", + ISC_R_SUCCESS, isc_tokentype_string }, + { "key\\=\"a \"", "key\\=\"a", ISC_R_SUCCESS, isc_tokentype_string, + "key\\=\"a", ISC_R_SUCCESS, isc_tokentype_string, "key\\=\"a", + ISC_R_SUCCESS, isc_tokentype_string }, + /* vpair with a key of 'key\=' (would need to be deescaped) */ + { "key\\==", "key\\==", ISC_R_SUCCESS, isc_tokentype_string, + "key\\==", ISC_R_SUCCESS, isc_tokentype_string, + "key\\==", ISC_R_SUCCESS, isc_tokentype_vpair }, + { "key\\==\"\"", "key\\==\"\"", ISC_R_SUCCESS, isc_tokentype_string, + "key\\==\"\"", ISC_R_SUCCESS, isc_tokentype_string, + "key\\==", ISC_R_SUCCESS, isc_tokentype_qvpair }, + { "key=\\\\\\\\", "key=\\\\\\\\", ISC_R_SUCCESS, isc_tokentype_string, + "key=\\\\\\\\", ISC_R_SUCCESS, isc_tokentype_string, "key=\\\\\\\\", + ISC_R_SUCCESS, isc_tokentype_vpair }, + { "key=\\\\\\\"", "key=\\\\\\\"", ISC_R_SUCCESS, isc_tokentype_string, + "key=\\\\\\\"", ISC_R_SUCCESS, isc_tokentype_string, "key=\\\\\\\"", + ISC_R_SUCCESS, isc_tokentype_vpair }, + /* incomplete escape sequence */ + { "key=\\\"\\", NULL, ISC_R_UNEXPECTEDEND, isc_tokentype_string, NULL, + ISC_R_UNEXPECTEDEND, 0, NULL, ISC_R_UNEXPECTEDEND, 0 }, + /* incomplete escape sequence */ + { "key=\\", NULL, ISC_R_UNEXPECTEDEND, isc_tokentype_string, NULL, + ISC_R_UNEXPECTEDEND, 0, NULL, ISC_R_UNEXPECTEDEND, 0 }, +}; + +/*% + * string + */ +static void +lex_string(void **state) { + isc_buffer_t buf; + isc_lex_t *lex = NULL; + isc_result_t result; + isc_token_t token; + size_t i; + + UNUSED(state); + + for (i = 0; i < ARRAY_SIZE(parse_tests); i++) { + result = isc_lex_create(test_mctx, 1024, &lex); + assert_int_equal(result, ISC_R_SUCCESS); + + isc_buffer_constinit(&buf, parse_tests[i].text, + strlen(parse_tests[i].text)); + isc_buffer_add(&buf, strlen(parse_tests[i].text)); + + result = isc_lex_openbuffer(lex, &buf); + assert_int_equal(result, ISC_R_SUCCESS); + + result = isc_lex_setsourceline(lex, 100); + assert_int_equal(result, ISC_R_SUCCESS); + + memset(&token, 0, sizeof(token)); + result = isc_lex_getmastertoken(lex, &token, + isc_tokentype_string, true); + if (debug) { + fprintf(stdout, "# '%s' -> result=%s/%s, type=%u/%u\n", + parse_tests[i].text, isc_result_toid(result), + isc_result_toid(parse_tests[i].string_result), + token.type, parse_tests[i].string_type); + } + + assert_int_equal(result, parse_tests[i].string_result); + if (result == ISC_R_SUCCESS) { + switch (token.type) { + case isc_tokentype_string: + case isc_tokentype_qstring: + case isc_tokentype_vpair: + case isc_tokentype_qvpair: + if (debug) { + fprintf(stdout, "# value='%s'\n", + AS_STR(token)); + } + assert_int_equal(token.type, + parse_tests[i].string_type); + assert_string_equal( + AS_STR(token), + parse_tests[i].string_value); + break; + default: + assert_int_equal(token.type, + parse_tests[i].string_type); + break; + } + } + + isc_lex_destroy(&lex); + } +} + +/*% + * qstring + */ +static void +lex_qstring(void **state) { + isc_buffer_t buf; + isc_lex_t *lex = NULL; + isc_result_t result; + isc_token_t token; + size_t i; + + UNUSED(state); + + for (i = 0; i < ARRAY_SIZE(parse_tests); i++) { + result = isc_lex_create(test_mctx, 1024, &lex); + assert_int_equal(result, ISC_R_SUCCESS); + + isc_buffer_constinit(&buf, parse_tests[i].text, + strlen(parse_tests[i].text)); + isc_buffer_add(&buf, strlen(parse_tests[i].text)); + + result = isc_lex_openbuffer(lex, &buf); + assert_int_equal(result, ISC_R_SUCCESS); + + result = isc_lex_setsourceline(lex, 100); + assert_int_equal(result, ISC_R_SUCCESS); + + memset(&token, 0, sizeof(token)); + result = isc_lex_getmastertoken(lex, &token, + isc_tokentype_qstring, true); + if (debug) { + fprintf(stdout, "# '%s' -> result=%s/%s, type=%u/%u\n", + parse_tests[i].text, isc_result_toid(result), + isc_result_toid(parse_tests[i].qstring_result), + token.type, parse_tests[i].qstring_type); + } + + assert_int_equal(result, parse_tests[i].qstring_result); + if (result == ISC_R_SUCCESS) { + switch (token.type) { + case isc_tokentype_string: + case isc_tokentype_qstring: + case isc_tokentype_vpair: + case isc_tokentype_qvpair: + if (debug) { + fprintf(stdout, "# value='%s'\n", + AS_STR(token)); + } + assert_int_equal(token.type, + parse_tests[i].qstring_type); + assert_string_equal( + AS_STR(token), + parse_tests[i].qstring_value); + break; + default: + assert_int_equal(token.type, + parse_tests[i].qstring_type); + break; + } + } + + isc_lex_destroy(&lex); + } +} + /*% * keypair is =. This has implications double quotes * in key names. @@ -133,52 +346,15 @@ lex_keypair(void **state) { isc_token_t token; size_t i; - struct { - const char *text; - const char *value; - isc_result_t result; - isc_tokentype_t type; - } tests[] = { - { "", "", ISC_R_SUCCESS, isc_tokentype_eof }, - { "1234", "1234", ISC_R_SUCCESS, isc_tokentype_string }, - { "1234=", "1234=", ISC_R_SUCCESS, isc_tokentype_vpair }, - { "1234=foo", "1234=foo", ISC_R_SUCCESS, isc_tokentype_vpair }, - { "1234=\"foo", NULL, ISC_R_UNEXPECTEDEND, 0 }, - { "1234=\"foo\"", "1234=foo", ISC_R_SUCCESS, - isc_tokentype_qvpair }, - { "key", "key", ISC_R_SUCCESS, isc_tokentype_string }, - { "\"key=", "\"key=", ISC_R_SUCCESS, isc_tokentype_vpair }, - { "\"key=\"", NULL, ISC_R_UNEXPECTEDEND, 0 }, - { "key=\"\"", "key=", ISC_R_SUCCESS, isc_tokentype_qvpair }, - { "key=\"a b\"", "key=a b", ISC_R_SUCCESS, - isc_tokentype_qvpair }, - { "key=\"a\tb\"", "key=a\tb", ISC_R_SUCCESS, - isc_tokentype_qvpair }, - /* double quote not immediately after '=' is not special. */ - { "key=c\"a b\"", "key=c\"a", ISC_R_SUCCESS, - isc_tokentype_vpair }, - /* remove special meaning for '=' by escaping */ - { "key\\=", "key\\=", ISC_R_SUCCESS, isc_tokentype_string }, - { "key\\=\"a\"", "key\\=\"a\"", ISC_R_SUCCESS, - isc_tokentype_string }, - { "key\\=\"a \"", "key\\=\"a", ISC_R_SUCCESS, - isc_tokentype_string }, - /* vpair with a key of 'key\=' (would need to be deescaped) */ - { "key\\==", "key\\==", ISC_R_SUCCESS, isc_tokentype_vpair }, - /* qvpair with a key of 'key\=' (would need to be deescaped) */ - { "key\\==\"\"", "key\\==", ISC_R_SUCCESS, - isc_tokentype_qvpair }, - }; - UNUSED(state); - for (i = 0; i < ARRAY_SIZE(tests); i++) { + for (i = 0; i < ARRAY_SIZE(parse_tests); i++) { result = isc_lex_create(test_mctx, 1024, &lex); assert_int_equal(result, ISC_R_SUCCESS); - isc_buffer_constinit(&buf, tests[i].text, - strlen(tests[i].text)); - isc_buffer_add(&buf, strlen(tests[i].text)); + isc_buffer_constinit(&buf, parse_tests[i].text, + strlen(parse_tests[i].text)); + isc_buffer_add(&buf, strlen(parse_tests[i].text)); result = isc_lex_openbuffer(lex, &buf); assert_int_equal(result, ISC_R_SUCCESS); @@ -191,12 +367,12 @@ lex_keypair(void **state) { isc_tokentype_qvpair, true); if (debug) { fprintf(stdout, "# '%s' -> result=%s/%s, type=%u/%u\n", - tests[i].text, isc_result_toid(result), - isc_result_toid(tests[i].result), token.type, - tests[i].type); + parse_tests[i].text, isc_result_toid(result), + isc_result_toid(parse_tests[i].qvpair_result), + token.type, parse_tests[i].qvpair_type); } - assert_int_equal(result, tests[i].result); + assert_int_equal(result, parse_tests[i].qvpair_result); if (result == ISC_R_SUCCESS) { switch (token.type) { case isc_tokentype_string: @@ -204,16 +380,18 @@ lex_keypair(void **state) { case isc_tokentype_vpair: case isc_tokentype_qvpair: if (debug) { -#define AS_STR(x) (x).value.as_textregion.base fprintf(stdout, "# value='%s'\n", AS_STR(token)); } - assert_int_equal(token.type, tests[i].type); - assert_string_equal(AS_STR(token), - tests[i].value); + assert_int_equal(token.type, + parse_tests[i].qvpair_type); + assert_string_equal( + AS_STR(token), + parse_tests[i].qvpair_value); break; default: - assert_int_equal(token.type, tests[i].type); + assert_int_equal(token.type, + parse_tests[i].qvpair_type); break; } } @@ -225,9 +403,9 @@ lex_keypair(void **state) { int main(int argc, char *argv[]) { const struct CMUnitTest tests[] = { - cmocka_unit_test(lex_0xff), - cmocka_unit_test(lex_keypair), - cmocka_unit_test(lex_setline), + cmocka_unit_test(lex_0xff), cmocka_unit_test(lex_keypair), + cmocka_unit_test(lex_setline), cmocka_unit_test(lex_string), + cmocka_unit_test(lex_qstring), }; UNUSED(argv); From f46a0c27df5e503ab5fe1b4750bbd4f24a716332 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Fri, 23 Jul 2021 16:25:43 +1000 Subject: [PATCH 10/12] Check that the hostname of the server is legal --- lib/dns/rdata/in_1/svcb_64.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/lib/dns/rdata/in_1/svcb_64.c b/lib/dns/rdata/in_1/svcb_64.c index 94679f07ae..2af6de074c 100644 --- a/lib/dns/rdata/in_1/svcb_64.c +++ b/lib/dns/rdata/in_1/svcb_64.c @@ -533,9 +533,7 @@ generic_fromtext_in_svcb(ARGS_FROMTEXT) { dns_name_t name; isc_buffer_t buffer; bool alias; -#if 0 bool ok = true; -#endif unsigned int used; UNUSED(type); @@ -565,7 +563,6 @@ generic_fromtext_in_svcb(ARGS_FROMTEXT) { origin = dns_rootname; } RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target)); -#if 0 if (!alias && (options & DNS_RDATA_CHECKNAMES) != 0) { ok = dns_name_ishostname(&name, false); } @@ -575,7 +572,6 @@ generic_fromtext_in_svcb(ARGS_FROMTEXT) { if (!ok && callbacks != NULL) { warn_badname(&name, lexer, callbacks); } -#endif if (alias) { return (ISC_R_SUCCESS); @@ -1180,27 +1176,24 @@ checkowner_in_svcb(ARGS_CHECKOWNER) { static inline bool generic_checknames_in_svcb(ARGS_CHECKNAMES) { -#if 0 isc_region_t region; dns_name_t name; -#endif + bool alias; - UNUSED(rdata); - UNUSED(bad); UNUSED(owner); -#if 0 dns_rdata_toregion(rdata, ®ion); + INSIST(region.length > 1); + alias = uint16_fromregion(®ion) == 0; isc_region_consume(®ion, 2); dns_name_init(&name, NULL); dns_name_fromregion(&name, ®ion); - if (!dns_name_ishostname(&name, false)) { + if (!alias && !dns_name_ishostname(&name, false)) { if (bad != NULL) { dns_name_clone(&name, bad); } return (false); } -#endif return (true); } From f6bfc685aaa70e260820a6b8c3a1a5bc49183d0a Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Mon, 26 Jul 2021 15:43:52 +1000 Subject: [PATCH 11/12] Add check-names for svbc (https) server name examples --- bin/tests/system/checkzone/tests.sh | 2 +- .../system/checkzone/zones/bad-svcb-servername.db | 15 +++++++++++++++ bin/tests/system/checkzone/zones/good-svcb.db | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 bin/tests/system/checkzone/zones/bad-svcb-servername.db diff --git a/bin/tests/system/checkzone/tests.sh b/bin/tests/system/checkzone/tests.sh index 8bab669a50..c9614a4b65 100644 --- a/bin/tests/system/checkzone/tests.sh +++ b/bin/tests/system/checkzone/tests.sh @@ -37,7 +37,7 @@ do echo_i "checking $db ($n)" ret=0 v=0 case $db in - zones/bad-dns-sd-reverse.db) + zones/bad-dns-sd-reverse.db|zones/bad-svcb-servername.db) $CHECKZONE -k fail -i local 0.0.0.0.in-addr.arpa $db > test.out.$n 2>&1 || v=$? ;; *) diff --git a/bin/tests/system/checkzone/zones/bad-svcb-servername.db b/bin/tests/system/checkzone/zones/bad-svcb-servername.db new file mode 100644 index 0000000000..91fc2dfe32 --- /dev/null +++ b/bin/tests/system/checkzone/zones/bad-svcb-servername.db @@ -0,0 +1,15 @@ +; Copyright (C) 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/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 + +svcb SVCB 1 _underscore.example. port=60 alpn=h3 ech="ZWFzdGVyIGVnZyE=" diff --git a/bin/tests/system/checkzone/zones/good-svcb.db b/bin/tests/system/checkzone/zones/good-svcb.db index e94916402c..8b1e4f8a01 100644 --- a/bin/tests/system/checkzone/zones/good-svcb.db +++ b/bin/tests/system/checkzone/zones/good-svcb.db @@ -21,3 +21,4 @@ svcb5 SVCB 5 . key9999="something" svcb6 SVCB 6 . mandatory=port,alpn port=60 alpn=h3 svcb7 SVCB 7 . mandatory=port,alpn port=60 alpn=h1,h3 svcb8 SVCB 8 . mandatory=port,alpn port=60 alpn="h1\\,h2,h3" +svcb9 SVCB 0 44._svbc.example.net. From 8ebb05b0b7c1eea7660051c57f3b92b3ea1eb3bb Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Fri, 17 Jul 2020 12:42:07 +1000 Subject: [PATCH 12/12] Add CHANGES and release notes --- CHANGES | 2 ++ doc/notes/notes-current.rst | 2 ++ 2 files changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index 951e3b68cc..031208f2ff 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,5 @@ +5696. [protocol] Add support for HTTPS and SVCB record types. [GL #1132] + 5695. [func] Dig can now display the BADCOOKIE message as part of processing it (+showbadcookie). [GL #2319] diff --git a/doc/notes/notes-current.rst b/doc/notes/notes-current.rst index b6cee02efe..e17d4ebb8c 100644 --- a/doc/notes/notes-current.rst +++ b/doc/notes/notes-current.rst @@ -35,6 +35,8 @@ New Features parameters to an ``http`` statement. The defaults are 300 and 100 respectively. :gl:`#2809` +- Add support for HTTPS and SVCB record types. :gl:`#1132` + Removed Features ~~~~~~~~~~~~~~~~