From 0ec77c2b926314e476eecdcf0837c77b9b592c5a Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Wed, 13 May 2020 14:37:41 +1000 Subject: [PATCH] Add +yaml support for EDE --- bin/tests/system/digdelv/clean.sh | 11 ++-- bin/tests/system/digdelv/tests.sh | 59 +++++++++++++++++++++ lib/dns/message.c | 87 +++++++++++++++++++++++-------- lib/isc/include/isc/util.h | 2 + 4 files changed, 133 insertions(+), 26 deletions(-) diff --git a/bin/tests/system/digdelv/clean.sh b/bin/tests/system/digdelv/clean.sh index 7e0f861086..efac74b923 100644 --- a/bin/tests/system/digdelv/clean.sh +++ b/bin/tests/system/digdelv/clean.sh @@ -11,9 +11,10 @@ set -e +rm -f ./*/anchor.* +rm -f ./*/named.conf rm -f ./*/named.memstats rm -f ./*/named.run -rm -f ./*/named.conf rm -f ./delv.out.test* rm -f ./dig.out.*test* rm -f ./dig.out.mm.* @@ -21,9 +22,9 @@ rm -f ./dig.out.mn.* rm -f ./dig.out.nm.* rm -f ./dig.out.nn.* rm -f ./host.out.test* -rm -f ./nslookup.out.test* -rm -f ./ns*/named.lock rm -f ./ns*/managed-keys.bind* -rm -f ./ns2/example.db ./ns2/K* ./ns2/keyid ./ns2/keydata -rm -f ./*/anchor.* +rm -f ./ns*/named.lock rm -f ./ns2/dsset-example. +rm -f ./ns2/example.db ./ns2/K* ./ns2/keyid ./ns2/keydata +rm -f ./nslookup.out.test* +rm -f ./yamlget.out.* diff --git a/bin/tests/system/digdelv/tests.sh b/bin/tests/system/digdelv/tests.sh index bfb6ccb9c8..66223bdefc 100644 --- a/bin/tests/system/digdelv/tests.sh +++ b/bin/tests/system/digdelv/tests.sh @@ -708,6 +708,65 @@ if [ -x "$DIG" ] ; then if [ $ret -ne 0 ]; then echo_i "failed"; fi status=$((status+ret)) + if [ $HAS_PYYAML -ne 0 ] ; then + n=$((n+1)) + echo_i "check that +yaml Extended DNS Error 0 is printed correctly ($n)" + # First defined EDE code, additional text "foo". + dig_with_opts @10.53.0.3 +yaml +ednsopt=ede:0000666f6f a.example +qr > dig.out.test$n 2>&1 || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE INFO-CODE > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "0 (Other)" ] || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE EXTRA-TEXT > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "foo" ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that +yaml Extended DNS Error 24 is printed correctly ($n)" + # Last defined EDE code, no additional text. + dig_with_opts @10.53.0.3 +yaml +ednsopt=ede:0018 a.example +qr > dig.out.test$n 2>&1 || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE INFO-CODE > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "24 (Invalid Data)" ] || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE EXTRA-TEXT > yamlget.out.test$n 2>&1 && ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that +yaml Extended DNS Error 25 is printed correctly ($n)" + # First undefined EDE code, additional text "foo". + dig_with_opts @10.53.0.3 +yaml +ednsopt=ede:0019666f6f a.example +qr > dig.out.test$n 2>&1 || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE INFO-CODE > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "25" ] || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE EXTRA-TEXT > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "foo" ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that invalid Extended DNS Error (length 0) is printed ($n)" + # EDE payload is too short + dig_with_opts @10.53.0.3 +yaml +ednsopt=ede a.example +qr > dig.out.test$n 2>&1 || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "None" ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that invalid +yaml Extended DNS Error (length 1) is printed ($n)" + # EDE payload is too short + dig_with_opts @10.53.0.3 +yaml +ednsopt=ede:00 a.example +qr > dig.out.test$n 2>&1 || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = '00 (".")' ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + fi + n=$((n+1)) echo_i "check that dig handles malformed option '+ednsopt=:' gracefully ($n)" ret=0 diff --git a/lib/dns/message.c b/lib/dns/message.c index 1448fd1df6..dd9dd23a12 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -3560,6 +3560,7 @@ dns_message_pseudosectiontoyaml(dns_message_t *msg, dns_pseudosection_t section, uint16_t optcode, optlen; size_t saved_count; unsigned char *optdata; + unsigned int indent; REQUIRE(DNS_MESSAGE_VALID(msg)); REQUIRE(target != NULL); @@ -3580,7 +3581,7 @@ dns_message_pseudosectiontoyaml(dns_message_t *msg, dns_pseudosection_t section, INDENT(style); ADD_STRING(target, "EDNS:\n"); - msg->indent.count++; + indent = ++msg->indent.count; INDENT(style); ADD_STRING(target, "version: "); @@ -3626,6 +3627,8 @@ dns_message_pseudosectiontoyaml(dns_message_t *msg, dns_pseudosection_t section, isc_buffer_init(&optbuf, rdata.data, rdata.length); isc_buffer_add(&optbuf, rdata.length); while (isc_buffer_remaininglength(&optbuf) != 0) { + bool extra_text = false; + msg->indent.count = indent; INSIST(isc_buffer_remaininglength(&optbuf) >= 4U); optcode = isc_buffer_getuint16(&optbuf); optlen = isc_buffer_getuint16(&optbuf); @@ -3718,6 +3721,33 @@ dns_message_pseudosectiontoyaml(dns_message_t *msg, dns_pseudosection_t section, ADD_STRING(target, "\n"); continue; } + } else if (optcode == DNS_OPT_EDE) { + INDENT(style); + ADD_STRING(target, "EDE:"); + if (optlen >= 2U) { + uint16_t ede; + ADD_STRING(target, "\n"); + msg->indent.count++; + INDENT(style); + ADD_STRING(target, "INFO-CODE:"); + ede = isc_buffer_getuint16(&optbuf); + snprintf(buf, sizeof(buf), " %u", ede); + ADD_STRING(target, buf); + if (ede < ARRAY_SIZE(edetext)) { + ADD_STRING(target, " ("); + ADD_STRING(target, + edetext[ede]); + ADD_STRING(target, ")"); + } + ADD_STRING(target, "\n"); + optlen -= 2; + if (optlen != 0) { + INDENT(style); + ADD_STRING(target, + "EXTRA-TEXT:"); + extra_text = true; + } + } } else if (optcode == DNS_OPT_CLIENT_TAG) { uint16_t id; INDENT(style); @@ -3751,23 +3781,31 @@ dns_message_pseudosectiontoyaml(dns_message_t *msg, dns_pseudosection_t section, if (optlen != 0) { int i; + bool utf8ok = false; ADD_STRING(target, " "); optdata = isc_buffer_current(&optbuf); - for (i = 0; i < optlen; i++) { - const char *sep; - switch (optcode) { - case DNS_OPT_COOKIE: - sep = ""; - break; - default: - sep = " "; - break; + if (extra_text) { + utf8ok = isc_utf8_valid(optdata, + optlen); + } + if (!utf8ok) { + for (i = 0; i < optlen; i++) { + const char *sep; + switch (optcode) { + case DNS_OPT_COOKIE: + sep = ""; + break; + default: + sep = " "; + break; + } + snprintf(buf, sizeof(buf), + "%02x%s", optdata[i], + sep); + ADD_STRING(target, buf); } - snprintf(buf, sizeof(buf), "%02x%s", - optdata[i], sep); - ADD_STRING(target, buf); } isc_buffer_forward(&optbuf, optlen); @@ -3806,24 +3844,34 @@ dns_message_pseudosectiontoyaml(dns_message_t *msg, dns_pseudosection_t section, * For non-COOKIE options, add a printable * version */ - ADD_STRING(target, "(\""); + if (!extra_text) { + ADD_STRING(target, "(\""); + } else { + ADD_STRING(target, "\""); + } if (isc_buffer_availablelength(target) < optlen) { result = ISC_R_NOSPACE; goto cleanup; } for (i = 0; i < optlen; i++) { - if (isprint(optdata[i])) { + if (isprint(optdata[i]) || + (utf8ok && optdata[i] > 127)) { isc_buffer_putmem( target, &optdata[i], 1); } else { isc_buffer_putstr(target, "."); } } - ADD_STRING(target, "\")"); + if (!extra_text) { + ADD_STRING(target, "\")"); + } else { + ADD_STRING(target, "\""); + } } ADD_STRING(target, "\n"); } + msg->indent.count = indent; result = ISC_R_SUCCESS; goto cleanup; case DNS_PSEUDOSECTION_TSIG: @@ -4038,7 +4086,6 @@ dns_message_pseudosectiontotext(dns_message_t *msg, dns_pseudosection_t section, ede = isc_buffer_getuint16(&optbuf); snprintf(buf, sizeof(buf), " %u", ede); ADD_STRING(target, buf); -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) if (ede < ARRAY_SIZE(edetext)) { ADD_STRING(target, " ("); ADD_STRING(target, @@ -4164,10 +4211,8 @@ dns_message_pseudosectiontotext(dns_message_t *msg, dns_pseudosection_t section, return (ISC_R_NOSPACE); } for (i = 0; i < optlen; i++) { - if (isprint(optdata[i])) { - isc_buffer_putmem( - target, &optdata[i], 1); - } else if (utf8ok && optdata[i] > 127) { + if (isprint(optdata[i]) || + (utf8ok && optdata[i] > 127)) { isc_buffer_putmem( target, &optdata[i], 1); } else { diff --git a/lib/isc/include/isc/util.h b/lib/isc/include/isc/util.h index c87dd750a8..eec94c023d 100644 --- a/lib/isc/include/isc/util.h +++ b/lib/isc/include/isc/util.h @@ -76,6 +76,8 @@ var = _u.v; \ } while (0) +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + /*% * Use this in translation units that would otherwise be empty, to * suppress compiler warnings.