diff --git a/CHANGES b/CHANGES
index 55d38ce9ee..7fe616acff 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+5278. [func] Add YAML output formats for dig, mdig and delv;
+ use the "+yaml" option to enable. [GL #1145]
+
--- 9.15.3 released ---
5277. [bug] Cache DB statistics could underflow when serve-stale
diff --git a/README.md b/README.md
index c5e7d916d9..e49fcd428f 100644
--- a/README.md
+++ b/README.md
@@ -125,6 +125,7 @@ include:
* Support for the new GeoIP2 geolocation API
* Improved DNSSEC key configuration using `dnssec-keys`
+* YAML output for dig, mdig, and delv.
### Building BIND
diff --git a/bin/delv/delv.c b/bin/delv/delv.c
index 0411abc7e4..78e0d15d8d 100644
--- a/bin/delv/delv.c
+++ b/bin/delv/delv.c
@@ -111,7 +111,8 @@ static bool
nottl = false,
multiline = false,
short_form = false,
- print_unknown_format = false;
+ print_unknown_format = false,
+ yaml = false;
static bool
resolve_trace = false,
@@ -353,52 +354,80 @@ setup_logging(FILE *errout) {
static void
print_status(dns_rdataset_t *rdataset) {
- const char *astr = "", *tstr = "";
+ char buf[1024] = { 0 };
REQUIRE(rdataset != NULL);
- if (!showtrust || !dns_rdataset_isassociated(rdataset))
+ if (!showtrust || !dns_rdataset_isassociated(rdataset)) {
return;
+ }
- if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
- astr = "negative response, ";
+ buf[0] = '\0';
+
+ if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
+ strlcat(buf, "negative response", sizeof(buf));
+ strlcat(buf, (yaml ? "_" : ", "), sizeof(buf));
+ }
switch (rdataset->trust) {
case dns_trust_none:
- tstr = "untrusted";
+ strlcat(buf, "untrusted", sizeof(buf));
break;
case dns_trust_pending_additional:
- tstr = "signed additional data, pending validation";
+ strlcat(buf, "signed additional data", sizeof(buf));
+ if (!yaml) {
+ strlcat(buf, ", ", sizeof(buf));
+ }
+ strlcat(buf, "pending validation", sizeof(buf));
break;
case dns_trust_pending_answer:
- tstr = "signed answer, pending validation";
+ strlcat(buf, "signed answer", sizeof(buf));
+ if (!yaml) {
+ strlcat(buf, ", ", sizeof(buf));
+ }
+ strlcat(buf, "pending validation", sizeof(buf));
break;
case dns_trust_additional:
- tstr = "unsigned additional data";
+ strlcat(buf, "unsigned additional data", sizeof(buf));
break;
case dns_trust_glue:
- tstr = "glue data";
+ strlcat(buf, "glue data", sizeof(buf));
break;
case dns_trust_answer:
if (root_validation) {
- tstr = "unsigned answer";
+ strlcat(buf, "unsigned answer", sizeof(buf));
+ } else {
+ strlcat(buf, "answer not validated", sizeof(buf));
}
break;
case dns_trust_authauthority:
- tstr = "authority data";
+ strlcat(buf, "authority data", sizeof(buf));
break;
case dns_trust_authanswer:
- tstr = "authoritative";
+ strlcat(buf, "authoritative", sizeof(buf));
break;
case dns_trust_secure:
- tstr = "fully validated";
+ strlcat(buf, "fully validated", sizeof(buf));
break;
case dns_trust_ultimate:
- tstr = "ultimate trust";
+ strlcat(buf, "ultimate trust", sizeof(buf));
break;
}
- printf("; %s%s\n", astr, tstr);
+ if (yaml) {
+ char *p;
+
+ /* Convert spaces to underscores for YAML */
+ for (p = buf; p != NULL && *p != '\0'; p++) {
+ if (*p == ' ') {
+ *p = '_';
+ }
+ }
+
+ printf(" - %s:\n", buf);
+ } else {
+ printf("; %s\n", buf);
+ }
}
static isc_result_t
@@ -425,8 +454,9 @@ printdata(dns_rdataset_t *rdataset, dns_name_t *owner,
return (ISC_R_SUCCESS);
if (first || rdataset->trust != trust) {
- if (!first && showtrust && !short_form)
+ if (!first && showtrust && !short_form && !yaml) {
putchar('\n');
+ }
print_status(rdataset);
trust = rdataset->trust;
first = false;
@@ -465,9 +495,11 @@ printdata(dns_rdataset_t *rdataset, dns_name_t *owner,
dns_rdata_reset(&rdata);
}
} else {
- if ((rdataset->attributes &
- DNS_RDATASETATTR_NEGATIVE) != 0)
+ if (!yaml && (rdataset->attributes &
+ DNS_RDATASETATTR_NEGATIVE) != 0)
+ {
isc_buffer_putstr(&target, "; ");
+ }
result = dns_master_rdatasettotext(owner, rdataset,
style, &target);
@@ -500,38 +532,52 @@ setup_style(dns_master_style_t **stylep) {
REQUIRE(stylep != NULL || *stylep == NULL);
styleflags |= DNS_STYLEFLAG_REL_OWNER;
- if (showcomments)
- styleflags |= DNS_STYLEFLAG_COMMENT;
- if (print_unknown_format)
- styleflags |= DNS_STYLEFLAG_UNKNOWNFORMAT;
- if (rrcomments)
- styleflags |= DNS_STYLEFLAG_RRCOMMENT;
- if (nottl)
- styleflags |= DNS_STYLEFLAG_NO_TTL;
- if (noclass)
- styleflags |= DNS_STYLEFLAG_NO_CLASS;
- if (nocrypto)
- styleflags |= DNS_STYLEFLAG_NOCRYPTO;
- if (multiline) {
- styleflags |= DNS_STYLEFLAG_MULTILINE;
- styleflags |= DNS_STYLEFLAG_COMMENT;
+ if (yaml) {
+ styleflags |= DNS_STYLEFLAG_YAML;
+ dns_master_indentstr = " ";
+ dns_master_indent = 2;
+ } else {
+ if (showcomments) {
+ styleflags |= DNS_STYLEFLAG_COMMENT;
+ }
+ if (print_unknown_format) {
+ styleflags |= DNS_STYLEFLAG_UNKNOWNFORMAT;
+ }
+ if (rrcomments) {
+ styleflags |= DNS_STYLEFLAG_RRCOMMENT;
+ }
+ if (nottl) {
+ styleflags |= DNS_STYLEFLAG_NO_TTL;
+ }
+ if (noclass) {
+ styleflags |= DNS_STYLEFLAG_NO_CLASS;
+ }
+ if (nocrypto) {
+ styleflags |= DNS_STYLEFLAG_NOCRYPTO;
+ }
+ if (multiline) {
+ styleflags |= DNS_STYLEFLAG_MULTILINE;
+ styleflags |= DNS_STYLEFLAG_COMMENT;
+ }
}
- if (multiline || (nottl && noclass))
+ if (multiline || (nottl && noclass)) {
result = dns_master_stylecreate(&style, styleflags,
24, 24, 24, 32, 80, 8,
splitwidth, mctx);
- else if (nottl || noclass)
+ } else if (nottl || noclass) {
result = dns_master_stylecreate(&style, styleflags,
24, 24, 32, 40, 80, 8,
splitwidth, mctx);
- else
+ } else {
result = dns_master_stylecreate(&style, styleflags,
24, 32, 40, 48, 80, 8,
splitwidth, mctx);
+ }
- if (result == ISC_R_SUCCESS)
+ if (result == ISC_R_SUCCESS) {
*stylep = style;
+ }
return (result);
}
@@ -1139,6 +1185,13 @@ plus_option(char *option) {
if (state)
resolve_trace = state;
break;
+ case 'y': /* yaml */
+ FULLCHECK("yaml");
+ yaml = state;
+ if (state) {
+ rrcomments = false;
+ }
+ break;
default:
invalid_option:
/*
@@ -1565,6 +1618,7 @@ main(int argc, char *argv[]) {
isc_result_t result;
dns_fixedname_t qfn;
dns_name_t *query_name, *response_name;
+ char namestr[DNS_NAME_FORMATSIZE];
dns_rdataset_t *rdataset;
dns_namelist_t namelist;
unsigned int resopt, clopt;
@@ -1653,9 +1707,18 @@ main(int argc, char *argv[]) {
ISC_LIST_INIT(namelist);
result = dns_client_resolve(client, query_name, dns_rdataclass_in,
qtype, resopt, &namelist);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS && !yaml) {
delv_log(ISC_LOG_ERROR, "resolution failed: %s",
isc_result_totext(result));
+ }
+
+ if (yaml) {
+ printf("type: DELV_RESULT\n");
+ dns_name_format(query_name, namestr, sizeof(namestr));
+ printf("query_name: %s\n", namestr);
+ printf("status: %s\n", isc_result_totext(result));
+ printf("records:\n");
+ }
for (response_name = ISC_LIST_HEAD(namelist);
response_name != NULL;
diff --git a/bin/delv/delv.docbook b/bin/delv/delv.docbook
index 78eb6feb04..8d009b6780 100644
--- a/bin/delv/delv.docbook
+++ b/bin/delv/delv.docbook
@@ -658,6 +658,16 @@
+
+
+
+
+
+ Print response data in YAML format.
+
+
+
+
diff --git a/bin/dig/dig.c b/bin/dig/dig.c
index 1c425fddf6..51b52b6ba6 100644
--- a/bin/dig/dig.c
+++ b/bin/dig/dig.c
@@ -64,7 +64,8 @@ static char hexcookie[81];
static bool short_form = false, printcmd = true,
plusquest = false, pluscomm = false,
- ipv4only = false, ipv6only = false, digrc = true;
+ ipv4only = false, ipv6only = false, digrc = true,
+ yaml = false;
static uint32_t splitwidth = 0xffffffff;
/*% opcode text */
@@ -262,7 +263,11 @@ received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) {
isc_sockaddr_format(from, fromtext, sizeof(fromtext));
- if (query->lookup->stats && !short_form) {
+ if (short_form || yaml) {
+ return;
+ }
+
+ if (query->lookup->stats) {
diff = isc_time_microdiff(&query->time_recv, &query->time_sent);
if (query->lookup->use_usec)
printf(";; Query time: %ld usec\n", (long) diff);
@@ -283,11 +288,15 @@ received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) {
*/
if (wcsftime(time_str, sizeof(time_str)/sizeof(time_str[0]),
L"%a %b %d %H:%M:%S %Z %Y", &tmnow) > 0U)
+ {
printf(";; WHEN: %ls\n", time_str);
+ }
#else
if (strftime(time_str, sizeof(time_str),
"%a %b %d %H:%M:%S %Z %Y", &tmnow) > 0U)
+ {
printf(";; WHEN: %s\n", time_str);
+ }
#endif
if (query->lookup->doing_xfr) {
printf(";; XFR size: %u records (messages %u, "
@@ -298,30 +307,32 @@ received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) {
printf(";; MSG SIZE rcvd: %u\n", bytes);
}
if (tsigkey != NULL) {
- if (!validated)
+ if (!validated) {
puts(";; WARNING -- Some TSIG could not "
"be validated");
+ }
}
if ((tsigkey == NULL) && (keysecret[0] != 0)) {
puts(";; WARNING -- TSIG key was not used.");
}
puts("");
- } else if (query->lookup->identify && !short_form) {
+ } else if (query->lookup->identify) {
diff = isc_time_microdiff(&query->time_recv, &query->time_sent);
- if (query->lookup->use_usec)
+ if (query->lookup->use_usec) {
printf(";; Received %" PRIu64 " bytes "
"from %s(%s) in %ld us\n\n",
query->lookup->doing_xfr
? query->byte_count
: (uint64_t)bytes,
fromtext, query->userarg, (long) diff);
- else
+ } else {
printf(";; Received %" PRIu64 " bytes "
"from %s(%s) in %ld ms\n\n",
query->lookup->doing_xfr
? query->byte_count
: (uint64_t)bytes,
fromtext, query->userarg, (long) diff / 1000);
+ }
}
}
@@ -364,18 +375,20 @@ say_message(dns_rdata_t *rdata, dig_query_t *query, isc_buffer_t *buf) {
styleflags |= DNS_STYLEFLAG_EXPANDAAAA;
result = dns_rdata_tofmttext(rdata, NULL, styleflags, 0,
splitwidth, " ", buf);
- if (result == ISC_R_NOSPACE)
+ if (result == ISC_R_NOSPACE) {
return (result);
+ }
check_result(result, "dns_rdata_totext");
if (query->lookup->identify) {
-
diff = isc_time_microdiff(&query->time_recv, &query->time_sent);
ADD_STRING(buf, " from server ");
ADD_STRING(buf, query->servname);
if (query->lookup->use_usec) {
- snprintf(store, sizeof(store), " in %" PRIu64 " us.", diff);
+ snprintf(store, sizeof(store),
+ " in %" PRIu64 " us.", diff);
} else {
- snprintf(store, sizeof(store), " in %" PRIu64 " ms.", diff / 1000);
+ snprintf(store, sizeof(store),
+ " in %" PRIu64 " ms.", diff / 1000);
}
ADD_STRING(buf, store);
}
@@ -415,8 +428,7 @@ short_answer(dns_message_t *msg, dns_messagetextflag_t flags,
loopresult = dns_rdataset_first(rdataset);
while (loopresult == ISC_R_SUCCESS) {
dns_rdataset_current(rdataset, &rdata);
- result = say_message(&rdata, query,
- buf);
+ result = say_message(&rdata, query, buf);
if (result == ISC_R_NOSPACE)
return (result);
check_result(result, "say_message");
@@ -458,63 +470,85 @@ isdotlocal(dns_message_t *msg) {
* Callback from dighost.c to print the reply from a server
*/
static isc_result_t
-printmessage(dig_query_t *query, dns_message_t *msg, bool headers) {
+printmessage(dig_query_t *query, const isc_buffer_t *msgbuf,
+ dns_message_t *msg, bool headers)
+{
isc_result_t result;
dns_messagetextflag_t flags;
isc_buffer_t *buf = NULL;
unsigned int len = OUTPUTBUF;
dns_master_style_t *style = NULL;
unsigned int styleflags = 0;
+ bool isquery = (msg == query->lookup->sendmsg);
+
+ UNUSED(msgbuf);
styleflags |= DNS_STYLEFLAG_REL_OWNER;
- if (query->lookup->comments)
- styleflags |= DNS_STYLEFLAG_COMMENT;
- if (query->lookup->print_unknown_format)
- styleflags |= DNS_STYLEFLAG_UNKNOWNFORMAT;
- /* Turn on rrcomments if explicitly enabled */
- if (query->lookup->rrcomments > 0)
- styleflags |= DNS_STYLEFLAG_RRCOMMENT;
- if (query->lookup->ttlunits)
- styleflags |= DNS_STYLEFLAG_TTL_UNITS;
- if (query->lookup->nottl)
- styleflags |= DNS_STYLEFLAG_NO_TTL;
- if (query->lookup->noclass)
- styleflags |= DNS_STYLEFLAG_NO_CLASS;
- if (query->lookup->nocrypto)
- styleflags |= DNS_STYLEFLAG_NOCRYPTO;
- if (query->lookup->expandaaaa)
- styleflags |= DNS_STYLEFLAG_EXPANDAAAA;
- if (query->lookup->multiline) {
- styleflags |= DNS_STYLEFLAG_OMIT_OWNER;
- styleflags |= DNS_STYLEFLAG_OMIT_CLASS;
- styleflags |= DNS_STYLEFLAG_REL_DATA;
- styleflags |= DNS_STYLEFLAG_OMIT_TTL;
- styleflags |= DNS_STYLEFLAG_TTL;
- styleflags |= DNS_STYLEFLAG_MULTILINE;
- /* Turn on rrcomments unless explicitly disabled */
- if (query->lookup->rrcomments >= 0)
+ if (yaml) {
+ dns_master_indentstr = " ";
+ dns_master_indent = 3;
+ styleflags |= DNS_STYLEFLAG_YAML;
+ } else {
+ if (query->lookup->comments) {
+ styleflags |= DNS_STYLEFLAG_COMMENT;
+ }
+ if (query->lookup->print_unknown_format) {
+ styleflags |= DNS_STYLEFLAG_UNKNOWNFORMAT;
+ }
+ /* Turn on rrcomments if explicitly enabled */
+ if (query->lookup->rrcomments > 0) {
styleflags |= DNS_STYLEFLAG_RRCOMMENT;
+ }
+ if (query->lookup->ttlunits) {
+ styleflags |= DNS_STYLEFLAG_TTL_UNITS;
+ }
+ if (query->lookup->nottl) {
+ styleflags |= DNS_STYLEFLAG_NO_TTL;
+ }
+ if (query->lookup->noclass) {
+ styleflags |= DNS_STYLEFLAG_NO_CLASS;
+ }
+ if (query->lookup->nocrypto) {
+ styleflags |= DNS_STYLEFLAG_NOCRYPTO;
+ }
+ if (query->lookup->expandaaaa) {
+ styleflags |= DNS_STYLEFLAG_EXPANDAAAA;
+ }
+ if (query->lookup->multiline) {
+ styleflags |= DNS_STYLEFLAG_OMIT_OWNER;
+ styleflags |= DNS_STYLEFLAG_OMIT_CLASS;
+ styleflags |= DNS_STYLEFLAG_REL_DATA;
+ styleflags |= DNS_STYLEFLAG_OMIT_TTL;
+ styleflags |= DNS_STYLEFLAG_TTL;
+ styleflags |= DNS_STYLEFLAG_MULTILINE;
+ /* Turn on rrcomments unless explicitly disabled */
+ if (query->lookup->rrcomments >= 0) {
+ styleflags |= DNS_STYLEFLAG_RRCOMMENT;
+ }
+ }
}
if (query->lookup->multiline ||
(query->lookup->nottl && query->lookup->noclass))
+ {
result = dns_master_stylecreate(&style, styleflags,
24, 24, 24, 32, 80, 8,
splitwidth, mctx);
- else if (query->lookup->nottl || query->lookup->noclass)
+ } else if (query->lookup->nottl || query->lookup->noclass) {
result = dns_master_stylecreate(&style, styleflags,
24, 24, 32, 40, 80, 8,
splitwidth, mctx);
- else
+ } else {
result = dns_master_stylecreate(&style, styleflags,
24, 32, 40, 48, 80, 8,
splitwidth, mctx);
+ }
check_result(result, "dns_master_stylecreate");
if (query->lookup->cmdline[0] != 0) {
if (!short_form && printcmd) {
fputs(query->lookup->cmdline, stdout);
}
- query->lookup->cmdline[0]=0;
+ query->lookup->cmdline[0] = '\0';
}
debug("printmessage(%s %s %s)", headers ? "headers" : "noheaders",
query->lookup->comments ? "comments" : "nocomments",
@@ -535,13 +569,110 @@ printmessage(dig_query_t *query, dns_message_t *msg, bool headers) {
result = isc_buffer_allocate(mctx, &buf, len);
check_result(result, "isc_buffer_allocate");
- if (query->lookup->comments && !short_form) {
- if (query->lookup->cmdline[0] != 0 && printcmd)
+ if (yaml) {
+ enum { Q = 0x1, R = 0x2 }; /* Q:query; R:ecursive */
+ unsigned int tflag = 0;
+ isc_sockaddr_t saddr;
+ char sockstr[ISC_SOCKADDR_FORMATSIZE];
+ uint16_t sport;
+ char *hash;
+ int pf;
+
+ printf("-\n");
+ printf(" type: MESSAGE\n");
+ printf(" message:\n");
+
+ if (isquery) {
+ tflag |= Q;
+ if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
+ tflag |= R;
+ }
+ } else if (((msg->flags & DNS_MESSAGEFLAG_RD) != 0) &&
+ ((msg->flags & DNS_MESSAGEFLAG_RA) != 0))
+ {
+ tflag |= R;
+ }
+
+ if (tflag == (Q|R)) {
+ printf(" type: RECURSIVE_QUERY\n");
+ } else if (tflag == Q) {
+ printf(" type: AUTH_QUERY\n");
+ } else if (tflag == R) {
+ printf(" type: RECURSIVE_RESPONSE\n");
+ } else {
+ printf(" type: AUTH_RESPONSE\n");
+ }
+
+ if (!isc_time_isepoch(&query->time_sent)) {
+ char tbuf[100];
+ isc_time_formatISO8601ms(&query->time_sent,
+ tbuf, sizeof(tbuf));
+ printf(" query_time: !!timestamp %s\n", tbuf);
+ }
+
+ if (!isquery && !isc_time_isepoch(&query->time_recv)) {
+ char tbuf[100];
+ isc_time_formatISO8601ms(&query->time_recv,
+ tbuf, sizeof(tbuf));
+ printf(" response_time: !!timestamp %s\n", tbuf);
+ }
+
+ printf(" message_size: %ub\n",
+ isc_buffer_usedlength(msgbuf));
+
+ pf = isc_sockaddr_pf(&query->sockaddr);
+ if (pf == PF_INET || pf == PF_INET6) {
+ printf(" socket_family: %s\n",
+ pf == PF_INET ? "INET" : "INET6");
+
+ printf(" socket_protocol: %s\n",
+ query->lookup->tcp_mode ? "TCP" : "UDP");
+
+ sport = isc_sockaddr_getport(&query->sockaddr);
+ isc_sockaddr_format(&query->sockaddr,
+ sockstr, sizeof(sockstr));
+ hash = strchr(sockstr, '#');
+ if (hash != NULL) {
+ *hash = '\0';
+ }
+ if (strcmp(sockstr, "::") == 0) {
+ strlcat(sockstr, "0", sizeof(sockstr));
+ }
+
+ printf(" response_address: %s\n", sockstr);
+ printf(" response_port: %u\n", sport);
+ }
+
+ if (query->sock != NULL &&
+ isc_socket_getsockname(query->sock, &saddr)
+ == ISC_R_SUCCESS)
+ {
+ sport = isc_sockaddr_getport(&saddr);
+ isc_sockaddr_format(&saddr, sockstr, sizeof(sockstr));
+ hash = strchr(sockstr, '#');
+ if (hash != NULL) {
+ *hash = '\0';
+ }
+ if (strcmp(sockstr, "::") == 0) {
+ strlcat(sockstr, "0", sizeof(sockstr));
+ }
+
+ printf(" query_address: %s\n", sockstr);
+ printf(" query_port: %u\n", sport);
+ }
+
+ printf(" %s:\n", isquery ? "query_message_data"
+ : "response_message_data");
+ result = dns_message_headertotext(msg, style, flags, buf);
+ } else if (query->lookup->comments && !short_form) {
+ if (query->lookup->cmdline[0] != '\0' && printcmd) {
printf("; %s\n", query->lookup->cmdline);
- if (msg == query->lookup->sendmsg)
+ }
+ if (msg == query->lookup->sendmsg) {
printf(";; Sending:\n");
- else
+ } else {
printf(";; Got answer:\n");
+ }
if (headers) {
if (isdotlocal(msg)) {
@@ -686,8 +817,9 @@ buftoosmall:
}
}
- if (headers && query->lookup->comments && !short_form)
+ if (headers && query->lookup->comments && !short_form && !yaml) {
printf("\n");
+ }
printf("%.*s", (int)isc_buffer_usedlength(buf),
(char *)isc_buffer_base(buf));
@@ -1545,6 +1677,15 @@ plus_option(char *option, bool is_batchfile,
lookup->tcp_mode_set = true;
}
break;
+ case 'y': /* yaml */
+ FULLCHECK("yaml");
+ yaml = state;
+ if (state) {
+ printcmd = false;
+ lookup->stats = false;
+ lookup->rrcomments = -1;
+ }
+ break;
case 'z': /* zflag */
FULLCHECK("zflag");
lookup->zflag = state;
@@ -2257,8 +2398,37 @@ query_finished(void) {
}
}
-void dig_setup(int argc, char **argv)
-{
+static void
+dig_error(const char *format, ...) {
+ va_list args;
+
+ if (yaml) {
+ printf("-\n");
+ printf(" type: DIG_ERROR\n");
+
+ /*
+ * Print an indent before a literal block quote.
+ * Note: this will break if used to print more than
+ * one line of text as only the first line would be
+ * indented.
+ */
+ printf(" message: |\n");
+ printf(" ");
+ } else {
+ printf(";; ");
+ }
+
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+
+ if (!yaml) {
+ printf("\n");
+ }
+}
+
+void
+dig_setup(int argc, char **argv) {
isc_result_t result;
ISC_LIST_INIT(lookup_list);
@@ -2272,6 +2442,7 @@ void dig_setup(int argc, char **argv)
dighost_received = received;
dighost_trying = trying;
dighost_shutdown = query_finished;
+ dighost_error = dig_error;
progname = argv[0];
preparse_args(argc, argv);
diff --git a/bin/dig/dig.docbook b/bin/dig/dig.docbook
index 8d16e76a56..86125c6040 100644
--- a/bin/dig/dig.docbook
+++ b/bin/dig/dig.docbook
@@ -1292,6 +1292,16 @@
+
+
+
+
+ Print the responses (and, if is in use,
+ also the outgoing queries) in a detailed YAML format.
+
+
+
+
diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c
index b20cb05c9c..d9ee70bcf1 100644
--- a/bin/dig/dighost.c
+++ b/bin/dig/dighost.c
@@ -193,11 +193,15 @@ dig_lookup_t *current_lookup = NULL;
/* dynamic callbacks */
isc_result_t
-(*dighost_printmessage)(dig_query_t *query, dns_message_t *msg,
- bool headers);
+(*dighost_printmessage)(dig_query_t *query, const isc_buffer_t *msgbuf,
+ dns_message_t *msg, bool headers);
void
-(*dighost_received)(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query);
+(*dighost_error)(const char *format, ...);
+
+void
+(*dighost_received)(unsigned int bytes, isc_sockaddr_t *from,
+ dig_query_t *query);
void
(*dighost_trying)(char *frm, dig_lookup_t *lookup);
@@ -2501,6 +2505,9 @@ setup_lookup(dig_lookup_t *lookup) {
COMMSIZE);
query->sendbuf = lookup->renderbuf;
+ isc_time_settoepoch(&query->time_sent);
+ isc_time_settoepoch(&query->time_recv);
+
ISC_LINK_INIT(query, clink);
ISC_LINK_INIT(query, link);
@@ -2509,16 +2516,6 @@ setup_lookup(dig_lookup_t *lookup) {
ISC_LIST_ENQUEUE(lookup->q, query, link);
}
- /* XXX qrflag, print_query, etc... */
- if (!ISC_LIST_EMPTY(lookup->q) && lookup->qr) {
- extrabytes = 0;
- dighost_printmessage(ISC_LIST_HEAD(lookup->q),
- lookup->sendmsg, true);
- if (lookup->stats) {
- printf(";; QUERY SIZE: %u\n\n",
- isc_buffer_usedlength(&lookup->renderbuf));
- }
- }
return (true);
}
@@ -2856,6 +2853,18 @@ send_udp(dig_query_t *query) {
sevent, ISC_SOCKFLAG_NORETRY);
check_result(result, "isc_socket_sendto2");
sendcount++;
+
+ /* XXX qrflag, print_query, etc... */
+ if (!ISC_LIST_EMPTY(query->lookup->q) && query->lookup->qr) {
+ extrabytes = 0;
+ dighost_printmessage(ISC_LIST_HEAD(query->lookup->q),
+ &query->lookup->renderbuf,
+ query->lookup->sendmsg, true);
+ if (query->lookup->stats) {
+ printf(";; QUERY SIZE: %u\n\n",
+ isc_buffer_usedlength(&query->lookup->renderbuf));
+ }
+ }
}
/*%
@@ -2955,11 +2964,11 @@ connect_timeout(isc_task_t *task, isc_event_t *event) {
isc_netaddr_fromsockaddr(&netaddr, &query->sockaddr);
isc_netaddr_format(&netaddr, buf, sizeof(buf));
- printf(";; no response from %s\n", buf);
+ dighost_error("no response from %s\n", buf);
} else {
fputs(l->cmdline, stdout);
- printf(";; connection timed out; no servers could be "
- "reached\n");
+ dighost_error("connection timed out; "
+ "no servers could be reached\n");
}
cancel_lookup(l);
check_next_lookup(l);
@@ -3031,8 +3040,8 @@ tcp_length_done(isc_task_t *task, isc_event_t *event) {
char sockstr[ISC_SOCKADDR_FORMATSIZE];
isc_sockaddr_format(&query->sockaddr, sockstr,
sizeof(sockstr));
- printf(";; communications error to %s: %s\n",
- sockstr, isc_result_totext(sevent->result));
+ dighost_error("communications error to %s: %s\n",
+ sockstr, isc_result_totext(sevent->result));
if (keep != NULL)
isc_socket_detach(&keep);
l = query->lookup;
@@ -3131,6 +3140,19 @@ launch_next_query(dig_query_t *query, bool include_question) {
check_result(result, "isc_socket_send");
sendcount++;
debug("sendcount=%d", sendcount);
+
+ /* XXX qrflag, print_query, etc... */
+ if (!ISC_LIST_EMPTY(query->lookup->q) && query->lookup->qr) {
+ extrabytes = 0;
+ dighost_printmessage(ISC_LIST_HEAD(query->lookup->q),
+ &query->lookup->renderbuf,
+ query->lookup->sendmsg, true);
+ if (query->lookup->stats) {
+ printf(";; QUERY SIZE: %u\n\n",
+ isc_buffer_usedlength(
+ &query->lookup->renderbuf));
+ }
+ }
}
query->waiting_connect = false;
#if 0
@@ -3505,7 +3527,6 @@ recv_done(isc_task_t *task, isc_event_t *event) {
query = event->ev_arg;
TIME_NOW(&query->time_recv);
- debug("lookup=%p, query=%p", query->lookup, query);
l = query->lookup;
@@ -3534,8 +3555,8 @@ recv_done(isc_task_t *task, isc_event_t *event) {
debug("in recv cancel handler");
query->waiting_connect = false;
} else {
- printf(";; communications error: %s\n",
- isc_result_totext(sevent->result));
+ dighost_error("communications error: %s\n",
+ isc_result_totext(sevent->result));
if (keep != NULL)
isc_socket_detach(&keep);
isc_socket_detach(&query->sock);
@@ -3886,19 +3907,19 @@ recv_done(isc_task_t *task, isc_event_t *event) {
if (msg->rcode == dns_rcode_nxdomain &&
(l->origin != NULL || l->need_search)) {
if (!next_origin(query->lookup) || showsearch) {
- dighost_printmessage(query, msg, true);
+ dighost_printmessage(query, &b, msg, true);
dighost_received(isc_buffer_usedlength(&b),
&sevent->address, query);
}
} else if (!l->trace && !l->ns_search_only) {
- dighost_printmessage(query, msg, true);
+ dighost_printmessage(query, &b, msg, true);
} else if (l->trace) {
int nl = 0;
int count = msg->counts[DNS_SECTION_ANSWER];
debug("in TRACE code");
if (!l->ns_search_only)
- dighost_printmessage(query, msg, true);
+ dighost_printmessage(query, &b, msg, true);
l->rdtype = l->qrdtype;
if (l->trace_root || (l->ns_search_only && count > 0)) {
@@ -3929,7 +3950,7 @@ recv_done(isc_task_t *task, isc_event_t *event) {
l->trace_root = false;
usesearch = false;
} else {
- dighost_printmessage(query, msg, true);
+ dighost_printmessage(query, &b, msg, true);
}
}
}
diff --git a/bin/dig/host.c b/bin/dig/host.c
index 7e9b6c5754..aa7cb8473e 100644
--- a/bin/dig/host.c
+++ b/bin/dig/host.c
@@ -400,13 +400,16 @@ chase_cnamechain(dns_message_t *msg, dns_name_t *qname) {
}
static isc_result_t
-printmessage(dig_query_t *query, dns_message_t *msg, bool headers) {
+printmessage(dig_query_t *query, const isc_buffer_t *msgbuf,
+ dns_message_t *msg, bool headers)
+{
bool did_flag = false;
dns_rdataset_t *opt, *tsig = NULL;
const dns_name_t *tsigname;
isc_result_t result = ISC_R_SUCCESS;
int force_error;
+ UNUSED(msgbuf);
UNUSED(headers);
/*
@@ -854,6 +857,17 @@ parse_args(bool is_batchfile, int argc, char **argv) {
ISC_LIST_APPEND(lookup_list, lookup, link);
}
+static void
+host_error(const char *format, ...) {
+ va_list args;
+
+ printf(";; ");
+ va_start(args, format);
+ vfprintf(stdout, format, args);
+ va_end(args);
+ printf("\n");
+}
+
int
main(int argc, char **argv) {
isc_result_t result;
@@ -871,6 +885,7 @@ main(int argc, char **argv) {
dighost_received = received;
dighost_trying = trying;
dighost_shutdown = host_shutdown;
+ dighost_error = host_error;
debug("main()");
progname = argv[0];
diff --git a/bin/dig/include/dig/dig.h b/bin/dig/include/dig/dig.h
index 41cc31a3a4..34327559ce 100644
--- a/bin/dig/include/dig/dig.h
+++ b/bin/dig/include/dig/dig.h
@@ -380,13 +380,22 @@ set_search_domain(char *domain);
* then assigned to the appropriate function pointer
*/
extern isc_result_t
-(*dighost_printmessage)(dig_query_t *query, dns_message_t *msg, bool headers);
+(*dighost_printmessage)(dig_query_t *query, const isc_buffer_t *msgbuf,
+ dns_message_t *msg, bool headers);
+
+/*
+ * Print an error message in the appropriate format.
+ */
+void
+(*dighost_error)(const char *format, ...);
+
/*%<
* Print the final result of the lookup.
*/
extern void
-(*dighost_received)(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query);
+(*dighost_received)(unsigned int bytes, isc_sockaddr_t *from,
+ dig_query_t *query);
/*%<
* Print a message about where and when the response
* was received from, like the final comment in the
diff --git a/bin/dig/nslookup.c b/bin/dig/nslookup.c
index 2363903e9d..f343fec7bc 100644
--- a/bin/dig/nslookup.c
+++ b/bin/dig/nslookup.c
@@ -429,16 +429,21 @@ chase_cnamechain(dns_message_t *msg, dns_name_t *qname) {
}
static isc_result_t
-printmessage(dig_query_t *query, dns_message_t *msg, bool headers) {
+printmessage(dig_query_t *query, const isc_buffer_t *msgbuf,
+ dns_message_t *msg, bool headers)
+{
char servtext[ISC_SOCKADDR_FORMATSIZE];
+ UNUSED(msgbuf);
+
/* I've we've gotten this far, we've reached a server. */
query_error = 0;
debug("printmessage()");
if(!default_lookups || query->lookup->rdtype == dns_rdatatype_a) {
- isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext));
+ isc_sockaddr_format(&query->sockaddr, servtext,
+ sizeof(servtext));
printf("Server:\t\t%s\n", query->userarg);
printf("Address:\t%s\n", servtext);
@@ -978,6 +983,17 @@ getinput(isc_task_t *task, isc_event_t *event) {
isc_app_shutdown();
}
+static void
+nsl_error(const char *format, ...) {
+ va_list args;
+
+ printf(";; ");
+ va_start(args, format);
+ vfprintf(stdout, format, args);
+ va_end(args);
+ printf("\n");
+}
+
int
main(int argc, char **argv) {
isc_result_t result;
@@ -995,6 +1011,7 @@ main(int argc, char **argv) {
dighost_received = received;
dighost_trying = trying;
dighost_shutdown = query_finished;
+ dighost_error = nsl_error;
result = isc_app_start();
check_result(result, "isc_app_start");
diff --git a/bin/tests/system/digdelv/tests.sh b/bin/tests/system/digdelv/tests.sh
index 0a0509f9be..9178f4ae4b 100644
--- a/bin/tests/system/digdelv/tests.sh
+++ b/bin/tests/system/digdelv/tests.sh
@@ -62,6 +62,11 @@ KEYID="$(cat ns2/keyid)"
KEYDATA="$(< ns2/keydata sed -e 's/+/[+]/g')"
NOSPLIT="$(< ns2/keydata sed -e 's/+/[+]/g' -e 's/ //g')"
+HAS_PYYAML=0
+if [ -n "$PYTHON" ] ; then
+ $PYTHON -c "import yaml" 2> /dev/null && HAS_PYYAML=1
+fi
+
if [ -x "$DIG" ] ; then
n=$((n+1))
echo_i "checking dig short form works ($n)"
@@ -716,6 +721,21 @@ if [ -x "$DIG" ] ; then
grep '^fd92:7065:0b8e:ffff:0000:0000:0000:0002$' dig.out.test$n > /dev/null || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
+
+ if [ $HAS_PYYAML -ne 0 ] ; then
+ n=$((n+1))
+ echo_i "check dig +yaml output ($n)"
+ ret=0
+ dig_with_opts +qr +yaml @10.53.0.3 any ns2.example > dig.out.test$n 2>&1 || ret=1
+ value=$($PYTHON yamlget.py dig.out.test$n 0 message query_message_data status || ret=1)
+ [ "$value" = "NOERROR" ] || ret=1
+ value=$($PYTHON yamlget.py dig.out.test$n 1 message response_message_data status || ret=1)
+ [ "$value" = "NOERROR" ] || ret=1
+ value=$($PYTHON yamlget.py dig.out.test$n 1 message response_message_data QUESTION_SECTION 0 || ret=1)
+ [ "$value" = "ns2.example. IN ANY" ] || ret=1
+ if [ $ret -ne 0 ]; then echo_i "failed"; fi
+ status=$((status+ret))
+ fi
else
echo_i "$DIG is needed, so skipping these dig tests"
fi
@@ -744,6 +764,19 @@ if [ -x "$MDIG" ] ; then
grep "; serial" < dig.out.test$n > /dev/null && ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
+
+ if [ $HAS_PYYAML -ne 0 ] ; then
+ n=$((n+1))
+ echo_i "check mdig +yaml output ($n)"
+ ret=0
+ mdig_with_opts +yaml @10.53.0.3 -t any ns2.example > dig.out.test$n 2>&1 || ret=1
+ value=$($PYTHON yamlget.py dig.out.test$n 0 message response_message_data status || ret=1)
+ [ "$value" = "NOERROR" ] || ret=1
+ value=$($PYTHON yamlget.py dig.out.test$n 0 message response_message_data QUESTION_SECTION 0 || ret=1)
+ [ "$value" = "ns2.example. IN ANY" ] || ret=1
+ if [ $ret -ne 0 ]; then echo_i "failed"; fi
+ status=$((status+ret))
+ fi
else
echo_i "$MDIG is needed, so skipping these mdig tests"
fi
@@ -965,6 +998,22 @@ if [ -x "$DELV" ] ; then
check_ttl_range delv.out.test$n SOA 300 || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
+
+ if [ $HAS_PYYAML -ne 0 ] ; then
+ n=$((n+1))
+ echo_i "check delv +yaml output ($n)"
+ ret=0
+ delv_with_opts +yaml @10.53.0.3 any ns2.example > delv.out.test$n 2>&1 || ret=1
+ value=$($PYTHON yamlget.py delv.out.test$n status || ret=1)
+ [ "$value" = "success" ] || ret=1
+ value=$($PYTHON yamlget.py delv.out.test$n query_name || ret=1)
+ [ "$value" = "ns2.example" ] || ret=1
+ value=$($PYTHON yamlget.py delv.out.test$n records 0 answer_not_validated 0 || ret=1)
+ count=$(echo $value | wc -w )
+ [ ${count:-0} -eq 5 ] || ret=1
+ if [ $ret -ne 0 ]; then echo_i "failed"; fi
+ status=$((status+ret))
+ fi
else
echo_i "$DELV is needed, so skipping these delv tests"
fi
diff --git a/bin/tests/system/digdelv/yamlget.py b/bin/tests/system/digdelv/yamlget.py
new file mode 100644
index 0000000000..50be7ebca0
--- /dev/null
+++ b/bin/tests/system/digdelv/yamlget.py
@@ -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 http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+############################################################################
+
+try:
+ import yaml
+except:
+ print("No python yaml module, skipping")
+ exit(1)
+
+import subprocess
+import pprint
+import sys
+
+f = open(sys.argv[1], "r")
+for item in yaml.safe_load_all(f):
+ for key in sys.argv[2:]:
+ try:
+ key = int(key)
+ except: pass
+ try:
+ item = item[key]
+ except:
+ print('error: index not found')
+ exit(1)
+ print (item)
diff --git a/bin/tests/system/dnstap/tests.sh b/bin/tests/system/dnstap/tests.sh
index 83877b102f..2b701a495f 100644
--- a/bin/tests/system/dnstap/tests.sh
+++ b/bin/tests/system/dnstap/tests.sh
@@ -484,7 +484,6 @@ ret=0
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
-
HAS_PYYAML=0
if [ -n "$PYTHON" ] ; then
$PYTHON -c "import yaml" 2> /dev/null && HAS_PYYAML=1
diff --git a/bin/tools/mdig.c b/bin/tools/mdig.c
index 0b796d1717..6188f9a038 100644
--- a/bin/tools/mdig.c
+++ b/bin/tools/mdig.c
@@ -105,6 +105,7 @@ static bool display_answer = true;
static bool display_authority = true;
static bool display_additional = true;
static bool display_unknown_format = false;
+static bool yaml = false;
static bool continue_on_error = false;
static uint32_t display_splitwidth = 0xffffffff;
static isc_sockaddr_t srcaddr;
@@ -211,7 +212,7 @@ recvresponse(isc_task_t *task, isc_event_t *event) {
isc_result_t result;
dns_message_t *query = NULL, *response = NULL;
unsigned int parseflags = 0;
- isc_buffer_t *buf = NULL;
+ isc_buffer_t *msgbuf = NULL, *buf = NULL;
unsigned int len = OUTPUTBUF;
dns_master_style_t *style = NULL;
unsigned int styleflags = 0;
@@ -239,36 +240,52 @@ recvresponse(isc_task_t *task, isc_event_t *event) {
parseflags |= DNS_MESSAGEPARSE_BESTEFFORT;
parseflags |= DNS_MESSAGEPARSE_IGNORETRUNCATION;
}
+
+
+ msgbuf = dns_request_getanswer(reqev->request);
result = dns_request_getresponse(reqev->request, response, parseflags);
CHECK("dns_request_getresponse", result);
styleflags |= DNS_STYLEFLAG_REL_OWNER;
- if (display_comments)
- styleflags |= DNS_STYLEFLAG_COMMENT;
- if (display_unknown_format)
- styleflags |= DNS_STYLEFLAG_UNKNOWNFORMAT;
- if (display_rrcomments > 0)
- styleflags |= DNS_STYLEFLAG_RRCOMMENT;
- if (display_ttlunits)
- styleflags |= DNS_STYLEFLAG_TTL_UNITS;
- if (!display_ttl)
- styleflags |= DNS_STYLEFLAG_NO_TTL;
- if (!display_class)
- styleflags |= DNS_STYLEFLAG_NO_CLASS;
- if (!display_crypto)
- styleflags |= DNS_STYLEFLAG_NOCRYPTO;
- if (display_multiline) {
- styleflags |= DNS_STYLEFLAG_OMIT_OWNER;
- styleflags |= DNS_STYLEFLAG_OMIT_CLASS;
- styleflags |= DNS_STYLEFLAG_REL_DATA;
- styleflags |= DNS_STYLEFLAG_OMIT_TTL;
- styleflags |= DNS_STYLEFLAG_TTL;
- styleflags |= DNS_STYLEFLAG_MULTILINE;
- styleflags |= DNS_STYLEFLAG_COMMENT;
- /* Turn on rrcomments unless explicitly disabled */
- if (display_rrcomments >= 0) {
+ if (yaml) {
+ dns_master_indentstr = " ";
+ dns_master_indent = 3;
+ styleflags |= DNS_STYLEFLAG_YAML;
+ } else {
+ if (display_comments) {
+ styleflags |= DNS_STYLEFLAG_COMMENT;
+ }
+ if (display_unknown_format) {
+ styleflags |= DNS_STYLEFLAG_UNKNOWNFORMAT;
+ }
+ if (display_rrcomments > 0) {
styleflags |= DNS_STYLEFLAG_RRCOMMENT;
}
+ if (display_ttlunits) {
+ styleflags |= DNS_STYLEFLAG_TTL_UNITS;
+ }
+ if (!display_ttl) {
+ styleflags |= DNS_STYLEFLAG_NO_TTL;
+ }
+ if (!display_class) {
+ styleflags |= DNS_STYLEFLAG_NO_CLASS;
+ }
+ if (!display_crypto) {
+ styleflags |= DNS_STYLEFLAG_NOCRYPTO;
+ }
+ if (display_multiline) {
+ styleflags |= DNS_STYLEFLAG_OMIT_OWNER;
+ styleflags |= DNS_STYLEFLAG_OMIT_CLASS;
+ styleflags |= DNS_STYLEFLAG_REL_DATA;
+ styleflags |= DNS_STYLEFLAG_OMIT_TTL;
+ styleflags |= DNS_STYLEFLAG_TTL;
+ styleflags |= DNS_STYLEFLAG_MULTILINE;
+ styleflags |= DNS_STYLEFLAG_COMMENT;
+ /* Turn on rrcomments unless explicitly disabled */
+ if (display_rrcomments >= 0) {
+ styleflags |= DNS_STYLEFLAG_RRCOMMENT;
+ }
+ }
}
if (display_multiline || (!display_ttl && !display_class))
result = dns_master_stylecreate(&style, styleflags,
@@ -295,7 +312,59 @@ recvresponse(isc_task_t *task, isc_event_t *event) {
result = isc_buffer_allocate(mctx, &buf, len);
CHECK("isc_buffer_allocate", result);
- if (display_comments && !display_short_form) {
+ if (yaml) {
+ char sockstr[ISC_SOCKADDR_FORMATSIZE];
+ uint16_t sport;
+ char *hash;
+ int pf;
+
+ printf("-\n");
+ printf(" type: MESSAGE\n");
+ printf(" message:\n");
+
+ if (((response->flags & DNS_MESSAGEFLAG_RD) != 0) &&
+ ((response->flags & DNS_MESSAGEFLAG_RA) != 0))
+ {
+ printf(" type: RECURSIVE_RESPONSE\n");
+ } else {
+ printf(" type: AUTH_RESPONSE\n");
+ }
+
+ printf(" message_size: %ub\n",
+ isc_buffer_usedlength(msgbuf));
+
+ pf = isc_sockaddr_pf(&dstaddr);
+ if (pf == PF_INET || pf == PF_INET6) {
+ printf(" socket_family: %s\n",
+ pf == PF_INET ? "INET" : "INET6");
+
+ printf(" socket_protocol: %s\n",
+ tcp_mode ? "TCP" : "UDP");
+
+ sport = isc_sockaddr_getport(&dstaddr);
+ isc_sockaddr_format(&dstaddr, sockstr, sizeof(sockstr));
+ hash = strchr(sockstr, '#');
+ if (hash != NULL) {
+ *hash = '\0';
+ }
+ printf(" response_address: %s\n", sockstr);
+ printf(" response_port: %u\n", sport);
+ }
+
+ if (have_src) {
+ sport = isc_sockaddr_getport(&srcaddr);
+ isc_sockaddr_format(&srcaddr, sockstr, sizeof(sockstr));
+ hash = strchr(sockstr, '#');
+ if (hash != NULL) {
+ *hash = '\0';
+ }
+ printf(" query_address: %s\n", sockstr);
+ printf(" query_port: %u\n", sport);
+ }
+
+ printf(" %s:\n", "response_message_data");
+ result = dns_message_headertotext(response, style, flags, buf);
+ } else if (display_comments && !display_short_form) {
printf(";; Got answer:\n");
if (display_headers) {
@@ -465,8 +534,11 @@ buftoosmall:
CHECK("dns_message_pseudosectiontotext", result);
}
- if (display_headers && display_comments && !display_short_form)
+ if (display_headers && display_comments &&
+ !display_short_form && !yaml)
+ {
printf("\n");
+ }
printf("%.*s", (int)isc_buffer_usedlength(buf),
(char *)isc_buffer_base(buf));
@@ -515,8 +587,7 @@ compute_cookie(unsigned char *cookie, size_t len) {
}
static isc_result_t
-sendquery(struct query *query, isc_task_t *task)
-{
+sendquery(struct query *query, isc_task_t *task) {
dns_request_t *request;
dns_message_t *message;
dns_name_t *qname;
@@ -699,8 +770,7 @@ sendquery(struct query *query, isc_task_t *task)
}
static void
-sendqueries(isc_task_t *task, isc_event_t *event)
-{
+sendqueries(isc_task_t *task, isc_event_t *event) {
struct query *query = (struct query *)event->ev_arg;
isc_event_free(&event);
@@ -1509,6 +1579,13 @@ plus_option(char *option, struct query *query, bool global)
GLOBAL();
tcp_mode = state;
break;
+ case 'y': /* yaml */
+ FULLCHECK("yaml");
+ yaml = state;
+ if (state) {
+ display_rrcomments = state;
+ }
+ break;
case 'z': /* zflag */
FULLCHECK("zflag");
query->have_zflag = state;
diff --git a/bin/tools/mdig.docbook b/bin/tools/mdig.docbook
index 72c8f9e6ae..2233b9f963 100644
--- a/bin/tools/mdig.docbook
+++ b/bin/tools/mdig.docbook
@@ -399,6 +399,15 @@
+
+
+
+
+ Print the responses in a detailed YAML format.
+
+
+
+
diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml
index 1ce7651786..5af54a7724 100644
--- a/doc/arm/notes.xml
+++ b/doc/arm/notes.xml
@@ -186,9 +186,16 @@
- Statistics channel groups are now toggleable. [GL #1030]
+ Statistics channel groups are now toggleable. [GL #1030]
+
+
+ dig, mdig and
+ delv can all now take a +yaml
+ option to print output in a a detailed YAML format. [RT #1145]
+
+
@@ -274,7 +281,7 @@
A SipHash 2-4 based DNS Cookie (RFC 7873) algorithm has been added and
made default. Old non-default HMAC-SHA based DNS Cookie algorithms
have been removed, and only the default AES algorithm is being kept
- for legacy reasons. This changes doesn't have any operational impact
+ for legacy reasons. This change doesn't have any operational impact
in most common scenarios. [GL #605]
@@ -370,8 +377,8 @@
- named-checkconf now correctly reports missing
- dnstap-output option when
+ named-checkconf now correctly reports
+ a missing dnstap-output option when
dnstap is set. [GL #1136]
diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h
index 1f793b4809..af6af7d1c7 100644
--- a/lib/dns/include/dns/message.h
+++ b/lib/dns/include/dns/message.h
@@ -384,6 +384,37 @@ dns_message_pseudosectiontotext(dns_message_t *msg,
*\li Note: On error return, *target may be partially filled with data.
*/
+isc_result_t
+dns_message_headertotext(dns_message_t *msg, const dns_master_style_t *style,
+ dns_messagetextflag_t flags, isc_buffer_t *target);
+/*%<
+ * Convert the header section of message 'msg' to a cleartext
+ * representation. This is called from dns_message_totext().
+ *
+ * Notes on flags:
+ *\li If #DNS_MESSAGETEXTFLAG_NOHEADERS is set, header lines will be
+ * suppressed and this function is a no-op.
+ *
+ * Requires:
+ *
+ *\li 'msg' is a valid message.
+ *
+ *\li 'target' is a valid buffer.
+ *
+ * Ensures:
+ *
+ *\li If the result is success:
+ * The used space in 'target' is updated.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOSPACE
+ *\li #ISC_R_NOMORE
+ *
+ *\li Note: On error return, *target may be partially filled with data.
+ */
+
isc_result_t
dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
dns_messagetextflag_t flags, isc_buffer_t *target);
diff --git a/lib/dns/include/dns/request.h b/lib/dns/include/dns/request.h
index 4efcff7684..7e8d4d7f5f 100644
--- a/lib/dns/include/dns/request.h
+++ b/lib/dns/include/dns/request.h
@@ -316,6 +316,20 @@ dns_request_getresponse(dns_request_t *request, dns_message_t *message,
*
*\li Any result that dns_message_parse() can return.
*/
+isc_buffer_t *
+dns_request_getanswer(dns_request_t *request);
+/*
+ * Get the response to 'request' as a buffer.
+ *
+ * Requires:
+ *
+ *\li 'request' is a valid request for which the caller has received the
+ * completion event.
+ *
+ * Returns:
+ *
+ *\li a pointer to the answer buffer.
+ */
bool
dns_request_usedtcp(dns_request_t *request);
diff --git a/lib/dns/masterdump.c b/lib/dns/masterdump.c
index 2de16eec4b..7a80bf274a 100644
--- a/lib/dns/masterdump.c
+++ b/lib/dns/masterdump.c
@@ -427,7 +427,7 @@ str_totext(const char *source, isc_buffer_t *target) {
static isc_result_t
ncache_summary(dns_rdataset_t *rdataset, bool omit_final_dot,
- isc_buffer_t *target)
+ dns_totext_ctx_t *ctx, isc_buffer_t *target)
{
isc_result_t result = ISC_R_SUCCESS;
dns_rdataset_t rds;
@@ -441,7 +441,22 @@ ncache_summary(dns_rdataset_t *rdataset, bool omit_final_dot,
for (result = dns_rdataset_first(&rds);
result == ISC_R_SUCCESS;
result = dns_rdataset_next(&rds)) {
- CHECK(str_totext("; ", target));
+ if ((ctx->style.flags & DNS_STYLEFLAG_INDENT) != 0 ||
+ (ctx->style.flags & DNS_STYLEFLAG_YAML) != 0)
+ {
+ unsigned int i;
+ for (i = 0; i < dns_master_indent; i++) {
+ CHECK(str_totext(dns_master_indentstr,
+ target));
+ }
+ }
+
+ if ((ctx->style.flags & DNS_STYLEFLAG_YAML) != 0) {
+ CHECK(str_totext("- ", target));
+ } else {
+ CHECK(str_totext("; ", target));
+ }
+
CHECK(dns_name_totext(&name, omit_final_dot, target));
CHECK(str_totext(" ", target));
CHECK(dns_rdatatype_totext(rds.type, target));
@@ -518,22 +533,21 @@ rdataset_totext(dns_rdataset_t *rdataset,
*/
if ((ctx->style.flags & DNS_STYLEFLAG_INDENT) != 0 ||
(ctx->style.flags & DNS_STYLEFLAG_YAML) != 0)
+ {
for (i = 0; i < dns_master_indent; i++)
RETERR(str_totext(dns_master_indentstr,
target));
-
- /*
- * YAML enumerator?
- */
- if ((ctx->style.flags & DNS_STYLEFLAG_YAML) != 0) {
- RETERR(str_totext("- ", target));
}
/*
- * Comment?
+ * YAML or comment prefix?
*/
- if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0)
+ if ((ctx->style.flags & DNS_STYLEFLAG_YAML) != 0) {
+ RETERR(str_totext("- ", target));
+ } else if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0)
+ {
RETERR(str_totext(";", target));
+ }
/*
* Owner name.
@@ -651,23 +665,17 @@ rdataset_totext(dns_rdataset_t *rdataset,
*/
INDENT_TO(rdata_column);
if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
- if ((ctx->style.flags & DNS_STYLEFLAG_INDENT) != 0 ||
- (ctx->style.flags & DNS_STYLEFLAG_YAML) != 0)
- {
- for (i = 0; i < dns_master_indent; i++)
- RETERR(str_totext(dns_master_indentstr,
- target));
- }
- if (NXDOMAIN(rdataset))
+ if (NXDOMAIN(rdataset)) {
RETERR(str_totext(";-$NXDOMAIN\n", target));
- else
+ } else {
RETERR(str_totext(";-$NXRRSET\n", target));
+ }
/*
* Print a summary of the cached records which make
* up the negative response.
*/
RETERR(ncache_summary(rdataset, omit_final_dot,
- target));
+ ctx, target));
break;
} else {
dns_rdata_t rdata = DNS_RDATA_INIT;
diff --git a/lib/dns/message.c b/lib/dns/message.c
index a3f9a5187d..a3e8189a23 100644
--- a/lib/dns/message.c
+++ b/lib/dns/message.c
@@ -4001,8 +4001,8 @@ dns_message_pseudosectiontotext(dns_message_t *msg,
}
isc_result_t
-dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
- dns_messagetextflag_t flags, isc_buffer_t *target)
+dns_message_headertotext(dns_message_t *msg, const dns_master_style_t *style,
+ dns_messagetextflag_t flags, isc_buffer_t *target)
{
char buf[sizeof("1234567890")];
isc_result_t result;
@@ -4010,9 +4010,11 @@ dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
REQUIRE(DNS_MESSAGE_VALID(msg));
REQUIRE(target != NULL);
- if (((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) &&
- (dns_master_styleflags(style) & DNS_STYLEFLAG_YAML))
- {
+ if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) != 0) {
+ return (ISC_R_SUCCESS);
+ }
+
+ if (dns_master_styleflags(style) & DNS_STYLEFLAG_YAML) {
INDENT(style);
ADD_STRING(target, "opcode: ");
ADD_STRING(target, opcodetext[msg->opcode]);
@@ -4020,30 +4022,38 @@ dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
INDENT(style);
ADD_STRING(target, "status: ");
result = dns_rcode_totext(msg->rcode, target);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS) {
return (result);
+ }
ADD_STRING(target, "\n");
INDENT(style);
ADD_STRING(target, "id: ");
- snprintf(buf, sizeof(buf), "%6u", msg->id);
+ snprintf(buf, sizeof(buf), "%u", msg->id);
ADD_STRING(target, buf);
ADD_STRING(target, "\n");
INDENT(style);
ADD_STRING(target, "flags:");
- if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
+ if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
ADD_STRING(target, " qr");
- if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
+ }
+ if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
ADD_STRING(target, " aa");
- if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
+ }
+ if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
ADD_STRING(target, " tc");
- if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
+ }
+ if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
ADD_STRING(target, " rd");
- if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
+ }
+ if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
ADD_STRING(target, " ra");
- if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
+ }
+ if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
ADD_STRING(target, " ad");
- if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
+ }
+ if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
ADD_STRING(target, " cd");
+ }
ADD_STRING(target, "\n");
/*
* The final unnamed flag must be zero.
@@ -4091,34 +4101,42 @@ dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
msg->counts[DNS_SECTION_ADDITIONAL]);
ADD_STRING(target, buf);
ADD_STRING(target, "\n");
- } else if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
+ } else {
INDENT(style);
ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
ADD_STRING(target, opcodetext[msg->opcode]);
ADD_STRING(target, ", status: ");
result = dns_rcode_totext(msg->rcode, target);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS) {
return (result);
+ }
ADD_STRING(target, ", id: ");
snprintf(buf, sizeof(buf), "%6u", msg->id);
ADD_STRING(target, buf);
ADD_STRING(target, "\n");
INDENT(style);
ADD_STRING(target, ";; flags:");
- if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
+ if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
ADD_STRING(target, " qr");
- if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
+ }
+ if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
ADD_STRING(target, " aa");
- if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
+ }
+ if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
ADD_STRING(target, " tc");
- if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
+ }
+ if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
ADD_STRING(target, " rd");
- if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
+ }
+ if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
ADD_STRING(target, " ra");
- if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
+ }
+ if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
ADD_STRING(target, " ad");
- if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
+ }
+ if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
ADD_STRING(target, " cd");
+ }
/*
* The final unnamed flag must be zero.
*/
@@ -4158,42 +4176,63 @@ dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
ADD_STRING(target, buf);
ADD_STRING(target, "\n");
}
- result = dns_message_pseudosectiontotext(msg,
- DNS_PSEUDOSECTION_OPT,
- style, flags, target);
- if (result != ISC_R_SUCCESS)
+
+ cleanup:
+ return (result);
+}
+
+isc_result_t
+dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
+ dns_messagetextflag_t flags, isc_buffer_t *target)
+{
+ isc_result_t result;
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(target != NULL);
+
+ result = dns_message_headertotext(msg, style, flags, target);
+ if (result != ISC_R_SUCCESS) {
return (result);
+ }
+
+ result = dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_OPT,
+ style, flags, target);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
style, flags, target);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS) {
return (result);
+ }
+
result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
style, flags, target);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS) {
return (result);
+ }
+
result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
style, flags, target);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS) {
return (result);
+ }
+
result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
style, flags, target);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS) {
return (result);
+ }
- result = dns_message_pseudosectiontotext(msg,
- DNS_PSEUDOSECTION_TSIG,
+ result = dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_TSIG,
style, flags, target);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS) {
return (result);
+ }
- result = dns_message_pseudosectiontotext(msg,
- DNS_PSEUDOSECTION_SIG0,
+ result = dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_SIG0,
style, flags, target);
- if (result != ISC_R_SUCCESS)
- return (result);
-
- cleanup:
return (result);
}
diff --git a/lib/dns/request.c b/lib/dns/request.c
index ecde2839f7..c7680c7371 100644
--- a/lib/dns/request.c
+++ b/lib/dns/request.c
@@ -1196,6 +1196,13 @@ dns_request_getresponse(dns_request_t *request, dns_message_t *message,
return (result);
}
+isc_buffer_t *
+dns_request_getanswer(dns_request_t *request) {
+ REQUIRE(VALID_REQUEST(request));
+
+ return (request->answer);
+}
+
bool
dns_request_usedtcp(dns_request_t *request) {
REQUIRE(VALID_REQUEST(request));
diff --git a/lib/dns/win32/libdns.def.in b/lib/dns/win32/libdns.def.in
index f0645696c0..99cbe11a6d 100644
--- a/lib/dns/win32/libdns.def.in
+++ b/lib/dns/win32/libdns.def.in
@@ -496,6 +496,7 @@ dns_message_gettemprdataset
dns_message_gettimeadjust
dns_message_gettsig
dns_message_gettsigkey
+dns_message_headertotext
dns_message_logfmtpacket
dns_message_logpacket
dns_message_movename
@@ -847,6 +848,7 @@ dns_request_create
dns_request_createraw
dns_request_createvia
dns_request_destroy
+dns_request_getanswer
dns_request_getresponse
dns_request_usedtcp
dns_requestmgr_attach
diff --git a/util/copyrights b/util/copyrights
index 6585a7c037..b508ed4517 100644
--- a/util/copyrights
+++ b/util/copyrights
@@ -501,6 +501,7 @@
./bin/tests/system/digdelv/prereq.sh SH 2018,2019
./bin/tests/system/digdelv/setup.sh SH 2018,2019
./bin/tests/system/digdelv/tests.sh SH 2015,2016,2017,2018,2019
+./bin/tests/system/digdelv/yamlget.py PYTHON 2019
./bin/tests/system/ditch.pl PERL 2015,2016,2018,2019
./bin/tests/system/dlz/clean.sh SH 2010,2012,2014,2016,2018,2019
./bin/tests/system/dlz/ns1/dns-root/com/broken/dns.d/@/DNAME=10=example.net.= TXT.BRIEF 2015,2016,2018,2019