From 71325852f1a52fcd0875d152344373eed87f56b5 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 16 Jul 2019 23:44:20 -0700 Subject: [PATCH 1/6] add "dig +yaml" output format --- bin/dig/dig.c | 269 +++++++++++++++++++++++++++------- bin/dig/dighost.c | 71 +++++---- bin/dig/host.c | 17 ++- bin/dig/include/dig/dig.h | 13 +- bin/dig/nslookup.c | 21 ++- lib/dns/include/dns/message.h | 31 ++++ lib/dns/message.c | 119 ++++++++++----- lib/dns/win32/libdns.def.in | 1 + 8 files changed, 423 insertions(+), 119 deletions(-) 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/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/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/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/win32/libdns.def.in b/lib/dns/win32/libdns.def.in index f0645696c0..2eb382c28a 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 From 5aa375f0d8247206068992faebba61aaf953ba6a Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Sat, 20 Jul 2019 14:35:59 -0400 Subject: [PATCH 2/6] add "mdig +yaml" output format --- bin/tools/mdig.c | 139 ++++++++++++++++++++++++++-------- lib/dns/include/dns/request.h | 14 ++++ lib/dns/request.c | 7 ++ lib/dns/win32/libdns.def.in | 1 + 4 files changed, 130 insertions(+), 31 deletions(-) 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/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/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 2eb382c28a..99cbe11a6d 100644 --- a/lib/dns/win32/libdns.def.in +++ b/lib/dns/win32/libdns.def.in @@ -848,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 From 241cf78fee9eeb52c87e044e94bb76ec4f2cf82e Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Sat, 20 Jul 2019 17:24:41 -0400 Subject: [PATCH 3/6] add "delv +yaml" output format --- bin/delv/delv.c | 141 +++++++++++++++++++++++++++++++------------ lib/dns/masterdump.c | 48 +++++++++------ 2 files changed, 130 insertions(+), 59 deletions(-) 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/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; From 617696fbfc606d384d0fda7d81a9b0f4893149c7 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Sat, 20 Jul 2019 19:19:53 -0400 Subject: [PATCH 4/6] document the +yaml option in dig, mdig and delv --- bin/delv/delv.docbook | 10 ++++++++++ bin/dig/dig.docbook | 10 ++++++++++ bin/tools/mdig.docbook | 9 +++++++++ 3 files changed, 29 insertions(+) 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.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/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. + + + + From 33887dd94172486a5c0ba3b25a5f2cbf51a2310a Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Sun, 21 Jul 2019 00:05:42 -0400 Subject: [PATCH 5/6] add digdelv +yaml system tests --- bin/tests/system/digdelv/tests.sh | 49 +++++++++++++++++++++++++++++ bin/tests/system/digdelv/yamlget.py | 33 +++++++++++++++++++ bin/tests/system/dnstap/tests.sh | 1 - util/copyrights | 1 + 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 bin/tests/system/digdelv/yamlget.py 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/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 From 2627287dbc676ecb8f28bed035ecec1eb845f576 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Sun, 21 Jul 2019 10:17:08 -0400 Subject: [PATCH 6/6] CHANGES, README, relnotes --- CHANGES | 3 +++ README.md | 1 + doc/arm/notes.xml | 15 +++++++++++---- 3 files changed, 15 insertions(+), 4 deletions(-) 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/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]