"Fossies" - the Fresh Open Source Software Archive

Member "nsd-4.3.6/dnstap/dnstap.c" (6 Apr 2021, 13059 Bytes) of package /linux/misc/dns/nsd-4.3.6.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 latest Fossies "Diffs" side-by-side code changes report: 4.3.5_vs_4.3.6.

    1 /* dnstap support for NSD */
    2 
    3 /*
    4  * Copyright (c) 2013-2014, Farsight Security, Inc.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  *
   11  * 1. Redistributions of source code must retain the above copyright
   12  * notice, this list of conditions and the following disclaimer.
   13  *
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  * notice, this list of conditions and the following disclaimer in the
   16  * documentation and/or other materials provided with the distribution.
   17  *
   18  * 3. Neither the name of the copyright holder nor the names of its
   19  * contributors may be used to endorse or promote products derived from
   20  * this software without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   25  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
   26  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   29  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   31  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   32  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   33  */
   34 
   35 #include "dnstap/dnstap_config.h"
   36 
   37 #ifdef USE_DNSTAP
   38 
   39 #include "config.h"
   40 #include <string.h>
   41 #include <sys/time.h>
   42 #ifdef HAVE_SYS_STAT_H
   43 #include <sys/stat.h>
   44 #endif
   45 #include <errno.h>
   46 #include <unistd.h>
   47 #include "util.h"
   48 #include "options.h"
   49 
   50 #include <fstrm.h>
   51 #include <protobuf-c/protobuf-c.h>
   52 
   53 #include "dnstap/dnstap.h"
   54 #include "dnstap/dnstap.pb-c.h"
   55 
   56 #define DNSTAP_CONTENT_TYPE     "protobuf:dnstap.Dnstap"
   57 #define DNSTAP_INITIAL_BUF_SIZE     256
   58 
   59 struct dt_msg {
   60     void        *buf;
   61     size_t      len_buf;
   62     Dnstap__Dnstap  d;
   63     Dnstap__Message m;
   64 };
   65 
   66 static int
   67 dt_pack(const Dnstap__Dnstap *d, void **buf, size_t *sz)
   68 {
   69     ProtobufCBufferSimple sbuf;
   70 
   71     memset(&sbuf, 0, sizeof(sbuf));
   72     sbuf.base.append = protobuf_c_buffer_simple_append;
   73     sbuf.len = 0;
   74     sbuf.alloced = DNSTAP_INITIAL_BUF_SIZE;
   75     sbuf.data = malloc(sbuf.alloced);
   76     if (sbuf.data == NULL)
   77         return 0;
   78     sbuf.must_free_data = 1;
   79 
   80     *sz = dnstap__dnstap__pack_to_buffer(d, (ProtobufCBuffer *) &sbuf);
   81     if (sbuf.data == NULL)
   82         return 0;
   83     *buf = sbuf.data;
   84 
   85     return 1;
   86 }
   87 
   88 static void
   89 dt_send(const struct dt_env *env, void *buf, size_t len_buf)
   90 {
   91     fstrm_res res;
   92     if (!buf)
   93         return;
   94     res = fstrm_iothr_submit(env->iothr, env->ioq, buf, len_buf,
   95                  fstrm_free_wrapper, NULL);
   96     if (res != fstrm_res_success)
   97         free(buf);
   98 }
   99 
  100 static void
  101 dt_msg_init(const struct dt_env *env,
  102         struct dt_msg *dm,
  103         Dnstap__Message__Type mtype)
  104 {
  105     memset(dm, 0, sizeof(*dm));
  106     dm->d.base.descriptor = &dnstap__dnstap__descriptor;
  107     dm->m.base.descriptor = &dnstap__message__descriptor;
  108     dm->d.type = DNSTAP__DNSTAP__TYPE__MESSAGE;
  109     dm->d.message = &dm->m;
  110     dm->m.type = mtype;
  111     if (env->identity != NULL) {
  112         dm->d.identity.data = (uint8_t *) env->identity;
  113         dm->d.identity.len = (size_t) env->len_identity;
  114         dm->d.has_identity = 1;
  115     }
  116     if (env->version != NULL) {
  117         dm->d.version.data = (uint8_t *) env->version;
  118         dm->d.version.len = (size_t) env->len_version;
  119         dm->d.has_version = 1;
  120     }
  121 }
  122 
  123 /* check that the socket file can be opened and exists, print error if not */
  124 static void
  125 check_socket_file(const char* socket_path)
  126 {
  127     struct stat statbuf;
  128     memset(&statbuf, 0, sizeof(statbuf));
  129     if(stat(socket_path, &statbuf) < 0) {
  130         log_msg(LOG_WARNING, "could not open dnstap-socket-path: %s, %s",
  131             socket_path, strerror(errno));
  132     }
  133 }
  134 
  135 struct dt_env *
  136 dt_create(const char *socket_path, unsigned num_workers)
  137 {
  138 #ifndef NDEBUG
  139     fstrm_res res;
  140 #endif
  141     struct dt_env *env;
  142     struct fstrm_iothr_options *fopt;
  143     struct fstrm_unix_writer_options *fuwopt;
  144     struct fstrm_writer *fw;
  145     struct fstrm_writer_options *fwopt;
  146 
  147     VERBOSITY(1, (LOG_INFO, "attempting to connect to dnstap socket %s",
  148         socket_path));
  149     assert(socket_path != NULL);
  150     assert(num_workers > 0);
  151     check_socket_file(socket_path);
  152 
  153     env = (struct dt_env *) calloc(1, sizeof(struct dt_env));
  154     if (!env)
  155         return NULL;
  156 
  157     fwopt = fstrm_writer_options_init();
  158 #ifndef NDEBUG
  159     res = 
  160 #else
  161     (void)
  162 #endif
  163         fstrm_writer_options_add_content_type(fwopt,
  164         DNSTAP_CONTENT_TYPE, sizeof(DNSTAP_CONTENT_TYPE) - 1);
  165     assert(res == fstrm_res_success);
  166 
  167     fuwopt = fstrm_unix_writer_options_init();
  168     fstrm_unix_writer_options_set_socket_path(fuwopt, socket_path);
  169 
  170     fw = fstrm_unix_writer_init(fuwopt, fwopt);
  171     assert(fw != NULL);
  172 
  173     fopt = fstrm_iothr_options_init();
  174     fstrm_iothr_options_set_num_input_queues(fopt, num_workers);
  175     env->iothr = fstrm_iothr_init(fopt, &fw);
  176     if (env->iothr == NULL) {
  177         log_msg(LOG_ERR, "dt_create: fstrm_iothr_init() failed");
  178         fstrm_writer_destroy(&fw);
  179         free(env);
  180         env = NULL;
  181     }
  182     fstrm_iothr_options_destroy(&fopt);
  183     fstrm_unix_writer_options_destroy(&fuwopt);
  184     fstrm_writer_options_destroy(&fwopt);
  185 
  186     return env;
  187 }
  188 
  189 static void
  190 dt_apply_identity(struct dt_env *env, struct nsd_options *cfg)
  191 {
  192     char buf[MAXHOSTNAMELEN+1];
  193     if (!cfg->dnstap_send_identity)
  194         return;
  195     free(env->identity);
  196     if (cfg->dnstap_identity == NULL || cfg->dnstap_identity[0] == 0) {
  197         if (gethostname(buf, MAXHOSTNAMELEN) == 0) {
  198             buf[MAXHOSTNAMELEN] = 0;
  199             env->identity = strdup(buf);
  200         } else {
  201             error("dt_apply_identity: gethostname() failed");
  202         }
  203     } else {
  204         env->identity = strdup(cfg->dnstap_identity);
  205     }
  206     if (env->identity == NULL)
  207         error("dt_apply_identity: strdup() failed");
  208     env->len_identity = (unsigned int)strlen(env->identity);
  209     VERBOSITY(1, (LOG_INFO, "dnstap identity field set to \"%s\"",
  210         env->identity));
  211 }
  212 
  213 static void
  214 dt_apply_version(struct dt_env *env, struct nsd_options *cfg)
  215 {
  216     if (!cfg->dnstap_send_version)
  217         return;
  218     free(env->version);
  219     if (cfg->dnstap_version == NULL || cfg->dnstap_version[0] == 0)
  220         env->version = strdup(PACKAGE_STRING);
  221     else
  222         env->version = strdup(cfg->dnstap_version);
  223     if (env->version == NULL)
  224         error("dt_apply_version: strdup() failed");
  225     env->len_version = (unsigned int)strlen(env->version);
  226     VERBOSITY(1, (LOG_INFO, "dnstap version field set to \"%s\"",
  227         env->version));
  228 }
  229 
  230 void
  231 dt_apply_cfg(struct dt_env *env, struct nsd_options *cfg)
  232 {
  233     if (!cfg->dnstap_enable)
  234         return;
  235 
  236     dt_apply_identity(env, cfg);
  237     dt_apply_version(env, cfg);
  238     if ((env->log_auth_query_messages = (unsigned int)
  239          cfg->dnstap_log_auth_query_messages))
  240     {
  241         VERBOSITY(1, (LOG_INFO, "dnstap Message/AUTH_QUERY enabled"));
  242     }
  243     if ((env->log_auth_response_messages = (unsigned int)
  244          cfg->dnstap_log_auth_response_messages))
  245     {
  246         VERBOSITY(1, (LOG_INFO, "dnstap Message/AUTH_RESPONSE enabled"));
  247     }
  248 }
  249 
  250 int
  251 dt_init(struct dt_env *env)
  252 {
  253     env->ioq = fstrm_iothr_get_input_queue(env->iothr);
  254     if (env->ioq == NULL)
  255         return 0;
  256     return 1;
  257 }
  258 
  259 void
  260 dt_delete(struct dt_env *env)
  261 {
  262     if (!env)
  263         return;
  264     VERBOSITY(1, (LOG_INFO, "closing dnstap socket"));
  265     fstrm_iothr_destroy(&env->iothr);
  266     free(env->identity);
  267     free(env->version);
  268     free(env);
  269 }
  270 
  271 static void
  272 dt_fill_timeval(const struct timeval *tv,
  273         uint64_t *time_sec, protobuf_c_boolean *has_time_sec,
  274         uint32_t *time_nsec, protobuf_c_boolean *has_time_nsec)
  275 {
  276 #ifndef S_SPLINT_S
  277     *time_sec = tv->tv_sec;
  278     *time_nsec = tv->tv_usec * 1000;
  279 #endif
  280     *has_time_sec = 1;
  281     *has_time_nsec = 1;
  282 }
  283 
  284 static void
  285 dt_fill_buffer(uint8_t* pkt, size_t pktlen, ProtobufCBinaryData *p, protobuf_c_boolean *has)
  286 {
  287     p->len = pktlen;
  288     p->data = pkt;
  289     *has = 1;
  290 }
  291 
  292 static void
  293 dt_msg_fill_net(struct dt_msg *dm,
  294 #ifdef INET6
  295         struct sockaddr_storage *rs,
  296         struct sockaddr_storage *qs,
  297 #else
  298         struct sockaddr_in *rs,
  299         struct sockaddr_in *qs,
  300 #endif
  301         int is_tcp,
  302         ProtobufCBinaryData *raddr, protobuf_c_boolean *has_raddr,
  303         uint32_t *rport, protobuf_c_boolean *has_rport,
  304         ProtobufCBinaryData *qaddr, protobuf_c_boolean *has_qaddr,
  305         uint32_t *qport, protobuf_c_boolean *has_qport)
  306 
  307 {
  308 #ifdef INET6
  309     assert(qs->ss_family == AF_INET6 || qs->ss_family == AF_INET);
  310     if (qs->ss_family == AF_INET6) {
  311         struct sockaddr_in6 *s = (struct sockaddr_in6 *) qs;
  312 
  313         /* socket_family */
  314         dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET6;
  315         dm->m.has_socket_family = 1;
  316 
  317         /* addr: query_address or response_address */
  318         qaddr->data = s->sin6_addr.s6_addr;
  319         qaddr->len = 16; /* IPv6 */
  320         *has_qaddr = 1;
  321 
  322         /* port: query_port or response_port */
  323         *qport = ntohs(s->sin6_port);
  324         *has_qport = 1;
  325     } else if (qs->ss_family == AF_INET) {
  326 #else
  327     if (qs->sin_family == AF_INET) {
  328 #endif /* INET6 */
  329         struct sockaddr_in *s = (struct sockaddr_in *) qs;
  330 
  331         /* socket_family */
  332         dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET;
  333         dm->m.has_socket_family = 1;
  334 
  335         /* addr: query_address or response_address */
  336         qaddr->data = (uint8_t *) &s->sin_addr.s_addr;
  337         qaddr->len = 4; /* IPv4 */
  338         *has_qaddr = 1;
  339 
  340         /* port: query_port or response_port */
  341         *qport = ntohs(s->sin_port);
  342         *has_qport = 1;
  343     }
  344 
  345 #ifdef INET6
  346         assert(rs->ss_family == AF_INET6 || rs->ss_family == AF_INET);
  347         if (rs->ss_family == AF_INET6) {
  348                 struct sockaddr_in6 *s = (struct sockaddr_in6 *) rs;
  349 
  350                 /* addr: query_address or response_address */
  351                 raddr->data = s->sin6_addr.s6_addr;
  352                 raddr->len = 16; /* IPv6 */
  353                 *has_raddr = 1;
  354 
  355                 /* port: query_port or response_port */
  356                 *rport = ntohs(s->sin6_port);
  357                 *has_rport = 1;
  358         } else if (rs->ss_family == AF_INET) {
  359 #else
  360         if (rs->sin_family == AF_INET) {
  361 #endif /* INET6 */
  362                 struct sockaddr_in *s = (struct sockaddr_in *) rs;
  363 
  364                 /* addr: query_address or response_address */
  365                 raddr->data = (uint8_t *) &s->sin_addr.s_addr;
  366                 raddr->len = 4; /* IPv4 */
  367                 *has_raddr = 1;
  368 
  369                 /* port: query_port or response_port */
  370                 *rport = ntohs(s->sin_port);
  371                 *has_rport = 1;
  372         }
  373 
  374 
  375     if (!is_tcp) {
  376         /* socket_protocol */
  377         dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__UDP;
  378         dm->m.has_socket_protocol = 1;
  379     } else {
  380         /* socket_protocol */
  381         dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP;
  382         dm->m.has_socket_protocol = 1;
  383     }
  384 }
  385 
  386 void
  387 dt_msg_send_auth_query(struct dt_env *env,
  388 #ifdef INET6
  389     struct sockaddr_storage* local_addr,
  390     struct sockaddr_storage* addr,
  391 #else
  392     struct sockaddr_in* local_addr,
  393     struct sockaddr_in* addr,
  394 #endif
  395     int is_tcp, uint8_t* zone, size_t zonelen, uint8_t* pkt, size_t pktlen)
  396 {
  397     struct dt_msg dm;
  398     struct timeval qtime;
  399 
  400     gettimeofday(&qtime, NULL);
  401 
  402     /* type */
  403     dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__AUTH_QUERY);
  404 
  405     if(zone) {
  406         /* query_zone */
  407         dm.m.query_zone.data = zone;
  408         dm.m.query_zone.len = zonelen;
  409         dm.m.has_query_zone = 1;
  410     }
  411 
  412     /* query_time */
  413     dt_fill_timeval(&qtime,
  414             &dm.m.query_time_sec, &dm.m.has_query_time_sec,
  415             &dm.m.query_time_nsec, &dm.m.has_query_time_nsec);
  416 
  417     /* query_message */
  418     dt_fill_buffer(pkt, pktlen, &dm.m.query_message, &dm.m.has_query_message);
  419 
  420     /* socket_family, socket_protocol, query_address, query_port, reponse_address (local_address), response_port (local_port) */
  421     dt_msg_fill_net(&dm, local_addr, addr, is_tcp,
  422             &dm.m.response_address, &dm.m.has_response_address,
  423             &dm.m.response_port, &dm.m.has_response_port,
  424             &dm.m.query_address, &dm.m.has_query_address,
  425             &dm.m.query_port, &dm.m.has_query_port);
  426 
  427 
  428     if (dt_pack(&dm.d, &dm.buf, &dm.len_buf))
  429         dt_send(env, dm.buf, dm.len_buf);
  430 }
  431 
  432 void
  433 dt_msg_send_auth_response(struct dt_env *env,
  434 #ifdef INET6
  435     struct sockaddr_storage* local_addr,
  436     struct sockaddr_storage* addr,
  437 #else
  438     struct sockaddr_in* local_addr,
  439     struct sockaddr_in* addr,
  440 #endif
  441     int is_tcp, uint8_t* zone, size_t zonelen, uint8_t* pkt, size_t pktlen)
  442 {
  443     struct dt_msg dm;
  444     struct timeval rtime;
  445 
  446     gettimeofday(&rtime, NULL);
  447 
  448     /* type */
  449     dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__AUTH_RESPONSE);
  450 
  451     if(zone) {
  452         /* query_zone */
  453         dm.m.query_zone.data = zone;
  454         dm.m.query_zone.len = zonelen;
  455         dm.m.has_query_zone = 1;
  456     }
  457 
  458     /* response_time */
  459     dt_fill_timeval(&rtime,
  460             &dm.m.response_time_sec, &dm.m.has_response_time_sec,
  461             &dm.m.response_time_nsec, &dm.m.has_response_time_nsec);
  462 
  463     /* response_message */
  464     dt_fill_buffer(pkt, pktlen, &dm.m.response_message, &dm.m.has_response_message);
  465 
  466     /* socket_family, socket_protocol, query_address, query_port, response_address (local_address), response_port (local_port)  */
  467     dt_msg_fill_net(&dm, local_addr, addr, is_tcp,
  468             &dm.m.response_address, &dm.m.has_response_address,
  469             &dm.m.response_port, &dm.m.has_response_port,
  470             &dm.m.query_address, &dm.m.has_query_address,
  471             &dm.m.query_port, &dm.m.has_query_port);
  472 
  473     if (dt_pack(&dm.d, &dm.buf, &dm.len_buf))
  474         dt_send(env, dm.buf, dm.len_buf);
  475 }
  476 
  477 #endif /* USE_DNSTAP */