"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.17.5/lib/dns/message.c" (4 Sep 2020, 118397 Bytes) of package /linux/misc/dns/bind9/9.17.5/bind-9.17.5.tar.xz:


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.17.4_vs_9.17.5.

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