"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/dns/message.c" (7 Sep 2020, 116460 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "message.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 9.11.22_vs_9.11.23.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 /*! \file */
   13 
   14 /***
   15  *** Imports
   16  ***/
   17 
   18 #include <config.h>
   19 #include <ctype.h>
   20 #include <inttypes.h>
   21 #include <stdbool.h>
   22 
   23 #include <isc/buffer.h>
   24 #include <isc/mem.h>
   25 #include <isc/print.h>
   26 #include <isc/string.h> /* Required for HP/UX (and others?) */
   27 #include <isc/utf8.h>
   28 #include <isc/util.h>
   29 
   30 #include <dns/dnssec.h>
   31 #include <dns/keyvalues.h>
   32 #include <dns/log.h>
   33 #include <dns/masterdump.h>
   34 #include <dns/message.h>
   35 #include <dns/opcode.h>
   36 #include <dns/rcode.h>
   37 #include <dns/rdata.h>
   38 #include <dns/rdatalist.h>
   39 #include <dns/rdataset.h>
   40 #include <dns/rdatastruct.h>
   41 #include <dns/result.h>
   42 #include <dns/tsig.h>
   43 #include <dns/ttl.h>
   44 #include <dns/view.h>
   45 
   46 #ifdef SKAN_MSG_DEBUG
   47 static void
   48 hexdump(const char *msg, const char *msg2, void *base, size_t len) {
   49     unsigned char *p;
   50     unsigned int cnt;
   51 
   52     p = base;
   53     cnt = 0;
   54 
   55     printf("*** %s [%s] (%u bytes @ %p)\n", msg, msg2, (unsigned)len, base);
   56 
   57     while (cnt < len) {
   58         if (cnt % 16 == 0)
   59             printf("%p: ", p);
   60         else if (cnt % 8 == 0)
   61             printf(" |");
   62         printf(" %02x %c", *p, (isprint(*p) ? *p : ' '));
   63         p++;
   64         cnt++;
   65 
   66         if (cnt % 16 == 0)
   67             printf("\n");
   68     }
   69 
   70     if (cnt % 16 != 0)
   71         printf("\n");
   72 }
   73 #endif
   74 
   75 #define DNS_MESSAGE_OPCODE_MASK     0x7800U
   76 #define DNS_MESSAGE_OPCODE_SHIFT    11
   77 #define DNS_MESSAGE_RCODE_MASK      0x000fU
   78 #define DNS_MESSAGE_FLAG_MASK       0x8ff0U
   79 #define DNS_MESSAGE_EDNSRCODE_MASK  0xff000000U
   80 #define DNS_MESSAGE_EDNSRCODE_SHIFT 24
   81 #define DNS_MESSAGE_EDNSVERSION_MASK    0x00ff0000U
   82 #define DNS_MESSAGE_EDNSVERSION_SHIFT   16
   83 
   84 #define VALID_NAMED_SECTION(s)  (((s) > DNS_SECTION_ANY) \
   85                  && ((s) < DNS_SECTION_MAX))
   86 #define VALID_SECTION(s)    (((s) >= DNS_SECTION_ANY) \
   87                  && ((s) < DNS_SECTION_MAX))
   88 #define ADD_STRING(b, s)    {if (strlen(s) >= \
   89                    isc_buffer_availablelength(b)) { \
   90                        result = ISC_R_NOSPACE; \
   91                        goto cleanup; \
   92                  } else \
   93                        isc_buffer_putstr(b, s);}
   94 #define VALID_PSEUDOSECTION(s)  (((s) >= DNS_PSEUDOSECTION_ANY) \
   95                  && ((s) < DNS_PSEUDOSECTION_MAX))
   96 
   97 #define OPTOUT(x) (((x)->attributes & DNS_RDATASETATTR_OPTOUT) != 0)
   98 
   99 /*%
  100  * This is the size of each individual scratchpad buffer, and the numbers
  101  * of various block allocations used within the server.
  102  * XXXMLG These should come from a config setting.
  103  */
  104 #define SCRATCHPAD_SIZE     512
  105 #define NAME_COUNT       64
  106 #define OFFSET_COUNT          4
  107 #define RDATA_COUNT       8
  108 #define RDATALIST_COUNT       8
  109 #define RDATASET_COUNT           64
  110 
  111 /*%
  112  * Text representation of the different items, for message_totext
  113  * functions.
  114  */
  115 static const char *sectiontext[] = {
  116     "QUESTION",
  117     "ANSWER",
  118     "AUTHORITY",
  119     "ADDITIONAL"
  120 };
  121 
  122 static const char *updsectiontext[] = {
  123     "ZONE",
  124     "PREREQUISITE",
  125     "UPDATE",
  126     "ADDITIONAL"
  127 };
  128 
  129 static const char *opcodetext[] = {
  130     "QUERY",
  131     "IQUERY",
  132     "STATUS",
  133     "RESERVED3",
  134     "NOTIFY",
  135     "UPDATE",
  136     "RESERVED6",
  137     "RESERVED7",
  138     "RESERVED8",
  139     "RESERVED9",
  140     "RESERVED10",
  141     "RESERVED11",
  142     "RESERVED12",
  143     "RESERVED13",
  144     "RESERVED14",
  145     "RESERVED15"
  146 };
  147 
  148 static const char *edetext[] = { "Other",
  149                  "Unsupported DNSKEY Algorithm",
  150                  "Unsupported DS Digest Type",
  151                  "Stale Answer",
  152                  "Forged Answer",
  153                  "DNSSEC Indeterminate",
  154                  "DNSSEC Bogus",
  155                  "Signature Expired",
  156                  "Signature Not Yet Valid",
  157                  "DNSKEY Missing",
  158                  "RRSIGs Missing",
  159                  "No Zone Key Bit Set",
  160                  "NSEC Missing",
  161                  "Cached Error",
  162                  "Not Ready",
  163                  "Blocked",
  164                  "Censored",
  165                  "Filtered",
  166                  "Prohibited",
  167                  "Stale NXDOMAIN Answer",
  168                  "Not Authoritative",
  169                  "Not Supported",
  170                  "No Reachable Authority",
  171                  "Network Error",
  172                  "Invalid Data" };
  173 
  174 /*%
  175  * "helper" type, which consists of a block of some type, and is linkable.
  176  * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
  177  * size, or the allocated elements will not be aligned correctly.
  178  */
  179 struct dns_msgblock {
  180     unsigned int            count;
  181     unsigned int            remaining;
  182     ISC_LINK(dns_msgblock_t)    link;
  183 }; /* dynamically sized */
  184 
  185 static inline dns_msgblock_t *
  186 msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
  187 
  188 #define msgblock_get(block, type) \
  189     ((type *)msgblock_internalget(block, sizeof(type)))
  190 
  191 static inline void *
  192 msgblock_internalget(dns_msgblock_t *, unsigned int);
  193 
  194 static inline void
  195 msgblock_reset(dns_msgblock_t *);
  196 
  197 static inline void
  198 msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
  199 
  200 static void
  201 logfmtpacket(dns_message_t *message, const char *description,
  202          isc_sockaddr_t *address, isc_logcategory_t *category,
  203          isc_logmodule_t *module, const dns_master_style_t *style,
  204          int level, isc_mem_t *mctx);
  205 
  206 /*
  207  * Allocate a new dns_msgblock_t, and return a pointer to it.  If no memory
  208  * is free, return NULL.
  209  */
  210 static inline dns_msgblock_t *
  211 msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
  212           unsigned int count)
  213 {
  214     dns_msgblock_t *block;
  215     unsigned int length;
  216 
  217     length = sizeof(dns_msgblock_t) + (sizeof_type * count);
  218 
  219     block = isc_mem_get(mctx, length);
  220     if (block == NULL)
  221         return (NULL);
  222 
  223     block->count = count;
  224     block->remaining = count;
  225 
  226     ISC_LINK_INIT(block, link);
  227 
  228     return (block);
  229 }
  230 
  231 /*
  232  * Return an element from the msgblock.  If no more are available, return
  233  * NULL.
  234  */
  235 static inline void *
  236 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
  237     void *ptr;
  238 
  239     if (block == NULL || block->remaining == 0)
  240         return (NULL);
  241 
  242     block->remaining--;
  243 
  244     ptr = (((unsigned char *)block)
  245            + sizeof(dns_msgblock_t)
  246            + (sizeof_type * block->remaining));
  247 
  248     return (ptr);
  249 }
  250 
  251 static inline void
  252 msgblock_reset(dns_msgblock_t *block) {
  253     block->remaining = block->count;
  254 }
  255 
  256 /*
  257  * Release memory associated with a message block.
  258  */
  259 static inline void
  260 msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type)
  261 {
  262     unsigned int length;
  263 
  264     length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);
  265 
  266     isc_mem_put(mctx, block, length);
  267 }
  268 
  269 /*
  270  * Allocate a new dynamic buffer, and attach it to this message as the
  271  * "current" buffer.  (which is always the last on the list, for our
  272  * uses)
  273  */
  274 static inline isc_result_t
  275 newbuffer(dns_message_t *msg, unsigned int size) {
  276     isc_result_t result;
  277     isc_buffer_t *dynbuf;
  278 
  279     dynbuf = NULL;
  280     result = isc_buffer_allocate(msg->mctx, &dynbuf, size);
  281     if (result != ISC_R_SUCCESS)
  282         return (ISC_R_NOMEMORY);
  283 
  284     ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
  285     return (ISC_R_SUCCESS);
  286 }
  287 
  288 static inline isc_buffer_t *
  289 currentbuffer(dns_message_t *msg) {
  290     isc_buffer_t *dynbuf;
  291 
  292     dynbuf = ISC_LIST_TAIL(msg->scratchpad);
  293     INSIST(dynbuf != NULL);
  294 
  295     return (dynbuf);
  296 }
  297 
  298 static inline void
  299 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
  300     ISC_LIST_PREPEND(msg->freerdata, rdata, link);
  301 }
  302 
  303 static inline dns_rdata_t *
  304 newrdata(dns_message_t *msg) {
  305     dns_msgblock_t *msgblock;
  306     dns_rdata_t *rdata;
  307 
  308     rdata = ISC_LIST_HEAD(msg->freerdata);
  309     if (rdata != NULL) {
  310         ISC_LIST_UNLINK(msg->freerdata, rdata, link);
  311         return (rdata);
  312     }
  313 
  314     msgblock = ISC_LIST_TAIL(msg->rdatas);
  315     rdata = msgblock_get(msgblock, dns_rdata_t);
  316     if (rdata == NULL) {
  317         msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
  318                          RDATA_COUNT);
  319         if (msgblock == NULL)
  320             return (NULL);
  321 
  322         ISC_LIST_APPEND(msg->rdatas, msgblock, link);
  323 
  324         rdata = msgblock_get(msgblock, dns_rdata_t);
  325     }
  326 
  327     dns_rdata_init(rdata);
  328     return (rdata);
  329 }
  330 
  331 static inline void
  332 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
  333     ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
  334 }
  335 
  336 static inline dns_rdatalist_t *
  337 newrdatalist(dns_message_t *msg) {
  338     dns_msgblock_t *msgblock;
  339     dns_rdatalist_t *rdatalist;
  340 
  341     rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
  342     if (rdatalist != NULL) {
  343         ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
  344         goto out;
  345     }
  346 
  347     msgblock = ISC_LIST_TAIL(msg->rdatalists);
  348     rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
  349     if (rdatalist == NULL) {
  350         msgblock = msgblock_allocate(msg->mctx,
  351                          sizeof(dns_rdatalist_t),
  352                          RDATALIST_COUNT);
  353         if (msgblock == NULL)
  354             return (NULL);
  355 
  356         ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
  357 
  358         rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
  359     }
  360  out:
  361     if (rdatalist != NULL)
  362         dns_rdatalist_init(rdatalist);
  363 
  364     return (rdatalist);
  365 }
  366 
  367 static inline dns_offsets_t *
  368 newoffsets(dns_message_t *msg) {
  369     dns_msgblock_t *msgblock;
  370     dns_offsets_t *offsets;
  371 
  372     msgblock = ISC_LIST_TAIL(msg->offsets);
  373     offsets = msgblock_get(msgblock, dns_offsets_t);
  374     if (offsets == NULL) {
  375         msgblock = msgblock_allocate(msg->mctx,
  376                          sizeof(dns_offsets_t),
  377                          OFFSET_COUNT);
  378         if (msgblock == NULL)
  379             return (NULL);
  380 
  381         ISC_LIST_APPEND(msg->offsets, msgblock, link);
  382 
  383         offsets = msgblock_get(msgblock, dns_offsets_t);
  384     }
  385 
  386     return (offsets);
  387 }
  388 
  389 static inline void
  390 msginitheader(dns_message_t *m) {
  391     m->id = 0;
  392     m->flags = 0;
  393     m->rcode = 0;
  394     m->opcode = 0;
  395     m->rdclass = 0;
  396 }
  397 
  398 static inline void
  399 msginitprivate(dns_message_t *m) {
  400     unsigned int i;
  401 
  402     for (i = 0; i < DNS_SECTION_MAX; i++) {
  403         m->cursors[i] = NULL;
  404         m->counts[i] = 0;
  405     }
  406     m->opt = NULL;
  407     m->sig0 = NULL;
  408     m->sig0name = NULL;
  409     m->tsig = NULL;
  410     m->tsigname = NULL;
  411     m->state = DNS_SECTION_ANY;  /* indicate nothing parsed or rendered */
  412     m->opt_reserved = 0;
  413     m->sig_reserved = 0;
  414     m->reserved = 0;
  415     m->buffer = NULL;
  416 }
  417 
  418 static inline void
  419 msginittsig(dns_message_t *m) {
  420     m->tsigstatus = dns_rcode_noerror;
  421     m->querytsigstatus = dns_rcode_noerror;
  422     m->tsigkey = NULL;
  423     m->tsigctx = NULL;
  424     m->sigstart = -1;
  425     m->sig0key = NULL;
  426     m->sig0status = dns_rcode_noerror;
  427     m->timeadjust = 0;
  428 }
  429 
  430 /*
  431  * Init elements to default state.  Used both when allocating a new element
  432  * and when resetting one.
  433  */
  434 static inline void
  435 msginit(dns_message_t *m) {
  436     msginitheader(m);
  437     msginitprivate(m);
  438     msginittsig(m);
  439     m->header_ok = 0;
  440     m->question_ok = 0;
  441     m->tcp_continuation = 0;
  442     m->verified_sig = 0;
  443     m->verify_attempted = 0;
  444     m->order = NULL;
  445     m->order_arg = NULL;
  446     m->query.base = NULL;
  447     m->query.length = 0;
  448     m->free_query = 0;
  449     m->saved.base = NULL;
  450     m->saved.length = 0;
  451     m->free_saved = 0;
  452     m->cc_ok = 0;
  453     m->cc_bad = 0;
  454     m->tkey = 0;
  455     m->rdclass_set = 0;
  456     m->querytsig = NULL;
  457 }
  458 
  459 static inline void
  460 msgresetnames(dns_message_t *msg, unsigned int first_section) {
  461     unsigned int i;
  462     dns_name_t *name, *next_name;
  463     dns_rdataset_t *rds, *next_rds;
  464 
  465     /*
  466      * Clean up name lists by calling the rdataset disassociate function.
  467      */
  468     for (i = first_section; i < DNS_SECTION_MAX; i++) {
  469         name = ISC_LIST_HEAD(msg->sections[i]);
  470         while (name != NULL) {
  471             next_name = ISC_LIST_NEXT(name, link);
  472             ISC_LIST_UNLINK(msg->sections[i], name, link);
  473 
  474             rds = ISC_LIST_HEAD(name->list);
  475             while (rds != NULL) {
  476                 next_rds = ISC_LIST_NEXT(rds, link);
  477                 ISC_LIST_UNLINK(name->list, rds, link);
  478 
  479                 INSIST(dns_rdataset_isassociated(rds));
  480                 dns_rdataset_disassociate(rds);
  481                 isc_mempool_put(msg->rdspool, rds);
  482                 rds = next_rds;
  483             }
  484             if (dns_name_dynamic(name))
  485                 dns_name_free(name, msg->mctx);
  486             isc_mempool_put(msg->namepool, name);
  487             name = next_name;
  488         }
  489     }
  490 }
  491 
  492 static void
  493 msgresetopt(dns_message_t *msg)
  494 {
  495     if (msg->opt != NULL) {
  496         if (msg->opt_reserved > 0) {
  497             dns_message_renderrelease(msg, msg->opt_reserved);
  498             msg->opt_reserved = 0;
  499         }
  500         INSIST(dns_rdataset_isassociated(msg->opt));
  501         dns_rdataset_disassociate(msg->opt);
  502         isc_mempool_put(msg->rdspool, msg->opt);
  503         msg->opt = NULL;
  504         msg->cc_ok = 0;
  505         msg->cc_bad = 0;
  506     }
  507 }
  508 
  509 static void
  510 msgresetsigs(dns_message_t *msg, bool replying) {
  511     if (msg->sig_reserved > 0) {
  512         dns_message_renderrelease(msg, msg->sig_reserved);
  513         msg->sig_reserved = 0;
  514     }
  515     if (msg->tsig != NULL) {
  516         INSIST(dns_rdataset_isassociated(msg->tsig));
  517         INSIST(msg->namepool != NULL);
  518         if (replying) {
  519             INSIST(msg->querytsig == NULL);
  520             msg->querytsig = msg->tsig;
  521         } else {
  522             dns_rdataset_disassociate(msg->tsig);
  523             isc_mempool_put(msg->rdspool, msg->tsig);
  524             if (msg->querytsig != NULL) {
  525                 dns_rdataset_disassociate(msg->querytsig);
  526                 isc_mempool_put(msg->rdspool, msg->querytsig);
  527             }
  528         }
  529         if (dns_name_dynamic(msg->tsigname))
  530             dns_name_free(msg->tsigname, msg->mctx);
  531         isc_mempool_put(msg->namepool, msg->tsigname);
  532         msg->tsig = NULL;
  533         msg->tsigname = NULL;
  534     } else if (msg->querytsig != NULL && !replying) {
  535         dns_rdataset_disassociate(msg->querytsig);
  536         isc_mempool_put(msg->rdspool, msg->querytsig);
  537         msg->querytsig = NULL;
  538     }
  539     if (msg->sig0 != NULL) {
  540         INSIST(dns_rdataset_isassociated(msg->sig0));
  541         dns_rdataset_disassociate(msg->sig0);
  542         isc_mempool_put(msg->rdspool, msg->sig0);
  543         if (msg->sig0name != NULL) {
  544             if (dns_name_dynamic(msg->sig0name))
  545                 dns_name_free(msg->sig0name, msg->mctx);
  546             isc_mempool_put(msg->namepool, msg->sig0name);
  547         }
  548         msg->sig0 = NULL;
  549         msg->sig0name = NULL;
  550     }
  551 }
  552 
  553 /*
  554  * Free all but one (or everything) for this message.  This is used by
  555  * both dns_message_reset() and dns_message_destroy().
  556  */
  557 static void
  558 msgreset(dns_message_t *msg, bool everything) {
  559     dns_msgblock_t *msgblock, *next_msgblock;
  560     isc_buffer_t *dynbuf, *next_dynbuf;
  561     dns_rdata_t *rdata;
  562     dns_rdatalist_t *rdatalist;
  563 
  564     msgresetnames(msg, 0);
  565     msgresetopt(msg);
  566     msgresetsigs(msg, false);
  567 
  568     /*
  569      * Clean up linked lists.
  570      */
  571 
  572     /*
  573      * Run through the free lists, and just unlink anything found there.
  574      * The memory isn't lost since these are part of message blocks we
  575      * have allocated.
  576      */
  577     rdata = ISC_LIST_HEAD(msg->freerdata);
  578     while (rdata != NULL) {
  579         ISC_LIST_UNLINK(msg->freerdata, rdata, link);
  580         rdata = ISC_LIST_HEAD(msg->freerdata);
  581     }
  582     rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
  583     while (rdatalist != NULL) {
  584         ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
  585         rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
  586     }
  587 
  588     dynbuf = ISC_LIST_HEAD(msg->scratchpad);
  589     INSIST(dynbuf != NULL);
  590     if (!everything) {
  591         isc_buffer_clear(dynbuf);
  592         dynbuf = ISC_LIST_NEXT(dynbuf, link);
  593     }
  594     while (dynbuf != NULL) {
  595         next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
  596         ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
  597         isc_buffer_free(&dynbuf);
  598         dynbuf = next_dynbuf;
  599     }
  600 
  601     msgblock = ISC_LIST_HEAD(msg->rdatas);
  602     if (!everything && msgblock != NULL) {
  603         msgblock_reset(msgblock);
  604         msgblock = ISC_LIST_NEXT(msgblock, link);
  605     }
  606     while (msgblock != NULL) {
  607         next_msgblock = ISC_LIST_NEXT(msgblock, link);
  608         ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
  609         msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
  610         msgblock = next_msgblock;
  611     }
  612 
  613     /*
  614      * rdatalists could be empty.
  615      */
  616 
  617     msgblock = ISC_LIST_HEAD(msg->rdatalists);
  618     if (!everything && msgblock != NULL) {
  619         msgblock_reset(msgblock);
  620         msgblock = ISC_LIST_NEXT(msgblock, link);
  621     }
  622     while (msgblock != NULL) {
  623         next_msgblock = ISC_LIST_NEXT(msgblock, link);
  624         ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
  625         msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
  626         msgblock = next_msgblock;
  627     }
  628 
  629     msgblock = ISC_LIST_HEAD(msg->offsets);
  630     if (!everything && msgblock != NULL) {
  631         msgblock_reset(msgblock);
  632         msgblock = ISC_LIST_NEXT(msgblock, link);
  633     }
  634     while (msgblock != NULL) {
  635         next_msgblock = ISC_LIST_NEXT(msgblock, link);
  636         ISC_LIST_UNLINK(msg->offsets, msgblock, link);
  637         msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t));
  638         msgblock = next_msgblock;
  639     }
  640 
  641     if (msg->tsigkey != NULL) {
  642         dns_tsigkey_detach(&msg->tsigkey);
  643         msg->tsigkey = NULL;
  644     }
  645 
  646     if (msg->tsigctx != NULL)
  647         dst_context_destroy(&msg->tsigctx);
  648 
  649     if (msg->query.base != NULL) {
  650         if (msg->free_query != 0)
  651             isc_mem_put(msg->mctx, msg->query.base,
  652                     msg->query.length);
  653         msg->query.base = NULL;
  654         msg->query.length = 0;
  655     }
  656 
  657     if (msg->saved.base != NULL) {
  658         if (msg->free_saved != 0)
  659             isc_mem_put(msg->mctx, msg->saved.base,
  660                     msg->saved.length);
  661         msg->saved.base = NULL;
  662         msg->saved.length = 0;
  663     }
  664 
  665     /*
  666      * cleanup the buffer cleanup list
  667      */
  668     dynbuf = ISC_LIST_HEAD(msg->cleanup);
  669     while (dynbuf != NULL) {
  670         next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
  671         ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
  672         isc_buffer_free(&dynbuf);
  673         dynbuf = next_dynbuf;
  674     }
  675 
  676     /*
  677      * Set other bits to normal default values.
  678      */
  679     if (!everything)
  680         msginit(msg);
  681 
  682     ENSURE(isc_mempool_getallocated(msg->namepool) == 0);
  683     ENSURE(isc_mempool_getallocated(msg->rdspool) == 0);
  684 }
  685 
  686 static unsigned int
  687 spacefortsig(dns_tsigkey_t *key, int otherlen) {
  688     isc_region_t r1, r2;
  689     unsigned int x;
  690     isc_result_t result;
  691 
  692     /*
  693      * The space required for an TSIG record is:
  694      *
  695      *  n1 bytes for the name
  696      *  2 bytes for the type
  697      *  2 bytes for the class
  698      *  4 bytes for the ttl
  699      *  2 bytes for the rdlength
  700      *  n2 bytes for the algorithm name
  701      *  6 bytes for the time signed
  702      *  2 bytes for the fudge
  703      *  2 bytes for the MAC size
  704      *  x bytes for the MAC
  705      *  2 bytes for the original id
  706      *  2 bytes for the error
  707      *  2 bytes for the other data length
  708      *  y bytes for the other data (at most)
  709      * ---------------------------------
  710      *     26 + n1 + n2 + x + y bytes
  711      */
  712 
  713     dns_name_toregion(&key->name, &r1);
  714     dns_name_toregion(key->algorithm, &r2);
  715     if (key->key == NULL)
  716         x = 0;
  717     else {
  718         result = dst_key_sigsize(key->key, &x);
  719         if (result != ISC_R_SUCCESS)
  720             x = 0;
  721     }
  722     return (26 + r1.length + r2.length + x + otherlen);
  723 }
  724 
  725 isc_result_t
  726 dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
  727 {
  728     dns_message_t *m;
  729     isc_result_t result;
  730     isc_buffer_t *dynbuf;
  731     unsigned int i;
  732 
  733     REQUIRE(mctx != NULL);
  734     REQUIRE(msgp != NULL);
  735     REQUIRE(*msgp == NULL);
  736     REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
  737         || intent == DNS_MESSAGE_INTENTRENDER);
  738 
  739     m = isc_mem_get(mctx, sizeof(dns_message_t));
  740     if (m == NULL)
  741         return (ISC_R_NOMEMORY);
  742 
  743     /*
  744      * No allocations until further notice.  Just initialize all lists
  745      * and other members that are freed in the cleanup phase here.
  746      */
  747 
  748     m->magic = DNS_MESSAGE_MAGIC;
  749     m->from_to_wire = intent;
  750     msginit(m);
  751 
  752     for (i = 0; i < DNS_SECTION_MAX; i++)
  753         ISC_LIST_INIT(m->sections[i]);
  754 
  755     m->mctx = NULL;
  756     isc_mem_attach(mctx, &m->mctx);
  757 
  758     ISC_LIST_INIT(m->scratchpad);
  759     ISC_LIST_INIT(m->cleanup);
  760     m->namepool = NULL;
  761     m->rdspool = NULL;
  762     ISC_LIST_INIT(m->rdatas);
  763     ISC_LIST_INIT(m->rdatalists);
  764     ISC_LIST_INIT(m->offsets);
  765     ISC_LIST_INIT(m->freerdata);
  766     ISC_LIST_INIT(m->freerdatalist);
  767 
  768     /*
  769      * Ok, it is safe to allocate (and then "goto cleanup" if failure)
  770      */
  771 
  772     result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool);
  773     if (result != ISC_R_SUCCESS)
  774         goto cleanup;
  775     isc_mempool_setfillcount(m->namepool, NAME_COUNT);
  776     isc_mempool_setfreemax(m->namepool, NAME_COUNT);
  777     isc_mempool_setname(m->namepool, "msg:names");
  778 
  779     result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t),
  780                     &m->rdspool);
  781     if (result != ISC_R_SUCCESS)
  782         goto cleanup;
  783     isc_mempool_setfillcount(m->rdspool, RDATASET_COUNT);
  784     isc_mempool_setfreemax(m->rdspool, RDATASET_COUNT);
  785     isc_mempool_setname(m->rdspool, "msg:rdataset");
  786 
  787     dynbuf = NULL;
  788     result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE);
  789     if (result != ISC_R_SUCCESS)
  790         goto cleanup;
  791     ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
  792 
  793     m->cctx = NULL;
  794 
  795     *msgp = m;
  796     return (ISC_R_SUCCESS);
  797 
  798     /*
  799      * Cleanup for error returns.
  800      */
  801  cleanup:
  802     dynbuf = ISC_LIST_HEAD(m->scratchpad);
  803     if (dynbuf != NULL) {
  804         ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
  805         isc_buffer_free(&dynbuf);
  806     }
  807     if (m->namepool != NULL)
  808         isc_mempool_destroy(&m->namepool);
  809     if (m->rdspool != NULL)
  810         isc_mempool_destroy(&m->rdspool);
  811     m->magic = 0;
  812     isc_mem_putanddetach(&mctx, m, sizeof(dns_message_t));
  813 
  814     return (ISC_R_NOMEMORY);
  815 }
  816 
  817 void
  818 dns_message_reset(dns_message_t *msg, unsigned int intent) {
  819     REQUIRE(DNS_MESSAGE_VALID(msg));
  820     REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
  821         || intent == DNS_MESSAGE_INTENTRENDER);
  822 
  823     msgreset(msg, false);
  824     msg->from_to_wire = intent;
  825 }
  826 
  827 void
  828 dns_message_destroy(dns_message_t **msgp) {
  829     dns_message_t *msg;
  830 
  831     REQUIRE(msgp != NULL);
  832     REQUIRE(DNS_MESSAGE_VALID(*msgp));
  833 
  834     msg = *msgp;
  835     *msgp = NULL;
  836 
  837     msgreset(msg, true);
  838     isc_mempool_destroy(&msg->namepool);
  839     isc_mempool_destroy(&msg->rdspool);
  840     msg->magic = 0;
  841     isc_mem_putanddetach(&msg->mctx, msg, sizeof(dns_message_t));
  842 }
  843 
  844 static isc_result_t
  845 findname(dns_name_t **foundname, dns_name_t *target,
  846      dns_namelist_t *section)
  847 {
  848     dns_name_t *curr;
  849 
  850     for (curr = ISC_LIST_TAIL(*section);
  851          curr != NULL;
  852          curr = ISC_LIST_PREV(curr, link)) {
  853         if (dns_name_equal(curr, target)) {
  854             if (foundname != NULL)
  855                 *foundname = curr;
  856             return (ISC_R_SUCCESS);
  857         }
  858     }
  859 
  860     return (ISC_R_NOTFOUND);
  861 }
  862 
  863 isc_result_t
  864 dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
  865          dns_rdatatype_t type, dns_rdatatype_t covers,
  866          dns_rdataset_t **rdataset)
  867 {
  868     dns_rdataset_t *curr;
  869 
  870     REQUIRE(name != NULL);
  871     REQUIRE(rdataset == NULL || *rdataset == NULL);
  872 
  873     for (curr = ISC_LIST_TAIL(name->list);
  874          curr != NULL;
  875          curr = ISC_LIST_PREV(curr, link)) {
  876         if (curr->rdclass == rdclass &&
  877             curr->type == type && curr->covers == covers) {
  878             if (rdataset != NULL)
  879                 *rdataset = curr;
  880             return (ISC_R_SUCCESS);
  881         }
  882     }
  883 
  884     return (ISC_R_NOTFOUND);
  885 }
  886 
  887 isc_result_t
  888 dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
  889              dns_rdatatype_t covers, dns_rdataset_t **rdataset)
  890 {
  891     dns_rdataset_t *curr;
  892 
  893     REQUIRE(name != NULL);
  894     REQUIRE(rdataset == NULL || *rdataset == NULL);
  895 
  896     for (curr = ISC_LIST_TAIL(name->list);
  897          curr != NULL;
  898          curr = ISC_LIST_PREV(curr, link)) {
  899         if (curr->type == type && curr->covers == covers) {
  900             if (ISC_UNLIKELY(rdataset != NULL))
  901                 *rdataset = curr;
  902             return (ISC_R_SUCCESS);
  903         }
  904     }
  905 
  906     return (ISC_R_NOTFOUND);
  907 }
  908 
  909 /*
  910  * Read a name from buffer "source".
  911  */
  912 static isc_result_t
  913 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
  914     dns_decompress_t *dctx)
  915 {
  916     isc_buffer_t *scratch;
  917     isc_result_t result;
  918     unsigned int tries;
  919 
  920     scratch = currentbuffer(msg);
  921 
  922     /*
  923      * First try:  use current buffer.
  924      * Second try:  allocate a new buffer and use that.
  925      */
  926     tries = 0;
  927     while (tries < 2) {
  928         result = dns_name_fromwire(name, source, dctx, 0,
  929                        scratch);
  930 
  931         if (result == ISC_R_NOSPACE) {
  932             tries++;
  933 
  934             result = newbuffer(msg, SCRATCHPAD_SIZE);
  935             if (result != ISC_R_SUCCESS)
  936                 return (result);
  937 
  938             scratch = currentbuffer(msg);
  939             dns_name_reset(name);
  940         } else {
  941             return (result);
  942         }
  943     }
  944 
  945     INSIST(0);
  946     ISC_UNREACHABLE();
  947 }
  948 
  949 static isc_result_t
  950 getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
  951      dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
  952      unsigned int rdatalen, dns_rdata_t *rdata)
  953 {
  954     isc_buffer_t *scratch;
  955     isc_result_t result;
  956     unsigned int tries;
  957     unsigned int trysize;
  958 
  959     scratch = currentbuffer(msg);
  960 
  961     isc_buffer_setactive(source, rdatalen);
  962 
  963     /*
  964      * First try:  use current buffer.
  965      * Second try:  allocate a new buffer of size
  966      *     max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
  967      *     (the data will fit if it was not more than 50% compressed)
  968      * Subsequent tries: double buffer size on each try.
  969      */
  970     tries = 0;
  971     trysize = 0;
  972     /* XXX possibly change this to a while (tries < 2) loop */
  973     for (;;) {
  974         result = dns_rdata_fromwire(rdata, rdclass, rdtype,
  975                         source, dctx, 0,
  976                         scratch);
  977 
  978         if (result == ISC_R_NOSPACE) {
  979             if (tries == 0) {
  980                 trysize = 2 * rdatalen;
  981                 if (trysize < SCRATCHPAD_SIZE)
  982                     trysize = SCRATCHPAD_SIZE;
  983             } else {
  984                 INSIST(trysize != 0);
  985                 if (trysize >= 65535)
  986                     return (ISC_R_NOSPACE);
  987                     /* XXX DNS_R_RRTOOLONG? */
  988                 trysize *= 2;
  989             }
  990             tries++;
  991             result = newbuffer(msg, trysize);
  992             if (result != ISC_R_SUCCESS)
  993                 return (result);
  994 
  995             scratch = currentbuffer(msg);
  996         } else {
  997             return (result);
  998         }
  999     }
 1000 }
 1001 
 1002 #define DO_ERROR(r)                 \
 1003     do {                        \
 1004         if (best_effort)            \
 1005             seen_problem = true;    \
 1006         else {                  \
 1007             result = r;         \
 1008             goto cleanup;           \
 1009         }                   \
 1010     } while (0)
 1011 
 1012 static isc_result_t
 1013 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
 1014          unsigned int options)
 1015 {
 1016     isc_region_t r;
 1017     unsigned int count;
 1018     dns_name_t *name;
 1019     dns_name_t *name2;
 1020     dns_offsets_t *offsets;
 1021     dns_rdataset_t *rdataset;
 1022     dns_rdatalist_t *rdatalist;
 1023     isc_result_t result;
 1024     dns_rdatatype_t rdtype;
 1025     dns_rdataclass_t rdclass;
 1026     dns_namelist_t *section;
 1027     bool free_name;
 1028     bool best_effort;
 1029     bool seen_problem;
 1030 
 1031     section = &msg->sections[DNS_SECTION_QUESTION];
 1032 
 1033     best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
 1034     seen_problem = false;
 1035 
 1036     name = NULL;
 1037     rdataset = NULL;
 1038     rdatalist = NULL;
 1039 
 1040     for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
 1041         name = isc_mempool_get(msg->namepool);
 1042         if (name == NULL)
 1043             return (ISC_R_NOMEMORY);
 1044         free_name = true;
 1045 
 1046         offsets = newoffsets(msg);
 1047         if (offsets == NULL) {
 1048             result = ISC_R_NOMEMORY;
 1049             goto cleanup;
 1050         }
 1051         dns_name_init(name, *offsets);
 1052 
 1053         /*
 1054          * Parse the name out of this packet.
 1055          */
 1056         isc_buffer_remainingregion(source, &r);
 1057         isc_buffer_setactive(source, r.length);
 1058         result = getname(name, source, msg, dctx);
 1059         if (result != ISC_R_SUCCESS)
 1060             goto cleanup;
 1061 
 1062         /*
 1063          * Run through the section, looking to see if this name
 1064          * is already there.  If it is found, put back the allocated
 1065          * name since we no longer need it, and set our name pointer
 1066          * to point to the name we found.
 1067          */
 1068         result = findname(&name2, name, section);
 1069 
 1070         /*
 1071          * If it is the first name in the section, accept it.
 1072          *
 1073          * If it is not, but is not the same as the name already
 1074          * in the question section, append to the section.  Note that
 1075          * here in the question section this is illegal, so return
 1076          * FORMERR.  In the future, check the opcode to see if
 1077          * this should be legal or not.  In either case we no longer
 1078          * need this name pointer.
 1079          */
 1080         if (result != ISC_R_SUCCESS) {
 1081             if (!ISC_LIST_EMPTY(*section))
 1082                 DO_ERROR(DNS_R_FORMERR);
 1083             ISC_LIST_APPEND(*section, name, link);
 1084             free_name = false;
 1085         } else {
 1086             isc_mempool_put(msg->namepool, name);
 1087             name = name2;
 1088             name2 = NULL;
 1089             free_name = false;
 1090         }
 1091 
 1092         /*
 1093          * Get type and class.
 1094          */
 1095         isc_buffer_remainingregion(source, &r);
 1096         if (r.length < 4) {
 1097             result = ISC_R_UNEXPECTEDEND;
 1098             goto cleanup;
 1099         }
 1100         rdtype = isc_buffer_getuint16(source);
 1101         rdclass = isc_buffer_getuint16(source);
 1102 
 1103         /*
 1104          * If this class is different than the one we already read,
 1105          * this is an error.
 1106          */
 1107         if (msg->rdclass_set == 0) {
 1108             msg->rdclass = rdclass;
 1109             msg->rdclass_set = 1;
 1110         } else if (msg->rdclass != rdclass)
 1111             DO_ERROR(DNS_R_FORMERR);
 1112 
 1113         /*
 1114          * Is this a TKEY query?
 1115          */
 1116         if (rdtype == dns_rdatatype_tkey)
 1117             msg->tkey = 1;
 1118 
 1119         /*
 1120          * Can't ask the same question twice.
 1121          */
 1122         result = dns_message_find(name, rdclass, rdtype, 0, NULL);
 1123         if (result == ISC_R_SUCCESS)
 1124             DO_ERROR(DNS_R_FORMERR);
 1125 
 1126         /*
 1127          * Allocate a new rdatalist.
 1128          */
 1129         rdatalist = newrdatalist(msg);
 1130         if (rdatalist == NULL) {
 1131             result = ISC_R_NOMEMORY;
 1132             goto cleanup;
 1133         }
 1134         rdataset =  isc_mempool_get(msg->rdspool);
 1135         if (rdataset == NULL) {
 1136             result = ISC_R_NOMEMORY;
 1137             goto cleanup;
 1138         }
 1139 
 1140         /*
 1141          * Convert rdatalist to rdataset, and attach the latter to
 1142          * the name.
 1143          */
 1144         rdatalist->type = rdtype;
 1145         rdatalist->rdclass = rdclass;
 1146 
 1147         dns_rdataset_init(rdataset);
 1148         result = dns_rdatalist_tordataset(rdatalist, rdataset);
 1149         if (result != ISC_R_SUCCESS)
 1150             goto cleanup;
 1151 
 1152         rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
 1153 
 1154         ISC_LIST_APPEND(name->list, rdataset, link);
 1155         rdataset = NULL;
 1156     }
 1157 
 1158     if (seen_problem)
 1159         return (DNS_R_RECOVERABLE);
 1160     return (ISC_R_SUCCESS);
 1161 
 1162  cleanup:
 1163     if (rdataset != NULL) {
 1164         INSIST(!dns_rdataset_isassociated(rdataset));
 1165         isc_mempool_put(msg->rdspool, rdataset);
 1166     }
 1167 #if 0
 1168     if (rdatalist != NULL)
 1169         isc_mempool_put(msg->rdlpool, rdatalist);
 1170 #endif
 1171     if (free_name)
 1172         isc_mempool_put(msg->namepool, name);
 1173 
 1174     return (result);
 1175 }
 1176 
 1177 static bool
 1178 update(dns_section_t section, dns_rdataclass_t rdclass) {
 1179     if (section == DNS_SECTION_PREREQUISITE)
 1180         return (rdclass == dns_rdataclass_any ||
 1181              rdclass == dns_rdataclass_none);
 1182     if (section == DNS_SECTION_UPDATE)
 1183         return (rdclass == dns_rdataclass_any);
 1184     return (false);
 1185 }
 1186 
 1187 /*
 1188  * Check to confirm that all DNSSEC records (DS, NSEC, NSEC3) have
 1189  * covering RRSIGs.
 1190  */
 1191 static bool
 1192 auth_signed(dns_namelist_t *section) {
 1193     dns_name_t *name;
 1194 
 1195     for (name = ISC_LIST_HEAD(*section);
 1196          name != NULL;
 1197          name = ISC_LIST_NEXT(name, link))
 1198     {
 1199         int auth_dnssec = 0, auth_rrsig = 0;
 1200         dns_rdataset_t *rds;
 1201 
 1202         for (rds = ISC_LIST_HEAD(name->list);
 1203              rds != NULL;
 1204              rds = ISC_LIST_NEXT(rds, link))
 1205         {
 1206             switch (rds->type) {
 1207             case dns_rdatatype_ds:
 1208                 auth_dnssec |= 0x1;
 1209                 break;
 1210             case dns_rdatatype_nsec:
 1211                 auth_dnssec |= 0x2;
 1212                 break;
 1213             case dns_rdatatype_nsec3:
 1214                 auth_dnssec |= 0x4;
 1215                 break;
 1216             case dns_rdatatype_rrsig:
 1217                 break;
 1218             default:
 1219                 continue;
 1220             }
 1221 
 1222             switch (rds->covers) {
 1223             case dns_rdatatype_ds:
 1224                 auth_rrsig |= 0x1;
 1225                 break;
 1226             case dns_rdatatype_nsec:
 1227                 auth_rrsig |= 0x2;
 1228                 break;
 1229             case dns_rdatatype_nsec3:
 1230                 auth_rrsig |= 0x4;
 1231                 break;
 1232             default:
 1233                 break;
 1234             }
 1235         }
 1236 
 1237         if (auth_dnssec != auth_rrsig)
 1238             return (false);
 1239     }
 1240 
 1241     return (true);
 1242 }
 1243 
 1244 static isc_result_t
 1245 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
 1246        dns_section_t sectionid, unsigned int options)
 1247 {
 1248     isc_region_t r;
 1249     unsigned int count, rdatalen;
 1250     dns_name_t *name = NULL;
 1251     dns_name_t *name2 = NULL;
 1252     dns_offsets_t *offsets;
 1253     dns_rdataset_t *rdataset;
 1254     dns_rdatalist_t *rdatalist;
 1255     isc_result_t result;
 1256     dns_rdatatype_t rdtype, covers;
 1257     dns_rdataclass_t rdclass;
 1258     dns_rdata_t *rdata;
 1259     dns_ttl_t ttl;
 1260     dns_namelist_t *section;
 1261     bool free_name = false, free_rdataset = false;
 1262     bool preserve_order, best_effort, seen_problem;
 1263     bool isedns, issigzero, istsig;
 1264 
 1265     preserve_order = ((options & DNS_MESSAGEPARSE_PRESERVEORDER) != 0);
 1266     best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
 1267     seen_problem = false;
 1268 
 1269     section = &msg->sections[sectionid];
 1270 
 1271     for (count = 0; count < msg->counts[sectionid]; count++) {
 1272         int recstart = source->current;
 1273         bool skip_name_search, skip_type_search;
 1274 
 1275         skip_name_search = false;
 1276         skip_type_search = false;
 1277         free_rdataset = false;
 1278         isedns = false;
 1279         issigzero = false;
 1280         istsig = false;
 1281 
 1282         name = isc_mempool_get(msg->namepool);
 1283         if (name == NULL)
 1284             return (ISC_R_NOMEMORY);
 1285         free_name = true;
 1286 
 1287         offsets = newoffsets(msg);
 1288         if (offsets == NULL) {
 1289             result = ISC_R_NOMEMORY;
 1290             goto cleanup;
 1291         }
 1292         dns_name_init(name, *offsets);
 1293 
 1294         /*
 1295          * Parse the name out of this packet.
 1296          */
 1297         isc_buffer_remainingregion(source, &r);
 1298         isc_buffer_setactive(source, r.length);
 1299         result = getname(name, source, msg, dctx);
 1300         if (result != ISC_R_SUCCESS)
 1301             goto cleanup;
 1302 
 1303         /*
 1304          * Get type, class, ttl, and rdatalen.  Verify that at least
 1305          * rdatalen bytes remain.  (Some of this is deferred to
 1306          * later.)
 1307          */
 1308         isc_buffer_remainingregion(source, &r);
 1309         if (r.length < 2 + 2 + 4 + 2) {
 1310             result = ISC_R_UNEXPECTEDEND;
 1311             goto cleanup;
 1312         }
 1313         rdtype = isc_buffer_getuint16(source);
 1314         rdclass = isc_buffer_getuint16(source);
 1315 
 1316         /*
 1317          * If there was no question section, we may not yet have
 1318          * established a class.  Do so now.
 1319          */
 1320         if (msg->rdclass_set == 0 &&
 1321             rdtype != dns_rdatatype_opt &&  /* class is UDP SIZE */
 1322             rdtype != dns_rdatatype_tsig && /* class is ANY */
 1323             rdtype != dns_rdatatype_tkey) { /* class is undefined */
 1324             msg->rdclass = rdclass;
 1325             msg->rdclass_set = 1;
 1326         }
 1327 
 1328         /*
 1329          * If this class is different than the one in the question
 1330          * section, bail.
 1331          */
 1332         if (msg->opcode != dns_opcode_update
 1333             && rdtype != dns_rdatatype_tsig
 1334             && rdtype != dns_rdatatype_opt
 1335             && rdtype != dns_rdatatype_key /* in a TKEY query */
 1336             && rdtype != dns_rdatatype_sig /* SIG(0) */
 1337             && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
 1338             && msg->rdclass != dns_rdataclass_any
 1339             && msg->rdclass != rdclass)
 1340             DO_ERROR(DNS_R_FORMERR);
 1341 
 1342         /*
 1343          * If this is not a TKEY query/response then the KEY
 1344          * record's class needs to match.
 1345          */
 1346         if (msg->opcode != dns_opcode_update && !msg->tkey &&
 1347             rdtype == dns_rdatatype_key &&
 1348             msg->rdclass != dns_rdataclass_any &&
 1349             msg->rdclass != rdclass)
 1350             DO_ERROR(DNS_R_FORMERR);
 1351 
 1352         /*
 1353          * Special type handling for TSIG, OPT, and TKEY.
 1354          */
 1355         if (rdtype == dns_rdatatype_tsig) {
 1356             /*
 1357              * If it is a tsig, verify that it is in the
 1358              * additional data section.
 1359              */
 1360             if (sectionid != DNS_SECTION_ADDITIONAL ||
 1361                 rdclass != dns_rdataclass_any ||
 1362                 count != msg->counts[sectionid]  - 1) {
 1363                 DO_ERROR(DNS_R_BADTSIG);
 1364             } else {
 1365                 skip_name_search = true;
 1366                 skip_type_search = true;
 1367                 istsig = true;
 1368             }
 1369         } else if (rdtype == dns_rdatatype_opt) {
 1370             /*
 1371              * The name of an OPT record must be ".", it
 1372              * must be in the additional data section, and
 1373              * it must be the first OPT we've seen.
 1374              */
 1375             if (!dns_name_equal(dns_rootname, name) ||
 1376                 sectionid != DNS_SECTION_ADDITIONAL ||
 1377                 msg->opt != NULL) {
 1378                 DO_ERROR(DNS_R_FORMERR);
 1379             } else {
 1380                 skip_name_search = true;
 1381                 skip_type_search = true;
 1382                 isedns = true;
 1383             }
 1384         } else if (rdtype == dns_rdatatype_tkey) {
 1385             /*
 1386              * A TKEY must be in the additional section if this
 1387              * is a query, and the answer section if this is a
 1388              * response.  Unless it's a Win2000 client.
 1389              *
 1390              * Its class is ignored.
 1391              */
 1392             dns_section_t tkeysection;
 1393 
 1394             if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
 1395                 tkeysection = DNS_SECTION_ADDITIONAL;
 1396             else
 1397                 tkeysection = DNS_SECTION_ANSWER;
 1398             if (sectionid != tkeysection &&
 1399                 sectionid != DNS_SECTION_ANSWER)
 1400                 DO_ERROR(DNS_R_FORMERR);
 1401         }
 1402 
 1403         /*
 1404          * ... now get ttl and rdatalen, and check buffer.
 1405          */
 1406         ttl = isc_buffer_getuint32(source);
 1407         rdatalen = isc_buffer_getuint16(source);
 1408         r.length -= (2 + 2 + 4 + 2);
 1409         if (r.length < rdatalen) {
 1410             result = ISC_R_UNEXPECTEDEND;
 1411             goto cleanup;
 1412         }
 1413 
 1414         /*
 1415          * Read the rdata from the wire format.  Interpret the
 1416          * rdata according to its actual class, even if it had a
 1417          * DynDNS meta-class in the packet (unless this is a TSIG).
 1418          * Then put the meta-class back into the finished rdata.
 1419          */
 1420         rdata = newrdata(msg);
 1421         if (rdata == NULL) {
 1422             result = ISC_R_NOMEMORY;
 1423             goto cleanup;
 1424         }
 1425         if (msg->opcode == dns_opcode_update &&
 1426             update(sectionid, rdclass)) {
 1427             if (rdatalen != 0) {
 1428                 result = DNS_R_FORMERR;
 1429                 goto cleanup;
 1430             }
 1431             /*
 1432              * When the rdata is empty, the data pointer is
 1433              * never dereferenced, but it must still be non-NULL.
 1434              * Casting 1 rather than "" avoids warnings about
 1435              * discarding the const attribute of a string,
 1436              * for compilers that would warn about such things.
 1437              */
 1438             rdata->data = (unsigned char *)1;
 1439             rdata->length = 0;
 1440             rdata->rdclass = rdclass;
 1441             rdata->type = rdtype;
 1442             rdata->flags = DNS_RDATA_UPDATE;
 1443             result = ISC_R_SUCCESS;
 1444         } else if (rdclass == dns_rdataclass_none &&
 1445                msg->opcode == dns_opcode_update &&
 1446                sectionid == DNS_SECTION_UPDATE) {
 1447             result = getrdata(source, msg, dctx, msg->rdclass,
 1448                       rdtype, rdatalen, rdata);
 1449         } else
 1450             result = getrdata(source, msg, dctx, rdclass,
 1451                       rdtype, rdatalen, rdata);
 1452         if (result != ISC_R_SUCCESS)
 1453             goto cleanup;
 1454         rdata->rdclass = rdclass;
 1455         if (rdtype == dns_rdatatype_rrsig &&
 1456             rdata->flags == 0) {
 1457             covers = dns_rdata_covers(rdata);
 1458             if (covers == 0)
 1459                 DO_ERROR(DNS_R_FORMERR);
 1460         } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
 1461                rdata->flags == 0) {
 1462             covers = dns_rdata_covers(rdata);
 1463             if (covers == 0) {
 1464                 if (sectionid != DNS_SECTION_ADDITIONAL ||
 1465                     count != msg->counts[sectionid]  - 1) {
 1466                     DO_ERROR(DNS_R_BADSIG0);
 1467                 } else {
 1468                     skip_name_search = true;
 1469                     skip_type_search = true;
 1470                     issigzero = true;
 1471                 }
 1472             } else {
 1473                 if (msg->rdclass != dns_rdataclass_any &&
 1474                     msg->rdclass != rdclass)
 1475                     DO_ERROR(DNS_R_FORMERR);
 1476             }
 1477         } else
 1478             covers = 0;
 1479 
 1480         /*
 1481          * Check the ownername of NSEC3 records
 1482          */
 1483         if (rdtype == dns_rdatatype_nsec3 &&
 1484             !dns_rdata_checkowner(name, msg->rdclass, rdtype,
 1485                       false)) {
 1486             result = DNS_R_BADOWNERNAME;
 1487             goto cleanup;
 1488         }
 1489 
 1490         /*
 1491          * If we are doing a dynamic update or this is a meta-type,
 1492          * don't bother searching for a name, just append this one
 1493          * to the end of the message.
 1494          */
 1495         if (preserve_order || msg->opcode == dns_opcode_update ||
 1496             skip_name_search) {
 1497             if (!isedns && !istsig && !issigzero) {
 1498                 ISC_LIST_APPEND(*section, name, link);
 1499                 free_name = false;
 1500             }
 1501         } else {
 1502             /*
 1503              * Run through the section, looking to see if this name
 1504              * is already there.  If it is found, put back the
 1505              * allocated name since we no longer need it, and set
 1506              * our name pointer to point to the name we found.
 1507              */
 1508             result = findname(&name2, name, section);
 1509 
 1510             /*
 1511              * If it is a new name, append to the section.
 1512              */
 1513             if (result == ISC_R_SUCCESS) {
 1514                 isc_mempool_put(msg->namepool, name);
 1515                 name = name2;
 1516             } else {
 1517                 ISC_LIST_APPEND(*section, name, link);
 1518             }
 1519             free_name = false;
 1520         }
 1521 
 1522         /*
 1523          * Search name for the particular type and class.
 1524          * Skip this stage if in update mode or this is a meta-type.
 1525          */
 1526         if (preserve_order || msg->opcode == dns_opcode_update ||
 1527             skip_type_search)
 1528             result = ISC_R_NOTFOUND;
 1529         else {
 1530             /*
 1531              * If this is a type that can only occur in
 1532              * the question section, fail.
 1533              */
 1534             if (dns_rdatatype_questiononly(rdtype))
 1535                 DO_ERROR(DNS_R_FORMERR);
 1536 
 1537             rdataset = NULL;
 1538             result = dns_message_find(name, rdclass, rdtype,
 1539                            covers, &rdataset);
 1540         }
 1541 
 1542         /*
 1543          * If we found an rdataset that matches, we need to
 1544          * append this rdata to that set.  If we did not, we need
 1545          * to create a new rdatalist, store the important bits there,
 1546          * convert it to an rdataset, and link the latter to the name.
 1547          * Yuck.  When appending, make certain that the type isn't
 1548          * a singleton type, such as SOA or CNAME.
 1549          *
 1550          * Note that this check will be bypassed when preserving order,
 1551          * the opcode is an update, or the type search is skipped.
 1552          */
 1553         if (result == ISC_R_SUCCESS) {
 1554             if (dns_rdatatype_issingleton(rdtype)) {
 1555                 dns_rdata_t *first;
 1556                 dns_rdatalist_fromrdataset(rdataset,
 1557                                &rdatalist);
 1558                 first = ISC_LIST_HEAD(rdatalist->rdata);
 1559                 INSIST(first != NULL);
 1560                 if (dns_rdata_compare(rdata, first) != 0)
 1561                     DO_ERROR(DNS_R_FORMERR);
 1562             }
 1563         }
 1564 
 1565         if (result == ISC_R_NOTFOUND) {
 1566             rdataset = isc_mempool_get(msg->rdspool);
 1567             if (rdataset == NULL) {
 1568                 result = ISC_R_NOMEMORY;
 1569                 goto cleanup;
 1570             }
 1571             free_rdataset = true;
 1572 
 1573             rdatalist = newrdatalist(msg);
 1574             if (rdatalist == NULL) {
 1575                 result = ISC_R_NOMEMORY;
 1576                 goto cleanup;
 1577             }
 1578 
 1579             rdatalist->type = rdtype;
 1580             rdatalist->covers = covers;
 1581             rdatalist->rdclass = rdclass;
 1582             rdatalist->ttl = ttl;
 1583 
 1584             dns_rdataset_init(rdataset);
 1585             RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
 1586                                    rdataset)
 1587                       == ISC_R_SUCCESS);
 1588             dns_rdataset_setownercase(rdataset, name);
 1589 
 1590             if (!isedns && !istsig && !issigzero) {
 1591                 ISC_LIST_APPEND(name->list, rdataset, link);
 1592                 free_rdataset = false;
 1593             }
 1594         }
 1595 
 1596         /*
 1597          * Minimize TTLs.
 1598          *
 1599          * Section 5.2 of RFC2181 says we should drop
 1600          * nonauthoritative rrsets where the TTLs differ, but we
 1601          * currently treat them the as if they were authoritative and
 1602          * minimize them.
 1603          */
 1604         if (ttl != rdataset->ttl) {
 1605             rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
 1606             if (ttl < rdataset->ttl)
 1607                 rdataset->ttl = ttl;
 1608         }
 1609 
 1610         /* Append this rdata to the rdataset. */
 1611         dns_rdatalist_fromrdataset(rdataset, &rdatalist);
 1612         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
 1613 
 1614         /*
 1615          * If this is an OPT, SIG(0) or TSIG record, remember it.
 1616          * Also, set the extended rcode for TSIG.
 1617          *
 1618          * Note msg->opt, msg->sig0 and msg->tsig will only be
 1619          * already set if best-effort parsing is enabled otherwise
 1620          * there will only be at most one of each.
 1621          */
 1622         if (isedns) {
 1623             dns_rcode_t ercode;
 1624 
 1625             msg->opt = rdataset;
 1626             rdataset = NULL;
 1627             free_rdataset = false;
 1628             ercode = (dns_rcode_t)
 1629                 ((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
 1630                  >> 20);
 1631             msg->rcode |= ercode;
 1632             isc_mempool_put(msg->namepool, name);
 1633             free_name = false;
 1634         } else if (issigzero) {
 1635             msg->sig0 = rdataset;
 1636             msg->sig0name = name;
 1637             msg->sigstart = recstart;
 1638             rdataset = NULL;
 1639             free_rdataset = false;
 1640             free_name = false;
 1641         } else if (istsig) {
 1642             msg->tsig = rdataset;
 1643             msg->tsigname = name;
 1644             msg->sigstart = recstart;
 1645             /*
 1646              * Windows doesn't like TSIG names to be compressed.
 1647              */
 1648             msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
 1649             rdataset = NULL;
 1650             free_rdataset = false;
 1651             free_name = false;
 1652         }
 1653 
 1654         if (seen_problem) {
 1655             if (free_name)
 1656                 isc_mempool_put(msg->namepool, name);
 1657             if (free_rdataset)
 1658                 isc_mempool_put(msg->rdspool, rdataset);
 1659             free_name = free_rdataset = false;
 1660         }
 1661         INSIST(free_name == false);
 1662         INSIST(free_rdataset == false);
 1663     }
 1664 
 1665     /*
 1666      * If any of DS, NSEC or NSEC3 appeared in the
 1667      * authority section of a query response without
 1668      * a covering RRSIG, FORMERR
 1669      */
 1670     if (sectionid == DNS_SECTION_AUTHORITY &&
 1671         msg->opcode == dns_opcode_query &&
 1672         ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) &&
 1673         ((msg->flags & DNS_MESSAGEFLAG_TC) == 0) &&
 1674         !preserve_order &&
 1675         !auth_signed(section))
 1676         DO_ERROR(DNS_R_FORMERR);
 1677 
 1678     if (seen_problem)
 1679         return (DNS_R_RECOVERABLE);
 1680     return (ISC_R_SUCCESS);
 1681 
 1682  cleanup:
 1683     if (free_name)
 1684         isc_mempool_put(msg->namepool, name);
 1685     if (free_rdataset)
 1686         isc_mempool_put(msg->rdspool, rdataset);
 1687 
 1688     return (result);
 1689 }
 1690 
 1691 isc_result_t
 1692 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
 1693           unsigned int options)
 1694 {
 1695     isc_region_t r;
 1696     dns_decompress_t dctx;
 1697     isc_result_t ret;
 1698     uint16_t tmpflags;
 1699     isc_buffer_t origsource;
 1700     bool seen_problem;
 1701     bool ignore_tc;
 1702 
 1703     REQUIRE(DNS_MESSAGE_VALID(msg));
 1704     REQUIRE(source != NULL);
 1705     REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
 1706 
 1707     seen_problem = false;
 1708     ignore_tc = ((options & DNS_MESSAGEPARSE_IGNORETRUNCATION) != 0);
 1709 
 1710     origsource = *source;
 1711 
 1712     msg->header_ok = 0;
 1713     msg->question_ok = 0;
 1714 
 1715     if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0) {
 1716         isc_buffer_usedregion(&origsource, &msg->saved);
 1717     } else {
 1718         msg->saved.length = isc_buffer_usedlength(&origsource);
 1719         msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
 1720         if (msg->saved.base == NULL) {
 1721             return (ISC_R_NOMEMORY);
 1722         }
 1723         memmove(msg->saved.base, isc_buffer_base(&origsource),
 1724             msg->saved.length);
 1725         msg->free_saved = 1;
 1726     }
 1727 
 1728     isc_buffer_remainingregion(source, &r);
 1729     if (r.length < DNS_MESSAGE_HEADERLEN)
 1730         return (ISC_R_UNEXPECTEDEND);
 1731 
 1732     msg->id = isc_buffer_getuint16(source);
 1733     tmpflags = isc_buffer_getuint16(source);
 1734     msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
 1735                >> DNS_MESSAGE_OPCODE_SHIFT);
 1736     msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
 1737     msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
 1738     msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
 1739     msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
 1740     msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
 1741     msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
 1742 
 1743     msg->header_ok = 1;
 1744     msg->state = DNS_SECTION_QUESTION;
 1745 
 1746     /*
 1747      * -1 means no EDNS.
 1748      */
 1749     dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
 1750 
 1751     dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
 1752 
 1753     ret = getquestions(source, msg, &dctx, options);
 1754     if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
 1755         goto truncated;
 1756     if (ret == DNS_R_RECOVERABLE) {
 1757         seen_problem = true;
 1758         ret = ISC_R_SUCCESS;
 1759     }
 1760     if (ret != ISC_R_SUCCESS)
 1761         return (ret);
 1762     msg->question_ok = 1;
 1763 
 1764     ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
 1765     if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
 1766         goto truncated;
 1767     if (ret == DNS_R_RECOVERABLE) {
 1768         seen_problem = true;
 1769         ret = ISC_R_SUCCESS;
 1770     }
 1771     if (ret != ISC_R_SUCCESS)
 1772         return (ret);
 1773 
 1774     ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
 1775     if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
 1776         goto truncated;
 1777     if (ret == DNS_R_RECOVERABLE) {
 1778         seen_problem = true;
 1779         ret = ISC_R_SUCCESS;
 1780     }
 1781     if (ret != ISC_R_SUCCESS)
 1782         return (ret);
 1783 
 1784     ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
 1785     if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
 1786         goto truncated;
 1787     if (ret == DNS_R_RECOVERABLE) {
 1788         seen_problem = true;
 1789         ret = ISC_R_SUCCESS;
 1790     }
 1791     if (ret != ISC_R_SUCCESS)
 1792         return (ret);
 1793 
 1794     isc_buffer_remainingregion(source, &r);
 1795     if (r.length != 0) {
 1796         isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
 1797                   DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
 1798                   "message has %u byte(s) of trailing garbage",
 1799                   r.length);
 1800     }
 1801 
 1802  truncated:
 1803 
 1804     if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
 1805         return (DNS_R_RECOVERABLE);
 1806     if (seen_problem == true)
 1807         return (DNS_R_RECOVERABLE);
 1808     return (ISC_R_SUCCESS);
 1809 }
 1810 
 1811 isc_result_t
 1812 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
 1813             isc_buffer_t *buffer)
 1814 {
 1815     isc_region_t r;
 1816 
 1817     REQUIRE(DNS_MESSAGE_VALID(msg));
 1818     REQUIRE(buffer != NULL);
 1819     REQUIRE(msg->buffer == NULL);
 1820     REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
 1821 
 1822     msg->cctx = cctx;
 1823 
 1824     /*
 1825      * Erase the contents of this buffer.
 1826      */
 1827     isc_buffer_clear(buffer);
 1828 
 1829     /*
 1830      * Make certain there is enough for at least the header in this
 1831      * buffer.
 1832      */
 1833     isc_buffer_availableregion(buffer, &r);
 1834     if (r.length < DNS_MESSAGE_HEADERLEN)
 1835         return (ISC_R_NOSPACE);
 1836 
 1837     if (r.length - DNS_MESSAGE_HEADERLEN < msg->reserved)
 1838         return (ISC_R_NOSPACE);
 1839 
 1840     /*
 1841      * Reserve enough space for the header in this buffer.
 1842      */
 1843     isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
 1844 
 1845     msg->buffer = buffer;
 1846 
 1847     return (ISC_R_SUCCESS);
 1848 }
 1849 
 1850 isc_result_t
 1851 dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
 1852     isc_region_t r, rn;
 1853 
 1854     REQUIRE(DNS_MESSAGE_VALID(msg));
 1855     REQUIRE(buffer != NULL);
 1856     REQUIRE(msg->buffer != NULL);
 1857 
 1858     /*
 1859      * Ensure that the new buffer is empty, and has enough space to
 1860      * hold the current contents.
 1861      */
 1862     isc_buffer_clear(buffer);
 1863 
 1864     isc_buffer_availableregion(buffer, &rn);
 1865     isc_buffer_usedregion(msg->buffer, &r);
 1866     REQUIRE(rn.length > r.length);
 1867 
 1868     /*
 1869      * Copy the contents from the old to the new buffer.
 1870      */
 1871     isc_buffer_add(buffer, r.length);
 1872     memmove(rn.base, r.base, r.length);
 1873 
 1874     msg->buffer = buffer;
 1875 
 1876     return (ISC_R_SUCCESS);
 1877 }
 1878 
 1879 void
 1880 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
 1881     REQUIRE(DNS_MESSAGE_VALID(msg));
 1882     REQUIRE(space <= msg->reserved);
 1883 
 1884     msg->reserved -= space;
 1885 }
 1886 
 1887 isc_result_t
 1888 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
 1889     isc_region_t r;
 1890 
 1891     REQUIRE(DNS_MESSAGE_VALID(msg));
 1892 
 1893     if (msg->buffer != NULL) {
 1894         isc_buffer_availableregion(msg->buffer, &r);
 1895         if (r.length < (space + msg->reserved))
 1896             return (ISC_R_NOSPACE);
 1897     }
 1898 
 1899     msg->reserved += space;
 1900 
 1901     return (ISC_R_SUCCESS);
 1902 }
 1903 
 1904 static inline bool
 1905 wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
 1906     int pass_needed;
 1907 
 1908     /*
 1909      * If we are not rendering class IN, this ordering is bogus.
 1910      */
 1911     if (rds->rdclass != dns_rdataclass_in)
 1912         return (false);
 1913 
 1914     switch (rds->type) {
 1915     case dns_rdatatype_a:
 1916     case dns_rdatatype_aaaa:
 1917         if (preferred_glue == rds->type)
 1918             pass_needed = 4;
 1919         else
 1920             pass_needed = 3;
 1921         break;
 1922     case dns_rdatatype_rrsig:
 1923     case dns_rdatatype_dnskey:
 1924         pass_needed = 2;
 1925         break;
 1926     default:
 1927         pass_needed = 1;
 1928     }
 1929 
 1930     if (pass_needed >= pass)
 1931         return (false);
 1932 
 1933     return (true);
 1934 }
 1935 
 1936 #ifdef ALLOW_FILTER_AAAA
 1937 /*
 1938  * Decide whether to not answer with an AAAA record and its RRSIG
 1939  */
 1940 static inline bool
 1941 norender_rdataset(const dns_rdataset_t *rdataset, unsigned int options,
 1942           dns_section_t sectionid)
 1943 {
 1944     if (sectionid == DNS_SECTION_QUESTION)
 1945         return (false);
 1946 
 1947     switch (rdataset->type) {
 1948     case dns_rdatatype_ns:
 1949         if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
 1950             sectionid != DNS_SECTION_AUTHORITY)
 1951             return (false);
 1952         break;
 1953 
 1954     case dns_rdatatype_aaaa:
 1955         if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0)
 1956             return (false);
 1957         break;
 1958 
 1959     case dns_rdatatype_rrsig:
 1960         if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
 1961             (rdataset->covers != dns_rdatatype_ns &&
 1962              rdataset->covers != dns_rdatatype_aaaa))
 1963             return (false);
 1964         if ((rdataset->covers == dns_rdatatype_ns) &&
 1965             (sectionid != DNS_SECTION_AUTHORITY))
 1966             return (false);
 1967         break;
 1968 
 1969     default:
 1970         return (false);
 1971     }
 1972 
 1973     if (rdataset->rdclass != dns_rdataclass_in)
 1974         return (false);
 1975 
 1976     return (true);
 1977 }
 1978 #endif
 1979 
 1980 static isc_result_t
 1981 renderset(dns_rdataset_t *rdataset, dns_name_t *owner_name,
 1982       dns_compress_t *cctx, isc_buffer_t *target,
 1983       unsigned int reserved, unsigned int options, unsigned int *countp)
 1984 {
 1985     isc_result_t result;
 1986 
 1987     /*
 1988      * Shrink the space in the buffer by the reserved amount.
 1989      */
 1990     if (target->length - target->used < reserved)
 1991         return (ISC_R_NOSPACE);
 1992 
 1993     target->length -= reserved;
 1994     result = dns_rdataset_towire(rdataset, owner_name,
 1995                      cctx, target, options, countp);
 1996     target->length += reserved;
 1997 
 1998     return (result);
 1999 }
 2000 
 2001 static void
 2002 maybe_clear_ad(dns_message_t *msg, dns_section_t sectionid) {
 2003     if (msg->counts[sectionid] == 0 &&
 2004         (sectionid == DNS_SECTION_ANSWER ||
 2005          (sectionid == DNS_SECTION_AUTHORITY &&
 2006           msg->counts[DNS_SECTION_ANSWER] == 0)))
 2007         msg->flags &= ~DNS_MESSAGEFLAG_AD;
 2008 }
 2009 
 2010 isc_result_t
 2011 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
 2012               unsigned int options)
 2013 {
 2014     dns_namelist_t *section;
 2015     dns_name_t *name, *next_name;
 2016     dns_rdataset_t *rdataset, *next_rdataset;
 2017     unsigned int count, total;
 2018     isc_result_t result;
 2019     isc_buffer_t st; /* for rollbacks */
 2020     int pass;
 2021     bool partial = false;
 2022     unsigned int rd_options;
 2023     dns_rdatatype_t preferred_glue = 0;
 2024 
 2025     REQUIRE(DNS_MESSAGE_VALID(msg));
 2026     REQUIRE(msg->buffer != NULL);
 2027     REQUIRE(VALID_NAMED_SECTION(sectionid));
 2028 
 2029     section = &msg->sections[sectionid];
 2030 
 2031     if ((sectionid == DNS_SECTION_ADDITIONAL)
 2032         && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
 2033         if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
 2034             preferred_glue = dns_rdatatype_a;
 2035             pass = 4;
 2036         } else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
 2037             preferred_glue = dns_rdatatype_aaaa;
 2038             pass = 4;
 2039         } else
 2040             pass = 3;
 2041     } else
 2042         pass = 1;
 2043 
 2044     if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
 2045         rd_options = 0;
 2046     else
 2047         rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
 2048 
 2049     /*
 2050      * Shrink the space in the buffer by the reserved amount.
 2051      */
 2052     if (msg->buffer->length - msg->buffer->used < msg->reserved)
 2053         return (ISC_R_NOSPACE);
 2054     msg->buffer->length -= msg->reserved;
 2055 
 2056     total = 0;
 2057     if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
 2058         partial = true;
 2059 
 2060     /*
 2061      * Render required glue first.  Set TC if it won't fit.
 2062      */
 2063     name = ISC_LIST_HEAD(*section);
 2064     if (name != NULL) {
 2065         rdataset = ISC_LIST_HEAD(name->list);
 2066         if (rdataset != NULL &&
 2067             (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 &&
 2068             (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) {
 2069             const void *order_arg = msg->order_arg;
 2070             st = *(msg->buffer);
 2071             count = 0;
 2072             if (partial)
 2073                 result = dns_rdataset_towirepartial(rdataset,
 2074                                     name,
 2075                                     msg->cctx,
 2076                                     msg->buffer,
 2077                                     msg->order,
 2078                                     order_arg,
 2079                                     rd_options,
 2080                                     &count,
 2081                                     NULL);
 2082             else
 2083                 result = dns_rdataset_towiresorted(rdataset,
 2084                                    name,
 2085                                    msg->cctx,
 2086                                    msg->buffer,
 2087                                    msg->order,
 2088                                    order_arg,
 2089                                    rd_options,
 2090                                    &count);
 2091             total += count;
 2092             if (partial && result == ISC_R_NOSPACE) {
 2093                 msg->flags |= DNS_MESSAGEFLAG_TC;
 2094                 msg->buffer->length += msg->reserved;
 2095                 msg->counts[sectionid] += total;
 2096                 return (result);
 2097             }
 2098             if (result == ISC_R_NOSPACE)
 2099                 msg->flags |= DNS_MESSAGEFLAG_TC;
 2100             if (result != ISC_R_SUCCESS) {
 2101                 INSIST(st.used < 65536);
 2102                 dns_compress_rollback(msg->cctx,
 2103                               (uint16_t)st.used);
 2104                 *(msg->buffer) = st;  /* rollback */
 2105                 msg->buffer->length += msg->reserved;
 2106                 msg->counts[sectionid] += total;
 2107                 return (result);
 2108             }
 2109             rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
 2110         }
 2111     }
 2112 
 2113     do {
 2114         name = ISC_LIST_HEAD(*section);
 2115         if (name == NULL) {
 2116             msg->buffer->length += msg->reserved;
 2117             msg->counts[sectionid] += total;
 2118             return (ISC_R_SUCCESS);
 2119         }
 2120 
 2121         while (name != NULL) {
 2122             next_name = ISC_LIST_NEXT(name, link);
 2123 
 2124             rdataset = ISC_LIST_HEAD(name->list);
 2125             while (rdataset != NULL) {
 2126                 next_rdataset = ISC_LIST_NEXT(rdataset, link);
 2127 
 2128                 if ((rdataset->attributes &
 2129                      DNS_RDATASETATTR_RENDERED) != 0)
 2130                     goto next;
 2131 
 2132                 if (((options & DNS_MESSAGERENDER_ORDERED)
 2133                      == 0)
 2134                     && (sectionid == DNS_SECTION_ADDITIONAL)
 2135                     && wrong_priority(rdataset, pass,
 2136                               preferred_glue))
 2137                     goto next;
 2138 
 2139 #ifdef ALLOW_FILTER_AAAA
 2140                 /*
 2141                  * Suppress AAAAs if asked and we are
 2142                  * not doing DNSSEC or are breaking DNSSEC.
 2143                  * Say so in the AD bit if we break DNSSEC.
 2144                  */
 2145                 if (norender_rdataset(rdataset, options, sectionid)) {
 2146                     if (sectionid == DNS_SECTION_ANSWER ||
 2147                         sectionid == DNS_SECTION_AUTHORITY)
 2148                         msg->flags &= ~DNS_MESSAGEFLAG_AD;
 2149                     if (OPTOUT(rdataset))
 2150                         msg->flags &= ~DNS_MESSAGEFLAG_AD;
 2151                     goto next;
 2152                 }
 2153 
 2154 #endif
 2155                 st = *(msg->buffer);
 2156 
 2157                 count = 0;
 2158                 if (partial)
 2159                     result = dns_rdataset_towirepartial(
 2160                               rdataset,
 2161                               name,
 2162                               msg->cctx,
 2163                               msg->buffer,
 2164                               msg->order,
 2165                               msg->order_arg,
 2166                               rd_options,
 2167                               &count,
 2168                               NULL);
 2169                 else
 2170                     result = dns_rdataset_towiresorted(
 2171                               rdataset,
 2172                               name,
 2173                               msg->cctx,
 2174                               msg->buffer,
 2175                               msg->order,
 2176                               msg->order_arg,
 2177                               rd_options,
 2178                               &count);
 2179 
 2180                 total += count;
 2181 
 2182                 /*
 2183                  * If out of space, record stats on what we
 2184                  * rendered so far, and return that status.
 2185                  *
 2186                  * XXXMLG Need to change this when
 2187                  * dns_rdataset_towire() can render partial
 2188                  * sets starting at some arbitrary point in the
 2189                  * set.  This will include setting a bit in the
 2190                  * rdataset to indicate that a partial
 2191                  * rendering was done, and some state saved
 2192                  * somewhere (probably in the message struct)
 2193                  * to indicate where to continue from.
 2194                  */
 2195                 if (partial && result == ISC_R_NOSPACE) {
 2196                     msg->buffer->length += msg->reserved;
 2197                     msg->counts[sectionid] += total;
 2198                     return (result);
 2199                 }
 2200                 if (result != ISC_R_SUCCESS) {
 2201                     INSIST(st.used < 65536);
 2202                     dns_compress_rollback(msg->cctx,
 2203                             (uint16_t)st.used);
 2204                     *(msg->buffer) = st;  /* rollback */
 2205                     msg->buffer->length += msg->reserved;
 2206                     msg->counts[sectionid] += total;
 2207                     maybe_clear_ad(msg, sectionid);
 2208                     return (result);
 2209                 }
 2210 
 2211                 /*
 2212                  * If we have rendered non-validated data,
 2213                  * ensure that the AD bit is not set.
 2214                  */
 2215                 if (rdataset->trust != dns_trust_secure &&
 2216                     (sectionid == DNS_SECTION_ANSWER ||
 2217                      sectionid == DNS_SECTION_AUTHORITY))
 2218                     msg->flags &= ~DNS_MESSAGEFLAG_AD;
 2219                 if (OPTOUT(rdataset))
 2220                     msg->flags &= ~DNS_MESSAGEFLAG_AD;
 2221 
 2222                 rdataset->attributes |=
 2223                     DNS_RDATASETATTR_RENDERED;
 2224 
 2225             next:
 2226                 rdataset = next_rdataset;
 2227             }
 2228 
 2229             name = next_name;
 2230         }
 2231     } while (--pass != 0);
 2232 
 2233     msg->buffer->length += msg->reserved;
 2234     msg->counts[sectionid] += total;
 2235 
 2236     return (ISC_R_SUCCESS);
 2237 }
 2238 
 2239 void
 2240 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
 2241     uint16_t tmp;
 2242     isc_region_t r;
 2243 
 2244     REQUIRE(DNS_MESSAGE_VALID(msg));
 2245     REQUIRE(target != NULL);
 2246 
 2247     isc_buffer_availableregion(target, &r);
 2248     REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
 2249 
 2250     isc_buffer_putuint16(target, msg->id);
 2251 
 2252     tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
 2253            & DNS_MESSAGE_OPCODE_MASK);
 2254     tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
 2255     tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
 2256 
 2257     INSIST(msg->counts[DNS_SECTION_QUESTION]  < 65536 &&
 2258            msg->counts[DNS_SECTION_ANSWER]    < 65536 &&
 2259            msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
 2260            msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
 2261 
 2262     isc_buffer_putuint16(target, tmp);
 2263     isc_buffer_putuint16(target,
 2264                 (uint16_t)msg->counts[DNS_SECTION_QUESTION]);
 2265     isc_buffer_putuint16(target,
 2266                 (uint16_t)msg->counts[DNS_SECTION_ANSWER]);
 2267     isc_buffer_putuint16(target,
 2268                 (uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
 2269     isc_buffer_putuint16(target,
 2270                 (uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
 2271 }
 2272 
 2273 isc_result_t
 2274 dns_message_renderend(dns_message_t *msg) {
 2275     isc_buffer_t tmpbuf;
 2276     isc_region_t r;
 2277     int result;
 2278     unsigned int count;
 2279 
 2280     REQUIRE(DNS_MESSAGE_VALID(msg));
 2281     REQUIRE(msg->buffer != NULL);
 2282 
 2283     if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
 2284         /*
 2285          * We have an extended rcode but are not using EDNS.
 2286          */
 2287         return (DNS_R_FORMERR);
 2288     }
 2289 
 2290     /*
 2291      * If we're adding a OPT, TSIG or SIG(0) to a truncated message,
 2292      * clear all rdatasets from the message except for the question
 2293      * before adding the OPT, TSIG or SIG(0).  If the question doesn't
 2294      * fit, don't include it.
 2295      */
 2296     if ((msg->tsigkey != NULL || msg->sig0key != NULL || msg->opt) &&
 2297         (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
 2298     {
 2299         isc_buffer_t *buf;
 2300 
 2301         msgresetnames(msg, DNS_SECTION_ANSWER);
 2302         buf = msg->buffer;
 2303         dns_message_renderreset(msg);
 2304         msg->buffer = buf;
 2305         isc_buffer_clear(msg->buffer);
 2306         isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
 2307         dns_compress_rollback(msg->cctx, 0);
 2308         result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
 2309                            0);
 2310         if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
 2311             return (result);
 2312     }
 2313 
 2314     /*
 2315      * If we've got an OPT record, render it.
 2316      */
 2317     if (msg->opt != NULL) {
 2318         dns_message_renderrelease(msg, msg->opt_reserved);
 2319         msg->opt_reserved = 0;
 2320         /*
 2321          * Set the extended rcode.  Cast msg->rcode to dns_ttl_t
 2322          * so that we do a unsigned shift.
 2323          */
 2324         msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
 2325         msg->opt->ttl |= (((dns_ttl_t)(msg->rcode) << 20) &
 2326                   DNS_MESSAGE_EDNSRCODE_MASK);
 2327         /*
 2328          * Render.
 2329          */
 2330         count = 0;
 2331         result = renderset(msg->opt, dns_rootname, msg->cctx,
 2332                    msg->buffer, msg->reserved, 0, &count);
 2333         msg->counts[DNS_SECTION_ADDITIONAL] += count;
 2334         if (result != ISC_R_SUCCESS)
 2335             return (result);
 2336     }
 2337 
 2338     /*
 2339      * If we're adding a TSIG record, generate and render it.
 2340      */
 2341     if (msg->tsigkey != NULL) {
 2342         dns_message_renderrelease(msg, msg->sig_reserved);
 2343         msg->sig_reserved = 0;
 2344         result = dns_tsig_sign(msg);
 2345         if (result != ISC_R_SUCCESS)
 2346             return (result);
 2347         count = 0;
 2348         result = renderset(msg->tsig, msg->tsigname, msg->cctx,
 2349                    msg->buffer, msg->reserved, 0, &count);
 2350         msg->counts[DNS_SECTION_ADDITIONAL] += count;
 2351         if (result != ISC_R_SUCCESS)
 2352             return (result);
 2353     }
 2354 
 2355     /*
 2356      * If we're adding a SIG(0) record, generate and render it.
 2357      */
 2358     if (msg->sig0key != NULL) {
 2359         dns_message_renderrelease(msg, msg->sig_reserved);
 2360         msg->sig_reserved = 0;
 2361         result = dns_dnssec_signmessage(msg, msg->sig0key);
 2362         if (result != ISC_R_SUCCESS)
 2363             return (result);
 2364         count = 0;
 2365         /*
 2366          * Note: dns_rootname is used here, not msg->sig0name, since
 2367          * the owner name of a SIG(0) is irrelevant, and will not
 2368          * be set in a message being rendered.
 2369          */
 2370         result = renderset(msg->sig0, dns_rootname, msg->cctx,
 2371                    msg->buffer, msg->reserved, 0, &count);
 2372         msg->counts[DNS_SECTION_ADDITIONAL] += count;
 2373         if (result != ISC_R_SUCCESS)
 2374             return (result);
 2375     }
 2376 
 2377     isc_buffer_usedregion(msg->buffer, &r);
 2378     isc_buffer_init(&tmpbuf, r.base, r.length);
 2379 
 2380     dns_message_renderheader(msg, &tmpbuf);
 2381 
 2382     msg->buffer = NULL;  /* forget about this buffer only on success XXX */
 2383 
 2384     return (ISC_R_SUCCESS);
 2385 }
 2386 
 2387 void
 2388 dns_message_renderreset(dns_message_t *msg) {
 2389     unsigned int i;
 2390     dns_name_t *name;
 2391     dns_rdataset_t *rds;
 2392 
 2393     /*
 2394      * Reset the message so that it may be rendered again.
 2395      */
 2396 
 2397     REQUIRE(DNS_MESSAGE_VALID(msg));
 2398     REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
 2399 
 2400     msg->buffer = NULL;
 2401 
 2402     for (i = 0; i < DNS_SECTION_MAX; i++) {
 2403         msg->cursors[i] = NULL;
 2404         msg->counts[i] = 0;
 2405         for (name = ISC_LIST_HEAD(msg->sections[i]);
 2406              name != NULL;
 2407              name = ISC_LIST_NEXT(name, link)) {
 2408             for (rds = ISC_LIST_HEAD(name->list);
 2409                  rds != NULL;
 2410                  rds = ISC_LIST_NEXT(rds, link)) {
 2411                 rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
 2412             }
 2413         }
 2414     }
 2415     if (msg->tsigname != NULL)
 2416         dns_message_puttempname(msg, &msg->tsigname);
 2417     if (msg->tsig != NULL) {
 2418         dns_rdataset_disassociate(msg->tsig);
 2419         dns_message_puttemprdataset(msg, &msg->tsig);
 2420     }
 2421     if (msg->sig0 != NULL) {
 2422         dns_rdataset_disassociate(msg->sig0);
 2423         dns_message_puttemprdataset(msg, &msg->sig0);
 2424     }
 2425 }
 2426 
 2427 isc_result_t
 2428 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
 2429     REQUIRE(DNS_MESSAGE_VALID(msg));
 2430     REQUIRE(VALID_NAMED_SECTION(section));
 2431 
 2432     msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
 2433 
 2434     if (msg->cursors[section] == NULL)
 2435         return (ISC_R_NOMORE);
 2436 
 2437     return (ISC_R_SUCCESS);
 2438 }
 2439 
 2440 isc_result_t
 2441 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
 2442     REQUIRE(DNS_MESSAGE_VALID(msg));
 2443     REQUIRE(VALID_NAMED_SECTION(section));
 2444     REQUIRE(msg->cursors[section] != NULL);
 2445 
 2446     msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
 2447 
 2448     if (msg->cursors[section] == NULL)
 2449         return (ISC_R_NOMORE);
 2450 
 2451     return (ISC_R_SUCCESS);
 2452 }
 2453 
 2454 void
 2455 dns_message_currentname(dns_message_t *msg, dns_section_t section,
 2456             dns_name_t **name)
 2457 {
 2458     REQUIRE(DNS_MESSAGE_VALID(msg));
 2459     REQUIRE(VALID_NAMED_SECTION(section));
 2460     REQUIRE(name != NULL && *name == NULL);
 2461     REQUIRE(msg->cursors[section] != NULL);
 2462 
 2463     *name = msg->cursors[section];
 2464 }
 2465 
 2466 isc_result_t
 2467 dns_message_findname(dns_message_t *msg, dns_section_t section,
 2468              dns_name_t *target, dns_rdatatype_t type,
 2469              dns_rdatatype_t covers, dns_name_t **name,
 2470              dns_rdataset_t **rdataset)
 2471 {
 2472     dns_name_t *foundname;
 2473     isc_result_t result;
 2474 
 2475     /*
 2476      * XXX These requirements are probably too intensive, especially
 2477      * where things can be NULL, but as they are they ensure that if
 2478      * something is NON-NULL, indicating that the caller expects it
 2479      * to be filled in, that we can in fact fill it in.
 2480      */
 2481     REQUIRE(msg != NULL);
 2482     REQUIRE(VALID_SECTION(section));
 2483     REQUIRE(target != NULL);
 2484     REQUIRE(name == NULL || *name == NULL);
 2485 
 2486     if (type == dns_rdatatype_any) {
 2487         REQUIRE(rdataset == NULL);
 2488     } else {
 2489         REQUIRE(rdataset == NULL || *rdataset == NULL);
 2490     }
 2491 
 2492     result = findname(&foundname, target,
 2493               &msg->sections[section]);
 2494 
 2495     if (result == ISC_R_NOTFOUND)
 2496         return (DNS_R_NXDOMAIN);
 2497     else if (result != ISC_R_SUCCESS)
 2498         return (result);
 2499 
 2500     if (name != NULL)
 2501         *name = foundname;
 2502 
 2503     /*
 2504      * And now look for the type.
 2505      */
 2506     if (ISC_UNLIKELY(type == dns_rdatatype_any))
 2507         return (ISC_R_SUCCESS);
 2508 
 2509     result = dns_message_findtype(foundname, type, covers, rdataset);
 2510     if (result == ISC_R_NOTFOUND)
 2511         return (DNS_R_NXRRSET);
 2512 
 2513     return (result);
 2514 }
 2515 
 2516 void
 2517 dns_message_movename(dns_message_t *msg, dns_name_t *name,
 2518              dns_section_t fromsection,
 2519              dns_section_t tosection)
 2520 {
 2521     REQUIRE(msg != NULL);
 2522     REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
 2523     REQUIRE(name != NULL);
 2524     REQUIRE(VALID_NAMED_SECTION(fromsection));
 2525     REQUIRE(VALID_NAMED_SECTION(tosection));
 2526 
 2527     /*
 2528      * Unlink the name from the old section
 2529      */
 2530     ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
 2531     ISC_LIST_APPEND(msg->sections[tosection], name, link);
 2532 }
 2533 
 2534 void
 2535 dns_message_addname(dns_message_t *msg, dns_name_t *name,
 2536             dns_section_t section)
 2537 {
 2538     REQUIRE(msg != NULL);
 2539     REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
 2540     REQUIRE(name != NULL);
 2541     REQUIRE(VALID_NAMED_SECTION(section));
 2542 
 2543     ISC_LIST_APPEND(msg->sections[section], name, link);
 2544 }
 2545 
 2546 void
 2547 dns_message_removename(dns_message_t *msg, dns_name_t *name,
 2548                dns_section_t section)
 2549 {
 2550     REQUIRE(msg != NULL);
 2551     REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
 2552     REQUIRE(name != NULL);
 2553     REQUIRE(VALID_NAMED_SECTION(section));
 2554 
 2555     ISC_LIST_UNLINK(msg->sections[section], name, link);
 2556 }
 2557 
 2558 isc_result_t
 2559 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
 2560     REQUIRE(DNS_MESSAGE_VALID(msg));
 2561     REQUIRE(item != NULL && *item == NULL);
 2562 
 2563     *item = isc_mempool_get(msg->namepool);
 2564     if (*item == NULL)
 2565         return (ISC_R_NOMEMORY);
 2566     dns_name_init(*item, NULL);
 2567 
 2568     return (ISC_R_SUCCESS);
 2569 }
 2570 
 2571 isc_result_t
 2572 dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
 2573     REQUIRE(DNS_MESSAGE_VALID(msg));
 2574     REQUIRE(item != NULL && *item == NULL);
 2575 
 2576     *item = newoffsets(msg);
 2577     if (*item == NULL)
 2578         return (ISC_R_NOMEMORY);
 2579 
 2580     return (ISC_R_SUCCESS);
 2581 }
 2582 
 2583 isc_result_t
 2584 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
 2585     REQUIRE(DNS_MESSAGE_VALID(msg));
 2586     REQUIRE(item != NULL && *item == NULL);
 2587 
 2588     *item = newrdata(msg);
 2589     if (*item == NULL)
 2590         return (ISC_R_NOMEMORY);
 2591 
 2592     return (ISC_R_SUCCESS);
 2593 }
 2594 
 2595 isc_result_t
 2596 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
 2597     REQUIRE(DNS_MESSAGE_VALID(msg));
 2598     REQUIRE(item != NULL && *item == NULL);
 2599 
 2600     *item = isc_mempool_get(msg->rdspool);
 2601     if (*item == NULL)
 2602         return (ISC_R_NOMEMORY);
 2603 
 2604     dns_rdataset_init(*item);
 2605 
 2606     return (ISC_R_SUCCESS);
 2607 }
 2608 
 2609 isc_result_t
 2610 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
 2611     REQUIRE(DNS_MESSAGE_VALID(msg));
 2612     REQUIRE(item != NULL && *item == NULL);
 2613 
 2614     *item = newrdatalist(msg);
 2615     if (*item == NULL)
 2616         return (ISC_R_NOMEMORY);
 2617 
 2618     return (ISC_R_SUCCESS);
 2619 }
 2620 
 2621 void
 2622 dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
 2623     REQUIRE(DNS_MESSAGE_VALID(msg));
 2624     REQUIRE(item != NULL && *item != NULL);
 2625 
 2626     if (dns_name_dynamic(*item))
 2627         dns_name_free(*item, msg->mctx);
 2628     isc_mempool_put(msg->namepool, *item);
 2629     *item = NULL;
 2630 }
 2631 
 2632 void
 2633 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
 2634     REQUIRE(DNS_MESSAGE_VALID(msg));
 2635     REQUIRE(item != NULL && *item != NULL);
 2636 
 2637     releaserdata(msg, *item);
 2638     *item = NULL;
 2639 }
 2640 
 2641 void
 2642 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
 2643     REQUIRE(DNS_MESSAGE_VALID(msg));
 2644     REQUIRE(item != NULL && *item != NULL);
 2645 
 2646     REQUIRE(!dns_rdataset_isassociated(*item));
 2647     isc_mempool_put(msg->rdspool, *item);
 2648     *item = NULL;
 2649 }
 2650 
 2651 void
 2652 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
 2653     REQUIRE(DNS_MESSAGE_VALID(msg));
 2654     REQUIRE(item != NULL && *item != NULL);
 2655 
 2656     releaserdatalist(msg, *item);
 2657     *item = NULL;
 2658 }
 2659 
 2660 isc_result_t
 2661 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
 2662                unsigned int *flagsp)
 2663 {
 2664     isc_region_t r;
 2665     isc_buffer_t buffer;
 2666     dns_messageid_t id;
 2667     unsigned int flags;
 2668 
 2669     REQUIRE(source != NULL);
 2670 
 2671     buffer = *source;
 2672 
 2673     isc_buffer_remainingregion(&buffer, &r);
 2674     if (r.length < DNS_MESSAGE_HEADERLEN)
 2675         return (ISC_R_UNEXPECTEDEND);
 2676 
 2677     id = isc_buffer_getuint16(&buffer);
 2678     flags = isc_buffer_getuint16(&buffer);
 2679     flags &= DNS_MESSAGE_FLAG_MASK;
 2680 
 2681     if (flagsp != NULL)
 2682         *flagsp = flags;
 2683     if (idp != NULL)
 2684         *idp = id;
 2685 
 2686     return (ISC_R_SUCCESS);
 2687 }
 2688 
 2689 isc_result_t
 2690 dns_message_reply(dns_message_t *msg, bool want_question_section) {
 2691     unsigned int clear_from;
 2692     isc_result_t result;
 2693 
 2694     REQUIRE(DNS_MESSAGE_VALID(msg));
 2695     REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
 2696 
 2697     if (!msg->header_ok)
 2698         return (DNS_R_FORMERR);
 2699     if (msg->opcode != dns_opcode_query &&
 2700         msg->opcode != dns_opcode_notify)
 2701         want_question_section = false;
 2702     if (msg->opcode == dns_opcode_update)
 2703         clear_from = DNS_SECTION_PREREQUISITE;
 2704     else if (want_question_section) {
 2705         if (!msg->question_ok)
 2706             return (DNS_R_FORMERR);
 2707         clear_from = DNS_SECTION_ANSWER;
 2708     } else
 2709         clear_from = DNS_SECTION_QUESTION;
 2710     msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
 2711     msgresetnames(msg, clear_from);
 2712     msgresetopt(msg);
 2713     msgresetsigs(msg, true);
 2714     msginitprivate(msg);
 2715     /*
 2716      * We now clear most flags and then set QR, ensuring that the
 2717      * reply's flags will be in a reasonable state.
 2718      */
 2719     if (msg->opcode == dns_opcode_query)
 2720         msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
 2721     else
 2722         msg->flags = 0;
 2723     msg->flags |= DNS_MESSAGEFLAG_QR;
 2724 
 2725     /*
 2726      * This saves the query TSIG status, if the query was signed, and
 2727      * reserves space in the reply for the TSIG.
 2728      */
 2729     if (msg->tsigkey != NULL) {
 2730         unsigned int otherlen = 0;
 2731         msg->querytsigstatus = msg->tsigstatus;
 2732         msg->tsigstatus = dns_rcode_noerror;
 2733         if (msg->querytsigstatus == dns_tsigerror_badtime)
 2734             otherlen = 6;
 2735         msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
 2736         result = dns_message_renderreserve(msg, msg->sig_reserved);
 2737         if (result != ISC_R_SUCCESS) {
 2738             msg->sig_reserved = 0;
 2739             return (result);
 2740         }
 2741     }
 2742     if (msg->saved.base != NULL) {
 2743         msg->query.base = msg->saved.base;
 2744         msg->query.length = msg->saved.length;
 2745         msg->free_query = msg->free_saved;
 2746         msg->saved.base = NULL;
 2747         msg->saved.length = 0;
 2748         msg->free_saved = 0;
 2749     }
 2750 
 2751     return (ISC_R_SUCCESS);
 2752 }
 2753 
 2754 dns_rdataset_t *
 2755 dns_message_getopt(dns_message_t *msg) {
 2756 
 2757     /*
 2758      * Get the OPT record for 'msg'.
 2759      */
 2760 
 2761     REQUIRE(DNS_MESSAGE_VALID(msg));
 2762 
 2763     return (msg->opt);
 2764 }
 2765 
 2766 isc_result_t
 2767 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
 2768     isc_result_t result;
 2769     dns_rdata_t rdata = DNS_RDATA_INIT;
 2770 
 2771     /*
 2772      * Set the OPT record for 'msg'.
 2773      */
 2774 
 2775     /*
 2776      * The space required for an OPT record is:
 2777      *
 2778      *  1 byte for the name
 2779      *  2 bytes for the type
 2780      *  2 bytes for the class
 2781      *  4 bytes for the ttl
 2782      *  2 bytes for the rdata length
 2783      * ---------------------------------
 2784      *     11 bytes
 2785      *
 2786      * plus the length of the rdata.
 2787      */
 2788 
 2789     REQUIRE(DNS_MESSAGE_VALID(msg));
 2790     REQUIRE(opt->type == dns_rdatatype_opt);
 2791     REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
 2792     REQUIRE(msg->state == DNS_SECTION_ANY);
 2793 
 2794     msgresetopt(msg);
 2795 
 2796     result = dns_rdataset_first(opt);
 2797     if (result != ISC_R_SUCCESS)
 2798         goto cleanup;
 2799     dns_rdataset_current(opt, &rdata);
 2800     msg->opt_reserved = 11 + rdata.length;
 2801     result = dns_message_renderreserve(msg, msg->opt_reserved);
 2802     if (result != ISC_R_SUCCESS) {
 2803         msg->opt_reserved = 0;
 2804         goto cleanup;
 2805     }
 2806 
 2807     msg->opt = opt;
 2808 
 2809     return (ISC_R_SUCCESS);
 2810 
 2811  cleanup:
 2812     dns_rdataset_disassociate(opt);
 2813     dns_message_puttemprdataset(msg, &opt);
 2814     return (result);
 2815 }
 2816 
 2817 dns_rdataset_t *
 2818 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
 2819 
 2820     /*
 2821      * Get the TSIG record and owner for 'msg'.
 2822      */
 2823 
 2824     REQUIRE(DNS_MESSAGE_VALID(msg));
 2825     REQUIRE(owner == NULL || *owner == NULL);
 2826 
 2827     if (owner != NULL)
 2828         *owner = msg->tsigname;
 2829     return (msg->tsig);
 2830 }
 2831 
 2832 isc_result_t
 2833 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
 2834     isc_result_t result;
 2835 
 2836     /*
 2837      * Set the TSIG key for 'msg'
 2838      */
 2839 
 2840     REQUIRE(DNS_MESSAGE_VALID(msg));
 2841 
 2842     if (key == NULL && msg->tsigkey != NULL) {
 2843         if (msg->sig_reserved != 0) {
 2844             dns_message_renderrelease(msg, msg->sig_reserved);
 2845             msg->sig_reserved = 0;
 2846         }
 2847         dns_tsigkey_detach(&msg->tsigkey);
 2848     }
 2849     if (key != NULL) {
 2850         REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
 2851         dns_tsigkey_attach(key, &msg->tsigkey);
 2852         if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
 2853             msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
 2854             result = dns_message_renderreserve(msg,
 2855                                msg->sig_reserved);
 2856             if (result != ISC_R_SUCCESS) {
 2857                 dns_tsigkey_detach(&msg->tsigkey);
 2858                 msg->sig_reserved = 0;
 2859                 return (result);
 2860             }
 2861         }
 2862     }
 2863     return (ISC_R_SUCCESS);
 2864 }
 2865 
 2866 dns_tsigkey_t *
 2867 dns_message_gettsigkey(dns_message_t *msg) {
 2868 
 2869     /*
 2870      * Get the TSIG key for 'msg'
 2871      */
 2872 
 2873     REQUIRE(DNS_MESSAGE_VALID(msg));
 2874 
 2875     return (msg->tsigkey);
 2876 }
 2877 
 2878 isc_result_t
 2879 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
 2880     dns_rdata_t *rdata = NULL;
 2881     dns_rdatalist_t *list = NULL;
 2882     dns_rdataset_t *set = NULL;
 2883     isc_buffer_t *buf = NULL;
 2884     isc_region_t r;
 2885     isc_result_t result;
 2886 
 2887     REQUIRE(DNS_MESSAGE_VALID(msg));
 2888     REQUIRE(msg->querytsig == NULL);
 2889 
 2890     if (querytsig == NULL)
 2891         return (ISC_R_SUCCESS);
 2892 
 2893     result = dns_message_gettemprdata(msg, &rdata);
 2894     if (result != ISC_R_SUCCESS)
 2895         goto cleanup;
 2896 
 2897     result = dns_message_gettemprdatalist(msg, &list);
 2898     if (result != ISC_R_SUCCESS)
 2899         goto cleanup;
 2900     result = dns_message_gettemprdataset(msg, &set);
 2901     if (result != ISC_R_SUCCESS)
 2902         goto cleanup;
 2903 
 2904     isc_buffer_usedregion(querytsig, &r);
 2905     result = isc_buffer_allocate(msg->mctx, &buf, r.length);
 2906     if (result != ISC_R_SUCCESS)
 2907         goto cleanup;
 2908     isc_buffer_putmem(buf, r.base, r.length);
 2909     isc_buffer_usedregion(buf, &r);
 2910     dns_rdata_init(rdata);
 2911     dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
 2912     dns_message_takebuffer(msg, &buf);
 2913     ISC_LIST_APPEND(list->rdata, rdata, link);
 2914     result = dns_rdatalist_tordataset(list, set);
 2915     if (result != ISC_R_SUCCESS)
 2916         goto cleanup;
 2917 
 2918     msg->querytsig = set;
 2919 
 2920     return (result);
 2921 
 2922  cleanup:
 2923     if (rdata != NULL)
 2924         dns_message_puttemprdata(msg, &rdata);
 2925     if (list != NULL)
 2926         dns_message_puttemprdatalist(msg, &list);
 2927     if (set != NULL)
 2928         dns_message_puttemprdataset(msg, &set);
 2929     return (ISC_R_NOMEMORY);
 2930 }
 2931 
 2932 isc_result_t
 2933 dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
 2934              isc_buffer_t **querytsig) {
 2935     isc_result_t result;
 2936     dns_rdata_t rdata = DNS_RDATA_INIT;
 2937     isc_region_t r;
 2938 
 2939     REQUIRE(DNS_MESSAGE_VALID(msg));
 2940     REQUIRE(mctx != NULL);
 2941     REQUIRE(querytsig != NULL && *querytsig == NULL);
 2942 
 2943     if (msg->tsig == NULL)
 2944         return (ISC_R_SUCCESS);
 2945 
 2946     result = dns_rdataset_first(msg->tsig);
 2947     if (result != ISC_R_SUCCESS)
 2948         return (result);
 2949     dns_rdataset_current(msg->tsig, &rdata);
 2950     dns_rdata_toregion(&rdata, &r);
 2951 
 2952     result = isc_buffer_allocate(mctx, querytsig, r.length);
 2953     if (result != ISC_R_SUCCESS)
 2954         return (result);
 2955     isc_buffer_putmem(*querytsig, r.base, r.length);
 2956     return (ISC_R_SUCCESS);
 2957 }
 2958 
 2959 dns_rdataset_t *
 2960 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
 2961 
 2962     /*
 2963      * Get the SIG(0) record for 'msg'.
 2964      */
 2965 
 2966     REQUIRE(DNS_MESSAGE_VALID(msg));
 2967     REQUIRE(owner == NULL || *owner == NULL);
 2968 
 2969     if (msg->sig0 != NULL && owner != NULL) {
 2970         /* If dns_message_getsig0 is called on a rendered message
 2971          * after the SIG(0) has been applied, we need to return the
 2972          * root name, not NULL.
 2973          */
 2974         if (msg->sig0name == NULL)
 2975             *owner = dns_rootname;
 2976         else
 2977             *owner = msg->sig0name;
 2978     }
 2979     return (msg->sig0);
 2980 }
 2981 
 2982 isc_result_t
 2983 dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
 2984     isc_region_t r;
 2985     unsigned int x;
 2986     isc_result_t result;
 2987 
 2988     /*
 2989      * Set the SIG(0) key for 'msg'
 2990      */
 2991 
 2992     /*
 2993      * The space required for an SIG(0) record is:
 2994      *
 2995      *  1 byte for the name
 2996      *  2 bytes for the type
 2997      *  2 bytes for the class
 2998      *  4 bytes for the ttl
 2999      *  2 bytes for the type covered
 3000      *  1 byte for the algorithm
 3001      *  1 bytes for the labels
 3002      *  4 bytes for the original ttl
 3003      *  4 bytes for the signature expiration
 3004      *  4 bytes for the signature inception
 3005      *  2 bytes for the key tag
 3006      *  n bytes for the signer's name
 3007      *  x bytes for the signature
 3008      * ---------------------------------
 3009      *     27 + n + x bytes
 3010      */
 3011     REQUIRE(DNS_MESSAGE_VALID(msg));
 3012     REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
 3013     REQUIRE(msg->state == DNS_SECTION_ANY);
 3014 
 3015     if (key != NULL) {
 3016         REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
 3017         dns_name_toregion(dst_key_name(key), &r);
 3018         result = dst_key_sigsize(key, &x);
 3019         if (result != ISC_R_SUCCESS) {
 3020             msg->sig_reserved = 0;
 3021             return (result);
 3022         }
 3023         msg->sig_reserved = 27 + r.length + x;
 3024         result = dns_message_renderreserve(msg, msg->sig_reserved);
 3025         if (result != ISC_R_SUCCESS) {
 3026             msg->sig_reserved = 0;
 3027             return (result);
 3028         }
 3029         msg->sig0key = key;
 3030     }
 3031     return (ISC_R_SUCCESS);
 3032 }
 3033 
 3034 dst_key_t *
 3035 dns_message_getsig0key(dns_message_t *msg) {
 3036 
 3037     /*
 3038      * Get the SIG(0) key for 'msg'
 3039      */
 3040 
 3041     REQUIRE(DNS_MESSAGE_VALID(msg));
 3042 
 3043     return (msg->sig0key);
 3044 }
 3045 
 3046 void
 3047 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
 3048     REQUIRE(DNS_MESSAGE_VALID(msg));
 3049     REQUIRE(buffer != NULL);
 3050     REQUIRE(ISC_BUFFER_VALID(*buffer));
 3051 
 3052     ISC_LIST_APPEND(msg->cleanup, *buffer, link);
 3053     *buffer = NULL;
 3054 }
 3055 
 3056 isc_result_t
 3057 dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
 3058     isc_result_t result = ISC_R_SUCCESS;
 3059     dns_rdata_t rdata = DNS_RDATA_INIT;
 3060 
 3061     REQUIRE(DNS_MESSAGE_VALID(msg));
 3062     REQUIRE(signer != NULL);
 3063     REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
 3064 
 3065     if (msg->tsig == NULL && msg->sig0 == NULL)
 3066         return (ISC_R_NOTFOUND);
 3067 
 3068     if (msg->verify_attempted == 0)
 3069         return (DNS_R_NOTVERIFIEDYET);
 3070 
 3071     if (!dns_name_hasbuffer(signer)) {
 3072         isc_buffer_t *dynbuf = NULL;
 3073         result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
 3074         if (result != ISC_R_SUCCESS)
 3075             return (result);
 3076         dns_name_setbuffer(signer, dynbuf);
 3077         dns_message_takebuffer(msg, &dynbuf);
 3078     }
 3079 
 3080     if (msg->sig0 != NULL) {
 3081         dns_rdata_sig_t sig;
 3082 
 3083         result = dns_rdataset_first(msg->sig0);
 3084         INSIST(result == ISC_R_SUCCESS);
 3085         dns_rdataset_current(msg->sig0, &rdata);
 3086 
 3087         result = dns_rdata_tostruct(&rdata, &sig, NULL);
 3088         if (result != ISC_R_SUCCESS)
 3089             return (result);
 3090 
 3091         if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
 3092             result = ISC_R_SUCCESS;
 3093         else
 3094             result = DNS_R_SIGINVALID;
 3095         dns_name_clone(&sig.signer, signer);
 3096         dns_rdata_freestruct(&sig);
 3097     } else {
 3098         const dns_name_t *identity;
 3099         dns_rdata_any_tsig_t tsig;
 3100 
 3101         result = dns_rdataset_first(msg->tsig);
 3102         INSIST(result == ISC_R_SUCCESS);
 3103         dns_rdataset_current(msg->tsig, &rdata);
 3104 
 3105         result = dns_rdata_tostruct(&rdata, &tsig, NULL);
 3106         INSIST(result == ISC_R_SUCCESS);
 3107         if (msg->verified_sig &&
 3108             msg->tsigstatus == dns_rcode_noerror &&
 3109             tsig.error == dns_rcode_noerror)
 3110         {
 3111             result = ISC_R_SUCCESS;
 3112         } else if ((!msg->verified_sig) ||
 3113                (msg->tsigstatus != dns_rcode_noerror))
 3114         {
 3115             result = DNS_R_TSIGVERIFYFAILURE;
 3116         } else {
 3117             INSIST(tsig.error != dns_rcode_noerror);
 3118             result = DNS_R_TSIGERRORSET;
 3119         }
 3120         dns_rdata_freestruct(&tsig);
 3121 
 3122         if (msg->tsigkey == NULL) {
 3123             /*
 3124              * If msg->tsigstatus & tsig.error are both
 3125              * dns_rcode_noerror, the message must have been
 3126              * verified, which means msg->tsigkey will be
 3127              * non-NULL.
 3128              */
 3129             INSIST(result != ISC_R_SUCCESS);
 3130         } else {
 3131             identity = dns_tsigkey_identity(msg->tsigkey);
 3132             if (identity == NULL) {
 3133                 if (result == ISC_R_SUCCESS)
 3134                     result = DNS_R_NOIDENTITY;
 3135                 identity = &msg->tsigkey->name;
 3136             }
 3137             dns_name_clone(identity, signer);
 3138         }
 3139     }
 3140 
 3141     return (result);
 3142 }
 3143 
 3144 void
 3145 dns_message_resetsig(dns_message_t *msg) {
 3146     REQUIRE(DNS_MESSAGE_VALID(msg));
 3147     msg->verified_sig = 0;
 3148     msg->verify_attempted = 0;
 3149     msg->tsigstatus = dns_rcode_noerror;
 3150     msg->sig0status = dns_rcode_noerror;
 3151     msg->timeadjust = 0;
 3152     if (msg->tsigkey != NULL) {
 3153         dns_tsigkey_detach(&msg->tsigkey);
 3154         msg->tsigkey = NULL;
 3155     }
 3156 }
 3157 
 3158 isc_result_t
 3159 dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
 3160     dns_message_resetsig(msg);
 3161     return (dns_message_checksig(msg, view));
 3162 }
 3163 
 3164 #ifdef SKAN_MSG_DEBUG
 3165 void
 3166 dns_message_dumpsig(dns_message_t *msg, char *txt1) {
 3167     dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
 3168     dns_rdata_any_tsig_t querytsig;
 3169     isc_result_t result;
 3170 
 3171     if (msg->tsig != NULL) {
 3172         result = dns_rdataset_first(msg->tsig);
 3173         RUNTIME_CHECK(result == ISC_R_SUCCESS);
 3174         dns_rdataset_current(msg->tsig, &querytsigrdata);
 3175         result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
 3176         RUNTIME_CHECK(result == ISC_R_SUCCESS);
 3177         hexdump(txt1, "TSIG", querytsig.signature,
 3178             querytsig.siglen);
 3179     }
 3180 
 3181     if (msg->querytsig != NULL) {
 3182         result = dns_rdataset_first(msg->querytsig);
 3183         RUNTIME_CHECK(result == ISC_R_SUCCESS);
 3184         dns_rdataset_current(msg->querytsig, &querytsigrdata);
 3185         result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
 3186         RUNTIME_CHECK(result == ISC_R_SUCCESS);
 3187         hexdump(txt1, "QUERYTSIG", querytsig.signature,
 3188             querytsig.siglen);
 3189     }
 3190 }
 3191 #endif
 3192 
 3193 isc_result_t
 3194 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
 3195     isc_buffer_t b, msgb;
 3196 
 3197     REQUIRE(DNS_MESSAGE_VALID(msg));
 3198 
 3199     if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
 3200         return (ISC_R_SUCCESS);
 3201 
 3202     INSIST(msg->saved.base != NULL);
 3203     isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
 3204     isc_buffer_add(&msgb, msg->saved.length);
 3205     if (msg->tsigkey != NULL || msg->tsig != NULL) {
 3206 #ifdef SKAN_MSG_DEBUG
 3207         dns_message_dumpsig(msg, "dns_message_checksig#1");
 3208 #endif
 3209         if (view != NULL)
 3210             return (dns_view_checksig(view, &msgb, msg));
 3211         else
 3212             return (dns_tsig_verify(&msgb, msg, NULL, NULL));
 3213     } else {
 3214         dns_rdata_t rdata = DNS_RDATA_INIT;
 3215         dns_rdata_sig_t sig;
 3216         dns_rdataset_t keyset;
 3217         isc_result_t result;
 3218 
 3219         result = dns_rdataset_first(msg->sig0);
 3220         INSIST(result == ISC_R_SUCCESS);
 3221         dns_rdataset_current(msg->sig0, &rdata);
 3222 
 3223         /*
 3224          * This can occur when the message is a dynamic update, since
 3225          * the rdata length checking is relaxed.  This should not
 3226          * happen in a well-formed message, since the SIG(0) is only
 3227          * looked for in the additional section, and the dynamic update
 3228          * meta-records are in the prerequisite and update sections.
 3229          */
 3230         if (rdata.length == 0)
 3231             return (ISC_R_UNEXPECTEDEND);
 3232 
 3233         result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
 3234         if (result != ISC_R_SUCCESS)
 3235             return (result);
 3236 
 3237         dns_rdataset_init(&keyset);
 3238         if (view == NULL)
 3239             return (DNS_R_KEYUNAUTHORIZED);
 3240         result = dns_view_simplefind(view, &sig.signer,
 3241                          dns_rdatatype_key /* SIG(0) */,
 3242                          0, 0, false, &keyset, NULL);
 3243 
 3244         if (result != ISC_R_SUCCESS) {
 3245             /* XXXBEW Should possibly create a fetch here */
 3246             result = DNS_R_KEYUNAUTHORIZED;
 3247             goto freesig;
 3248         } else if (keyset.trust < dns_trust_secure) {
 3249             /* XXXBEW Should call a validator here */
 3250             result = DNS_R_KEYUNAUTHORIZED;
 3251             goto freesig;
 3252         }
 3253         result = dns_rdataset_first(&keyset);
 3254         INSIST(result == ISC_R_SUCCESS);
 3255         for (;
 3256              result == ISC_R_SUCCESS;
 3257              result = dns_rdataset_next(&keyset))
 3258         {
 3259             dst_key_t *key = NULL;
 3260 
 3261             dns_rdata_reset(&rdata);
 3262             dns_rdataset_current(&keyset, &rdata);
 3263             isc_buffer_init(&b, rdata.data, rdata.length);
 3264             isc_buffer_add(&b, rdata.length);
 3265 
 3266             result = dst_key_fromdns(&sig.signer, rdata.rdclass,
 3267                          &b, view->mctx, &key);
 3268             if (result != ISC_R_SUCCESS)
 3269                 continue;
 3270             if (dst_key_alg(key) != sig.algorithm ||
 3271                 dst_key_id(key) != sig.keyid ||
 3272                 !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
 3273                   dst_key_proto(key) == DNS_KEYPROTO_ANY))
 3274             {
 3275                 dst_key_free(&key);
 3276                 continue;
 3277             }
 3278             result = dns_dnssec_verifymessage(&msgb, msg, key);
 3279             dst_key_free(&key);
 3280             if (result == ISC_R_SUCCESS)
 3281                 break;
 3282         }
 3283         if (result == ISC_R_NOMORE)
 3284             result = DNS_R_KEYUNAUTHORIZED;
 3285 
 3286  freesig:
 3287         if (dns_rdataset_isassociated(&keyset))
 3288             dns_rdataset_disassociate(&keyset);
 3289         dns_rdata_freestruct(&sig);
 3290         return (result);
 3291     }
 3292 }
 3293 
 3294 #define INDENT(sp) \
 3295     do { \
 3296         unsigned int __i; \
 3297         dns_masterstyle_flags_t  __flags = dns_master_styleflags(sp); \
 3298         if ((__flags & DNS_STYLEFLAG_INDENT) == 0ULL && \
 3299             (__flags & DNS_STYLEFLAG_YAML) == 0ULL) \
 3300             break; \
 3301         for (__i = 0; __i < dns_master_indent; __i++) { \
 3302             ADD_STRING(target, dns_master_indentstr); \
 3303         } \
 3304     } while (0)
 3305 
 3306 isc_result_t
 3307 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
 3308               const dns_master_style_t *style,
 3309               dns_messagetextflag_t flags,
 3310               isc_buffer_t *target) {
 3311     dns_name_t *name, empty_name;
 3312     dns_rdataset_t *rdataset;
 3313     isc_result_t result = ISC_R_SUCCESS;
 3314     bool seensoa = false;
 3315     unsigned int saveindent;
 3316     dns_masterstyle_flags_t sflags;
 3317 
 3318     REQUIRE(DNS_MESSAGE_VALID(msg));
 3319     REQUIRE(target != NULL);
 3320     REQUIRE(VALID_SECTION(section));
 3321 
 3322     saveindent = dns_master_indent;
 3323     sflags = dns_master_styleflags(style);
 3324     if (ISC_LIST_EMPTY(msg->sections[section]))
 3325         goto cleanup;
 3326 
 3327 
 3328     INDENT(style);
 3329     if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
 3330         if (msg->opcode != dns_opcode_update) {
 3331             ADD_STRING(target, sectiontext[section]);
 3332         } else {
 3333             ADD_STRING(target, updsectiontext[section]);
 3334         }
 3335         ADD_STRING(target, "_SECTION:\n");
 3336     } else if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
 3337         ADD_STRING(target, ";; ");
 3338         if (msg->opcode != dns_opcode_update) {
 3339             ADD_STRING(target, sectiontext[section]);
 3340         } else {
 3341             ADD_STRING(target, updsectiontext[section]);
 3342         }
 3343         ADD_STRING(target, " SECTION:\n");
 3344     }
 3345 
 3346     dns_name_init(&empty_name, NULL);
 3347     result = dns_message_firstname(msg, section);
 3348     if (result != ISC_R_SUCCESS) {
 3349         goto cleanup;
 3350     }
 3351     if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
 3352         dns_master_indent++;
 3353     }
 3354     do {
 3355         name = NULL;
 3356         dns_message_currentname(msg, section, &name);
 3357         for (rdataset = ISC_LIST_HEAD(name->list);
 3358              rdataset != NULL;
 3359              rdataset = ISC_LIST_NEXT(rdataset, link)) {
 3360             if (section == DNS_SECTION_ANSWER &&
 3361                 rdataset->type == dns_rdatatype_soa) {
 3362                 if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
 3363                     continue;
 3364                 if (seensoa &&
 3365                     (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
 3366                     continue;
 3367                 seensoa = true;
 3368             }
 3369             if (section == DNS_SECTION_QUESTION) {
 3370                 INDENT(style);
 3371                 if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
 3372                     ADD_STRING(target, "- ");
 3373                 } else {
 3374                     ADD_STRING(target, ";");
 3375                 }
 3376                 result = dns_master_questiontotext(name,
 3377                                    rdataset,
 3378                                    style,
 3379                                    target);
 3380             } else {
 3381                 result = dns_master_rdatasettotext(name,
 3382                                    rdataset,
 3383                                    style,
 3384                                    target);
 3385             }
 3386             if (result != ISC_R_SUCCESS)
 3387                 goto cleanup;
 3388         }
 3389         result = dns_message_nextname(msg, section);
 3390     } while (result == ISC_R_SUCCESS);
 3391     if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
 3392         dns_master_indent--;
 3393     }
 3394     if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
 3395         (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0 &&
 3396         (sflags & DNS_STYLEFLAG_YAML) == 0)
 3397     {
 3398         INDENT(style);
 3399         ADD_STRING(target, "\n");
 3400     }
 3401     if (result == ISC_R_NOMORE)
 3402         result = ISC_R_SUCCESS;
 3403 
 3404  cleanup:
 3405     dns_master_indent = saveindent;
 3406     return (result);
 3407 }
 3408 
 3409 static isc_result_t
 3410 render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
 3411     int i;
 3412     char addr[16], addr_text[64];
 3413     uint16_t family;
 3414     uint8_t addrlen, addrbytes, scopelen;
 3415     isc_result_t result;
 3416 
 3417     /*
 3418      * Note: This routine needs to handle malformed ECS options.
 3419      */
 3420 
 3421     if (isc_buffer_remaininglength(ecsbuf) < 4)
 3422         return (DNS_R_OPTERR);
 3423     family = isc_buffer_getuint16(ecsbuf);
 3424     addrlen = isc_buffer_getuint8(ecsbuf);
 3425     scopelen = isc_buffer_getuint8(ecsbuf);
 3426 
 3427     addrbytes = (addrlen + 7) / 8;
 3428     if (isc_buffer_remaininglength(ecsbuf) < addrbytes)
 3429         return (DNS_R_OPTERR);
 3430 
 3431     if (addrbytes > sizeof(addr))
 3432         return (DNS_R_OPTERR);
 3433 
 3434     memset(addr, 0, sizeof(addr));
 3435     for (i = 0; i < addrbytes; i ++)
 3436         addr[i] = isc_buffer_getuint8(ecsbuf);
 3437 
 3438     switch (family) {
 3439     case 0:
 3440         if (addrlen != 0U || scopelen != 0U)
 3441             return (DNS_R_OPTERR);
 3442         strlcpy(addr_text, "0", sizeof(addr_text));
 3443         break;
 3444     case 1:
 3445         if (addrlen > 32 || scopelen > 32)
 3446             return (DNS_R_OPTERR);
 3447         inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
 3448         break;
 3449     case 2:
 3450         if (addrlen > 128 || scopelen > 128)
 3451             return (DNS_R_OPTERR);
 3452         inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
 3453         break;
 3454     default:
 3455         return (DNS_R_OPTERR);
 3456     }
 3457 
 3458     ADD_STRING(target, ": ");
 3459     ADD_STRING(target, addr_text);
 3460     snprintf(addr_text, sizeof(addr_text), "/%d/%d", addrlen, scopelen);
 3461     ADD_STRING(target, addr_text);
 3462 
 3463     result = ISC_R_SUCCESS;
 3464 
 3465  cleanup:
 3466     return (result);
 3467 }
 3468 
 3469 static isc_result_t
 3470 render_llq(isc_buffer_t *optbuf, isc_buffer_t *target) {
 3471     char buf[sizeof("18446744073709551615")]; /* 2^64-1 */
 3472     isc_result_t result = ISC_R_SUCCESS;
 3473     uint32_t u;
 3474     uint64_t q;
 3475 
 3476     u = isc_buffer_getuint16(optbuf);
 3477     ADD_STRING(target, " Version: ");
 3478     snprintf(buf, sizeof(buf), "%u", u);
 3479     ADD_STRING(target, buf);
 3480 
 3481     u = isc_buffer_getuint16(optbuf);
 3482     ADD_STRING(target, ", Opcode: ");
 3483     snprintf(buf, sizeof(buf), "%u", u);
 3484     ADD_STRING(target, buf);
 3485 
 3486     u = isc_buffer_getuint16(optbuf);
 3487     ADD_STRING(target, ", Error: ");
 3488     snprintf(buf, sizeof(buf), "%u", u);
 3489     ADD_STRING(target, buf);
 3490 
 3491     q = isc_buffer_getuint32(optbuf);
 3492     q <<= 32;
 3493     q |= isc_buffer_getuint32(optbuf);
 3494     ADD_STRING(target, ", Identifier: ");
 3495     snprintf(buf, sizeof(buf), "%" PRIu64, q);
 3496     ADD_STRING(target, buf);
 3497 
 3498     u = isc_buffer_getuint32(optbuf);
 3499     ADD_STRING(target, ", Lifetime: ");
 3500     snprintf(buf, sizeof(buf), "%u", u);
 3501     ADD_STRING(target, buf);
 3502  cleanup:
 3503     return (result);
 3504 }
 3505 
 3506 static isc_result_t
 3507 dns_message_pseudosectiontoyaml(dns_message_t *msg,
 3508                 dns_pseudosection_t section,
 3509                 const dns_master_style_t *style,
 3510                 dns_messagetextflag_t flags,
 3511                 isc_buffer_t *target)
 3512 {
 3513     dns_rdataset_t *ps = NULL;
 3514     dns_name_t *name = NULL;
 3515     isc_result_t result = ISC_R_SUCCESS;
 3516     char buf[sizeof("1234567890")];
 3517     uint32_t mbz;
 3518     dns_rdata_t rdata;
 3519     isc_buffer_t optbuf;
 3520     uint16_t optcode, optlen;
 3521     unsigned char *optdata;
 3522     unsigned int saveindent = dns_master_indent;
 3523     unsigned int optindent;
 3524 
 3525     REQUIRE(DNS_MESSAGE_VALID(msg));
 3526     REQUIRE(target != NULL);
 3527     REQUIRE(VALID_PSEUDOSECTION(section));
 3528 
 3529     switch (section) {
 3530     case DNS_PSEUDOSECTION_OPT:
 3531         ps = dns_message_getopt(msg);
 3532         if (ps == NULL) {
 3533             goto cleanup;
 3534         }
 3535 
 3536         INDENT(style);
 3537         ADD_STRING(target, "OPT_PSEUDOSECTION:\n");
 3538         dns_master_indent++;
 3539 
 3540         INDENT(style);
 3541         ADD_STRING(target, "EDNS:\n");
 3542         dns_master_indent++;
 3543 
 3544         INDENT(style);
 3545         ADD_STRING(target, "version: ");
 3546         snprintf(buf, sizeof(buf), "%u",
 3547              (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
 3548         ADD_STRING(target, buf);
 3549         ADD_STRING(target, "\n");
 3550         INDENT(style);
 3551         ADD_STRING(target, "flags:");
 3552         if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
 3553             ADD_STRING(target, " do");
 3554         ADD_STRING(target, "\n");
 3555         mbz = ps->ttl & 0xffff;
 3556         mbz &= ~DNS_MESSAGEEXTFLAG_DO;      /* Known Flags. */
 3557         if (mbz != 0) {
 3558             INDENT(style);
 3559             ADD_STRING(target, "MBZ: ");
 3560             snprintf(buf, sizeof(buf), "0x%.4x", mbz);
 3561             ADD_STRING(target, buf);
 3562             ADD_STRING(target, "\n");
 3563         }
 3564         INDENT(style);
 3565         ADD_STRING(target, "udp: ");
 3566         snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
 3567         ADD_STRING(target, buf);
 3568         result = dns_rdataset_first(ps);
 3569         if (result != ISC_R_SUCCESS) {
 3570             result = ISC_R_SUCCESS;
 3571             goto cleanup;
 3572         }
 3573 
 3574         /*
 3575          * Print EDNS info, if any.
 3576          *
 3577          * WARNING: The option contents may be malformed as
 3578          * dig +ednsopt=value:<content> does not perform validity
 3579          * checking.
 3580          */
 3581         dns_rdata_init(&rdata);
 3582         dns_rdataset_current(ps, &rdata);
 3583 
 3584         isc_buffer_init(&optbuf, rdata.data, rdata.length);
 3585         isc_buffer_add(&optbuf, rdata.length);
 3586         optindent = dns_master_indent;
 3587         while (isc_buffer_remaininglength(&optbuf) != 0) {
 3588             bool extra_text = false;
 3589             dns_master_indent = optindent;
 3590             INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
 3591             optcode = isc_buffer_getuint16(&optbuf);
 3592             optlen = isc_buffer_getuint16(&optbuf);
 3593             INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
 3594 
 3595             if (optcode == DNS_OPT_LLQ) {
 3596                 INDENT(style);
 3597                 if (optlen == 18U) {
 3598                     ADD_STRING(target, "LLQ: ");
 3599                     result = render_llq(&optbuf, target);
 3600                     if (result != ISC_R_SUCCESS) {
 3601                         goto cleanup;
 3602                     }
 3603                     ADD_STRING(target, "\n");
 3604                     continue;
 3605                 }
 3606                 ADD_STRING(target, "LLQ");
 3607             } else if (optcode == DNS_OPT_NSID) {
 3608                 INDENT(style);
 3609                 ADD_STRING(target, "NSID");
 3610             } else if (optcode == DNS_OPT_COOKIE) {
 3611                 INDENT(style);
 3612                 ADD_STRING(target, "COOKIE");
 3613             } else if (optcode == DNS_OPT_CLIENT_SUBNET) {
 3614                 isc_buffer_t ecsbuf;
 3615                 INDENT(style);
 3616                 ADD_STRING(target, "CLIENT-SUBNET");
 3617                 isc_buffer_init(&ecsbuf,
 3618                         isc_buffer_current(&optbuf),
 3619                         optlen);
 3620                 isc_buffer_add(&ecsbuf, optlen);
 3621                 result = render_ecs(&ecsbuf, target);
 3622                 if (result == ISC_R_NOSPACE)
 3623                     goto cleanup;
 3624                 if (result == ISC_R_SUCCESS) {
 3625                     isc_buffer_forward(&optbuf, optlen);
 3626                     ADD_STRING(target, "\n");
 3627                     continue;
 3628                 }
 3629                 ADD_STRING(target, "\n");
 3630             } else if (optcode == DNS_OPT_EXPIRE) {
 3631                 if (optlen == 4) {
 3632                     uint32_t secs;
 3633                     secs = isc_buffer_getuint32(&optbuf);
 3634                     INDENT(style);
 3635                     ADD_STRING(target, "EXPIRE: ");
 3636                     snprintf(buf, sizeof(buf), "%u", secs);
 3637                     ADD_STRING(target, buf);
 3638                     ADD_STRING(target, " (");
 3639                     result = dns_ttl_totext(secs,
 3640                                 true,
 3641                                 target);
 3642                     if (result != ISC_R_SUCCESS)
 3643                         goto cleanup;
 3644                     ADD_STRING(target, ")\n");
 3645                     continue;
 3646                 }
 3647                 INDENT(style);
 3648                 ADD_STRING(target, "EXPIRE");
 3649             } else if (optcode == DNS_OPT_PAD) {
 3650                 INDENT(style);
 3651                 ADD_STRING(target, "PAD");
 3652             } else if (optcode == DNS_OPT_KEY_TAG) {
 3653                 INDENT(style);
 3654                 ADD_STRING(target, "KEY-TAG");
 3655                 if (optlen > 0U && (optlen % 2U) == 0U) {
 3656                     const char *sep = ": ";
 3657                     uint16_t id;
 3658                     while (optlen > 0U) {
 3659                         id = isc_buffer_getuint16(&optbuf);
 3660                         snprintf(buf, sizeof(buf), "%s%u",
 3661                              sep, id);
 3662                         ADD_STRING(target, buf);
 3663                         sep = ", ";
 3664                         optlen -= 2;
 3665                     }
 3666                     ADD_STRING(target, "\n");
 3667                     continue;
 3668                 }
 3669             } else if (optcode == DNS_OPT_EDE) {
 3670                 INDENT(style);
 3671                 ADD_STRING(target, "EDE");
 3672                 if (optlen >= 2U) {
 3673                     uint16_t ede;
 3674                     ADD_STRING(target, ":\n");
 3675                     dns_master_indent++;
 3676                     INDENT(style);
 3677                     ADD_STRING(target, "INFO-CODE:");
 3678                     ede = isc_buffer_getuint16(&optbuf);
 3679                     snprintf(buf, sizeof(buf), " %u", ede);
 3680                     ADD_STRING(target, buf);
 3681                     if (ede < ARRAY_SIZE(edetext)) {
 3682                         ADD_STRING(target, " (");
 3683                         ADD_STRING(target,
 3684                                edetext[ede]);
 3685                         ADD_STRING(target, ")");
 3686                     }
 3687                     ADD_STRING(target, "\n");
 3688                     optlen -= 2;
 3689                     if (optlen != 0) {
 3690                         INDENT(style);
 3691                         ADD_STRING(target,
 3692                                "EXTRA-TEXT");
 3693                         extra_text = true;
 3694                     }
 3695                 }
 3696             } else if (optcode == DNS_OPT_CLIENT_TAG) {
 3697                 uint16_t id;
 3698                 INDENT(style);
 3699                 ADD_STRING(target, "CLIENT-TAG");
 3700                 if (optlen == 2U) {
 3701                     id = isc_buffer_getuint16(&optbuf);
 3702                     snprintf(buf, sizeof(buf), ": %u\n",
 3703                          id);
 3704                     ADD_STRING(target, buf);
 3705                     optlen -= 2;
 3706                     POST(optlen);
 3707                     continue;
 3708                 }
 3709             } else if (optcode == DNS_OPT_SERVER_TAG) {
 3710                 uint16_t id;
 3711                 INDENT(style);
 3712                 ADD_STRING(target, "SERVER-TAG");
 3713                 if (optlen == 2U) {
 3714                     id = isc_buffer_getuint16(&optbuf);
 3715                     snprintf(buf, sizeof(buf), ": %u\n",
 3716                          id);
 3717                     ADD_STRING(target, buf);
 3718                     optlen -= 2;
 3719                     POST(optlen);
 3720                     continue;
 3721                 }
 3722             } else {
 3723                 INDENT(style);
 3724                 ADD_STRING(target, "OPT: ");
 3725                 snprintf(buf, sizeof(buf), "%u", optcode);
 3726                 ADD_STRING(target, buf);
 3727                 ADD_STRING(target, "\n");
 3728             }
 3729 
 3730             if (optlen != 0) {
 3731                 int i;
 3732                 bool utf8ok = false;
 3733 
 3734                 ADD_STRING(target, ": ");
 3735 
 3736                 optdata = isc_buffer_current(&optbuf);
 3737                 if (extra_text) {
 3738                     utf8ok = isc_utf8_valid(optdata,
 3739                                 optlen);
 3740                 }
 3741                 if (!utf8ok) {
 3742                     for (i = 0; i < optlen; i++) {
 3743                         const char *sep;
 3744                         switch (optcode) {
 3745                         case DNS_OPT_COOKIE:
 3746                             sep = "";
 3747                             break;
 3748                         default:
 3749                             sep = " ";
 3750                             break;
 3751                         }
 3752                         snprintf(buf, sizeof(buf),
 3753                              "%02x%s", optdata[i],
 3754                              sep);
 3755                         ADD_STRING(target, buf);
 3756                     }
 3757                 }
 3758 
 3759                 isc_buffer_forward(&optbuf, optlen);
 3760 
 3761                 if (optcode == DNS_OPT_COOKIE) {
 3762                     /*
 3763                      * Valid server cookie?
 3764                      */
 3765                     if (msg->cc_ok && optlen >= 16)
 3766                         ADD_STRING(target, " (good)");
 3767                     /*
 3768                      * Server cookie is not valid but
 3769                      * we had our cookie echoed back.
 3770                      */
 3771                     if (msg->cc_ok && optlen < 16)
 3772                         ADD_STRING(target, " (echoed)");
 3773                     /*
 3774                      * We didn't get our cookie echoed
 3775                      * back.
 3776                      */
 3777                     if (msg->cc_bad)
 3778                         ADD_STRING(target, " (bad)");
 3779                     ADD_STRING(target, "\n");
 3780                     continue;
 3781                 }
 3782 
 3783                 if (optcode == DNS_OPT_CLIENT_SUBNET) {
 3784                     ADD_STRING(target, "\n");
 3785                     continue;
 3786                 }
 3787 
 3788                 /*
 3789                  * For non-COOKIE options, add a printable
 3790                  * version
 3791                  */
 3792                 if (!extra_text) {
 3793                     ADD_STRING(target, "(\"");
 3794                 } else {
 3795                     ADD_STRING(target, "\"");
 3796                 }
 3797                 if (isc_buffer_availablelength(target) < optlen)
 3798                 {
 3799                     result = ISC_R_NOSPACE;
 3800                     goto cleanup;
 3801                 }
 3802                 for (i = 0; i < optlen; i++) {
 3803                     if (isprint(optdata[i]) ||
 3804                         (utf8ok && optdata[i] > 127)) {
 3805                         isc_buffer_putmem(
 3806                             target, &optdata[i], 1);
 3807                     } else {
 3808                         isc_buffer_putstr(target, ".");
 3809                     }
 3810                 }
 3811                 if (!extra_text) {
 3812                     ADD_STRING(target, "\")");
 3813                 } else {
 3814                     ADD_STRING(target, "\"");
 3815                 }
 3816             }
 3817             ADD_STRING(target, "\n");
 3818         }
 3819         dns_master_indent = optindent;
 3820         result = ISC_R_SUCCESS;
 3821         goto cleanup;
 3822     case DNS_PSEUDOSECTION_TSIG:
 3823         ps = dns_message_gettsig(msg, &name);
 3824         if (ps == NULL) {
 3825             result = ISC_R_SUCCESS;
 3826             goto cleanup;
 3827         }
 3828         INDENT(style);
 3829         ADD_STRING(target, "TSIG_PSEUDOSECTION:\n");
 3830         result = dns_master_rdatasettotext(name, ps, style, target);
 3831         ADD_STRING(target, "\n");
 3832         goto cleanup;
 3833     case DNS_PSEUDOSECTION_SIG0:
 3834         ps = dns_message_getsig0(msg, &name);
 3835         if (ps == NULL) {
 3836             result = ISC_R_SUCCESS;
 3837             goto cleanup;
 3838         }
 3839         INDENT(style);
 3840         ADD_STRING(target, "SIG0_PSEUDOSECTION:\n");
 3841         result = dns_master_rdatasettotext(name, ps, style, target);
 3842         if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
 3843             (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
 3844             ADD_STRING(target, "\n");
 3845         goto cleanup;
 3846     }
 3847 
 3848     result = ISC_R_UNEXPECTED;
 3849 
 3850  cleanup:
 3851     dns_master_indent = saveindent;
 3852     return (result);
 3853 }
 3854 
 3855 isc_result_t
 3856 dns_message_pseudosectiontotext(dns_message_t *msg,
 3857                 dns_pseudosection_t section,
 3858                 const dns_master_style_t *style,
 3859                 dns_messagetextflag_t flags,
 3860                 isc_buffer_t *target)
 3861 {
 3862     dns_rdataset_t *ps = NULL;
 3863     dns_name_t *name = NULL;
 3864     isc_result_t result;
 3865     char buf[sizeof("1234567890 ")];
 3866     uint32_t mbz;
 3867     dns_rdata_t rdata;
 3868     isc_buffer_t optbuf;
 3869     uint16_t optcode, optlen;
 3870     unsigned char *optdata;
 3871 
 3872     REQUIRE(DNS_MESSAGE_VALID(msg));
 3873     REQUIRE(target != NULL);
 3874     REQUIRE(VALID_PSEUDOSECTION(section));
 3875 
 3876     if ((dns_master_styleflags(style) & DNS_STYLEFLAG_YAML) != 0)
 3877         return (dns_message_pseudosectiontoyaml(msg, section, style,
 3878                             flags, target));
 3879     switch (section) {
 3880     case DNS_PSEUDOSECTION_OPT:
 3881         ps = dns_message_getopt(msg);
 3882         if (ps == NULL)
 3883             return (ISC_R_SUCCESS);
 3884         if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
 3885             INDENT(style);
 3886             ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
 3887         }
 3888 
 3889         INDENT(style);
 3890         ADD_STRING(target, "; EDNS: version: ");
 3891         snprintf(buf, sizeof(buf), "%u",
 3892              (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
 3893         ADD_STRING(target, buf);
 3894         ADD_STRING(target, ", flags:");
 3895         if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
 3896             ADD_STRING(target, " do");
 3897         mbz = ps->ttl & 0xffff;
 3898         mbz &= ~DNS_MESSAGEEXTFLAG_DO;      /* Known Flags. */
 3899         if (mbz != 0) {
 3900             ADD_STRING(target, "; MBZ: ");
 3901             snprintf(buf, sizeof(buf), "0x%.4x", mbz);
 3902             ADD_STRING(target, buf);
 3903             ADD_STRING(target, ", udp: ");
 3904         } else
 3905             ADD_STRING(target, "; udp: ");
 3906         snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
 3907         ADD_STRING(target, buf);
 3908 
 3909         result = dns_rdataset_first(ps);
 3910         if (result != ISC_R_SUCCESS)
 3911             return (ISC_R_SUCCESS);
 3912 
 3913         /*
 3914          * Print EDNS info, if any.
 3915          *
 3916          * WARNING: The option contents may be malformed as
 3917          * dig +ednsopt=value:<content> does not validity
 3918          * checking.
 3919          */
 3920         dns_rdata_init(&rdata);
 3921         dns_rdataset_current(ps, &rdata);
 3922 
 3923         isc_buffer_init(&optbuf, rdata.data, rdata.length);
 3924         isc_buffer_add(&optbuf, rdata.length);
 3925         while (isc_buffer_remaininglength(&optbuf) != 0) {
 3926             INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
 3927             optcode = isc_buffer_getuint16(&optbuf);
 3928             optlen = isc_buffer_getuint16(&optbuf);
 3929             INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
 3930 
 3931             INDENT(style);
 3932 
 3933             if (optcode == DNS_OPT_LLQ) {
 3934                 if (optlen == 18U) {
 3935                     ADD_STRING(target, "; LLQ:");
 3936                     result = render_llq(&optbuf, target);
 3937                     if (result != ISC_R_SUCCESS) {
 3938                         return (result);
 3939                     }
 3940                     ADD_STRING(target, "\n");
 3941                     continue;
 3942                 }
 3943                 ADD_STRING(target, "; LLQ");
 3944             } else if (optcode == DNS_OPT_NSID) {
 3945                 ADD_STRING(target, "; NSID");
 3946             } else if (optcode == DNS_OPT_COOKIE) {
 3947                 ADD_STRING(target, "; COOKIE");
 3948             } else if (optcode == DNS_OPT_CLIENT_SUBNET) {
 3949                 isc_buffer_t ecsbuf;
 3950 
 3951                 ADD_STRING(target, "; CLIENT-SUBNET");
 3952                 isc_buffer_init(&ecsbuf,
 3953                         isc_buffer_current(&optbuf),
 3954                         optlen);
 3955                 isc_buffer_add(&ecsbuf, optlen);
 3956                 result = render_ecs(&ecsbuf, target);
 3957                 if (result == ISC_R_NOSPACE)
 3958                     return (result);
 3959                 if (result == ISC_R_SUCCESS) {
 3960                     isc_buffer_forward(&optbuf, optlen);
 3961                     ADD_STRING(target, "\n");
 3962                     continue;
 3963                 }
 3964             } else if (optcode == DNS_OPT_EXPIRE) {
 3965                 if (optlen == 4) {
 3966                     uint32_t secs;
 3967                     secs = isc_buffer_getuint32(&optbuf);
 3968                     ADD_STRING(target, "; EXPIRE: ");
 3969                     snprintf(buf, sizeof(buf), "%u", secs);
 3970                     ADD_STRING(target, buf);
 3971                     ADD_STRING(target, " (");
 3972                     result = dns_ttl_totext(secs,
 3973                                 true,
 3974                                 target);
 3975                     if (result != ISC_R_SUCCESS)
 3976                         return (result);
 3977                     ADD_STRING(target, ")\n");
 3978                     continue;
 3979                 }
 3980                 ADD_STRING(target, "; EXPIRE");
 3981             } else if (optcode == DNS_OPT_PAD) {
 3982                 ADD_STRING(target, "; PAD");
 3983             } else if (optcode == DNS_OPT_KEY_TAG) {
 3984                 ADD_STRING(target, "; KEY-TAG");
 3985                 if (optlen > 0U && (optlen % 2U) == 0U) {
 3986                     const char *sep = ": ";
 3987                     uint16_t id;
 3988                     while (optlen > 0U) {
 3989                         id = isc_buffer_getuint16(&optbuf);
 3990                         snprintf(buf, sizeof(buf), "%s%u",
 3991                              sep, id);
 3992                         ADD_STRING(target, buf);
 3993                         sep = ", ";
 3994                         optlen -= 2;
 3995                     }
 3996                     ADD_STRING(target, "\n");
 3997                     continue;
 3998                 }
 3999             } else if (optcode == DNS_OPT_EDE) {
 4000                 ADD_STRING(target, "; EDE");
 4001                 if (optlen >= 2U) {
 4002                     uint16_t ede;
 4003                     ede = isc_buffer_getuint16(&optbuf);
 4004                     snprintf(buf, sizeof(buf), ": %u", ede);
 4005                     ADD_STRING(target, buf);
 4006                     if (ede < ARRAY_SIZE(edetext)) {
 4007                         ADD_STRING(target, " (");
 4008                         ADD_STRING(target,
 4009                                edetext[ede]);
 4010                         ADD_STRING(target, ")");
 4011                     }
 4012                     optlen -= 2;
 4013                 } else if (optlen == 1U) {
 4014                     /* Malformed */
 4015                     optdata = isc_buffer_current(&optbuf);
 4016                     snprintf(buf, sizeof(buf),
 4017                          ": %02x (\"%c\")\n",
 4018                          optdata[0],
 4019                          isprint(optdata[0])
 4020                              ? optdata[0]
 4021                              : '.');
 4022                     isc_buffer_forward(&optbuf, optlen);
 4023                     ADD_STRING(target, buf);
 4024                     continue;
 4025                 }
 4026             } else if (optcode == DNS_OPT_CLIENT_TAG) {
 4027                 uint16_t id;
 4028                 ADD_STRING(target, "; CLIENT-TAG");
 4029                 if (optlen == 2U) {
 4030                     id = isc_buffer_getuint16(&optbuf);
 4031                     snprintf(buf, sizeof(buf), ": %u\n",
 4032                          id);
 4033                     ADD_STRING(target, buf);
 4034                     optlen -= 2;
 4035                     POST(optlen);
 4036                     continue;
 4037                 }
 4038             } else if (optcode == DNS_OPT_SERVER_TAG) {
 4039                 uint16_t id;
 4040                 ADD_STRING(target, "; SERVER-TAG");
 4041                 if (optlen == 2U) {
 4042                     id = isc_buffer_getuint16(&optbuf);
 4043                     snprintf(buf, sizeof(buf), ": %u\n",
 4044                          id);
 4045                     ADD_STRING(target, buf);
 4046                     optlen -= 2;
 4047                     POST(optlen);
 4048                     continue;
 4049                 }
 4050             } else {
 4051                 ADD_STRING(target, "; OPT=");
 4052                 snprintf(buf, sizeof(buf), "%u", optcode);
 4053                 ADD_STRING(target, buf);
 4054             }
 4055 
 4056             if (optlen != 0) {
 4057                 int i;
 4058                 bool utf8ok = false;
 4059                 ADD_STRING(target, ": ");
 4060 
 4061                 optdata = isc_buffer_current(&optbuf);
 4062                 if (optcode == DNS_OPT_EDE) {
 4063                     utf8ok = isc_utf8_valid(optdata,
 4064                                 optlen);
 4065                 }
 4066                 if (!utf8ok) {
 4067                     for (i = 0; i < optlen; i++) {
 4068                         const char *sep;
 4069                         switch (optcode) {
 4070                         case DNS_OPT_COOKIE:
 4071                             sep = "";
 4072                             break;
 4073                         default:
 4074                             sep = " ";
 4075                             break;
 4076                         }
 4077                         snprintf(buf, sizeof(buf),
 4078                              "%02x%s", optdata[i],
 4079                              sep);
 4080                         ADD_STRING(target, buf);
 4081                     }
 4082                 }
 4083 
 4084                 isc_buffer_forward(&optbuf, optlen);
 4085 
 4086                 if (optcode == DNS_OPT_COOKIE) {
 4087                     /*
 4088                      * Valid server cookie?
 4089                      */
 4090                     if (msg->cc_ok && optlen >= 16)
 4091                         ADD_STRING(target, " (good)");
 4092                     /*
 4093                      * Server cookie is not valid but
 4094                      * we had our cookie echoed back.
 4095                      */
 4096                     if (msg->cc_ok && optlen < 16)
 4097                         ADD_STRING(target, " (echoed)");
 4098                     /*
 4099                      * We didn't get our cookie echoed
 4100                      * back.
 4101                      */
 4102                     if (msg->cc_bad)
 4103                         ADD_STRING(target, " (bad)");
 4104                     ADD_STRING(target, "\n");
 4105                     continue;
 4106                 }
 4107 
 4108                 if (optcode == DNS_OPT_CLIENT_SUBNET) {
 4109                     ADD_STRING(target, "\n");
 4110                     continue;
 4111                 }
 4112 
 4113                 /*
 4114                  * For non-COOKIE options, add a printable
 4115                  * version.
 4116                  */
 4117                 if (optcode != DNS_OPT_EDE) {
 4118                     ADD_STRING(target, "(\"");
 4119                 } else {
 4120                     ADD_STRING(target, "(");
 4121                 }
 4122                 if (isc_buffer_availablelength(target) < optlen)
 4123                     return (ISC_R_NOSPACE);
 4124                 for (i = 0; i < optlen; i++) {
 4125                     if (isprint(optdata[i]) ||
 4126                         (utf8ok && optdata[i] > 127)) {
 4127                         isc_buffer_putmem(
 4128                             target, &optdata[i], 1);
 4129                     } else {
 4130                         isc_buffer_putstr(target, ".");
 4131                     }
 4132                 }
 4133                 if (optcode != DNS_OPT_EDE) {
 4134                     ADD_STRING(target, "\")");
 4135                 } else {
 4136                     ADD_STRING(target, ")");
 4137                 }
 4138             }
 4139             ADD_STRING(target, "\n");
 4140         }
 4141         return (ISC_R_SUCCESS);
 4142     case DNS_PSEUDOSECTION_TSIG:
 4143         ps = dns_message_gettsig(msg, &name);
 4144         if (ps == NULL)
 4145             return (ISC_R_SUCCESS);
 4146         INDENT(style);
 4147         if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
 4148             ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
 4149         result = dns_master_rdatasettotext(name, ps, style, target);
 4150         if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
 4151             (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
 4152             ADD_STRING(target, "\n");
 4153         return (result);
 4154     case DNS_PSEUDOSECTION_SIG0:
 4155         ps = dns_message_getsig0(msg, &name);
 4156         if (ps == NULL)
 4157             return (ISC_R_SUCCESS);
 4158         INDENT(style);
 4159         if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
 4160             ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
 4161         result = dns_master_rdatasettotext(name, ps, style, target);
 4162         if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
 4163             (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
 4164             ADD_STRING(target, "\n");
 4165         return (result);
 4166     }
 4167     result = ISC_R_UNEXPECTED;
 4168  cleanup:
 4169     return (result);
 4170 }
 4171 
 4172 isc_result_t
 4173 dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
 4174            dns_messagetextflag_t flags, isc_buffer_t *target)
 4175 {
 4176     char buf[sizeof("1234567890")];
 4177     isc_result_t result;
 4178 
 4179     REQUIRE(DNS_MESSAGE_VALID(msg));
 4180     REQUIRE(target != NULL);
 4181 
 4182     if (((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) &&
 4183          (dns_master_styleflags(style) & DNS_STYLEFLAG_YAML))
 4184     {
 4185         INDENT(style);
 4186         ADD_STRING(target, "opcode: ");
 4187         ADD_STRING(target, opcodetext[msg->opcode]);
 4188         ADD_STRING(target, "\n");
 4189         INDENT(style);
 4190         ADD_STRING(target, "status: ");
 4191         result = dns_rcode_totext(msg->rcode, target);
 4192         if (result != ISC_R_SUCCESS)
 4193             return (result);
 4194         ADD_STRING(target, "\n");
 4195         INDENT(style);
 4196         ADD_STRING(target, "id: ");
 4197         snprintf(buf, sizeof(buf), "%6u", msg->id);
 4198         ADD_STRING(target, buf);
 4199         ADD_STRING(target, "\n");
 4200         INDENT(style);
 4201         ADD_STRING(target, "flags:");
 4202         if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
 4203             ADD_STRING(target, " qr");
 4204         if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
 4205             ADD_STRING(target, " aa");
 4206         if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
 4207             ADD_STRING(target, " tc");
 4208         if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
 4209             ADD_STRING(target, " rd");
 4210         if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
 4211             ADD_STRING(target, " ra");
 4212         if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
 4213             ADD_STRING(target, " ad");
 4214         if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
 4215             ADD_STRING(target, " cd");
 4216         ADD_STRING(target, "\n");
 4217         /*
 4218          * The final unnamed flag must be zero.
 4219          */
 4220         if ((msg->flags & 0x0040U) != 0) {
 4221             INDENT(style);
 4222             ADD_STRING(target, "MBZ: 0x4");
 4223             ADD_STRING(target, "\n");
 4224         }
 4225         if (msg->opcode != dns_opcode_update) {
 4226             INDENT(style);
 4227             ADD_STRING(target, "QUESTION: ");
 4228         } else {
 4229             ADD_STRING(target, "ZONE: ");
 4230         }
 4231         snprintf(buf, sizeof(buf), "%1u",
 4232              msg->counts[DNS_SECTION_QUESTION]);
 4233         ADD_STRING(target, buf);
 4234         ADD_STRING(target, "\n");
 4235         if (msg->opcode != dns_opcode_update) {
 4236             INDENT(style);
 4237             ADD_STRING(target, "ANSWER: ");
 4238         } else {
 4239             INDENT(style);
 4240             ADD_STRING(target, "PREREQ: ");
 4241         }
 4242         snprintf(buf, sizeof(buf), "%1u",
 4243              msg->counts[DNS_SECTION_ANSWER]);
 4244         ADD_STRING(target, buf);
 4245         ADD_STRING(target, "\n");
 4246         if (msg->opcode != dns_opcode_update) {
 4247             INDENT(style);
 4248             ADD_STRING(target, "AUTHORITY: ");
 4249         } else {
 4250             INDENT(style);
 4251             ADD_STRING(target, "UPDATE: ");
 4252         }
 4253         snprintf(buf, sizeof(buf), "%1u",
 4254             msg->counts[DNS_SECTION_AUTHORITY]);
 4255         ADD_STRING(target, buf);
 4256         ADD_STRING(target, "\n");
 4257         INDENT(style);
 4258         ADD_STRING(target, "ADDITIONAL: ");
 4259         snprintf(buf, sizeof(buf), "%1u",
 4260             msg->counts[DNS_SECTION_ADDITIONAL]);
 4261         ADD_STRING(target, buf);
 4262         ADD_STRING(target, "\n");
 4263     } else if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
 4264         INDENT(style);
 4265         ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
 4266         ADD_STRING(target, opcodetext[msg->opcode]);
 4267         ADD_STRING(target, ", status: ");
 4268         result = dns_rcode_totext(msg->rcode, target);
 4269         if (result != ISC_R_SUCCESS)
 4270             return (result);
 4271         ADD_STRING(target, ", id: ");
 4272         snprintf(buf, sizeof(buf), "%6u", msg->id);
 4273         ADD_STRING(target, buf);
 4274         ADD_STRING(target, "\n");
 4275         INDENT(style);
 4276         ADD_STRING(target, ";; flags:");
 4277         if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
 4278             ADD_STRING(target, " qr");
 4279         if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
 4280             ADD_STRING(target, " aa");
 4281         if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
 4282             ADD_STRING(target, " tc");
 4283         if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
 4284             ADD_STRING(target, " rd");
 4285         if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
 4286             ADD_STRING(target, " ra");
 4287         if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
 4288             ADD_STRING(target, " ad");
 4289         if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
 4290             ADD_STRING(target, " cd");
 4291         /*
 4292          * The final unnamed flag must be zero.
 4293          */
 4294         if ((msg->flags & 0x0040U) != 0) {
 4295             INDENT(style);
 4296             ADD_STRING(target, "; MBZ: 0x4");
 4297         }
 4298         if (msg->opcode != dns_opcode_update) {
 4299             INDENT(style);
 4300             ADD_STRING(target, "; QUESTION: ");
 4301         } else {
 4302             INDENT(style);
 4303             ADD_STRING(target, "; ZONE: ");
 4304         }
 4305         snprintf(buf, sizeof(buf), "%1u",
 4306              msg->counts[DNS_SECTION_QUESTION]);
 4307         ADD_STRING(target, buf);
 4308         if (msg->opcode != dns_opcode_update) {
 4309             ADD_STRING(target, ", ANSWER: ");
 4310         } else {
 4311             ADD_STRING(target, ", PREREQ: ");
 4312         }
 4313         snprintf(buf, sizeof(buf), "%1u",
 4314              msg->counts[DNS_SECTION_ANSWER]);
 4315         ADD_STRING(target, buf);
 4316         if (msg->opcode != dns_opcode_update) {
 4317             ADD_STRING(target, ", AUTHORITY: ");
 4318         } else {
 4319             ADD_STRING(target, ", UPDATE: ");
 4320         }
 4321         snprintf(buf, sizeof(buf), "%1u",
 4322             msg->counts[DNS_SECTION_AUTHORITY]);
 4323         ADD_STRING(target, buf);
 4324         ADD_STRING(target, ", ADDITIONAL: ");
 4325         snprintf(buf, sizeof(buf), "%1u",
 4326             msg->counts[DNS_SECTION_ADDITIONAL]);
 4327         ADD_STRING(target, buf);
 4328         ADD_STRING(target, "\n");
 4329     }
 4330     result = dns_message_pseudosectiontotext(msg,
 4331                          DNS_PSEUDOSECTION_OPT,
 4332                          style, flags, target);
 4333     if (result != ISC_R_SUCCESS)
 4334         return (result);
 4335 
 4336     result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
 4337                        style, flags, target);
 4338     if (result != ISC_R_SUCCESS)
 4339         return (result);
 4340     result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
 4341                        style, flags, target);
 4342     if (result != ISC_R_SUCCESS)
 4343         return (result);
 4344     result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
 4345                        style, flags, target);
 4346     if (result != ISC_R_SUCCESS)
 4347         return (result);
 4348     result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
 4349                        style, flags, target);
 4350     if (result != ISC_R_SUCCESS)
 4351         return (result);
 4352 
 4353     result = dns_message_pseudosectiontotext(msg,
 4354                          DNS_PSEUDOSECTION_TSIG,
 4355                          style, flags, target);
 4356     if (result != ISC_R_SUCCESS)
 4357         return (result);
 4358 
 4359     result = dns_message_pseudosectiontotext(msg,
 4360                          DNS_PSEUDOSECTION_SIG0,
 4361                          style, flags, target);
 4362     if (result != ISC_R_SUCCESS)
 4363         return (result);
 4364 
 4365  cleanup:
 4366     return (result);
 4367 }
 4368 
 4369 isc_region_t *
 4370 dns_message_getrawmessage(dns_message_t *msg) {
 4371     REQUIRE(DNS_MESSAGE_VALID(msg));
 4372     return (&msg->saved);
 4373 }
 4374 
 4375 void
 4376 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
 4377              const void *order_arg)
 4378 {
 4379     REQUIRE(DNS_MESSAGE_VALID(msg));
 4380     msg->order = order;
 4381     msg->order_arg = order_arg;
 4382 }
 4383 
 4384 void
 4385 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
 4386     REQUIRE(DNS_MESSAGE_VALID(msg));
 4387     msg->timeadjust = timeadjust;
 4388 }
 4389 
 4390 int
 4391 dns_message_gettimeadjust(dns_message_t *msg) {
 4392     REQUIRE(DNS_MESSAGE_VALID(msg));
 4393     return (msg->timeadjust);
 4394 }
 4395 
 4396 isc_result_t
 4397 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
 4398 
 4399     REQUIRE(opcode < 16);
 4400 
 4401     if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
 4402         return (ISC_R_NOSPACE);
 4403     isc_buffer_putstr(target, opcodetext[opcode]);
 4404     return (ISC_R_SUCCESS);
 4405 }
 4406 
 4407 void
 4408 dns_message_logpacket(dns_message_t *message, const char *description,
 4409               isc_logcategory_t *category, isc_logmodule_t *module,
 4410               int level, isc_mem_t *mctx)
 4411 {
 4412     logfmtpacket(message, description, NULL, category, module,
 4413              &dns_master_style_debug, level, mctx);
 4414 }
 4415 
 4416 void
 4417 dns_message_logpacket2(dns_message_t *message,
 4418                const char *description, isc_sockaddr_t *address,
 4419                isc_logcategory_t *category, isc_logmodule_t *module,
 4420                int level, isc_mem_t *mctx)
 4421 {
 4422     REQUIRE(address != NULL);
 4423 
 4424     logfmtpacket(message, description, address, category, module,
 4425              &dns_master_style_debug, level, mctx);
 4426 }
 4427 
 4428 void
 4429 dns_message_logfmtpacket(dns_message_t *message, const char *description,
 4430              isc_logcategory_t *category, isc_logmodule_t *module,
 4431              const dns_master_style_t *style, int level,
 4432              isc_mem_t *mctx)
 4433 {
 4434     logfmtpacket(message, description, NULL, category, module, style,
 4435              level, mctx);
 4436 }
 4437 
 4438 void
 4439 dns_message_logfmtpacket2(dns_message_t *message,
 4440               const char *description, isc_sockaddr_t *address,
 4441               isc_logcategory_t *category, isc_logmodule_t *module,
 4442               const dns_master_style_t *style, int level,
 4443               isc_mem_t *mctx)
 4444 {
 4445     REQUIRE(address != NULL);
 4446 
 4447     logfmtpacket(message, description, address, category, module, style,
 4448              level, mctx);
 4449 }
 4450 
 4451 static void
 4452 logfmtpacket(dns_message_t *message, const char *description,
 4453          isc_sockaddr_t *address, isc_logcategory_t *category,
 4454          isc_logmodule_t *module, const dns_master_style_t *style,
 4455          int level, isc_mem_t *mctx)
 4456 {
 4457     char addrbuf[ISC_SOCKADDR_FORMATSIZE] = { 0 };
 4458     const char *newline = "\n";
 4459     const char *space = " ";
 4460     isc_buffer_t buffer;
 4461     char *buf = NULL;
 4462     int len = 1024;
 4463     isc_result_t result;
 4464 
 4465     if (! isc_log_wouldlog(dns_lctx, level))
 4466         return;
 4467 
 4468     /*
 4469      * Note that these are multiline debug messages.  We want a newline
 4470      * to appear in the log after each message.
 4471      */
 4472 
 4473     if (address != NULL)
 4474         isc_sockaddr_format(address, addrbuf, sizeof(addrbuf));
 4475     else
 4476         newline = space = "";
 4477 
 4478     do {
 4479         buf = isc_mem_get(mctx, len);
 4480         if (buf == NULL)
 4481             break;
 4482         isc_buffer_init(&buffer, buf, len);
 4483         result = dns_message_totext(message, style, 0, &buffer);
 4484         if (result == ISC_R_NOSPACE) {
 4485             isc_mem_put(mctx, buf, len);
 4486             len += 1024;
 4487         } else if (result == ISC_R_SUCCESS)
 4488             isc_log_write(dns_lctx, category, module, level,
 4489                       "%s%s%s%s%.*s", description, space,
 4490                       addrbuf, newline,
 4491                       (int)isc_buffer_usedlength(&buffer),
 4492                       buf);
 4493     } while (result == ISC_R_NOSPACE);
 4494 
 4495     if (buf != NULL)
 4496         isc_mem_put(mctx, buf, len);
 4497 }
 4498 
 4499 isc_result_t
 4500 dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp,
 4501              unsigned int version, uint16_t udpsize,
 4502              unsigned int flags, dns_ednsopt_t *ednsopts, size_t count)
 4503 {
 4504     dns_rdataset_t *rdataset = NULL;
 4505     dns_rdatalist_t *rdatalist = NULL;
 4506     dns_rdata_t *rdata = NULL;
 4507     isc_result_t result;
 4508     unsigned int len = 0, i;
 4509 
 4510     REQUIRE(DNS_MESSAGE_VALID(message));
 4511     REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
 4512 
 4513     result = dns_message_gettemprdatalist(message, &rdatalist);
 4514     if (result != ISC_R_SUCCESS)
 4515         return (result);
 4516     result = dns_message_gettemprdata(message, &rdata);
 4517     if (result != ISC_R_SUCCESS)
 4518         goto cleanup;
 4519     result = dns_message_gettemprdataset(message, &rdataset);
 4520     if (result != ISC_R_SUCCESS)
 4521         goto cleanup;
 4522 
 4523     rdatalist->type = dns_rdatatype_opt;
 4524 
 4525     /*
 4526      * Set Maximum UDP buffer size.
 4527      */
 4528     rdatalist->rdclass = udpsize;
 4529 
 4530     /*
 4531      * Set EXTENDED-RCODE and Z to 0.
 4532      */
 4533     rdatalist->ttl = (version << 16);
 4534     rdatalist->ttl |= (flags & 0xffff);
 4535 
 4536     /*
 4537      * Set EDNS options if applicable
 4538      */
 4539     if (count != 0U) {
 4540         isc_buffer_t *buf = NULL;
 4541         for (i = 0; i < count; i++)
 4542             len += ednsopts[i].length + 4;
 4543 
 4544         if (len > 0xffffU) {
 4545             result = ISC_R_NOSPACE;
 4546             goto cleanup;
 4547         }
 4548 
 4549         result = isc_buffer_allocate(message->mctx, &buf, len);
 4550         if (result != ISC_R_SUCCESS)
 4551             goto cleanup;
 4552 
 4553         for (i = 0; i < count; i++)  {
 4554             isc_buffer_putuint16(buf, ednsopts[i].code);
 4555             isc_buffer_putuint16(buf, ednsopts[i].length);
 4556             if (ednsopts[i].length != 0) {
 4557                 isc_buffer_putmem(buf, ednsopts[i].value,
 4558                           ednsopts[i].length);
 4559             }
 4560         }
 4561         rdata->data = isc_buffer_base(buf);
 4562         rdata->length = len;
 4563         dns_message_takebuffer(message, &buf);
 4564     } else {
 4565         rdata->data = NULL;
 4566         rdata->length = 0;
 4567     }
 4568 
 4569     rdata->rdclass = rdatalist->rdclass;
 4570     rdata->type = rdatalist->type;
 4571     rdata->flags = 0;
 4572 
 4573     ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
 4574     result = dns_rdatalist_tordataset(rdatalist, rdataset);
 4575     RUNTIME_CHECK(result == ISC_R_SUCCESS);
 4576 
 4577     *rdatasetp = rdataset;
 4578     return (ISC_R_SUCCESS);
 4579 
 4580  cleanup:
 4581     if (rdata != NULL)
 4582         dns_message_puttemprdata(message, &rdata);
 4583     if (rdataset != NULL)
 4584         dns_message_puttemprdataset(message, &rdataset);
 4585     if (rdatalist != NULL)
 4586         dns_message_puttemprdatalist(message, &rdatalist);
 4587     return (result);
 4588 }
 4589 
 4590 void
 4591 dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass) {
 4592 
 4593     REQUIRE(DNS_MESSAGE_VALID(msg));
 4594     REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
 4595     REQUIRE(msg->state == DNS_SECTION_ANY);
 4596     REQUIRE(msg->rdclass_set == 0);
 4597 
 4598     msg->rdclass = rdclass;
 4599     msg->rdclass_set = 1;
 4600 }