]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
4545. [func] Make dnstap-read output more functionally usable.
authorwpk <wpk@isc.org>
Wed, 28 Dec 2016 09:06:40 +0000 (10:06 +0100)
committerwpk <wpk@isc.org>
Wed, 28 Dec 2016 10:57:28 +0000 (11:57 +0100)
[RT #43642]

4544. [func] Add message/payload size to dnstap-read YAML output.
[RT #43622]

CHANGES
bin/tests/system/dnstap/ns2/example.db
bin/tests/system/dnstap/tests.sh
bin/tests/system/dnstap/ydump.py [new file with mode: 0644]
bin/tools/dnstap-read.c
bin/tools/dnstap-read.docbook
lib/dns/include/dns/masterdump.h
lib/dns/masterdump.c
lib/dns/message.c
lib/dns/win32/libdns.def.in

diff --git a/CHANGES b/CHANGES
index 33c581d9c5908e2d7386e948ec6e4dbd5ef1f5fc..99912796bba06eca80d4908315d8626c3769177d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,9 @@
+4545.  [func]          Make dnstap-read output more functionally usable.
+                       [RT #43642]
+
+4544.  [func]          Add message/payload size to dnstap-read YAML output.
+                       [RT #43622]
+
 4543.  [bug]           dns_client_startupdate now delays sending the update
                        request until isc_app_ctxrun has been called.
                        [RT #43976]
index 4073cbee4e89922be9243cc991a9563eda5b1df9..8cb4da36116d83cf965b9574070a8325bd79fef0 100644 (file)
@@ -18,6 +18,8 @@ ns2.example.          A       10.53.0.2
 
 $ORIGIN example.
 a                      A       10.0.0.1
+a                      A       10.0.0.3
+a                      A       10.0.0.5
                        MX      10 mail.example.
 
 mail                   A       10.0.0.2
index 45f622b056c7ef90a9b9c1c52ca94f56c0324c8e..06fc24a9420bb189165c26d34b6f65968c6569d9 100644 (file)
@@ -344,6 +344,18 @@ 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" && HAS_PYYAML=1
+fi
+
+if [ $HAS_PYYAML ] ; then
+       echo "I:checking dnstap-read YAML output"
+       ret=0
+       $PYTHON ydump.py "$DNSTAPREAD" "ns3/dnstap.out.save" > /dev/null || ret=1
+       if [ $ret != 0 ]; then echo "I: failed"; fi
+       status=`expr $status + $ret`
+fi
 
 if [ -n "$FSTRM_CAPTURE" ] ; then
        $DIG +short @10.53.0.4 -p 5300 a.example > dig.out
diff --git a/bin/tests/system/dnstap/ydump.py b/bin/tests/system/dnstap/ydump.py
new file mode 100644 (file)
index 0000000..1ce4783
--- /dev/null
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+
+try:
+    import yaml
+except:
+    print "I: No python yaml module, skipping"
+    exit(1)
+
+import subprocess
+import pprint
+import sys
+
+DNSTAP_READ=sys.argv[1]
+DATAFILE=sys.argv[2]
+
+f = subprocess.Popen([DNSTAP_READ, '-y', DATAFILE], stdout=subprocess.PIPE)
+pprint.pprint([l for l in yaml.load_all(f.stdout)])
index 5bda5cc99e598dfe43fe159208017086f44b9826..585a1dfb32dd96f6ece03991024e72dad8a5ce8b 100644 (file)
@@ -83,10 +83,68 @@ usage(void) {
 }
 
 static void
-print_yaml(dns_dtdata_t *d) {
-       Dnstap__Dnstap *frame = d->frame;
+print_dtdata(dns_dtdata_t *dt) {
+       isc_result_t result;
+       isc_buffer_t *b = NULL;
+
+       isc_buffer_allocate(mctx, &b, 2048);
+       if (b == NULL)
+               fatal("out of memory");
+
+       CHECKM(dns_dt_datatotext(dt, &b), "dns_dt_datatotext");
+       printf("%.*s\n", (int) isc_buffer_usedlength(b),
+              (char *) isc_buffer_base(b));
+
+ cleanup:
+       if (b != NULL)
+               isc_buffer_free(&b);
+}
+
+static void
+print_packet(dns_dtdata_t *dt, const dns_master_style_t *style) {
+       isc_buffer_t *b = NULL;
+       isc_result_t result;
+
+       if (dt->msg != NULL) {
+               size_t textlen = 2048;
+
+               isc_buffer_allocate(mctx, &b, textlen);
+               if (b == NULL)
+                       fatal("out of memory");
+
+               for (;;) {
+                       isc_buffer_reserve(&b, textlen);
+                       if (b == NULL)
+                               fatal("out of memory");
+
+                       result = dns_message_totext(dt->msg, style, 0, b);
+                       if (result == ISC_R_NOSPACE) {
+                               textlen *= 2;
+                               continue;
+                       } else if (result == ISC_R_SUCCESS) {
+                               printf("%.*s",
+                                      (int) isc_buffer_usedlength(b),
+                                      (char *) isc_buffer_base(b));
+                               isc_buffer_free(&b);
+                       } else {
+                               isc_buffer_free(&b);
+                               CHECKM(result, "dns_message_totext");
+                       }
+                       break;
+               }
+       }
+
+ cleanup:
+       if (b != NULL)
+               isc_buffer_free(&b);
+}
+
+static void
+print_yaml(dns_dtdata_t *dt) {
+       Dnstap__Dnstap *frame = dt->frame;
        Dnstap__Message *m = frame->message;
        const ProtobufCEnumValue *ftype, *mtype;
+       static isc_boolean_t first = ISC_TRUE;
 
        ftype = protobuf_c_enum_descriptor_get_value(
                                     &dnstap__dnstap__type__descriptor,
@@ -94,6 +152,11 @@ print_yaml(dns_dtdata_t *d) {
        if (ftype == NULL)
                return;
 
+       if (!first)
+               printf("---\n");
+       else
+               first = ISC_FALSE;
+
        printf("type: %s\n", ftype->name);
 
        if (frame->has_identity)
@@ -117,18 +180,23 @@ print_yaml(dns_dtdata_t *d) {
 
        printf("  type: %s\n", mtype->name);
 
-       if (!isc_time_isepoch(&d->qtime)) {
+       if (!isc_time_isepoch(&dt->qtime)) {
                char buf[100];
-               isc_time_formatISO8601(&d->qtime, buf, sizeof(buf));
+               isc_time_formatISO8601(&dt->qtime, buf, sizeof(buf));
                printf("  query_time: !!timestamp %s\n", buf);
        }
 
-       if (!isc_time_isepoch(&d->rtime)) {
+       if (!isc_time_isepoch(&dt->rtime)) {
                char buf[100];
-               isc_time_formatISO8601(&d->rtime, buf, sizeof(buf));
+               isc_time_formatISO8601(&dt->rtime, buf, sizeof(buf));
                printf("  response_time: !!timestamp %s\n", buf);
        }
 
+        if (dt->msgdata.base != NULL) {
+                printf("  message_size: %zdb\n", (size_t) dt->msgdata.length);
+        } else
+                printf("  message_size: 0b\n");
+
        if (m->has_socket_family) {
                const ProtobufCEnumValue *type =
                        protobuf_c_enum_descriptor_get_value(
@@ -138,7 +206,7 @@ print_yaml(dns_dtdata_t *d) {
                        printf("  socket_family: %s\n", type->name);
        }
 
-       printf("  socket_protocol: %s\n", d->tcp ? "TCP" : "UDP");
+       printf("  socket_protocol: %s\n", dt->tcp ? "TCP" : "UDP");
 
        if (m->has_query_address) {
                ProtobufCBinaryData *ip = &m->query_address;
@@ -186,9 +254,18 @@ print_yaml(dns_dtdata_t *d) {
                }
        }
 
-       if (d->msg != NULL)
-               printf("  %s: |\n", ((d->type & DNS_DTTYPE_QUERY) != 0)
-                                    ? "query_message" : "response_message");
+       if (dt->msg != NULL) {
+               printf("  %s:\n", ((dt->type & DNS_DTTYPE_QUERY) != 0)
+                                    ? "query_message_data"
+                                    : "response_message_data");
+
+               print_packet(dt, &dns_master_style_yaml);
+
+               printf("  %s: |\n", ((dt->type & DNS_DTTYPE_QUERY) != 0)
+                                    ? "query_message"
+                                    : "response_message");
+               print_packet(dt, &dns_master_style_indent);
+       }
 };
 
 int
@@ -197,7 +274,6 @@ main(int argc, char *argv[]) {
        dns_message_t *message = NULL;
        isc_buffer_t *b = NULL;
        dns_dtdata_t *dt = NULL;
-       const dns_master_style_t *style = &dns_master_style_debug;
        dns_dthandle_t *handle = NULL;
        int rv = 0, ch;
 
@@ -212,9 +288,8 @@ main(int argc, char *argv[]) {
                                break;
                        case 'y':
                                yaml = ISC_TRUE;
-                               style = &dns_master_style_indent;
-                               dns_master_indentstr = "    ";
-                               printmessage = ISC_TRUE;
+                               dns_master_indentstr = "  ";
+                               dns_master_indent = 2;
                                break;
                        default:
                                usage();
@@ -261,44 +336,15 @@ main(int argc, char *argv[]) {
                        continue;
                }
 
-               if (yaml)
+               if (yaml) {
                        print_yaml(dt);
-               else {
-                       CHECKM(dns_dt_datatotext(dt, &b), "dns_dt_datatotext");
-                       printf("%.*s\n", (int) isc_buffer_usedlength(b),
-                              (char *) isc_buffer_base(b));
+               } else if (printmessage) {
+                       print_dtdata(dt);
+                       print_packet(dt, &dns_master_style_debug);
+               } else {
+                       print_dtdata(dt);
                }
 
-               if (printmessage && dt->msg != NULL) {
-                       size_t textlen = 2048;
-
-                       isc_buffer_clear(b);
-
-                       for (;;) {
-                               isc_buffer_reserve(&b, textlen);
-                               if (b == NULL)
-                                       fatal("out of memory");
-                               result = dns_message_totext(dt->msg, style,
-                                                           0, b);
-                               if (result == ISC_R_NOSPACE) {
-                                       textlen *= 2;
-                                       continue;
-                               } else if (result == ISC_R_SUCCESS) {
-                                       printf("%.*s",
-                                              (int) isc_buffer_usedlength(b),
-                                              (char *) isc_buffer_base(b));
-                                       isc_buffer_free(&b);
-                               } else {
-                                       isc_buffer_free(&b);
-                                       CHECKM(result, "dns_message_totext");
-                               }
-                               break;
-                       }
-               }
-
-               if (yaml)
-                       printf("---\n");
-
                dns_dtdata_free(&dt);
        }
 
index 3dfef705751e3d3e7742b2b77253f1fcb0668f4c..f8706fe25270a5a5d6b7ac06fda764909999a602 100644 (file)
@@ -86,7 +86,7 @@
         <listitem>
           <para>
             Print <command>dnstap</command> data in a detailed YAML
-            format. Implies <option>-p</option>.
+            format.
           </para>
         </listitem>
       </varlistentry>
index 4e01ea9ce0160f1284eb754deea17bcff829a7cc..84fd5671b75a50a8f318e444ce6f4dced3451835 100644 (file)
@@ -103,6 +103,9 @@ typedef struct dns_master_style dns_master_style_t;
 /*% Indent output. */
 #define DNS_STYLEFLAG_INDENT           0x40000000U
 
+/*% Output in YAML style. */
+#define DNS_STYLEFLAG_YAML             0x80000000U
+
 ISC_LANG_BEGINDECLS
 
 /***
@@ -167,14 +170,32 @@ LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_indent;
  */
 LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_keyzone;
 
+/*%
+ * YAML-compatible output
+ */
+LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_yaml;
+
 /*%
  * The default indent string to prepend lines with when using
- * styleflag DNS_STYLEFLAG_INDENT.  This is set to "\t" by default.
- * The indent preceeds everything else on the line, including comment
- * characters (;).
+ * styleflag DNS_STYLEFLAG_INDENT or DNS_STYLEFLAG_YAML.
+ * This is set to "\t" by default. The indent is repeated
+ * 'dns_master_indent' times. This precedes everything else
+ * on the line, including comment characters (;).
+ *
+ * XXX: Changing this value at runtime is not thread-safe.
  */
 LIBDNS_EXTERNAL_DATA extern const char *dns_master_indentstr;
 
+/*%
+ * The number of copies of the indent string to put at the beginning
+ * of the line when using DNS_STYLEFLAG_INDENT or DNS_STYLEFLAG_YAML.
+ * This is set to 1 by default. It is increased and decreased
+ * to adjust indentation levels when producing YAML output.
+ *
+ * XXX: This is not thread-safe.
+ */
+LIBDNS_EXTERNAL_DATA extern unsigned int dns_master_indent;
+
 /***
  ***   Functions
  ***/
@@ -394,6 +415,7 @@ dns_master_stylecreate2(dns_master_style_t **style, unsigned int flags,
                       unsigned int type_column, unsigned int rdata_column,
                       unsigned int line_length, unsigned int tab_width,
                       unsigned int split_width, isc_mem_t *mctx);
+
 void
 dns_master_styledestroy(dns_master_style_t **style, isc_mem_t *mctx);
 
index dfcfeccfc98b2fad5b2b3baab65441cfadb16c12..b799e5287cc85715a4e0fdbae3d2f00a636bd515 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <stdlib.h>
 
+#include <isc/buffer.h>
 #include <isc/event.h>
 #include <isc/file.h>
 #include <isc/magic.h>
@@ -185,11 +186,22 @@ dns_master_style_comment = {
        24, 32, 40, 48, 80, 8, UINT_MAX
 };
 
+/*%
+ * YAML style
+ */
+LIBDNS_EXTERNAL_DATA const dns_master_style_t
+dns_master_style_yaml = {
+       DNS_STYLEFLAG_YAML |
+       DNS_STYLEFLAG_REL_OWNER |
+       DNS_STYLEFLAG_INDENT,
+       24, 32, 40, 48, 80, 8, UINT_MAX
+};
 
 /*%
  * Default indent string.
  */
 LIBDNS_EXTERNAL_DATA const char *dns_master_indentstr = "\t";
+LIBDNS_EXTERNAL_DATA unsigned int dns_master_indent = 1;
 
 #define N_SPACES 10
 static char spaces[N_SPACES+1] = "          ";
@@ -321,14 +333,15 @@ totext_ctx_init(const dns_master_style_t *style, dns_totext_ctx_t *ctx) {
                r.base[0] = '\n';
                isc_buffer_add(&buf, 1);
 
-               if ((ctx->style.flags & DNS_STYLEFLAG_INDENT) != 0) {
-                       unsigned int ilen = strlen(dns_master_indentstr);
-                       isc_buffer_availableregion(&buf, &r);
-                       if (r.length < ilen)
-                               return (DNS_R_TEXTTOOLONG);
-                       isc_buffer_putmem(&buf,
-                               (const isc_uint8_t *) dns_master_indentstr,
-                               (unsigned int)ilen);
+               if ((ctx->style.flags & DNS_STYLEFLAG_INDENT) != 0 ||
+                   (ctx->style.flags & DNS_STYLEFLAG_YAML) != 0)
+               {
+                       unsigned int i, len = strlen(dns_master_indentstr);
+                       for (i = 0; i < dns_master_indent; i++) {
+                               if (isc_buffer_availablelength(&buf) < len)
+                                       return (DNS_R_TEXTTOOLONG);
+                               isc_buffer_putstr(&buf, dns_master_indentstr);
+                       }
                }
 
                if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0) {
@@ -373,7 +386,11 @@ totext_ctx_init(const dns_master_style_t *style, dns_totext_ctx_t *ctx) {
 
 #define INDENT_TO(col) \
        do { \
-                if ((result = indent(&column, ctx->style.col, \
+                if ((ctx->style.flags & DNS_STYLEFLAG_YAML) != 0) { \
+                       if ((result = str_totext(" ", target)) \
+                           != ISC_R_SUCCESS) \
+                               return (result); \
+                } else if ((result = indent(&column, ctx->style.col, \
                                      ctx->style.tab_width, target)) \
                     != ISC_R_SUCCESS) \
                            return (result); \
@@ -465,6 +482,7 @@ rdataset_totext(dns_rdataset_t *rdataset,
        unsigned int type_start;
        dns_fixedname_t fixed;
        dns_name_t *name = NULL;
+       unsigned int i;
 
        REQUIRE(DNS_RDATASET_VALID(rdataset));
 
@@ -487,8 +505,18 @@ rdataset_totext(dns_rdataset_t *rdataset,
                /*
                 * Indent?
                 */
-               if ((ctx->style.flags & DNS_STYLEFLAG_INDENT) != 0)
-                       RETERR(str_totext(dns_master_indentstr, target));
+               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?
@@ -612,9 +640,13 @@ 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)
-                               RETERR(str_totext(dns_master_indentstr,
-                                                 target));
+                       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))
                                RETERR(str_totext(";-$NXDOMAIN\n", target));
                        else
@@ -984,11 +1016,16 @@ dump_rdatasets_text(isc_mem_t *mctx, dns_name_t *name,
 
        for (i = 0; i < n; i++) {
                dns_rdataset_t *rds = sorted[i];
-               if (ctx->style.flags & DNS_STYLEFLAG_TRUST)
-                       fprintf(f, "%s; %s\n",
-                               (ctx->style.flags & DNS_STYLEFLAG_INDENT)
-                                ? dns_master_indentstr : "",
-                               dns_trust_totext(rds->trust));
+               if (ctx->style.flags & DNS_STYLEFLAG_TRUST) {
+                       if ((ctx->style.flags & DNS_STYLEFLAG_INDENT) != 0 ||
+                           (ctx->style.flags & DNS_STYLEFLAG_YAML) != 0)
+                       {
+                               unsigned int j;
+                               for (j = 0; j < dns_master_indent; j++)
+                                       fprintf(f, "%s", dns_master_indentstr);
+                       }
+                       fprintf(f, "; %s\n", dns_trust_totext(rds->trust));
+               }
                if (((rds->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) &&
                    (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) {
                        /* Omit negative cache entries */
@@ -1008,10 +1045,14 @@ dump_rdatasets_text(isc_mem_t *mctx, dns_name_t *name,
                        memset(buf, 0, sizeof(buf));
                        isc_buffer_init(&b, buf, sizeof(buf) - 1);
                        dns_time64_totext((isc_uint64_t)rds->resign, &b);
-                       fprintf(f, "%s; resign=%s\n",
-                               (ctx->style.flags & DNS_STYLEFLAG_INDENT)
-                                ? dns_master_indentstr : "",
-                               buf);
+                       if ((ctx->style.flags & DNS_STYLEFLAG_INDENT) != 0 ||
+                           (ctx->style.flags & DNS_STYLEFLAG_YAML) != 0)
+                       {
+                               unsigned int j;
+                               for (j = 0; j < dns_master_indent; j++)
+                                       fprintf(f, "%s", dns_master_indentstr);
+                       }
+                       fprintf(f, "; resign=%s\n", buf);
                }
                dns_rdataset_disassociate(rds);
        }
@@ -2066,7 +2107,6 @@ dns_master_stylecreate2(dns_master_style_t **stylep, unsigned int flags,
        style->line_length = line_length;
        style->tab_width = tab_width;
        style->split_width = split_width;
-
        *stylep = style;
        return (ISC_R_SUCCESS);
 }
index 4df8a154fbb1828a89fc45792a529baa3a3b80ff..c9732b2c113691f180a4f52ac7396a8568e6e96f 100644 (file)
@@ -80,8 +80,10 @@ hexdump(const char *msg, const char *msg2, void *base, size_t len) {
 #define VALID_SECTION(s)       (((s) >= DNS_SECTION_ANY) \
                                 && ((s) < DNS_SECTION_MAX))
 #define ADD_STRING(b, s)       {if (strlen(s) >= \
-                                  isc_buffer_availablelength(b)) \
-                                      return(ISC_R_NOSPACE); else \
+                                  isc_buffer_availablelength(b)) { \
+                                      result = ISC_R_NOSPACE; \
+                                      goto cleanup; \
+                                 } else \
                                       isc_buffer_putstr(b, s);}
 #define VALID_PSEUDOSECTION(s) (((s) >= DNS_PSEUDOSECTION_ANY) \
                                 && ((s) < DNS_PSEUDOSECTION_MAX))
@@ -3160,6 +3162,17 @@ dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
        }
 }
 
+#define INDENT(sp) \
+       do { \
+               unsigned int __i, __flags = dns_master_styleflags(sp); \
+               if ((__flags & DNS_STYLEFLAG_INDENT) == 0 && \
+                   (__flags & DNS_STYLEFLAG_YAML) == 0) \
+                       break; \
+               for (__i = 0; __i < dns_master_indent; __i++) { \
+                       ADD_STRING(target, dns_master_indentstr); \
+               } \
+       } while (0)
+
 isc_result_t
 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
                          const dns_master_style_t *style,
@@ -3167,20 +3180,29 @@ dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
                          isc_buffer_t *target) {
        dns_name_t *name, empty_name;
        dns_rdataset_t *rdataset;
-       isc_result_t result;
+       isc_result_t result = ISC_R_SUCCESS;
        isc_boolean_t seensoa = ISC_FALSE;
-       unsigned int sflags = dns_master_styleflags(style);
+       unsigned int sflags, saveindent;
 
        REQUIRE(DNS_MESSAGE_VALID(msg));
        REQUIRE(target != NULL);
        REQUIRE(VALID_SECTION(section));
 
+       saveindent = dns_master_indent;
+       sflags = dns_master_styleflags(style);
        if (ISC_LIST_EMPTY(msg->sections[section]))
-               return (ISC_R_SUCCESS);
+               goto cleanup;
+
 
-       if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
-               if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
-                       ADD_STRING(target, dns_master_indentstr);
+       INDENT(style);
+       if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
+               if (msg->opcode != dns_opcode_update) {
+                       ADD_STRING(target, sectiontext[section]);
+               } else {
+                       ADD_STRING(target, updsectiontext[section]);
+               }
+               ADD_STRING(target, "_SECTION:\n");
+       } else if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
                ADD_STRING(target, ";; ");
                if (msg->opcode != dns_opcode_update) {
                        ADD_STRING(target, sectiontext[section]);
@@ -3193,7 +3215,10 @@ dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
        dns_name_init(&empty_name, NULL);
        result = dns_message_firstname(msg, section);
        if (result != ISC_R_SUCCESS) {
-               return (result);
+               goto cleanup;
+       }
+       if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
+               dns_master_indent++;
        }
        do {
                name = NULL;
@@ -3211,10 +3236,12 @@ dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
                                seensoa = ISC_TRUE;
                        }
                        if (section == DNS_SECTION_QUESTION) {
-                               if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
-                                       ADD_STRING(target,
-                                                  dns_master_indentstr);
-                               ADD_STRING(target, ";");
+                               INDENT(style);
+                               if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
+                                       ADD_STRING(target, "- ");
+                               } else {
+                                       ADD_STRING(target, ";");
+                               }
                                result = dns_master_questiontotext(name,
                                                                   rdataset,
                                                                   style,
@@ -3226,18 +3253,25 @@ dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
                                                                   target);
                        }
                        if (result != ISC_R_SUCCESS)
-                               return (result);
+                               goto cleanup;
                }
                result = dns_message_nextname(msg, section);
        } while (result == ISC_R_SUCCESS);
+       if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
+               dns_master_indent--;
+       }
        if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
-           (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
-               if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
-                       ADD_STRING(target, dns_master_indentstr);
+           (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0 &&
+           (sflags & DNS_STYLEFLAG_YAML) == 0)
+       {
+               INDENT(style);
                ADD_STRING(target, "\n");
        }
        if (result == ISC_R_NOMORE)
                result = ISC_R_SUCCESS;
+
+ cleanup:
+       dns_master_indent = saveindent;
        return (result);
 }
 
@@ -3247,6 +3281,7 @@ render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
        char addr[16], addr_text[64];
        isc_uint16_t family;
        isc_uint8_t addrlen, addrbytes, scopelen;
+       isc_result_t result;
 
        /*
         * Note: This routine needs to handle malformed ECS options.
@@ -3293,7 +3328,256 @@ render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
        ADD_STRING(target, addr_text);
        snprintf(addr_text, sizeof(addr_text), "/%d/%d", addrlen, scopelen);
        ADD_STRING(target, addr_text);
-       return (ISC_R_SUCCESS);
+
+       result = ISC_R_SUCCESS;
+
+ cleanup:
+       return (result);
+}
+
+
+static isc_result_t
+dns_message_pseudosectiontoyaml(dns_message_t *msg,
+                               dns_pseudosection_t section,
+                               const dns_master_style_t *style,
+                               dns_messagetextflag_t flags,
+                               isc_buffer_t *target)
+{
+       dns_rdataset_t *ps = NULL;
+       dns_name_t *name = NULL;
+       isc_result_t result = ISC_R_SUCCESS;
+       char buf[sizeof("1234567890")];
+       isc_uint32_t mbz;
+       dns_rdata_t rdata;
+       isc_buffer_t optbuf;
+       isc_uint16_t optcode, optlen;
+       unsigned char *optdata;
+       unsigned int saveindent = dns_master_indent;
+
+       REQUIRE(DNS_MESSAGE_VALID(msg));
+       REQUIRE(target != NULL);
+       REQUIRE(VALID_PSEUDOSECTION(section));
+
+       switch (section) {
+       case DNS_PSEUDOSECTION_OPT:
+               ps = dns_message_getopt(msg);
+               if (ps == NULL) {
+                       goto cleanup;
+               }
+
+               INDENT(style);
+               ADD_STRING(target, "OPT_PSEUDOSECTION:\n");
+               dns_master_indent++;
+
+               INDENT(style);
+               ADD_STRING(target, "EDNS:\n");
+               dns_master_indent++;
+
+               INDENT(style);
+               ADD_STRING(target, "version: ");
+               snprintf(buf, sizeof(buf), "%u",
+                        (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
+               ADD_STRING(target, buf);
+               ADD_STRING(target, "\n");
+               INDENT(style);
+               ADD_STRING(target, "flags:");
+               if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
+                       ADD_STRING(target, " do");
+               ADD_STRING(target, "\n");
+               mbz = ps->ttl & 0xffff;
+               mbz &= ~DNS_MESSAGEEXTFLAG_DO;          /* Known Flags. */
+               if (mbz != 0) {
+                       INDENT(style);
+                       ADD_STRING(target, "MBZ: ");
+                       snprintf(buf, sizeof(buf), "0x%.4x", mbz);
+                       ADD_STRING(target, buf);
+                       ADD_STRING(target, "\n");
+               }
+               INDENT(style);
+               ADD_STRING(target, "udp: ");
+               snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
+               ADD_STRING(target, buf);
+               result = dns_rdataset_first(ps);
+               if (result != ISC_R_SUCCESS) {
+                       result = ISC_R_SUCCESS;
+                       goto cleanup;
+               }
+
+               /*
+                * Print EDNS info, if any.
+                *
+                * WARNING: The option contents may be malformed as
+                * dig +ednsopt=value:<content> does not validity
+                * checking.
+                */
+               dns_rdata_init(&rdata);
+               dns_rdataset_current(ps, &rdata);
+
+               isc_buffer_init(&optbuf, rdata.data, rdata.length);
+               isc_buffer_add(&optbuf, rdata.length);
+               while (isc_buffer_remaininglength(&optbuf) != 0) {
+                       INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
+                       optcode = isc_buffer_getuint16(&optbuf);
+                       optlen = isc_buffer_getuint16(&optbuf);
+                       INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
+
+                       if (optcode == DNS_OPT_NSID) {
+                               INDENT(style);
+                               ADD_STRING(target, "NSID");
+                       } else if (optcode == DNS_OPT_COOKIE) {
+                               INDENT(style);
+                               ADD_STRING(target, "COOKIE");
+                       } else if (optcode == DNS_OPT_CLIENT_SUBNET) {
+                               isc_buffer_t ecsbuf;
+                               INDENT(style);
+                               ADD_STRING(target, "CLIENT-SUBNET");
+                               isc_buffer_init(&ecsbuf,
+                                               isc_buffer_current(&optbuf),
+                                               optlen);
+                               isc_buffer_add(&ecsbuf, optlen);
+                               result = render_ecs(&ecsbuf, target);
+                               if (result == ISC_R_NOSPACE)
+                                       goto cleanup;
+                               if (result == ISC_R_SUCCESS) {
+                                       isc_buffer_forward(&optbuf, optlen);
+                                       ADD_STRING(target, "\n");
+                                       continue;
+                               }
+                               ADD_STRING(target, "\n");
+                       } else if (optcode == DNS_OPT_EXPIRE) {
+                               if (optlen == 4) {
+                                       isc_uint32_t secs;
+                                       secs = isc_buffer_getuint32(&optbuf);
+                                       INDENT(style);
+                                       ADD_STRING(target, "EXPIRE: ");
+                                       snprintf(buf, sizeof(buf), "%u", secs);
+                                       ADD_STRING(target, buf);
+                                       ADD_STRING(target, " (");
+                                       result = dns_ttl_totext(secs,
+                                                               ISC_TRUE,
+                                                               target);
+                                       if (result != ISC_R_SUCCESS)
+                                               goto cleanup;
+                                       ADD_STRING(target, ")\n");
+                                       continue;
+                               }
+                               INDENT(style);
+                               ADD_STRING(target, "EXPIRE");
+                       } else if (optcode == DNS_OPT_PAD) {
+                               INDENT(style);
+                               ADD_STRING(target, "PAD");
+                       } else {
+                               INDENT(style);
+                               ADD_STRING(target, "OPT: ");
+                               snprintf(buf, sizeof(buf), "%u", optcode);
+                               ADD_STRING(target, buf);
+                               ADD_STRING(target, "\n");
+                       }
+
+                       if (optlen != 0) {
+                               int i;
+                               ADD_STRING(target, ": ");
+
+                               optdata = isc_buffer_current(&optbuf);
+                               for (i = 0; i < optlen; i++) {
+                                       const char *sep;
+                                       switch (optcode) {
+                                       case DNS_OPT_COOKIE:
+                                               sep = "";
+                                               break;
+                                       default:
+                                               sep = " ";
+                                               break;
+                                       }
+                                       snprintf(buf, sizeof(buf), "%02x%s",
+                                                optdata[i], sep);
+                                       ADD_STRING(target, buf);
+                               }
+
+                               isc_buffer_forward(&optbuf, optlen);
+
+                               if (optcode == DNS_OPT_COOKIE) {
+                                       /*
+                                        * Valid server cookie?
+                                        */
+                                       if (msg->cc_ok && optlen >= 16)
+                                               ADD_STRING(target, " (good)");
+                                       /*
+                                        * Server cookie is not valid but
+                                        * we had our cookie echoed back.
+                                        */
+                                       if (msg->cc_ok && optlen < 16)
+                                               ADD_STRING(target, " (echoed)");
+                                       /*
+                                        * We didn't get our cookie echoed
+                                        * back.
+                                        */
+                                       if (msg->cc_bad)
+                                               ADD_STRING(target, " (bad)");
+                                       ADD_STRING(target, "\n");
+                                       continue;
+                               }
+
+                               if (optcode == DNS_OPT_CLIENT_SUBNET) {
+                                       ADD_STRING(target, "\n");
+                                       continue;
+                               }
+
+                               /*
+                                * For non-COOKIE options, add a printable
+                                * version
+                                */
+                               ADD_STRING(target, "(\"");
+                               if (isc_buffer_availablelength(target) < optlen)
+                               {
+                                       result = ISC_R_NOSPACE;
+                                       goto cleanup;
+                               }
+                               for (i = 0; i < optlen; i++) {
+                                       if (isprint(optdata[i]))
+                                               isc_buffer_putmem(target,
+                                                                 &optdata[i],
+                                                                 1);
+                                       else
+                                               isc_buffer_putstr(target, ".");
+                               }
+                               ADD_STRING(target, "\")");
+                       }
+                       ADD_STRING(target, "\n");
+               }
+               result = ISC_R_SUCCESS;
+               goto cleanup;
+       case DNS_PSEUDOSECTION_TSIG:
+               ps = dns_message_gettsig(msg, &name);
+               if (ps == NULL) {
+                       result = ISC_R_SUCCESS;
+                       goto cleanup;
+               }
+               INDENT(style);
+               ADD_STRING(target, "TSIG_PSEUDOSECTION:\n");
+               result = dns_master_rdatasettotext(name, ps, style, target);
+               ADD_STRING(target, "\n");
+               goto cleanup;
+       case DNS_PSEUDOSECTION_SIG0:
+               ps = dns_message_getsig0(msg, &name);
+               if (ps == NULL) {
+                       result = ISC_R_SUCCESS;
+                       goto cleanup;
+               }
+               INDENT(style);
+               ADD_STRING(target, "SIG0_PSEUDOSECTION:\n");
+               result = dns_master_rdatasettotext(name, ps, style, target);
+               if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
+                   (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
+                       ADD_STRING(target, "\n");
+               goto cleanup;
+       }
+
+       result = ISC_R_UNEXPECTED;
+
+ cleanup:
+       dns_master_indent = saveindent;
+       return (result);
 }
 
 isc_result_t
@@ -3312,25 +3596,25 @@ dns_message_pseudosectiontotext(dns_message_t *msg,
        isc_buffer_t optbuf;
        isc_uint16_t optcode, optlen;
        unsigned char *optdata;
-       unsigned int sflags = dns_master_styleflags(style);
 
        REQUIRE(DNS_MESSAGE_VALID(msg));
        REQUIRE(target != NULL);
        REQUIRE(VALID_PSEUDOSECTION(section));
 
+       if ((dns_master_styleflags(style) & DNS_STYLEFLAG_YAML) != 0)
+               return (dns_message_pseudosectiontoyaml(msg, section, style,
+                                                       flags, target));
        switch (section) {
        case DNS_PSEUDOSECTION_OPT:
                ps = dns_message_getopt(msg);
                if (ps == NULL)
                        return (ISC_R_SUCCESS);
                if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
-                       if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
-                               ADD_STRING(target, dns_master_indentstr);
+                       INDENT(style);
                        ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
                }
 
-               if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
-                       ADD_STRING(target, dns_master_indentstr);
+               INDENT(style);
                ADD_STRING(target, "; EDNS: version: ");
                snprintf(buf, sizeof(buf), "%u",
                         (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
@@ -3372,8 +3656,7 @@ dns_message_pseudosectiontotext(dns_message_t *msg,
                        optlen = isc_buffer_getuint16(&optbuf);
                        INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
 
-                       if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
-                               ADD_STRING(target, dns_master_indentstr);
+                       INDENT(style);
 
                        if (optcode == DNS_OPT_NSID) {
                                ADD_STRING(target, "; NSID");
@@ -3493,8 +3776,7 @@ dns_message_pseudosectiontotext(dns_message_t *msg,
                ps = dns_message_gettsig(msg, &name);
                if (ps == NULL)
                        return (ISC_R_SUCCESS);
-               if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
-                       ADD_STRING(target, dns_master_indentstr);
+               INDENT(style);
                if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
                        ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
                result = dns_master_rdatasettotext(name, ps, style, target);
@@ -3506,8 +3788,7 @@ dns_message_pseudosectiontotext(dns_message_t *msg,
                ps = dns_message_getsig0(msg, &name);
                if (ps == NULL)
                        return (ISC_R_SUCCESS);
-               if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
-                       ADD_STRING(target, dns_master_indentstr);
+               INDENT(style);
                if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
                        ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
                result = dns_master_rdatasettotext(name, ps, style, target);
@@ -3516,23 +3797,104 @@ dns_message_pseudosectiontotext(dns_message_t *msg,
                        ADD_STRING(target, "\n");
                return (result);
        }
-       return (ISC_R_UNEXPECTED);
+       result = ISC_R_UNEXPECTED;
+ 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)
 {
-       unsigned int sflags = dns_master_styleflags(style);
        char buf[sizeof("1234567890")];
        isc_result_t result;
 
        REQUIRE(DNS_MESSAGE_VALID(msg));
        REQUIRE(target != NULL);
 
-       if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
-               if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
-                       ADD_STRING(target, dns_master_indentstr);
+       if (((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) &&
+            (dns_master_styleflags(style) & DNS_STYLEFLAG_YAML))
+       {
+               INDENT(style);
+               ADD_STRING(target, "opcode: ");
+               ADD_STRING(target, opcodetext[msg->opcode]);
+               ADD_STRING(target, "\n");
+               INDENT(style);
+               ADD_STRING(target, "status: ");
+               result = dns_rcode_totext(msg->rcode, target);
+               if (result != ISC_R_SUCCESS)
+                       return (result);
+               ADD_STRING(target, "\n");
+               INDENT(style);
+               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)
+                       ADD_STRING(target, " qr");
+               if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
+                       ADD_STRING(target, " aa");
+               if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
+                       ADD_STRING(target, " tc");
+               if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
+                       ADD_STRING(target, " rd");
+               if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
+                       ADD_STRING(target, " ra");
+               if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
+                       ADD_STRING(target, " ad");
+               if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
+                       ADD_STRING(target, " cd");
+               ADD_STRING(target, "\n");
+               /*
+                * The final unnamed flag must be zero.
+                */
+               if ((msg->flags & 0x0040U) != 0) {
+                       INDENT(style);
+                       ADD_STRING(target, "MBZ: 0x4");
+                       ADD_STRING(target, "\n");
+               }
+               if (msg->opcode != dns_opcode_update) {
+                       INDENT(style);
+                       ADD_STRING(target, "QUESTION: ");
+               } else {
+                       ADD_STRING(target, "ZONE: ");
+               }
+               snprintf(buf, sizeof(buf), "%1u",
+                        msg->counts[DNS_SECTION_QUESTION]);
+               ADD_STRING(target, buf);
+               ADD_STRING(target, "\n");
+               if (msg->opcode != dns_opcode_update) {
+                       INDENT(style);
+                       ADD_STRING(target, "ANSWER: ");
+               } else {
+                       INDENT(style);
+                       ADD_STRING(target, "PREREQ: ");
+               }
+               snprintf(buf, sizeof(buf), "%1u",
+                        msg->counts[DNS_SECTION_ANSWER]);
+               ADD_STRING(target, buf);
+               ADD_STRING(target, "\n");
+               if (msg->opcode != dns_opcode_update) {
+                       INDENT(style);
+                       ADD_STRING(target, "AUTHORITY: ");
+               } else {
+                       INDENT(style);
+                       ADD_STRING(target, "UPDATE: ");
+               }
+               snprintf(buf, sizeof(buf), "%1u",
+                       msg->counts[DNS_SECTION_AUTHORITY]);
+               ADD_STRING(target, buf);
+               ADD_STRING(target, "\n");
+               INDENT(style);
+               ADD_STRING(target, "ADDITIONAL: ");
+               snprintf(buf, sizeof(buf), "%1u",
+                       msg->counts[DNS_SECTION_ADDITIONAL]);
+               ADD_STRING(target, buf);
+               ADD_STRING(target, "\n");
+       } else if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
+               INDENT(style);
                ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
                ADD_STRING(target, opcodetext[msg->opcode]);
                ADD_STRING(target, ", status: ");
@@ -3543,8 +3905,7 @@ dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
                snprintf(buf, sizeof(buf), "%6u", msg->id);
                ADD_STRING(target, buf);
                ADD_STRING(target, "\n");
-               if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
-                       ADD_STRING(target, dns_master_indentstr);
+               INDENT(style);
                ADD_STRING(target, ";; flags:");
                if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
                        ADD_STRING(target, " qr");
@@ -3564,17 +3925,14 @@ dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
                 * The final unnamed flag must be zero.
                 */
                if ((msg->flags & 0x0040U) != 0) {
-                       if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
-                               ADD_STRING(target, dns_master_indentstr);
+                       INDENT(style);
                        ADD_STRING(target, "; MBZ: 0x4");
                }
                if (msg->opcode != dns_opcode_update) {
-                       if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
-                               ADD_STRING(target, dns_master_indentstr);
+                       INDENT(style);
                        ADD_STRING(target, "; QUESTION: ");
                } else {
-                       if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
-                               ADD_STRING(target, dns_master_indentstr);
+                       INDENT(style);
                        ADD_STRING(target, "; ZONE: ");
                }
                snprintf(buf, sizeof(buf), "%1u",
@@ -3637,7 +3995,8 @@ dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
        if (result != ISC_R_SUCCESS)
                return (result);
 
-       return (ISC_R_SUCCESS);
+ cleanup:
+       return (result);
 }
 
 isc_region_t *
index db1be5cecd1ed688e6501cde63682120de7d4748..f2104fff6f897cfb4e2710d33b273c83a2d02ecb 100644 (file)
@@ -501,6 +501,7 @@ dns_master_questiontotext
 dns_master_rdatasettotext
 dns_master_stylecreate
 dns_master_stylecreate2
+dns_master_stylecreate3
 dns_master_styledestroy
 dns_master_styleflags
 dns_message_addname