"Fossies" - the Fresh Open Source Software Archive

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


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

    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 /*
   13  * Copyright (c) 2013-2014, Farsight Security, Inc.
   14  * All rights reserved.
   15  *
   16  * Redistribution and use in source and binary forms, with or without
   17  * modification, are permitted provided that the following conditions
   18  * are met:
   19  *
   20  * 1. Redistributions of source code must retain the above copyright
   21  * notice, this list of conditions and the following disclaimer.
   22  *
   23  * 2. Redistributions in binary form must reproduce the above copyright
   24  * notice, this list of conditions and the following disclaimer in the
   25  * documentation and/or other materials provided with the distribution.
   26  *
   27  * 3. Neither the name of the copyright holder nor the names of its
   28  * contributors may be used to endorse or promote products derived from
   29  * this software without specific prior written permission.
   30  *
   31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   33  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   34  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
   35  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   36  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   37  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   38  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   39  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   40  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   41  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   42  */
   43 
   44 /*! \file */
   45 
   46 #include <config.h>
   47 
   48 #ifndef HAVE_DNSTAP
   49 #error DNSTAP not configured.
   50 #endif /* HAVE_DNSTAP */
   51 
   52 #include <inttypes.h>
   53 #include <stdbool.h>
   54 #include <stdlib.h>
   55 
   56 #include <isc/buffer.h>
   57 #include <isc/file.h>
   58 #include <isc/mem.h>
   59 #include <isc/once.h>
   60 #include <isc/print.h>
   61 #include <isc/sockaddr.h>
   62 #include <isc/thread.h>
   63 #include <isc/time.h>
   64 #include <isc/types.h>
   65 #include <isc/util.h>
   66 
   67 #include <dns/dnstap.h>
   68 #include <dns/log.h>
   69 #include <dns/message.h>
   70 #include <dns/name.h>
   71 #include <dns/rdataset.h>
   72 #include <dns/result.h>
   73 #include <dns/stats.h>
   74 #include <dns/types.h>
   75 #include <dns/view.h>
   76 
   77 #include <protobuf-c/protobuf-c.h>
   78 #include "dnstap.pb-c.h"
   79 
   80 #define DTENV_MAGIC         ISC_MAGIC('D', 't', 'n', 'v')
   81 #define VALID_DTENV(env)        ISC_MAGIC_VALID(env, DTENV_MAGIC)
   82 
   83 #define DNSTAP_CONTENT_TYPE "protobuf:dnstap.Dnstap"
   84 #define DNSTAP_INITIAL_BUF_SIZE 256
   85 
   86 struct dns_dtmsg {
   87     void *buf;
   88     size_t len;
   89     Dnstap__Dnstap d;
   90     Dnstap__Message m;
   91 };
   92 
   93 struct dns_dthandle {
   94     dns_dtmode_t mode;
   95     struct fstrm_reader *reader;
   96     isc_mem_t *mctx;
   97 };
   98 
   99 struct dns_dtenv {
  100     unsigned int magic;
  101     isc_refcount_t refcount;
  102 
  103     isc_mem_t *mctx;
  104 
  105     struct fstrm_iothr *iothr;
  106     struct fstrm_iothr_options *fopt;
  107 
  108     isc_region_t identity;
  109     isc_region_t version;
  110     char *path;
  111     dns_dtmode_t mode;
  112     isc_stats_t *stats;
  113 };
  114 
  115 #define CHECK(x) do { \
  116     result = (x); \
  117     if (result != ISC_R_SUCCESS) \
  118         goto cleanup; \
  119     } while (0)
  120 
  121 static isc_mutex_t dt_mutex;
  122 static bool dt_initialized = false;
  123 static isc_thread_key_t dt_key;
  124 static isc_once_t mutex_once = ISC_ONCE_INIT;
  125 static isc_mem_t *dt_mctx = NULL;
  126 
  127 /*
  128  * Change under task exclusive.
  129  */
  130 static unsigned int generation;
  131 
  132 static void
  133 mutex_init(void) {
  134     RUNTIME_CHECK(isc_mutex_init(&dt_mutex) == ISC_R_SUCCESS);
  135 }
  136 
  137 static void
  138 dtfree(void *arg) {
  139     free(arg);
  140     isc_thread_key_setspecific(dt_key, NULL);
  141 }
  142 
  143 static isc_result_t
  144 dt_init(void) {
  145     isc_result_t result;
  146 
  147     result = isc_once_do(&mutex_once, mutex_init);
  148     if (result != ISC_R_SUCCESS)
  149         return (result);
  150 
  151     if (dt_initialized)
  152         return (ISC_R_SUCCESS);
  153 
  154     LOCK(&dt_mutex);
  155     if (!dt_initialized) {
  156         int ret;
  157 
  158         if (dt_mctx == NULL)
  159             result = isc_mem_create2(0, 0, &dt_mctx, 0);
  160         if (result != ISC_R_SUCCESS)
  161             goto unlock;
  162         isc_mem_setname(dt_mctx, "dt", NULL);
  163         isc_mem_setdestroycheck(dt_mctx, false);
  164 
  165         ret = isc_thread_key_create(&dt_key, dtfree);
  166         if (ret == 0)
  167             dt_initialized = true;
  168         else
  169             result = ISC_R_FAILURE;
  170     }
  171 unlock:
  172     UNLOCK(&dt_mutex);
  173 
  174     return (result);
  175 }
  176 
  177 isc_result_t
  178 dns_dt_create(isc_mem_t *mctx, dns_dtmode_t mode, const char *path,
  179           struct fstrm_iothr_options **foptp, dns_dtenv_t **envp)
  180 {
  181     isc_result_t result = ISC_R_SUCCESS;
  182     fstrm_res res;
  183     struct fstrm_unix_writer_options *fuwopt = NULL;
  184     struct fstrm_file_options *ffwopt = NULL;
  185     struct fstrm_writer_options *fwopt = NULL;
  186     struct fstrm_writer *fw = NULL;
  187     dns_dtenv_t *env = NULL;
  188 
  189     REQUIRE(path != NULL);
  190     REQUIRE(envp != NULL && *envp == NULL);
  191     REQUIRE(foptp!= NULL && *foptp != NULL);
  192 
  193     isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP,
  194               DNS_LOGMODULE_DNSTAP, ISC_LOG_INFO,
  195               "opening dnstap destination '%s'", path);
  196 
  197     generation++;
  198 
  199     env = isc_mem_get(mctx, sizeof(dns_dtenv_t));
  200     if (env == NULL)
  201         CHECK(ISC_R_NOMEMORY);
  202 
  203     memset(env, 0, sizeof(dns_dtenv_t));
  204 
  205     CHECK(isc_refcount_init(&env->refcount, 1));
  206     CHECK(isc_stats_create(mctx, &env->stats, dns_dnstapcounter_max));
  207     env->path = isc_mem_strdup(mctx, path);
  208     if (env->path == NULL)
  209         CHECK(ISC_R_NOMEMORY);
  210 
  211     fwopt = fstrm_writer_options_init();
  212     if (fwopt == NULL)
  213         CHECK(ISC_R_NOMEMORY);
  214 
  215     res = fstrm_writer_options_add_content_type(fwopt,
  216                         DNSTAP_CONTENT_TYPE,
  217                         sizeof(DNSTAP_CONTENT_TYPE) - 1);
  218     if (res != fstrm_res_success)
  219         CHECK(ISC_R_FAILURE);
  220 
  221     if (mode == dns_dtmode_file) {
  222         ffwopt = fstrm_file_options_init();
  223         if (ffwopt != NULL) {
  224             fstrm_file_options_set_file_path(ffwopt, env->path);
  225             fw = fstrm_file_writer_init(ffwopt, fwopt);
  226         }
  227     } else if (mode == dns_dtmode_unix) {
  228         fuwopt = fstrm_unix_writer_options_init();
  229         if (fuwopt != NULL) {
  230             fstrm_unix_writer_options_set_socket_path(fuwopt,
  231                                   env->path);
  232             fw = fstrm_unix_writer_init(fuwopt, fwopt);
  233         }
  234     } else
  235         CHECK(ISC_R_FAILURE);
  236 
  237     if (fw == NULL)
  238         CHECK(ISC_R_FAILURE);
  239 
  240     env->iothr = fstrm_iothr_init(*foptp, &fw);
  241     if (env->iothr == NULL) {
  242         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP,
  243                   DNS_LOGMODULE_DNSTAP, ISC_LOG_WARNING,
  244                   "unable to initialize dnstap I/O thread");
  245         fstrm_writer_destroy(&fw);
  246         CHECK(ISC_R_FAILURE);
  247     }
  248     env->mode = mode;
  249     env->fopt = *foptp;
  250     *foptp = NULL;
  251 
  252     isc_mem_attach(mctx, &env->mctx);
  253 
  254     env->magic = DTENV_MAGIC;
  255     *envp = env;
  256 
  257  cleanup:
  258     if (ffwopt != NULL)
  259         fstrm_file_options_destroy(&ffwopt);
  260 
  261     if (fuwopt != NULL)
  262         fstrm_unix_writer_options_destroy(&fuwopt);
  263 
  264     if (fwopt != NULL)
  265         fstrm_writer_options_destroy(&fwopt);
  266 
  267     if (result != ISC_R_SUCCESS) {
  268         if (env != NULL) {
  269             if (env->mctx != NULL)
  270                 isc_mem_detach(&env->mctx);
  271             if (env->path != NULL)
  272                 isc_mem_free(mctx, env->path);
  273             if (env->stats != NULL)
  274                 isc_stats_detach(&env->stats);
  275             isc_mem_put(mctx, env, sizeof(dns_dtenv_t));
  276         }
  277     }
  278 
  279     return (result);
  280 }
  281 
  282 isc_result_t
  283 dns_dt_reopen(dns_dtenv_t *env, int roll) {
  284     isc_result_t result = ISC_R_SUCCESS;
  285     fstrm_res res;
  286     isc_logfile_t file;
  287     struct fstrm_unix_writer_options *fuwopt = NULL;
  288     struct fstrm_file_options *ffwopt = NULL;
  289     struct fstrm_writer_options *fwopt = NULL;
  290     struct fstrm_writer *fw = NULL;
  291 
  292     REQUIRE(VALID_DTENV(env));
  293 
  294     /*
  295      * Check that we can create a new fw object.
  296      */
  297     fwopt = fstrm_writer_options_init();
  298     if (fwopt == NULL)
  299         return (ISC_R_NOMEMORY);
  300 
  301     res = fstrm_writer_options_add_content_type(fwopt,
  302                         DNSTAP_CONTENT_TYPE,
  303                         sizeof(DNSTAP_CONTENT_TYPE) - 1);
  304     if (res != fstrm_res_success)
  305         CHECK(ISC_R_FAILURE);
  306 
  307     if (env->mode == dns_dtmode_file) {
  308         ffwopt = fstrm_file_options_init();
  309         if (ffwopt != NULL) {
  310             fstrm_file_options_set_file_path(ffwopt, env->path);
  311             fw = fstrm_file_writer_init(ffwopt, fwopt);
  312         }
  313     } else if (env->mode == dns_dtmode_unix) {
  314         fuwopt = fstrm_unix_writer_options_init();
  315         if (fuwopt != NULL) {
  316             fstrm_unix_writer_options_set_socket_path(fuwopt,
  317                                   env->path);
  318             fw = fstrm_unix_writer_init(fuwopt, fwopt);
  319         }
  320     } else
  321         CHECK(ISC_R_NOTIMPLEMENTED);
  322 
  323     if (fw == NULL)
  324         CHECK(ISC_R_FAILURE);
  325 
  326     /*
  327      * We are committed here.
  328      */
  329     isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP,
  330               DNS_LOGMODULE_DNSTAP, ISC_LOG_INFO,
  331               "%s dnstap destination '%s'",
  332               (roll < 0) ? "reopening" : "rolling",
  333               env->path);
  334 
  335     generation++;
  336 
  337     if (env->iothr != NULL)
  338         fstrm_iothr_destroy(&env->iothr);
  339 
  340     if (env->mode == dns_dtmode_file && roll >= 0) {
  341         /*
  342          * Create a temporary isc_logfile_t structure so we can
  343          * take advantage of the logfile rolling facility.
  344          */
  345         char *filename = isc_mem_strdup(env->mctx, env->path);
  346         file.name = filename;
  347         file.stream = NULL;
  348         file.versions = roll != 0 ? roll : ISC_LOG_ROLLINFINITE;
  349         file.maximum_size = 0;
  350         file.maximum_reached = false;
  351         result = isc_logfile_roll(&file);
  352         isc_mem_free(env->mctx, filename);
  353         CHECK(result);
  354     }
  355 
  356     env->iothr = fstrm_iothr_init(env->fopt, &fw);
  357     if (env->iothr == NULL) {
  358         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP,
  359                   DNS_LOGMODULE_DNSTAP, ISC_LOG_WARNING,
  360                   "unable to initialize dnstap I/O thread");
  361         CHECK(ISC_R_FAILURE);
  362     }
  363 
  364  cleanup:
  365     if (ffwopt != NULL)
  366         fstrm_file_options_destroy(&ffwopt);
  367 
  368     if (fw != NULL)
  369         fstrm_writer_destroy(&fw);
  370 
  371     if (fwopt != NULL)
  372         fstrm_writer_options_destroy(&fwopt);
  373 
  374     if (fuwopt != NULL)
  375         fstrm_unix_writer_options_destroy(&fuwopt);
  376 
  377     return (result);
  378 }
  379 
  380 static isc_result_t
  381 toregion(dns_dtenv_t *env, isc_region_t *r, const char *str) {
  382     unsigned char *p = NULL;
  383 
  384     REQUIRE(r != NULL);
  385 
  386     if (str != NULL) {
  387         p = (unsigned char *) isc_mem_strdup(env->mctx, str);
  388         if (p == NULL)
  389             return (ISC_R_NOMEMORY);
  390     }
  391 
  392     if (r->base != NULL) {
  393         isc_mem_free(env->mctx, r->base);
  394         r->length = 0;
  395     }
  396 
  397     if (p != NULL) {
  398         r->base = p;
  399         r->length = strlen((char *) p);
  400     }
  401 
  402     return (ISC_R_SUCCESS);
  403 }
  404 
  405 isc_result_t
  406 dns_dt_setidentity(dns_dtenv_t *env, const char *identity) {
  407     REQUIRE(VALID_DTENV(env));
  408 
  409     return (toregion(env, &env->identity, identity));
  410 }
  411 
  412 isc_result_t
  413 dns_dt_setversion(dns_dtenv_t *env, const char *version) {
  414     REQUIRE(VALID_DTENV(env));
  415 
  416     return (toregion(env, &env->version, version));
  417 }
  418 
  419 static struct fstrm_iothr_queue *
  420 dt_queue(dns_dtenv_t *env) {
  421     isc_result_t result;
  422     struct ioq {
  423         unsigned int generation;
  424         struct fstrm_iothr_queue *ioq;
  425     } *ioq;
  426 
  427     REQUIRE(VALID_DTENV(env));
  428 
  429     if (env->iothr == NULL)
  430         return (NULL);
  431 
  432     result = dt_init();
  433     if (result != ISC_R_SUCCESS)
  434         return (NULL);
  435 
  436     ioq = (struct ioq *)isc_thread_key_getspecific(dt_key);
  437     if (ioq != NULL && ioq->generation != generation) {
  438         result = isc_thread_key_setspecific(dt_key, NULL);
  439         if (result != ISC_R_SUCCESS)
  440             return (NULL);
  441         free(ioq);
  442         ioq = NULL;
  443     }
  444     if (ioq == NULL) {
  445         ioq = malloc(sizeof(*ioq));
  446         if (ioq == NULL)
  447             return (NULL);
  448         ioq->generation = generation;
  449         ioq->ioq = fstrm_iothr_get_input_queue(env->iothr);
  450         if (ioq->ioq == NULL) {
  451             free(ioq);
  452             return (NULL);
  453         }
  454         result = isc_thread_key_setspecific(dt_key, ioq);
  455         if (result != ISC_R_SUCCESS) {
  456             free(ioq);
  457             return (NULL);
  458         }
  459     }
  460 
  461     return (ioq->ioq);
  462 }
  463 
  464 void
  465 dns_dt_attach(dns_dtenv_t *source, dns_dtenv_t **destp) {
  466     REQUIRE(VALID_DTENV(source));
  467     REQUIRE(destp != NULL && *destp == NULL);
  468 
  469     isc_refcount_increment(&source->refcount, NULL);
  470     *destp = source;
  471 }
  472 
  473 isc_result_t
  474 dns_dt_getstats(dns_dtenv_t *env, isc_stats_t **statsp) {
  475     REQUIRE(VALID_DTENV(env));
  476     REQUIRE(statsp != NULL && *statsp == NULL);
  477 
  478     if (env->stats == NULL)
  479         return (ISC_R_NOTFOUND);
  480     isc_stats_attach(env->stats, statsp);
  481     return (ISC_R_SUCCESS);
  482 }
  483 
  484 static void
  485 destroy(dns_dtenv_t *env) {
  486 
  487     isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP,
  488               DNS_LOGMODULE_DNSTAP, ISC_LOG_INFO,
  489               "closing dnstap");
  490     env->magic = 0;
  491 
  492     generation++;
  493 
  494     if (env->iothr != NULL)
  495         fstrm_iothr_destroy(&env->iothr);
  496     if (env->fopt != NULL)
  497         fstrm_iothr_options_destroy(&env->fopt);
  498 
  499     if (env->identity.base != NULL) {
  500         isc_mem_free(env->mctx, env->identity.base);
  501         env->identity.length = 0;
  502     }
  503     if (env->version.base != NULL) {
  504         isc_mem_free(env->mctx, env->version.base);
  505         env->version.length = 0;
  506     }
  507     if (env->path != NULL)
  508         isc_mem_free(env->mctx, env->path);
  509     if (env->stats != NULL)
  510         isc_stats_detach(&env->stats);
  511 
  512     isc_mem_putanddetach(&env->mctx, env, sizeof(*env));
  513 }
  514 
  515 void
  516 dns_dt_detach(dns_dtenv_t **envp) {
  517     unsigned int refs;
  518     dns_dtenv_t *env;
  519 
  520     REQUIRE(envp != NULL && VALID_DTENV(*envp));
  521 
  522     env = *envp;
  523     *envp = NULL;
  524 
  525     isc_refcount_decrement(&env->refcount, &refs);
  526     if (refs == 0)
  527         destroy(env);
  528 }
  529 
  530 static isc_result_t
  531 pack_dt(const Dnstap__Dnstap *d, void **buf, size_t *sz) {
  532     ProtobufCBufferSimple sbuf;
  533 
  534     REQUIRE(d != NULL);
  535     REQUIRE(sz != NULL);
  536 
  537     memset(&sbuf, 0, sizeof(sbuf));
  538     sbuf.base.append = protobuf_c_buffer_simple_append;
  539     sbuf.len = 0;
  540     sbuf.alloced = DNSTAP_INITIAL_BUF_SIZE;
  541 
  542     /* Need to use malloc() here because protobuf uses free() */
  543     sbuf.data = malloc(sbuf.alloced);
  544     if (sbuf.data == NULL)
  545         return (ISC_R_NOMEMORY);
  546     sbuf.must_free_data = 1;
  547 
  548     *sz = dnstap__dnstap__pack_to_buffer(d, (ProtobufCBuffer *) &sbuf);
  549     if (sbuf.data == NULL)
  550         return (ISC_R_FAILURE);
  551     *buf = sbuf.data;
  552 
  553     return (ISC_R_SUCCESS);
  554 }
  555 
  556 static void
  557 send_dt(dns_dtenv_t *env, void *buf, size_t len) {
  558     struct fstrm_iothr_queue *ioq;
  559     fstrm_res res;
  560 
  561     REQUIRE(env != NULL);
  562 
  563     if (buf == NULL)
  564         return;
  565 
  566     ioq = dt_queue(env);
  567     if (ioq == NULL) {
  568         free(buf);
  569         return;
  570     }
  571 
  572     res = fstrm_iothr_submit(env->iothr, ioq, buf, len,
  573                  fstrm_free_wrapper, NULL);
  574     if (res != fstrm_res_success) {
  575         if (env->stats != NULL)
  576             isc_stats_increment(env->stats,
  577                         dns_dnstapcounter_drop);
  578         free(buf);
  579     } else {
  580         if (env->stats != NULL)
  581             isc_stats_increment(env->stats,
  582                         dns_dnstapcounter_success);
  583     }
  584 }
  585 
  586 static void
  587 init_msg(dns_dtenv_t *env, dns_dtmsg_t *dm, Dnstap__Message__Type mtype) {
  588     memset(dm, 0, sizeof(*dm));
  589     dm->d.base.descriptor = &dnstap__dnstap__descriptor;
  590     dm->m.base.descriptor = &dnstap__message__descriptor;
  591     dm->d.type = DNSTAP__DNSTAP__TYPE__MESSAGE;
  592     dm->d.message = &dm->m;
  593     dm->m.type = mtype;
  594 
  595     if (env->identity.length != 0) {
  596         dm->d.identity.data = env->identity.base;
  597         dm->d.identity.len = env->identity.length;
  598         dm->d.has_identity = true;
  599     }
  600 
  601     if (env->version.length != 0) {
  602         dm->d.version.data = env->version.base;
  603         dm->d.version.len = env->version.length;
  604         dm->d.has_version = true;
  605     }
  606 }
  607 
  608 static Dnstap__Message__Type
  609 dnstap_type(dns_dtmsgtype_t msgtype) {
  610     switch (msgtype) {
  611     case DNS_DTTYPE_SQ:
  612         return (DNSTAP__MESSAGE__TYPE__STUB_QUERY);
  613     case DNS_DTTYPE_SR:
  614         return (DNSTAP__MESSAGE__TYPE__STUB_RESPONSE);
  615     case DNS_DTTYPE_CQ:
  616         return (DNSTAP__MESSAGE__TYPE__CLIENT_QUERY);
  617     case DNS_DTTYPE_CR:
  618         return (DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE);
  619     case DNS_DTTYPE_AQ:
  620         return (DNSTAP__MESSAGE__TYPE__AUTH_QUERY);
  621     case DNS_DTTYPE_AR:
  622         return (DNSTAP__MESSAGE__TYPE__AUTH_RESPONSE);
  623     case DNS_DTTYPE_RQ:
  624         return (DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY);
  625     case DNS_DTTYPE_RR:
  626         return (DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE);
  627     case DNS_DTTYPE_FQ:
  628         return (DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY);
  629     case DNS_DTTYPE_FR:
  630         return (DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE);
  631     case DNS_DTTYPE_TQ:
  632         return (DNSTAP__MESSAGE__TYPE__TOOL_QUERY);
  633     case DNS_DTTYPE_TR:
  634         return (DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE);
  635     default:
  636         INSIST(0);
  637         ISC_UNREACHABLE();
  638     }
  639 }
  640 
  641 static void
  642 cpbuf(isc_buffer_t *buf, ProtobufCBinaryData *p, protobuf_c_boolean *has) {
  643     p->data = isc_buffer_base(buf);
  644     p->len = isc_buffer_usedlength(buf);
  645     *has = 1;
  646 }
  647 
  648 static void
  649 setaddr(dns_dtmsg_t *dm, isc_sockaddr_t *sa, bool tcp,
  650     ProtobufCBinaryData *addr, protobuf_c_boolean *has_addr,
  651     uint32_t *port, protobuf_c_boolean *has_port)
  652 {
  653     int family = isc_sockaddr_pf(sa);
  654 
  655     if (family != AF_INET6 && family != AF_INET)
  656         return;
  657 
  658     if (family == AF_INET6) {
  659         dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET6;
  660         addr->data = sa->type.sin6.sin6_addr.s6_addr;
  661         addr->len = 16;
  662         *port = ntohs(sa->type.sin6.sin6_port);
  663     } else {
  664         dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET;
  665         addr->data = (uint8_t *) &sa->type.sin.sin_addr.s_addr;
  666         addr->len = 4;
  667         *port = ntohs(sa->type.sin.sin_port);
  668     }
  669 
  670     if (tcp)
  671         dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP;
  672     else
  673         dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__UDP;
  674 
  675     dm->m.has_socket_protocol = 1;
  676     dm->m.has_socket_family = 1;
  677     *has_addr = 1;
  678     *has_port = 1;
  679 }
  680 
  681 void
  682 dns_dt_send(dns_view_t *view, dns_dtmsgtype_t msgtype,
  683         isc_sockaddr_t *qaddr, isc_sockaddr_t *raddr,
  684         bool tcp, isc_region_t *zone, isc_time_t *qtime,
  685         isc_time_t *rtime, isc_buffer_t *buf)
  686 {
  687     isc_time_t now, *t;
  688     dns_dtmsg_t dm;
  689 
  690     REQUIRE(DNS_VIEW_VALID(view));
  691 
  692     if ((msgtype & view->dttypes) == 0)
  693         return;
  694 
  695     if (view->dtenv == NULL)
  696         return;
  697 
  698     REQUIRE(VALID_DTENV(view->dtenv));
  699 
  700     TIME_NOW(&now);
  701     t = &now;
  702 
  703     init_msg(view->dtenv, &dm, dnstap_type(msgtype));
  704 
  705     /* Query/response times */
  706     switch (msgtype) {
  707     case DNS_DTTYPE_AR:
  708     case DNS_DTTYPE_CR:
  709     case DNS_DTTYPE_RR:
  710     case DNS_DTTYPE_FR:
  711     case DNS_DTTYPE_SR:
  712     case DNS_DTTYPE_TR:
  713         if (rtime != NULL)
  714             t = rtime;
  715 
  716         dm.m.response_time_sec = isc_time_seconds(t);
  717         dm.m.has_response_time_sec = 1;
  718         dm.m.response_time_nsec = isc_time_nanoseconds(t);
  719         dm.m.has_response_time_nsec = 1;
  720 
  721         cpbuf(buf, &dm.m.response_message, &dm.m.has_response_message);
  722 
  723         /* Types RR and FR get both query and response times */
  724         if (msgtype == DNS_DTTYPE_CR || msgtype == DNS_DTTYPE_AR)
  725             break;
  726 
  727         /* FALLTHROUGH */
  728     case DNS_DTTYPE_AQ:
  729     case DNS_DTTYPE_CQ:
  730     case DNS_DTTYPE_FQ:
  731     case DNS_DTTYPE_RQ:
  732     case DNS_DTTYPE_SQ:
  733     case DNS_DTTYPE_TQ:
  734         if (qtime != NULL)
  735             t = qtime;
  736 
  737         dm.m.query_time_sec = isc_time_seconds(t);
  738         dm.m.has_query_time_sec = 1;
  739         dm.m.query_time_nsec = isc_time_nanoseconds(t);
  740         dm.m.has_query_time_nsec = 1;
  741 
  742         cpbuf(buf, &dm.m.query_message, &dm.m.has_query_message);
  743         break;
  744     default:
  745         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP,
  746                   DNS_LOGMODULE_DNSTAP, ISC_LOG_ERROR,
  747                   "invalid dnstap message type %d", msgtype);
  748         return;
  749     }
  750 
  751     /* Zone/bailiwick */
  752     switch (msgtype) {
  753     case DNS_DTTYPE_AR:
  754     case DNS_DTTYPE_RQ:
  755     case DNS_DTTYPE_RR:
  756     case DNS_DTTYPE_FQ:
  757     case DNS_DTTYPE_FR:
  758         if (zone != NULL && zone->base != NULL && zone->length != 0) {
  759             dm.m.query_zone.data = zone->base;
  760             dm.m.query_zone.len = zone->length;
  761             dm.m.has_query_zone = 1;
  762         }
  763         break;
  764     default:
  765         break;
  766     }
  767 
  768     if (qaddr != NULL) {
  769         setaddr(&dm, qaddr, tcp,
  770             &dm.m.query_address, &dm.m.has_query_address,
  771             &dm.m.query_port, &dm.m.has_query_port);
  772     }
  773     if (raddr != NULL) {
  774         setaddr(&dm, raddr, tcp,
  775             &dm.m.response_address, &dm.m.has_response_address,
  776             &dm.m.response_port, &dm.m.has_response_port);
  777     }
  778 
  779     if (pack_dt(&dm.d, &dm.buf, &dm.len) == ISC_R_SUCCESS)
  780         send_dt(view->dtenv, dm.buf, dm.len);
  781 }
  782 
  783 void
  784 dns_dt_shutdown() {
  785     if (dt_mctx != NULL)
  786         isc_mem_detach(&dt_mctx);
  787 }
  788 
  789 static isc_result_t
  790 putstr(isc_buffer_t **b, const char *str) {
  791     isc_result_t result;
  792 
  793     result = isc_buffer_reserve(b, strlen(str));
  794     if (result != ISC_R_SUCCESS)
  795         return (ISC_R_NOSPACE);
  796 
  797     isc_buffer_putstr(*b, str);
  798     return (ISC_R_SUCCESS);
  799 }
  800 
  801 static isc_result_t
  802 putaddr(isc_buffer_t **b, isc_region_t *ip) {
  803     char buf[64];
  804 
  805     if (ip->length == 4) {
  806         if (!inet_ntop(AF_INET, ip->base, buf, sizeof(buf)))
  807             return (ISC_R_FAILURE);
  808     } else if (ip->length == 16) {
  809         if (!inet_ntop(AF_INET6, ip->base, buf, sizeof(buf)))
  810             return (ISC_R_FAILURE);
  811     } else
  812         return (ISC_R_BADADDRESSFORM);
  813 
  814     return (putstr(b, buf));
  815 }
  816 
  817 static bool
  818 dnstap_file(struct fstrm_reader *r) {
  819     fstrm_res res;
  820     const struct fstrm_control *control = NULL;
  821     const uint8_t *rtype = NULL;
  822     size_t dlen = strlen(DNSTAP_CONTENT_TYPE), rlen = 0;
  823     size_t n = 0;
  824 
  825     res = fstrm_reader_get_control(r, FSTRM_CONTROL_START, &control);
  826     if (res != fstrm_res_success)
  827         return (false);
  828 
  829     res = fstrm_control_get_num_field_content_type(control, &n);
  830     if (res != fstrm_res_success)
  831         return (false);
  832     if (n > 0) {
  833         res = fstrm_control_get_field_content_type(control, 0,
  834                                &rtype, &rlen);
  835         if (res != fstrm_res_success)
  836             return (false);
  837 
  838         if (rlen != dlen)
  839             return (false);
  840 
  841         if (memcmp(DNSTAP_CONTENT_TYPE, rtype, dlen) == 0)
  842             return (true);
  843     }
  844 
  845     return (false);
  846 }
  847 
  848 isc_result_t
  849 dns_dt_open(const char *filename, dns_dtmode_t mode, isc_mem_t *mctx,
  850         dns_dthandle_t **handlep)
  851 {
  852     isc_result_t result;
  853     struct fstrm_file_options *fopt = NULL;
  854     fstrm_res res;
  855     dns_dthandle_t *handle;
  856 
  857     REQUIRE(handlep != NULL && *handlep == NULL);
  858 
  859     handle = isc_mem_get(mctx, sizeof(*handle));
  860     if (handle == NULL)
  861         CHECK(ISC_R_NOMEMORY);
  862 
  863     handle->mode = mode;
  864     handle->mctx = NULL;
  865 
  866     switch(mode) {
  867     case dns_dtmode_file:
  868         fopt = fstrm_file_options_init();
  869         if (fopt == NULL)
  870             CHECK(ISC_R_NOMEMORY);
  871 
  872         fstrm_file_options_set_file_path(fopt, filename);
  873 
  874         handle->reader = fstrm_file_reader_init(fopt, NULL);
  875         if (handle->reader == NULL)
  876             CHECK(ISC_R_NOMEMORY);
  877 
  878         res = fstrm_reader_open(handle->reader);
  879         if (res != fstrm_res_success)
  880             CHECK(ISC_R_FAILURE);
  881 
  882         if (!dnstap_file(handle->reader))
  883             CHECK(DNS_R_BADDNSTAP);
  884         break;
  885     case dns_dtmode_unix:
  886         return (ISC_R_NOTIMPLEMENTED);
  887     default:
  888         INSIST(0);
  889         ISC_UNREACHABLE();
  890     }
  891 
  892     isc_mem_attach(mctx, &handle->mctx);
  893     result = ISC_R_SUCCESS;
  894     *handlep = handle;
  895     handle = NULL;
  896 
  897  cleanup:
  898     if (result != ISC_R_SUCCESS &&
  899         handle != NULL && handle->reader != NULL)
  900     {
  901         fstrm_reader_destroy(&handle->reader);
  902         handle->reader = NULL;
  903     }
  904     if (fopt != NULL)
  905         fstrm_file_options_destroy(&fopt);
  906     if (handle != NULL)
  907         isc_mem_put(mctx, handle, sizeof(*handle));
  908     return (result);
  909 }
  910 
  911 isc_result_t
  912 dns_dt_getframe(dns_dthandle_t *handle, uint8_t **bufp, size_t *sizep) {
  913     const uint8_t *data;
  914     fstrm_res res;
  915 
  916     REQUIRE(handle != NULL);
  917     REQUIRE(bufp != NULL);
  918     REQUIRE(sizep != NULL);
  919 
  920     data = (const uint8_t *) *bufp;
  921 
  922     res = fstrm_reader_read(handle->reader, &data, sizep);
  923     switch (res) {
  924     case fstrm_res_success:
  925         if (data == NULL)
  926             return (ISC_R_FAILURE);
  927         DE_CONST(data, *bufp);
  928         return (ISC_R_SUCCESS);
  929     case fstrm_res_stop:
  930         return (ISC_R_NOMORE);
  931     default:
  932         return (ISC_R_FAILURE);
  933     }
  934 }
  935 
  936 void
  937 dns_dt_close(dns_dthandle_t **handlep) {
  938     dns_dthandle_t *handle;
  939 
  940     REQUIRE(handlep != NULL && *handlep != NULL);
  941 
  942     handle = *handlep;
  943     *handlep = NULL;
  944 
  945     if (handle->reader != NULL) {
  946         fstrm_reader_destroy(&handle->reader);
  947         handle->reader = NULL;
  948     }
  949     isc_mem_putanddetach(&handle->mctx, handle, sizeof(*handle));
  950 }
  951 
  952 isc_result_t
  953 dns_dt_parse(isc_mem_t *mctx, isc_region_t *src, dns_dtdata_t **destp) {
  954     isc_result_t result;
  955     Dnstap__Dnstap *frame;
  956     Dnstap__Message *m;
  957     dns_dtdata_t *d = NULL;
  958     isc_buffer_t b;
  959 
  960     REQUIRE(src != NULL);
  961     REQUIRE(destp != NULL && *destp == NULL);
  962 
  963     d = isc_mem_get(mctx, sizeof(*d));
  964     if (d == NULL)
  965         return (ISC_R_NOMEMORY);
  966 
  967     memset(d, 0, sizeof(*d));
  968     isc_mem_attach(mctx, &d->mctx);
  969 
  970     d->frame = dnstap__dnstap__unpack(NULL, src->length, src->base);
  971     if (d->frame == NULL)
  972         CHECK(ISC_R_NOMEMORY);
  973 
  974     frame = (Dnstap__Dnstap *)d->frame;
  975 
  976     if (frame->type != DNSTAP__DNSTAP__TYPE__MESSAGE)
  977         CHECK(DNS_R_BADDNSTAP);
  978 
  979     m = frame->message;
  980 
  981     /* Message type */
  982     switch (m->type) {
  983     case DNSTAP__MESSAGE__TYPE__AUTH_QUERY:
  984         d->type = DNS_DTTYPE_AQ;
  985         break;
  986     case DNSTAP__MESSAGE__TYPE__AUTH_RESPONSE:
  987         d->type = DNS_DTTYPE_AR;
  988         break;
  989     case DNSTAP__MESSAGE__TYPE__CLIENT_QUERY:
  990         d->type = DNS_DTTYPE_CQ;
  991         break;
  992     case DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE:
  993         d->type = DNS_DTTYPE_CR;
  994         break;
  995     case DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY:
  996         d->type = DNS_DTTYPE_FQ;
  997         break;
  998     case DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE:
  999         d->type = DNS_DTTYPE_FR;
 1000         break;
 1001     case DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY:
 1002         d->type = DNS_DTTYPE_RQ;
 1003         break;
 1004     case DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE:
 1005         d->type = DNS_DTTYPE_RR;
 1006         break;
 1007     case DNSTAP__MESSAGE__TYPE__STUB_QUERY:
 1008         d->type = DNS_DTTYPE_SQ;
 1009         break;
 1010     case DNSTAP__MESSAGE__TYPE__STUB_RESPONSE:
 1011         d->type = DNS_DTTYPE_SR;
 1012         break;
 1013     case DNSTAP__MESSAGE__TYPE__TOOL_QUERY:
 1014         d->type = DNS_DTTYPE_TQ;
 1015         break;
 1016     case DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE:
 1017         d->type = DNS_DTTYPE_TR;
 1018         break;
 1019     default:
 1020         CHECK(DNS_R_BADDNSTAP);
 1021     }
 1022 
 1023     /* Query? */
 1024     if ((d->type & DNS_DTTYPE_QUERY) != 0)
 1025         d->query = true;
 1026     else
 1027         d->query = false;
 1028 
 1029     /* Parse DNS message */
 1030     if (d->query && m->has_query_message) {
 1031         d->msgdata.base = m->query_message.data;
 1032         d->msgdata.length = m->query_message.len;
 1033     } else if (!d->query && m->has_response_message) {
 1034         d->msgdata.base = m->response_message.data;
 1035         d->msgdata.length = m->response_message.len;
 1036     }
 1037 
 1038     isc_buffer_init(&b, d->msgdata.base, d->msgdata.length);
 1039     isc_buffer_add(&b, d->msgdata.length);
 1040     CHECK(dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &d->msg));
 1041     result = dns_message_parse(d->msg, &b, 0);
 1042     if (result != ISC_R_SUCCESS) {
 1043         if (result != DNS_R_RECOVERABLE)
 1044             dns_message_destroy(&d->msg);
 1045         result = ISC_R_SUCCESS;
 1046     }
 1047 
 1048     /* Timestamp */
 1049     if (d->query) {
 1050         if (m->has_query_time_sec && m->has_query_time_nsec)
 1051             isc_time_set(&d->qtime, m->query_time_sec,
 1052                      m->query_time_nsec);
 1053     } else {
 1054         if (m->has_response_time_sec && m->has_response_time_nsec)
 1055             isc_time_set(&d->rtime, m->response_time_sec,
 1056                      m->response_time_nsec);
 1057     }
 1058 
 1059     /* Peer address */
 1060     if (m->has_query_address) {
 1061         d->qaddr.base = m->query_address.data;
 1062         d->qaddr.length = m->query_address.len;
 1063     }
 1064     if (m->has_query_port) {
 1065         d->qport = m->query_port;
 1066     }
 1067 
 1068     if (m->has_response_address) {
 1069         d->raddr.base = m->response_address.data;
 1070         d->raddr.length = m->response_address.len;
 1071     }
 1072     if (m->has_response_port) {
 1073         d->rport = m->response_port;
 1074     }
 1075 
 1076     /* Socket protocol */
 1077     if (m->has_socket_protocol) {
 1078         const ProtobufCEnumValue *type =
 1079             protobuf_c_enum_descriptor_get_value(
 1080                 &dnstap__socket_protocol__descriptor,
 1081                 m->socket_protocol);
 1082         if (type != NULL &&
 1083             type->value == DNSTAP__SOCKET_PROTOCOL__TCP)
 1084             d->tcp = true;
 1085         else
 1086             d->tcp = false;
 1087     }
 1088 
 1089     /* Query tuple */
 1090     if (d->msg != NULL) {
 1091         dns_name_t *name = NULL;
 1092         dns_rdataset_t *rdataset;
 1093 
 1094         CHECK(dns_message_firstname(d->msg, DNS_SECTION_QUESTION));
 1095         dns_message_currentname(d->msg, DNS_SECTION_QUESTION, &name);
 1096         rdataset = ISC_LIST_HEAD(name->list);
 1097 
 1098         dns_name_format(name, d->namebuf, sizeof(d->namebuf));
 1099         dns_rdatatype_format(rdataset->type, d->typebuf,
 1100                      sizeof(d->typebuf));
 1101         dns_rdataclass_format(rdataset->rdclass, d->classbuf,
 1102                       sizeof(d->classbuf));
 1103     }
 1104 
 1105     *destp = d;
 1106 
 1107  cleanup:
 1108     if (result != ISC_R_SUCCESS)
 1109         dns_dtdata_free(&d);
 1110 
 1111     return (result);
 1112 }
 1113 
 1114 isc_result_t
 1115 dns_dt_datatotext(dns_dtdata_t *d, isc_buffer_t **dest) {
 1116     isc_result_t result;
 1117     char buf[100];
 1118 
 1119     REQUIRE(d != NULL);
 1120     REQUIRE(dest != NULL && *dest != NULL);
 1121 
 1122     memset(buf, 0, sizeof(buf));
 1123 
 1124     /* Timestamp */
 1125     if (d->query && !isc_time_isepoch(&d->qtime))
 1126         isc_time_formattimestamp(&d->qtime, buf, sizeof(buf));
 1127     else if (!d->query && !isc_time_isepoch(&d->rtime))
 1128         isc_time_formattimestamp(&d->rtime, buf, sizeof(buf));
 1129 
 1130     if (buf[0] == '\0')
 1131         CHECK(putstr(dest, "???\?-?\?-?? ??:??:??.??? "));
 1132     else {
 1133         CHECK(putstr(dest, buf));
 1134         CHECK(putstr(dest, " "));
 1135     }
 1136 
 1137     /* Type mnemonic */
 1138     switch (d->type) {
 1139     case DNS_DTTYPE_AQ:
 1140         CHECK(putstr(dest, "AQ "));
 1141         break;
 1142     case DNS_DTTYPE_AR:
 1143         CHECK(putstr(dest, "AR "));
 1144         break;
 1145     case DNS_DTTYPE_CQ:
 1146         CHECK(putstr(dest, "CQ "));
 1147         break;
 1148     case DNS_DTTYPE_CR:
 1149         CHECK(putstr(dest, "CR "));
 1150         break;
 1151     case DNS_DTTYPE_FQ:
 1152         CHECK(putstr(dest, "FQ "));
 1153         break;
 1154     case DNS_DTTYPE_FR:
 1155         CHECK(putstr(dest, "FR "));
 1156         break;
 1157     case DNS_DTTYPE_RQ:
 1158         CHECK(putstr(dest, "RQ "));
 1159         break;
 1160     case DNS_DTTYPE_RR:
 1161         CHECK(putstr(dest, "RR "));
 1162         break;
 1163     case DNS_DTTYPE_SQ:
 1164         CHECK(putstr(dest, "SQ "));
 1165         break;
 1166     case DNS_DTTYPE_SR:
 1167         CHECK(putstr(dest, "SR "));
 1168         break;
 1169     case DNS_DTTYPE_TQ:
 1170         CHECK(putstr(dest, "TQ "));
 1171         break;
 1172     case DNS_DTTYPE_TR:
 1173         CHECK(putstr(dest, "TR "));
 1174         break;
 1175     default:
 1176         return (DNS_R_BADDNSTAP);
 1177     }
 1178 
 1179     /* Query and response addresses */
 1180     if (d->qaddr.length != 0) {
 1181         CHECK(putaddr(dest, &d->qaddr));
 1182         snprintf(buf, sizeof(buf), ":%u", d->qport);
 1183         CHECK(putstr(dest, buf));
 1184     } else {
 1185         CHECK(putstr(dest, "?"));
 1186     }
 1187     if ((d->type & DNS_DTTYPE_QUERY) != 0) {
 1188         CHECK(putstr(dest, " -> "));
 1189     } else {
 1190         CHECK(putstr(dest, " <- "));
 1191     }
 1192     if (d->raddr.length != 0) {
 1193         CHECK(putaddr(dest, &d->raddr));
 1194         snprintf(buf, sizeof(buf), ":%u", d->rport);
 1195         CHECK(putstr(dest, buf));
 1196     } else {
 1197         CHECK(putstr(dest, "?"));
 1198     }
 1199 
 1200     CHECK(putstr(dest, " "));
 1201 
 1202     /* Protocol */
 1203     if (d->tcp)
 1204         CHECK(putstr(dest, "TCP "));
 1205     else
 1206         CHECK(putstr(dest, "UDP "));
 1207 
 1208     /* Message size */
 1209     if (d->msgdata.base != NULL) {
 1210         snprintf(buf, sizeof(buf), "%zub ", (size_t) d->msgdata.length);
 1211         CHECK(putstr(dest, buf));
 1212     } else
 1213         CHECK(putstr(dest, "0b "));
 1214 
 1215     /* Query tuple */
 1216     if (d->namebuf[0] == '\0')
 1217         CHECK(putstr(dest, "?/"));
 1218     else {
 1219         CHECK(putstr(dest, d->namebuf));
 1220         CHECK(putstr(dest, "/"));
 1221     }
 1222 
 1223     if (d->classbuf[0] == '\0')
 1224         CHECK(putstr(dest, "?/"));
 1225     else {
 1226         CHECK(putstr(dest, d->classbuf));
 1227         CHECK(putstr(dest, "/"));
 1228     }
 1229 
 1230     if (d->typebuf[0] == '\0')
 1231         CHECK(putstr(dest, "?"));
 1232     else
 1233         CHECK(putstr(dest, d->typebuf));
 1234 
 1235     CHECK(isc_buffer_reserve(dest, 1));
 1236     isc_buffer_putuint8(*dest, 0);
 1237 
 1238  cleanup:
 1239     return (result);
 1240 }
 1241 
 1242 void
 1243 dns_dtdata_free(dns_dtdata_t **dp) {
 1244     dns_dtdata_t *d;
 1245 
 1246     REQUIRE(dp != NULL && *dp != NULL);
 1247 
 1248     d = *dp;
 1249 
 1250     if (d->msg != NULL)
 1251         dns_message_destroy(&d->msg);
 1252     if (d->frame != NULL)
 1253         dnstap__dnstap__free_unpacked(d->frame, NULL);
 1254 
 1255     isc_mem_putanddetach(&d->mctx, d, sizeof(*d));
 1256 
 1257     *dp = NULL;
 1258 }