From 8fefb27f7671dbea72f12706a73be5d9e232ccc2 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Mon, 8 Jul 2024 14:00:14 +1000 Subject: [PATCH 1/2] Fix yaml output In yaml mode we emit a string for each question and record. Certain names and data could result in invalid yaml being produced. Use single quote string for all questions and records. This requires that single quotes get converted to two quotes within the string. (cherry picked from commit 393d7fa78e7344b515e0d271009e29754980bb36) --- lib/dns/masterdump.c | 75 ++++++++++++++++++++++++++++++++++---------- lib/dns/message.c | 4 +-- 2 files changed, 59 insertions(+), 20 deletions(-) diff --git a/lib/dns/masterdump.c b/lib/dns/masterdump.c index 4946d0d237..69ab7851e5 100644 --- a/lib/dns/masterdump.c +++ b/lib/dns/masterdump.c @@ -475,12 +475,44 @@ str_totext(const char *source, isc_buffer_t *target) { return (ISC_R_SUCCESS); } +static isc_result_t +yaml_stringify(isc_buffer_t *target, char *start) { + isc_region_t r; + char *s = start; + char *tmp = NULL; + + isc_buffer_availableregion(target, &r); + if (r.length < 1) { + return (ISC_R_NOSPACE); + } + + /* NUL terminate buffer for string operations below */ + r.base[0] = '\0'; + + /* Escape quotes in string using quote quote */ + while ((tmp = strchr(s, '\'')) != NULL) { + isc_buffer_availableregion(target, &r); + /* Space to shift by 1 with trailing NUL? */ + if (r.length < 2) { + return (ISC_R_NOSPACE); + } + memmove(tmp + 1, tmp, + (char *)isc_buffer_used(target) - tmp + 1); + isc_buffer_add(target, 1); + /* We now have "''..." - skip both quotes. */ + s = tmp + 2; + } + + return (ISC_R_SUCCESS); +} + static isc_result_t ncache_summary(dns_rdataset_t *rdataset, bool omit_final_dot, dns_totext_ctx_t *ctx, isc_buffer_t *target) { isc_result_t result = ISC_R_SUCCESS; dns_rdataset_t rds; dns_name_t name; + char *start = NULL; dns_rdataset_init(&rds); dns_name_init(&name, NULL); @@ -501,7 +533,8 @@ ncache_summary(dns_rdataset_t *rdataset, bool omit_final_dot, } if ((ctx->style.flags & DNS_STYLEFLAG_YAML) != 0) { - CHECK(str_totext("- ", target)); + CHECK(str_totext("- '", target)); + start = isc_buffer_used(target); } else { CHECK(str_totext("; ", target)); } @@ -512,7 +545,7 @@ ncache_summary(dns_rdataset_t *rdataset, bool omit_final_dot, if (rds.type == dns_rdatatype_rrsig) { CHECK(str_totext(" ", target)); CHECK(dns_rdatatype_totext(rds.covers, target)); - CHECK(str_totext(" ...\n", target)); + CHECK(str_totext(" ...", target)); } else { dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_current(&rds, &rdata); @@ -520,8 +553,12 @@ ncache_summary(dns_rdataset_t *rdataset, bool omit_final_dot, CHECK(dns_rdata_tofmttext(&rdata, dns_rootname, 0, 0, 0, " ", target)); - CHECK(str_totext("\n", target)); } + if (start != NULL) { + RETERR(yaml_stringify(target, start)); + CHECK(str_totext("\'", target)); + } + CHECK(str_totext("\n", target)); } dns_rdataset_disassociate(&rds); result = dns_rdataset_next(rdataset); @@ -559,6 +596,7 @@ rdataset_totext(dns_rdataset_t *rdataset, const dns_name_t *owner_name, dns_fixedname_t fixed; dns_name_t *name = NULL; unsigned int i; + char *start = NULL; REQUIRE(DNS_RDATASET_VALID(rdataset)); @@ -592,7 +630,8 @@ rdataset_totext(dns_rdataset_t *rdataset, const dns_name_t *owner_name, * YAML or comment prefix? */ if ((ctx->style.flags & DNS_STYLEFLAG_YAML) != 0) { - RETERR(str_totext("- ", target)); + RETERR(str_totext("- '", target)); + start = isc_buffer_used(target); } else if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0) { RETERR(str_totext(";", target)); @@ -740,7 +779,6 @@ rdataset_totext(dns_rdataset_t *rdataset, const dns_name_t *owner_name, break; } else { dns_rdata_t rdata = DNS_RDATA_INIT; - isc_region_t r; dns_rdataset_current(rdataset, &rdata); @@ -750,13 +788,12 @@ rdataset_totext(dns_rdataset_t *rdataset, const dns_name_t *owner_name, ctx->style.rdata_column, ctx->style.split_width, ctx->linebreak, target)); - - isc_buffer_availableregion(target, &r); - if (r.length < 1) { - return (ISC_R_NOSPACE); + if (start != NULL) { + RETERR(yaml_stringify(target, start)); + RETERR(str_totext("'\n", target)); + } else { + RETERR(str_totext("\n", target)); } - r.base[0] = '\n'; - isc_buffer_add(target, 1); } first = false; @@ -792,7 +829,7 @@ question_totext(dns_rdataset_t *rdataset, const dns_name_t *owner_name, isc_buffer_t *target) { unsigned int column; isc_result_t result; - isc_region_t r; + char *start = NULL; REQUIRE(DNS_RDATASET_VALID(rdataset)); result = dns_rdataset_first(rdataset); @@ -800,6 +837,11 @@ question_totext(dns_rdataset_t *rdataset, const dns_name_t *owner_name, column = 0; + if ((ctx->style.flags & DNS_STYLEFLAG_YAML) != 0) { + RETERR(str_totext("- '", target)); + start = isc_buffer_used(target); + } + /* Owner name */ { unsigned int name_start = target->used; @@ -842,12 +884,11 @@ question_totext(dns_rdataset_t *rdataset, const dns_name_t *owner_name, column += (target->used - type_start); } - isc_buffer_availableregion(target, &r); - if (r.length < 1) { - return (ISC_R_NOSPACE); + if (start != NULL) { + RETERR(yaml_stringify(target, start)); + RETERR(str_totext("\'", target)); } - r.base[0] = '\n'; - isc_buffer_add(target, 1); + RETERR(str_totext("\n", target)); return (ISC_R_SUCCESS); } diff --git a/lib/dns/message.c b/lib/dns/message.c index 1d3b6fe2d3..213b6f529a 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -3396,9 +3396,7 @@ dns_message_sectiontotext(dns_message_t *msg, dns_section_t section, } if (section == DNS_SECTION_QUESTION) { INDENT(style); - if ((sflags & DNS_STYLEFLAG_YAML) != 0) { - ADD_STRING(target, "- "); - } else { + if ((sflags & DNS_STYLEFLAG_YAML) == 0) { ADD_STRING(target, ";"); } result = dns_master_questiontotext( From 4eb6db47acc981706193fbd1e8e589631adf9696 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Mon, 8 Jul 2024 15:49:48 +1000 Subject: [PATCH 2/2] Test yaml output with yaml specials (cherry picked from commit fadf461761dd20d5175f9eff446cbef37360385d) --- bin/tests/system/digdelv/ns2/example.db.in | 39 +++++++++++++++ bin/tests/system/digdelv/tests.sh | 55 ++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/bin/tests/system/digdelv/ns2/example.db.in b/bin/tests/system/digdelv/ns2/example.db.in index c711049e98..8a88e038cf 100644 --- a/bin/tests/system/digdelv/ns2/example.db.in +++ b/bin/tests/system/digdelv/ns2/example.db.in @@ -49,3 +49,42 @@ hours 10800 A 10.53.0.2 minutes 2700 A 10.53.0.2 ;TTL of 45 seconds seconds 45 A 10.53.0.2 +; domain names with yaml special values and data with ': ' +yaml TXT "a: b" +'.yaml TXT "a: b" +[.yaml TXT "a: b" +{.yaml TXT "a: b" +&.yaml TXT "a: b" +#.yaml TXT "a: b" +all.yaml TXT ( \000 \001 \002 \003 \004 \005 \006 \007 + \008 \009 \010 \011 \012 \013 \014 \015 + \016 \017 \018 \019 \020 \021 \022 \023 + \024 \025 \026 \027 \028 \029 \030 \031 + \032 \033 \034 \035 \036 \037 \038 \039 + \040 \041 \042 \043 \044 \045 \046 \047 + \048 \049 \050 \051 \052 \053 \054 \055 + \056 \057 \058 \059 \060 \061 \062 \063 + \064 \065 \066 \067 \068 \069 \070 \071 + \072 \073 \074 \075 \076 \077 \078 \079 + \080 \081 \082 \083 \084 \085 \086 \087 + \088 \089 \090 \091 \092 \093 \094 \095 + \096 \097 \098 \099 \100 \101 \102 \103 + \104 \105 \106 \107 \108 \109 \110 \111 + \112 \113 \114 \115 \116 \117 \118 \119 + \120 \121 \122 \123 \124 \125 \126 \127 + \128 \129 \130 \131 \132 \133 \134 \135 + \136 \137 \138 \139 \140 \141 \142 \143 + \144 \145 \146 \147 \148 \149 \150 \151 + \152 \153 \154 \155 \156 \157 \158 \159 + \160 \161 \162 \163 \164 \165 \166 \167 + \168 \169 \170 \171 \172 \173 \174 \175 + \176 \177 \178 \179 \180 \181 \182 \183 + \184 \185 \186 \187 \188 \189 \190 \191 + \192 \193 \194 \195 \196 \197 \198 \199 + \200 \201 \202 \203 \204 \205 \206 \207 + \208 \209 \210 \211 \212 \213 \214 \215 + \216 \217 \218 \219 \220 \221 \222 \223 + \224 \225 \226 \227 \228 \229 \230 \231 + \232 \233 \234 \235 \236 \237 \238 \239 + \240 \241 \242 \243 \244 \245 \246 \247 + \248 \249 \250 \251 \252 \253 \254 \255 ) diff --git a/bin/tests/system/digdelv/tests.sh b/bin/tests/system/digdelv/tests.sh index d7393057c4..5b8cfdb902 100644 --- a/bin/tests/system/digdelv/tests.sh +++ b/bin/tests/system/digdelv/tests.sh @@ -1407,5 +1407,60 @@ else echo_i "$DELV is needed, so skipping these delv tests" fi +if [ $HAS_PYYAML -ne 0 ]; then + for qname in "yaml" "'.yaml" "[.yaml" "{.yaml" "&.yaml" "#.yaml"; do + n=$((n + 1)) + echo_i "check yaml special '${yaml}.example' ($n)" + ret=0 + dig_with_opts @10.53.0.3 +yaml "${qname}.example" TXT +qr >dig.out.test$n 2>&1 || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data QUESTION_SECTION 0 >yamlget.out.test$n 2>&1 || ret=1 + read -r value yamlget.out.test$n 2>&1 || ret=1 + read -r value dig.out.test$n 2>&1 || ret=1 + $PYTHON yamlget.py dig.out.test$n 1 message response_message_data ANSWER_SECTION 0 >yamlget.out.test$n 2>&1 || ret=1 + read -r value " "?" "@" "A" "B" "C" "D" "E" "F" "G" "H"' + expected="$expected "'"I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V"' + expected="$expected "'"W" "X" "Y" "Z" "[" "\\" "]" "^" "_" "`" "a" "b" "c" "d"' + expected="$expected "'"e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r"' + expected="$expected "'"s" "t" "u" "v" "w" "x" "y" "z" "{" "|" "}" "~" "\127"' + expected="$expected "'"\128" "\129" "\130" "\131" "\132" "\133" "\134" "\135"' + expected="$expected "'"\136" "\137" "\138" "\139" "\140" "\141" "\142" "\143"' + expected="$expected "'"\144" "\145" "\146" "\147" "\148" "\149" "\150" "\151"' + expected="$expected "'"\152" "\153" "\154" "\155" "\156" "\157" "\158" "\159"' + expected="$expected "'"\160" "\161" "\162" "\163" "\164" "\165" "\166" "\167"' + expected="$expected "'"\168" "\169" "\170" "\171" "\172" "\173" "\174" "\175"' + expected="$expected "'"\176" "\177" "\178" "\179" "\180" "\181" "\182" "\183"' + expected="$expected "'"\184" "\185" "\186" "\187" "\188" "\189" "\190" "\191"' + expected="$expected "'"\192" "\193" "\194" "\195" "\196" "\197" "\198" "\199"' + expected="$expected "'"\200" "\201" "\202" "\203" "\204" "\205" "\206" "\207"' + expected="$expected "'"\208" "\209" "\210" "\211" "\212" "\213" "\214" "\215"' + expected="$expected "'"\216" "\217" "\218" "\219" "\220" "\221" "\222" "\223"' + expected="$expected "'"\224" "\225" "\226" "\227" "\228" "\229" "\230" "\231"' + expected="$expected "'"\232" "\233" "\234" "\235" "\236" "\237" "\238" "\239"' + expected="$expected "'"\240" "\241" "\242" "\243" "\244" "\245" "\246" "\247"' + expected="$expected "'"\248" "\249" "\250" "\251" "\252" "\253" "\254" "\255"' + [ "$value" = "$expected" ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status + ret)) +fi + echo_i "exit status: $status" [ $status -eq 0 ] || exit 1