dnstap.c revision 574176a88d7fc412312e11a274d74cd2f122a0f4
/*
* Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/*
* Copyright (c) 2013-2014, Farsight Security, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*! \file */
#include <config.h>
#ifndef HAVE_DNSTAP
#endif /* HAVE_DNSTAP */
#include <stdlib.h>
#include <isc/sockaddr.h>
#include <dns/rdataset.h>
#include <dns/dnstap.pb-c.h>
#include <protobuf-c/protobuf-c.h>
#define DNSTAP_CONTENT_TYPE "protobuf:dnstap.Dnstap"
#define DNSTAP_INITIAL_BUF_SIZE 256
struct dns_dtmsg {
void *buf;
};
struct dns_dthandle {
struct fstrm_reader *reader;
};
struct dns_dtenv {
unsigned int magic;
struct fstrm_iothr *iothr;
struct fstrm_iothr_options *fopt;
char *path;
};
#define CHECK(x) do { \
result = (x); \
if (result != ISC_R_SUCCESS) \
goto cleanup; \
} while (0)
static isc_mutex_t dt_mutex;
static isc_thread_key_t dt_key;
/*
* Change under task exclusive.
*/
static unsigned int generation;
static void
mutex_init(void) {
}
static void
}
static isc_result_t
dt_init(void) {
if (result != ISC_R_SUCCESS)
return (result);
if (dt_initialized)
return (ISC_R_SUCCESS);
if (!dt_initialized) {
int ret;
if (result != ISC_R_SUCCESS)
goto unlock;
if (ret == 0)
else
}
return (result);
}
{
"opening dnstap destination '%s'", path);
generation++;
sizeof(DNSTAP_CONTENT_TYPE) - 1);
if (res != fstrm_res_success)
if (mode == dns_dtmode_file) {
}
} else if (mode == dns_dtmode_unix) {
}
} else
"unable to initialize dnstap I/O thread");
}
if (result != ISC_R_SUCCESS) {
}
}
return (result);
}
/*
* Check that we can create a new fw object.
*/
return (ISC_R_NOMEMORY);
sizeof(DNSTAP_CONTENT_TYPE) - 1);
if (res != fstrm_res_success)
}
}
} else
/*
* We are committed here.
*/
"%s dnstap destination '%s'",
generation++;
/*
* Create a temporary isc_logfile_t structure so we can
* take advantage of the logfile rolling facility.
*/
file.maximum_size = 0;
}
"unable to initialize dnstap I/O thread");
}
return (result);
}
static isc_result_t
unsigned char *p = NULL;
if (p == NULL)
return (ISC_R_NOMEMORY);
}
r->length = 0;
}
if (p != NULL) {
r->base = p;
}
return (ISC_R_SUCCESS);
}
}
}
static struct fstrm_iothr_queue *
struct ioq {
unsigned int generation;
struct fstrm_iothr_queue *ioq;
} *ioq;
return (NULL);
if (result != ISC_R_SUCCESS)
return (NULL);
if (result != ISC_R_SUCCESS)
return (NULL);
}
return (NULL);
return (NULL);
}
if (result != ISC_R_SUCCESS) {
return (NULL);
}
}
}
void
}
return (ISC_R_NOTFOUND);
return (ISC_R_SUCCESS);
}
static void
"closing dnstap");
generation++;
}
}
}
void
unsigned int refs;
if (refs == 0)
}
static isc_result_t
/* Need to use malloc() here because protobuf uses free() */
return (ISC_R_NOMEMORY);
return (ISC_R_FAILURE);
return (ISC_R_SUCCESS);
}
static void
struct fstrm_iothr_queue *ioq;
return;
return;
}
if (res != fstrm_res_success) {
} else {
}
}
static void
}
}
}
static Dnstap__Message__Type
switch (msgtype) {
case DNS_DTTYPE_SQ:
return (DNSTAP__MESSAGE__TYPE__STUB_QUERY);
case DNS_DTTYPE_SR:
return (DNSTAP__MESSAGE__TYPE__STUB_RESPONSE);
case DNS_DTTYPE_CQ:
return (DNSTAP__MESSAGE__TYPE__CLIENT_QUERY);
case DNS_DTTYPE_CR:
return (DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE);
case DNS_DTTYPE_AQ:
return (DNSTAP__MESSAGE__TYPE__AUTH_QUERY);
case DNS_DTTYPE_AR:
return (DNSTAP__MESSAGE__TYPE__AUTH_RESPONSE);
case DNS_DTTYPE_RQ:
return (DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY);
case DNS_DTTYPE_RR:
return (DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE);
case DNS_DTTYPE_FQ:
return (DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY);
case DNS_DTTYPE_FR:
case DNS_DTTYPE_TQ:
return (DNSTAP__MESSAGE__TYPE__TOOL_QUERY);
case DNS_DTTYPE_TR:
return (DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE);
default:
INSIST(0);
}
}
static void
*has = 1;
}
static void
{
return;
} else {
}
if (tcp)
else
*has_addr = 1;
*has_port = 1;
}
void
{
isc_time_t now, *t;
return;
return;
t = &now;
switch (msgtype) {
case DNS_DTTYPE_AR:
case DNS_DTTYPE_CR:
case DNS_DTTYPE_RR:
case DNS_DTTYPE_FR:
case DNS_DTTYPE_SR:
case DNS_DTTYPE_TR:
t = rtime;
/* Types RR and FR get both query and response times */
break;
/* FALLTHROUGH */
case DNS_DTTYPE_AQ:
case DNS_DTTYPE_CQ:
case DNS_DTTYPE_FQ:
case DNS_DTTYPE_RQ:
case DNS_DTTYPE_SQ:
case DNS_DTTYPE_TQ:
t = qtime;
break;
default:
"invalid dnstap message type %d", msgtype);
return;
}
switch (msgtype) {
case DNS_DTTYPE_AR:
case DNS_DTTYPE_RQ:
case DNS_DTTYPE_RR:
case DNS_DTTYPE_FQ:
case DNS_DTTYPE_FR:
}
break;
default:
break;
}
}
}
}
void
dns_dt_shutdown() {
}
static isc_result_t
if (result != ISC_R_SUCCESS)
return (ISC_R_NOSPACE);
isc_buffer_putstr(*b, str);
return (ISC_R_SUCCESS);
}
static isc_result_t
char buf[64];
return (ISC_R_FAILURE);
return (ISC_R_FAILURE);
} else
return (ISC_R_BADADDRESSFORM);
}
static isc_boolean_t
dnstap_file(struct fstrm_reader *r) {
size_t n = 0;
if (res != fstrm_res_success)
return (ISC_FALSE);
if (res != fstrm_res_success)
return (ISC_FALSE);
if (n > 0) {
if (res != fstrm_res_success)
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_TRUE);
}
return (ISC_FALSE);
}
{
switch(mode) {
case dns_dtmode_file:
if (res != fstrm_res_success)
break;
case dns_dtmode_unix:
return (ISC_R_NOTIMPLEMENTED);
default:
INSIST(0);
}
}
return (result);
}
const isc_uint8_t *data;
switch (res) {
case fstrm_res_success:
return (ISC_R_FAILURE);
return (ISC_R_SUCCESS);
case fstrm_res_stop:
return (ISC_R_NOMORE);
default:
return (ISC_R_FAILURE);
}
}
void
}
}
Dnstap__Message *m;
dns_dtdata_t *d = NULL;
isc_buffer_t b;
d = isc_mem_get(mctx, sizeof(*d));
if (d == NULL)
return (ISC_R_NOMEMORY);
memset(d, 0, sizeof(*d));
/* Message type */
switch (m->type) {
d->type = DNS_DTTYPE_AQ;
break;
d->type = DNS_DTTYPE_AR;
break;
d->type = DNS_DTTYPE_CQ;
break;
d->type = DNS_DTTYPE_CR;
break;
d->type = DNS_DTTYPE_FQ;
break;
d->type = DNS_DTTYPE_FR;
break;
d->type = DNS_DTTYPE_RQ;
break;
d->type = DNS_DTTYPE_RR;
break;
d->type = DNS_DTTYPE_SQ;
break;
d->type = DNS_DTTYPE_SR;
break;
d->type = DNS_DTTYPE_TQ;
break;
d->type = DNS_DTTYPE_TR;
break;
default:
}
/* Query? */
if ((d->type & DNS_DTTYPE_QUERY) != 0)
else
/* Parse DNS message */
if (d->query && m->has_query_message) {
} else if (!d->query && m->has_response_message) {
}
if (result != ISC_R_SUCCESS) {
if (result != DNS_R_RECOVERABLE)
dns_message_destroy(&d->msg);
}
/* Timestamp */
if (d->query) {
if (m->has_query_time_sec && m->has_query_time_nsec)
m->query_time_nsec);
} else {
if (m->has_response_time_sec && m->has_response_time_nsec)
m->response_time_nsec);
}
/* Peer address */
if (m->has_query_address) {
}
if (m->has_query_port) {
d->qport = m->query_port;
}
if (m->has_response_address) {
}
if (m->has_response_port) {
d->rport = m->response_port;
}
/* Socket protocol */
if (m->has_socket_protocol) {
const ProtobufCEnumValue *type =
m->socket_protocol);
else
}
/* Query tuple */
sizeof(d->typebuf));
sizeof(d->classbuf));
}
*destp = d;
if (result != ISC_R_SUCCESS)
dns_dtdata_free(&d);
return (result);
}
char buf[100];
/* Timestamp */
if (buf[0] == '\0')
else {
}
/* Type mnemonic */
switch (d->type) {
case DNS_DTTYPE_AQ:
break;
case DNS_DTTYPE_AR:
break;
case DNS_DTTYPE_CQ:
break;
case DNS_DTTYPE_CR:
break;
case DNS_DTTYPE_FQ:
break;
case DNS_DTTYPE_FR:
break;
case DNS_DTTYPE_RQ:
break;
case DNS_DTTYPE_RR:
break;
case DNS_DTTYPE_SQ:
break;
case DNS_DTTYPE_SR:
break;
case DNS_DTTYPE_TQ:
break;
case DNS_DTTYPE_TR:
break;
default:
return (DNS_R_BADDNSTAP);
}
/* Query and response addresses */
} else {
}
if ((d->type & DNS_DTTYPE_QUERY) != 0) {
} else {
}
} else {
}
/* Protocol */
if (d->tcp)
else
/* Message size */
} else
/* Query tuple */
if (d->namebuf[0] == '\0')
else {
}
if (d->classbuf[0] == '\0')
else {
}
if (d->typebuf[0] == '\0')
else
isc_buffer_putuint8(*dest, 0);
return (result);
}
void
dns_dtdata_t *d;
d = *dp;
dns_message_destroy(&d->msg);
isc_mem_putanddetach(&d->mctx, d, sizeof(*d));
}