2015-10-02 12:32:42 -07:00
|
|
|
/*
|
2018-02-23 09:53:12 +01:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
2015-10-02 12:32:42 -07:00
|
|
|
*
|
2016-06-27 14:56:38 +10:00
|
|
|
* 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/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
|
|
* information regarding copyright ownership.
|
2015-10-02 12:32:42 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
#error DNSTAP not configured.
|
|
|
|
#endif /* HAVE_DNSTAP */
|
|
|
|
|
2018-03-28 14:19:37 +02:00
|
|
|
#include <inttypes.h>
|
2018-04-17 08:29:14 -07:00
|
|
|
#include <stdbool.h>
|
2016-06-29 11:38:45 +10:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2015-10-02 12:32:42 -07:00
|
|
|
#include <isc/buffer.h>
|
|
|
|
#include <isc/file.h>
|
2017-03-08 23:20:40 -08:00
|
|
|
#include <isc/log.h>
|
2015-10-02 12:32:42 -07:00
|
|
|
#include <isc/mem.h>
|
2018-02-05 21:04:39 +01:00
|
|
|
#include <isc/mutex.h>
|
2015-10-02 12:32:42 -07:00
|
|
|
#include <isc/once.h>
|
2015-10-02 14:38:59 -07:00
|
|
|
#include <isc/print.h>
|
2015-10-02 12:32:42 -07:00
|
|
|
#include <isc/sockaddr.h>
|
2018-02-05 21:22:53 +01:00
|
|
|
#include <isc/task.h>
|
2015-10-02 12:32:42 -07:00
|
|
|
#include <isc/thread.h>
|
|
|
|
#include <isc/time.h>
|
|
|
|
#include <isc/types.h>
|
|
|
|
#include <isc/util.h>
|
|
|
|
|
|
|
|
#include <dns/dnstap.h>
|
2018-02-05 21:04:39 +01:00
|
|
|
#include <dns/events.h>
|
2015-10-02 12:32:42 -07:00
|
|
|
#include <dns/log.h>
|
|
|
|
#include <dns/message.h>
|
2016-08-18 11:16:06 +10:00
|
|
|
#include <dns/name.h>
|
2015-10-02 12:32:42 -07:00
|
|
|
#include <dns/rdataset.h>
|
|
|
|
#include <dns/result.h>
|
2016-08-18 11:16:06 +10:00
|
|
|
#include <dns/stats.h>
|
2016-04-13 10:12:21 -07:00
|
|
|
#include <dns/types.h>
|
2015-10-02 12:32:42 -07:00
|
|
|
#include <dns/view.h>
|
|
|
|
|
|
|
|
#include <dns/dnstap.pb-c.h>
|
|
|
|
#include <protobuf-c/protobuf-c.h>
|
|
|
|
|
|
|
|
#define DTENV_MAGIC ISC_MAGIC('D', 't', 'n', 'v')
|
|
|
|
#define VALID_DTENV(env) ISC_MAGIC_VALID(env, DTENV_MAGIC)
|
|
|
|
|
|
|
|
#define DNSTAP_CONTENT_TYPE "protobuf:dnstap.Dnstap"
|
|
|
|
#define DNSTAP_INITIAL_BUF_SIZE 256
|
|
|
|
|
2016-04-13 10:12:21 -07:00
|
|
|
struct dns_dtmsg {
|
2015-10-02 12:32:42 -07:00
|
|
|
void *buf;
|
|
|
|
size_t len;
|
|
|
|
Dnstap__Dnstap d;
|
|
|
|
Dnstap__Message m;
|
2016-04-13 10:12:21 -07:00
|
|
|
};
|
2015-10-02 12:32:42 -07:00
|
|
|
|
2016-08-25 10:03:22 +10:00
|
|
|
struct dns_dthandle {
|
2016-08-25 23:45:37 +00:00
|
|
|
dns_dtmode_t mode;
|
|
|
|
struct fstrm_reader *reader;
|
2016-08-25 10:03:22 +10:00
|
|
|
isc_mem_t *mctx;
|
|
|
|
};
|
|
|
|
|
2016-06-24 09:37:04 +10:00
|
|
|
struct dns_dtenv {
|
|
|
|
unsigned int magic;
|
|
|
|
isc_refcount_t refcount;
|
|
|
|
|
|
|
|
isc_mem_t *mctx;
|
|
|
|
|
|
|
|
struct fstrm_iothr *iothr;
|
2016-08-25 10:03:22 +10:00
|
|
|
struct fstrm_iothr_options *fopt;
|
2016-06-24 09:37:04 +10:00
|
|
|
|
2018-02-05 21:19:44 +01:00
|
|
|
isc_task_t *reopen_task;
|
2018-02-05 21:04:39 +01:00
|
|
|
isc_mutex_t reopen_lock; /* locks 'reopen_queued' */
|
2018-04-17 08:29:14 -07:00
|
|
|
bool reopen_queued;
|
2018-02-05 21:19:44 +01:00
|
|
|
|
2016-06-24 09:37:04 +10:00
|
|
|
isc_region_t identity;
|
|
|
|
isc_region_t version;
|
|
|
|
char *path;
|
2016-07-13 01:12:47 -07:00
|
|
|
dns_dtmode_t mode;
|
2017-03-08 23:20:40 -08:00
|
|
|
isc_offset_t max_size;
|
|
|
|
int rolls;
|
|
|
|
isc_log_rollsuffix_t suffix;
|
2016-08-18 11:16:06 +10:00
|
|
|
isc_stats_t *stats;
|
2016-06-24 09:37:04 +10:00
|
|
|
};
|
|
|
|
|
2015-10-02 12:32:42 -07:00
|
|
|
#define CHECK(x) do { \
|
|
|
|
result = (x); \
|
|
|
|
if (result != ISC_R_SUCCESS) \
|
|
|
|
goto cleanup; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
static isc_mutex_t dt_mutex;
|
2018-04-17 08:29:14 -07:00
|
|
|
static bool dt_initialized = false;
|
2015-10-02 12:32:42 -07:00
|
|
|
static isc_thread_key_t dt_key;
|
|
|
|
static isc_once_t mutex_once = ISC_ONCE_INIT;
|
|
|
|
static isc_mem_t *dt_mctx = NULL;
|
|
|
|
|
2016-08-25 10:03:22 +10:00
|
|
|
/*
|
|
|
|
* Change under task exclusive.
|
|
|
|
*/
|
2016-08-24 22:06:00 -04:00
|
|
|
static unsigned int generation;
|
2016-08-25 10:03:22 +10:00
|
|
|
|
2015-10-02 12:32:42 -07:00
|
|
|
static void
|
|
|
|
mutex_init(void) {
|
|
|
|
RUNTIME_CHECK(isc_mutex_init(&dt_mutex) == ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dtfree(void *arg) {
|
2016-08-25 10:03:22 +10:00
|
|
|
free(arg);
|
2015-10-02 12:32:42 -07:00
|
|
|
isc_thread_key_setspecific(dt_key, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
dt_init(void) {
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
result = isc_once_do(&mutex_once, mutex_init);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
|
|
|
|
if (dt_initialized)
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
LOCK(&dt_mutex);
|
|
|
|
if (!dt_initialized) {
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (dt_mctx == NULL)
|
|
|
|
result = isc_mem_create2(0, 0, &dt_mctx, 0);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto unlock;
|
|
|
|
isc_mem_setname(dt_mctx, "dt", NULL);
|
2018-04-17 08:29:14 -07:00
|
|
|
isc_mem_setdestroycheck(dt_mctx, false);
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
ret = isc_thread_key_create(&dt_key, dtfree);
|
|
|
|
if (ret == 0)
|
2018-04-17 08:29:14 -07:00
|
|
|
dt_initialized = true;
|
2015-10-02 12:32:42 -07:00
|
|
|
else
|
|
|
|
result = ISC_R_FAILURE;
|
|
|
|
}
|
|
|
|
unlock:
|
|
|
|
UNLOCK(&dt_mutex);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_dt_create(isc_mem_t *mctx, dns_dtmode_t mode, const char *path,
|
2018-04-05 16:27:36 +02:00
|
|
|
struct fstrm_iothr_options **foptp, isc_task_t *reopen_task,
|
|
|
|
dns_dtenv_t **envp)
|
2015-10-02 12:32:42 -07:00
|
|
|
{
|
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
|
|
fstrm_res res;
|
|
|
|
struct fstrm_unix_writer_options *fuwopt = NULL;
|
|
|
|
struct fstrm_file_options *ffwopt = NULL;
|
|
|
|
struct fstrm_writer_options *fwopt = NULL;
|
|
|
|
struct fstrm_writer *fw = NULL;
|
|
|
|
dns_dtenv_t *env = NULL;
|
|
|
|
|
|
|
|
REQUIRE(path != NULL);
|
|
|
|
REQUIRE(envp != NULL && *envp == NULL);
|
2017-03-08 23:20:40 -08:00
|
|
|
REQUIRE(foptp != NULL && *foptp != NULL);
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP,
|
|
|
|
DNS_LOGMODULE_DNSTAP, ISC_LOG_INFO,
|
|
|
|
"opening dnstap destination '%s'", path);
|
|
|
|
|
2016-08-24 22:06:00 -04:00
|
|
|
generation++;
|
2016-08-25 10:03:22 +10:00
|
|
|
|
2015-10-02 12:32:42 -07:00
|
|
|
env = isc_mem_get(mctx, sizeof(dns_dtenv_t));
|
|
|
|
if (env == NULL)
|
|
|
|
CHECK(ISC_R_NOMEMORY);
|
|
|
|
|
|
|
|
memset(env, 0, sizeof(dns_dtenv_t));
|
|
|
|
|
|
|
|
CHECK(isc_refcount_init(&env->refcount, 1));
|
2016-08-18 11:16:06 +10:00
|
|
|
CHECK(isc_stats_create(mctx, &env->stats, dns_dnstapcounter_max));
|
2016-06-24 09:37:04 +10:00
|
|
|
env->path = isc_mem_strdup(mctx, path);
|
|
|
|
if (env->path == NULL)
|
|
|
|
CHECK(ISC_R_NOMEMORY);
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
fwopt = fstrm_writer_options_init();
|
|
|
|
if (fwopt == NULL)
|
|
|
|
CHECK(ISC_R_NOMEMORY);
|
|
|
|
|
|
|
|
res = fstrm_writer_options_add_content_type(fwopt,
|
|
|
|
DNSTAP_CONTENT_TYPE,
|
|
|
|
sizeof(DNSTAP_CONTENT_TYPE) - 1);
|
|
|
|
if (res != fstrm_res_success)
|
|
|
|
CHECK(ISC_R_FAILURE);
|
|
|
|
|
|
|
|
if (mode == dns_dtmode_file) {
|
|
|
|
ffwopt = fstrm_file_options_init();
|
|
|
|
if (ffwopt != NULL) {
|
2016-06-24 09:37:04 +10:00
|
|
|
fstrm_file_options_set_file_path(ffwopt, env->path);
|
2015-10-02 12:32:42 -07:00
|
|
|
fw = fstrm_file_writer_init(ffwopt, fwopt);
|
|
|
|
}
|
|
|
|
} else if (mode == dns_dtmode_unix) {
|
|
|
|
fuwopt = fstrm_unix_writer_options_init();
|
|
|
|
if (fuwopt != NULL) {
|
2016-06-24 09:37:04 +10:00
|
|
|
fstrm_unix_writer_options_set_socket_path(fuwopt,
|
|
|
|
env->path);
|
2015-10-02 12:32:42 -07:00
|
|
|
fw = fstrm_unix_writer_init(fuwopt, fwopt);
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
CHECK(ISC_R_FAILURE);
|
|
|
|
|
|
|
|
if (fw == NULL)
|
|
|
|
CHECK(ISC_R_FAILURE);
|
|
|
|
|
2016-08-25 10:03:22 +10:00
|
|
|
env->iothr = fstrm_iothr_init(*foptp, &fw);
|
2015-10-02 12:32:42 -07:00
|
|
|
if (env->iothr == NULL) {
|
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP,
|
|
|
|
DNS_LOGMODULE_DNSTAP, ISC_LOG_WARNING,
|
|
|
|
"unable to initialize dnstap I/O thread");
|
|
|
|
fstrm_writer_destroy(&fw);
|
|
|
|
CHECK(ISC_R_FAILURE);
|
|
|
|
}
|
2016-07-13 01:12:47 -07:00
|
|
|
env->mode = mode;
|
2017-02-06 16:03:37 -08:00
|
|
|
env->max_size = 0;
|
2017-03-08 23:20:40 -08:00
|
|
|
env->rolls = ISC_LOG_ROLLINFINITE;
|
2016-08-25 10:03:22 +10:00
|
|
|
env->fopt = *foptp;
|
|
|
|
*foptp = NULL;
|
2015-10-02 12:32:42 -07:00
|
|
|
|
2018-02-05 21:19:44 +01:00
|
|
|
env->reopen_task = reopen_task;
|
2018-02-05 21:04:39 +01:00
|
|
|
isc_mutex_init(&env->reopen_lock);
|
2018-04-17 08:29:14 -07:00
|
|
|
env->reopen_queued = false;
|
2018-02-05 21:19:44 +01:00
|
|
|
|
2015-10-02 12:32:42 -07:00
|
|
|
isc_mem_attach(mctx, &env->mctx);
|
|
|
|
|
|
|
|
env->magic = DTENV_MAGIC;
|
|
|
|
*envp = env;
|
|
|
|
|
|
|
|
cleanup:
|
2016-07-13 16:56:11 +10:00
|
|
|
if (ffwopt != NULL)
|
|
|
|
fstrm_file_options_destroy(&ffwopt);
|
|
|
|
|
2015-10-02 12:32:42 -07:00
|
|
|
if (fuwopt != NULL)
|
|
|
|
fstrm_unix_writer_options_destroy(&fuwopt);
|
|
|
|
|
|
|
|
if (fwopt != NULL)
|
|
|
|
fstrm_writer_options_destroy(&fwopt);
|
|
|
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2016-06-23 12:18:03 +10:00
|
|
|
if (env != NULL) {
|
2018-02-05 21:04:39 +01:00
|
|
|
isc_mutex_destroy(&env->reopen_lock);
|
2016-06-23 12:18:03 +10:00
|
|
|
if (env->mctx != NULL)
|
|
|
|
isc_mem_detach(&env->mctx);
|
2016-06-24 09:37:04 +10:00
|
|
|
if (env->path != NULL)
|
|
|
|
isc_mem_free(mctx, env->path);
|
2016-08-18 11:16:06 +10:00
|
|
|
if (env->stats != NULL)
|
|
|
|
isc_stats_detach(&env->stats);
|
2015-10-02 12:32:42 -07:00
|
|
|
isc_mem_put(mctx, env, sizeof(dns_dtenv_t));
|
2016-06-23 12:18:03 +10:00
|
|
|
}
|
2015-10-02 12:32:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2017-02-06 16:03:37 -08:00
|
|
|
isc_result_t
|
2018-03-28 14:19:37 +02:00
|
|
|
dns_dt_setupfile(dns_dtenv_t *env, uint64_t max_size, int rolls,
|
2017-03-08 23:20:40 -08:00
|
|
|
isc_log_rollsuffix_t suffix)
|
|
|
|
{
|
2017-02-06 16:03:37 -08:00
|
|
|
REQUIRE(VALID_DTENV(env));
|
|
|
|
|
2017-03-08 23:20:40 -08:00
|
|
|
/*
|
|
|
|
* If we're using unix domain socket mode, then any
|
|
|
|
* change from the default values is invalid.
|
|
|
|
*/
|
|
|
|
if (env->mode == dns_dtmode_unix) {
|
|
|
|
if (max_size == 0 && rolls == ISC_LOG_ROLLINFINITE &&
|
|
|
|
suffix == isc_log_rollsuffix_increment)
|
|
|
|
{
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
} else {
|
|
|
|
return (ISC_R_INVALIDFILE);
|
|
|
|
}
|
2017-02-06 16:03:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
env->max_size = max_size;
|
|
|
|
env->rolls = rolls;
|
2017-03-08 23:20:40 -08:00
|
|
|
env->suffix = suffix;
|
2017-02-06 16:03:37 -08:00
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2016-06-24 09:37:04 +10:00
|
|
|
isc_result_t
|
2016-07-13 01:12:47 -07:00
|
|
|
dns_dt_reopen(dns_dtenv_t *env, int roll) {
|
2016-08-25 10:03:22 +10:00
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
2016-06-24 09:37:04 +10:00
|
|
|
fstrm_res res;
|
2016-08-25 10:03:22 +10:00
|
|
|
isc_logfile_t file;
|
|
|
|
struct fstrm_unix_writer_options *fuwopt = NULL;
|
|
|
|
struct fstrm_file_options *ffwopt = NULL;
|
|
|
|
struct fstrm_writer_options *fwopt = NULL;
|
|
|
|
struct fstrm_writer *fw = NULL;
|
2016-06-24 09:37:04 +10:00
|
|
|
|
|
|
|
REQUIRE(VALID_DTENV(env));
|
|
|
|
|
2018-02-05 21:22:53 +01:00
|
|
|
/*
|
|
|
|
* Run in task-exclusive mode.
|
|
|
|
*/
|
|
|
|
result = isc_task_beginexclusive(env->reopen_task);
|
|
|
|
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
|
|
|
|
2016-08-25 10:03:22 +10:00
|
|
|
/*
|
|
|
|
* Check that we can create a new fw object.
|
|
|
|
*/
|
|
|
|
fwopt = fstrm_writer_options_init();
|
2017-03-08 23:20:40 -08:00
|
|
|
if (fwopt == NULL) {
|
2018-02-05 21:22:53 +01:00
|
|
|
isc_task_endexclusive(env->reopen_task);
|
2016-08-25 10:03:22 +10:00
|
|
|
return (ISC_R_NOMEMORY);
|
2017-03-08 23:20:40 -08:00
|
|
|
}
|
2016-08-25 10:03:22 +10:00
|
|
|
|
|
|
|
res = fstrm_writer_options_add_content_type(fwopt,
|
|
|
|
DNSTAP_CONTENT_TYPE,
|
|
|
|
sizeof(DNSTAP_CONTENT_TYPE) - 1);
|
2017-03-08 23:20:40 -08:00
|
|
|
if (res != fstrm_res_success) {
|
2016-08-25 10:03:22 +10:00
|
|
|
CHECK(ISC_R_FAILURE);
|
2017-03-08 23:20:40 -08:00
|
|
|
}
|
2016-08-25 10:03:22 +10:00
|
|
|
|
|
|
|
if (env->mode == dns_dtmode_file) {
|
|
|
|
ffwopt = fstrm_file_options_init();
|
|
|
|
if (ffwopt != NULL) {
|
|
|
|
fstrm_file_options_set_file_path(ffwopt, env->path);
|
|
|
|
fw = fstrm_file_writer_init(ffwopt, fwopt);
|
|
|
|
}
|
|
|
|
} else if (env->mode == dns_dtmode_unix) {
|
|
|
|
fuwopt = fstrm_unix_writer_options_init();
|
|
|
|
if (fuwopt != NULL) {
|
|
|
|
fstrm_unix_writer_options_set_socket_path(fuwopt,
|
|
|
|
env->path);
|
|
|
|
fw = fstrm_unix_writer_init(fuwopt, fwopt);
|
|
|
|
}
|
2017-03-08 23:20:40 -08:00
|
|
|
} else {
|
2016-08-25 10:03:22 +10:00
|
|
|
CHECK(ISC_R_NOTIMPLEMENTED);
|
2017-03-08 23:20:40 -08:00
|
|
|
}
|
2016-07-13 01:12:47 -07:00
|
|
|
|
2017-03-08 23:20:40 -08:00
|
|
|
if (fw == NULL) {
|
2016-08-25 10:03:22 +10:00
|
|
|
CHECK(ISC_R_FAILURE);
|
2017-03-08 23:20:40 -08:00
|
|
|
}
|
2016-08-25 10:03:22 +10:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We are committed here.
|
|
|
|
*/
|
2016-06-24 09:37:04 +10:00
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP,
|
|
|
|
DNS_LOGMODULE_DNSTAP, ISC_LOG_INFO,
|
2016-07-13 01:12:47 -07:00
|
|
|
"%s dnstap destination '%s'",
|
|
|
|
(roll < 0) ? "reopening" : "rolling",
|
2016-06-24 09:37:04 +10:00
|
|
|
env->path);
|
2016-08-24 22:06:00 -04:00
|
|
|
|
|
|
|
generation++;
|
2016-08-25 23:45:37 +00:00
|
|
|
|
2017-03-08 23:20:40 -08:00
|
|
|
if (env->iothr != NULL) {
|
2016-08-25 10:03:22 +10:00
|
|
|
fstrm_iothr_destroy(&env->iothr);
|
2017-03-08 23:20:40 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (roll != 0) {
|
|
|
|
roll = env->rolls;
|
|
|
|
}
|
2016-06-24 09:37:04 +10:00
|
|
|
|
2017-03-08 23:20:40 -08:00
|
|
|
if (env->mode == dns_dtmode_file && roll != 0) {
|
2016-07-13 01:12:47 -07:00
|
|
|
/*
|
|
|
|
* Create a temporary isc_logfile_t structure so we can
|
|
|
|
* take advantage of the logfile rolling facility.
|
|
|
|
*/
|
|
|
|
char *filename = isc_mem_strdup(env->mctx, env->path);
|
|
|
|
file.name = filename;
|
|
|
|
file.stream = NULL;
|
2017-03-08 23:20:40 -08:00
|
|
|
file.versions = roll != 0 ? roll : env->rolls;
|
2016-07-13 01:12:47 -07:00
|
|
|
file.maximum_size = 0;
|
2018-04-17 08:29:14 -07:00
|
|
|
file.maximum_reached = false;
|
2017-03-08 23:20:40 -08:00
|
|
|
file.suffix = env->suffix;
|
2016-07-13 01:12:47 -07:00
|
|
|
result = isc_logfile_roll(&file);
|
|
|
|
isc_mem_free(env->mctx, filename);
|
2016-08-25 10:03:22 +10:00
|
|
|
CHECK(result);
|
2016-06-24 09:37:04 +10:00
|
|
|
}
|
|
|
|
|
2016-08-25 10:03:22 +10:00
|
|
|
env->iothr = fstrm_iothr_init(env->fopt, &fw);
|
|
|
|
if (env->iothr == NULL) {
|
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP,
|
|
|
|
DNS_LOGMODULE_DNSTAP, ISC_LOG_WARNING,
|
|
|
|
"unable to initialize dnstap I/O thread");
|
|
|
|
CHECK(ISC_R_FAILURE);
|
|
|
|
}
|
2016-07-13 01:12:47 -07:00
|
|
|
|
2016-08-25 10:03:22 +10:00
|
|
|
cleanup:
|
|
|
|
if (ffwopt != NULL)
|
|
|
|
fstrm_file_options_destroy(&ffwopt);
|
|
|
|
|
|
|
|
if (fw != NULL)
|
|
|
|
fstrm_writer_destroy(&fw);
|
|
|
|
|
|
|
|
if (fwopt != NULL)
|
|
|
|
fstrm_writer_options_destroy(&fwopt);
|
|
|
|
|
|
|
|
if (fuwopt != NULL)
|
|
|
|
fstrm_unix_writer_options_destroy(&fuwopt);
|
|
|
|
|
2018-02-05 21:22:53 +01:00
|
|
|
isc_task_endexclusive(env->reopen_task);
|
|
|
|
|
2016-08-25 10:03:22 +10:00
|
|
|
return (result);
|
2016-06-24 09:37:04 +10:00
|
|
|
}
|
|
|
|
|
2015-10-02 12:32:42 -07:00
|
|
|
static isc_result_t
|
|
|
|
toregion(dns_dtenv_t *env, isc_region_t *r, const char *str) {
|
|
|
|
unsigned char *p = NULL;
|
|
|
|
|
|
|
|
REQUIRE(r != NULL);
|
|
|
|
|
|
|
|
if (str != NULL) {
|
|
|
|
p = (unsigned char *) isc_mem_strdup(env->mctx, str);
|
|
|
|
if (p == NULL)
|
|
|
|
return (ISC_R_NOMEMORY);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r->base != NULL) {
|
|
|
|
isc_mem_free(env->mctx, r->base);
|
|
|
|
r->length = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p != NULL) {
|
|
|
|
r->base = p;
|
|
|
|
r->length = strlen((char *) p);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_dt_setidentity(dns_dtenv_t *env, const char *identity) {
|
|
|
|
REQUIRE(VALID_DTENV(env));
|
|
|
|
|
|
|
|
return (toregion(env, &env->identity, identity));
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_dt_setversion(dns_dtenv_t *env, const char *version) {
|
|
|
|
REQUIRE(VALID_DTENV(env));
|
|
|
|
|
|
|
|
return (toregion(env, &env->version, version));
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct fstrm_iothr_queue *
|
|
|
|
dt_queue(dns_dtenv_t *env) {
|
|
|
|
isc_result_t result;
|
2016-08-25 10:03:22 +10:00
|
|
|
struct ioq {
|
2016-08-24 22:06:00 -04:00
|
|
|
unsigned int generation;
|
2016-08-25 10:03:22 +10:00
|
|
|
struct fstrm_iothr_queue *ioq;
|
|
|
|
} *ioq;
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
REQUIRE(VALID_DTENV(env));
|
|
|
|
|
2016-08-25 10:03:22 +10:00
|
|
|
if (env->iothr == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
2015-10-02 12:32:42 -07:00
|
|
|
result = dt_init();
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (NULL);
|
|
|
|
|
2016-08-25 10:03:22 +10:00
|
|
|
ioq = (struct ioq *)isc_thread_key_getspecific(dt_key);
|
2016-08-24 22:06:00 -04:00
|
|
|
if (ioq != NULL && ioq->generation != generation) {
|
2016-08-25 10:03:22 +10:00
|
|
|
result = isc_thread_key_setspecific(dt_key, NULL);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (NULL);
|
|
|
|
free(ioq);
|
|
|
|
ioq = NULL;
|
|
|
|
}
|
2015-10-02 12:32:42 -07:00
|
|
|
if (ioq == NULL) {
|
2016-08-25 10:03:22 +10:00
|
|
|
ioq = malloc(sizeof(*ioq));
|
|
|
|
if (ioq == NULL)
|
|
|
|
return (NULL);
|
2016-08-24 22:06:00 -04:00
|
|
|
ioq->generation = generation;
|
2016-08-25 10:03:22 +10:00
|
|
|
ioq->ioq = fstrm_iothr_get_input_queue(env->iothr);
|
|
|
|
if (ioq->ioq == NULL) {
|
|
|
|
free(ioq);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
result = isc_thread_key_setspecific(dt_key, ioq);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
free(ioq);
|
|
|
|
return (NULL);
|
2015-10-02 12:32:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-25 10:03:22 +10:00
|
|
|
return (ioq->ioq);
|
2015-10-02 12:32:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_dt_attach(dns_dtenv_t *source, dns_dtenv_t **destp) {
|
|
|
|
REQUIRE(VALID_DTENV(source));
|
|
|
|
REQUIRE(destp != NULL && *destp == NULL);
|
|
|
|
|
|
|
|
isc_refcount_increment(&source->refcount, NULL);
|
|
|
|
*destp = source;
|
|
|
|
}
|
|
|
|
|
2016-08-18 11:16:06 +10:00
|
|
|
isc_result_t
|
|
|
|
dns_dt_getstats(dns_dtenv_t *env, isc_stats_t **statsp) {
|
|
|
|
REQUIRE(VALID_DTENV(env));
|
|
|
|
REQUIRE(statsp != NULL && *statsp == NULL);
|
|
|
|
|
|
|
|
if (env->stats == NULL)
|
|
|
|
return (ISC_R_NOTFOUND);
|
|
|
|
isc_stats_attach(env->stats, statsp);
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2015-10-02 12:32:42 -07:00
|
|
|
static void
|
2016-06-23 12:18:03 +10:00
|
|
|
destroy(dns_dtenv_t *env) {
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP,
|
|
|
|
DNS_LOGMODULE_DNSTAP, ISC_LOG_INFO,
|
|
|
|
"closing dnstap");
|
|
|
|
env->magic = 0;
|
|
|
|
|
2016-08-24 22:06:00 -04:00
|
|
|
generation++;
|
2016-08-25 10:03:22 +10:00
|
|
|
|
|
|
|
if (env->iothr != NULL)
|
|
|
|
fstrm_iothr_destroy(&env->iothr);
|
|
|
|
if (env->fopt != NULL)
|
|
|
|
fstrm_iothr_options_destroy(&env->fopt);
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
if (env->identity.base != NULL) {
|
|
|
|
isc_mem_free(env->mctx, env->identity.base);
|
|
|
|
env->identity.length = 0;
|
|
|
|
}
|
|
|
|
if (env->version.base != NULL) {
|
|
|
|
isc_mem_free(env->mctx, env->version.base);
|
|
|
|
env->version.length = 0;
|
|
|
|
}
|
2016-06-24 09:37:04 +10:00
|
|
|
if (env->path != NULL)
|
|
|
|
isc_mem_free(env->mctx, env->path);
|
2016-08-18 11:16:06 +10:00
|
|
|
if (env->stats != NULL)
|
|
|
|
isc_stats_detach(&env->stats);
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
isc_mem_putanddetach(&env->mctx, env, sizeof(*env));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_dt_detach(dns_dtenv_t **envp) {
|
|
|
|
unsigned int refs;
|
2016-06-23 12:50:47 +10:00
|
|
|
dns_dtenv_t *env;
|
2015-10-02 12:32:42 -07:00
|
|
|
|
2016-06-23 12:18:03 +10:00
|
|
|
REQUIRE(envp != NULL && VALID_DTENV(*envp));
|
2015-10-02 12:32:42 -07:00
|
|
|
|
2016-06-23 12:18:03 +10:00
|
|
|
env = *envp;
|
2015-10-02 12:32:42 -07:00
|
|
|
*envp = NULL;
|
2016-06-23 12:18:03 +10:00
|
|
|
|
|
|
|
isc_refcount_decrement(&env->refcount, &refs);
|
|
|
|
if (refs == 0)
|
|
|
|
destroy(env);
|
2015-10-02 12:32:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
pack_dt(const Dnstap__Dnstap *d, void **buf, size_t *sz) {
|
|
|
|
ProtobufCBufferSimple sbuf;
|
|
|
|
|
|
|
|
REQUIRE(d != NULL);
|
|
|
|
REQUIRE(sz != NULL);
|
|
|
|
|
|
|
|
memset(&sbuf, 0, sizeof(sbuf));
|
|
|
|
sbuf.base.append = protobuf_c_buffer_simple_append;
|
|
|
|
sbuf.len = 0;
|
|
|
|
sbuf.alloced = DNSTAP_INITIAL_BUF_SIZE;
|
|
|
|
|
|
|
|
/* Need to use malloc() here because protobuf uses free() */
|
|
|
|
sbuf.data = malloc(sbuf.alloced);
|
|
|
|
if (sbuf.data == NULL)
|
|
|
|
return (ISC_R_NOMEMORY);
|
|
|
|
sbuf.must_free_data = 1;
|
|
|
|
|
|
|
|
*sz = dnstap__dnstap__pack_to_buffer(d, (ProtobufCBuffer *) &sbuf);
|
|
|
|
if (sbuf.data == NULL)
|
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
*buf = sbuf.data;
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
send_dt(dns_dtenv_t *env, void *buf, size_t len) {
|
|
|
|
struct fstrm_iothr_queue *ioq;
|
|
|
|
fstrm_res res;
|
|
|
|
|
|
|
|
REQUIRE(env != NULL);
|
|
|
|
|
|
|
|
if (buf == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ioq = dt_queue(env);
|
|
|
|
if (ioq == NULL) {
|
|
|
|
free(buf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = fstrm_iothr_submit(env->iothr, ioq, buf, len,
|
|
|
|
fstrm_free_wrapper, NULL);
|
2016-08-18 11:16:06 +10:00
|
|
|
if (res != fstrm_res_success) {
|
|
|
|
if (env->stats != NULL)
|
|
|
|
isc_stats_increment(env->stats,
|
|
|
|
dns_dnstapcounter_drop);
|
2015-10-02 12:32:42 -07:00
|
|
|
free(buf);
|
2016-08-18 11:16:06 +10:00
|
|
|
} else {
|
|
|
|
if (env->stats != NULL)
|
|
|
|
isc_stats_increment(env->stats,
|
|
|
|
dns_dnstapcounter_success);
|
|
|
|
}
|
2015-10-02 12:32:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
init_msg(dns_dtenv_t *env, dns_dtmsg_t *dm, Dnstap__Message__Type mtype) {
|
|
|
|
memset(dm, 0, sizeof(*dm));
|
|
|
|
dm->d.base.descriptor = &dnstap__dnstap__descriptor;
|
|
|
|
dm->m.base.descriptor = &dnstap__message__descriptor;
|
|
|
|
dm->d.type = DNSTAP__DNSTAP__TYPE__MESSAGE;
|
|
|
|
dm->d.message = &dm->m;
|
|
|
|
dm->m.type = mtype;
|
|
|
|
|
|
|
|
if (env->identity.length != 0) {
|
|
|
|
dm->d.identity.data = env->identity.base;
|
|
|
|
dm->d.identity.len = env->identity.length;
|
2018-04-17 08:29:14 -07:00
|
|
|
dm->d.has_identity = true;
|
2015-10-02 12:32:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (env->version.length != 0) {
|
|
|
|
dm->d.version.data = env->version.base;
|
|
|
|
dm->d.version.len = env->version.length;
|
2018-04-17 08:29:14 -07:00
|
|
|
dm->d.has_version = true;
|
2015-10-02 12:32:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static Dnstap__Message__Type
|
|
|
|
dnstap_type(dns_dtmsgtype_t msgtype) {
|
|
|
|
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:
|
|
|
|
return (DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE);
|
|
|
|
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
|
|
|
|
cpbuf(isc_buffer_t *buf, ProtobufCBinaryData *p, protobuf_c_boolean *has) {
|
|
|
|
p->data = isc_buffer_base(buf);
|
|
|
|
p->len = isc_buffer_usedlength(buf);
|
|
|
|
*has = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2018-04-17 08:29:14 -07:00
|
|
|
setaddr(dns_dtmsg_t *dm, isc_sockaddr_t *sa, bool tcp,
|
2015-10-02 12:32:42 -07:00
|
|
|
ProtobufCBinaryData *addr, protobuf_c_boolean *has_addr,
|
2018-03-28 14:19:37 +02:00
|
|
|
uint32_t *port, protobuf_c_boolean *has_port)
|
2015-10-02 12:32:42 -07:00
|
|
|
{
|
|
|
|
int family = isc_sockaddr_pf(sa);
|
|
|
|
|
|
|
|
if (family != AF_INET6 && family != AF_INET)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (family == AF_INET6) {
|
|
|
|
dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET6;
|
|
|
|
addr->data = sa->type.sin6.sin6_addr.s6_addr;
|
|
|
|
addr->len = 16;
|
|
|
|
*port = ntohs(sa->type.sin6.sin6_port);
|
|
|
|
} else {
|
|
|
|
dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET;
|
2018-03-28 14:19:37 +02:00
|
|
|
addr->data = (uint8_t *) &sa->type.sin.sin_addr.s_addr;
|
2015-10-02 12:32:42 -07:00
|
|
|
addr->len = 4;
|
|
|
|
*port = ntohs(sa->type.sin.sin_port);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tcp)
|
|
|
|
dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP;
|
|
|
|
else
|
|
|
|
dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__UDP;
|
|
|
|
|
|
|
|
dm->m.has_socket_protocol = 1;
|
|
|
|
dm->m.has_socket_family = 1;
|
|
|
|
*has_addr = 1;
|
|
|
|
*has_port = 1;
|
|
|
|
}
|
|
|
|
|
2018-02-05 21:04:39 +01:00
|
|
|
/*%
|
|
|
|
* Invoke dns_dt_reopen() and re-allow dnstap output file rolling. This
|
|
|
|
* function is run in the context of the task stored in the 'reopen_task' field
|
|
|
|
* of the dnstap environment structure.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
perform_reopen(isc_task_t *task, isc_event_t *event) {
|
|
|
|
dns_dtenv_t *env;
|
|
|
|
|
|
|
|
REQUIRE(event != NULL);
|
|
|
|
REQUIRE(event->ev_type == DNS_EVENT_FREESTORAGE);
|
|
|
|
|
|
|
|
env = (dns_dtenv_t *)event->ev_arg;
|
|
|
|
|
|
|
|
REQUIRE(VALID_DTENV(env));
|
|
|
|
REQUIRE(task == env->reopen_task);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Roll output file in the context of env->reopen_task.
|
|
|
|
*/
|
|
|
|
dns_dt_reopen(env, env->rolls);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clean up.
|
|
|
|
*/
|
|
|
|
isc_event_free(&event);
|
|
|
|
isc_task_detach(&task);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Re-allow output file rolling.
|
|
|
|
*/
|
|
|
|
LOCK(&env->reopen_lock);
|
2018-04-17 08:29:14 -07:00
|
|
|
env->reopen_queued = false;
|
2018-02-05 21:04:39 +01:00
|
|
|
UNLOCK(&env->reopen_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* Check whether a dnstap output file roll is due and if so, initiate it (the
|
|
|
|
* actual roll happens asynchronously).
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
check_file_size_and_maybe_reopen(dns_dtenv_t *env) {
|
|
|
|
isc_task_t *reopen_task = NULL;
|
|
|
|
isc_event_t *event;
|
|
|
|
struct stat statbuf;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the task from which the output file should be reopened was not
|
|
|
|
* specified, abort.
|
|
|
|
*/
|
|
|
|
if (env->reopen_task == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If an output file roll is not currently queued, check the current
|
|
|
|
* size of the output file to see whether a roll is needed. Return if
|
|
|
|
* it is not.
|
|
|
|
*/
|
|
|
|
LOCK(&env->reopen_lock);
|
|
|
|
if (env->reopen_queued || stat(env->path, &statbuf) < 0 ||
|
|
|
|
statbuf.st_size <= env->max_size)
|
|
|
|
{
|
|
|
|
goto unlock_and_return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We need to roll the output file, but it needs to be done in the
|
|
|
|
* context of env->reopen_task. Allocate and send an event to achieve
|
|
|
|
* that, then disallow output file rolling until the roll we queue is
|
|
|
|
* completed.
|
|
|
|
*/
|
|
|
|
event = isc_event_allocate(env->mctx, NULL, DNS_EVENT_FREESTORAGE,
|
|
|
|
perform_reopen, env, sizeof(*event));
|
|
|
|
if (event == NULL) {
|
|
|
|
goto unlock_and_return;
|
|
|
|
}
|
|
|
|
isc_task_attach(env->reopen_task, &reopen_task);
|
|
|
|
isc_task_send(reopen_task, &event);
|
2018-04-17 08:29:14 -07:00
|
|
|
env->reopen_queued = true;
|
2018-02-05 21:04:39 +01:00
|
|
|
|
|
|
|
unlock_and_return:
|
|
|
|
UNLOCK(&env->reopen_lock);
|
|
|
|
}
|
|
|
|
|
2015-10-02 12:32:42 -07:00
|
|
|
void
|
|
|
|
dns_dt_send(dns_view_t *view, dns_dtmsgtype_t msgtype,
|
2017-02-03 17:05:58 -08:00
|
|
|
isc_sockaddr_t *qaddr, isc_sockaddr_t *raddr,
|
2018-04-17 08:29:14 -07:00
|
|
|
bool tcp, isc_region_t *zone, isc_time_t *qtime,
|
2017-02-03 17:05:58 -08:00
|
|
|
isc_time_t *rtime, isc_buffer_t *buf)
|
2015-10-02 12:32:42 -07:00
|
|
|
{
|
|
|
|
isc_time_t now, *t;
|
|
|
|
dns_dtmsg_t dm;
|
|
|
|
|
|
|
|
REQUIRE(DNS_VIEW_VALID(view));
|
|
|
|
|
|
|
|
if ((msgtype & view->dttypes) == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (view->dtenv == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
REQUIRE(VALID_DTENV(view->dtenv));
|
|
|
|
|
2017-02-06 16:03:37 -08:00
|
|
|
if (view->dtenv->max_size != 0) {
|
2018-02-05 21:04:39 +01:00
|
|
|
check_file_size_and_maybe_reopen(view->dtenv);
|
2017-02-06 16:03:37 -08:00
|
|
|
}
|
|
|
|
|
2015-10-02 12:32:42 -07:00
|
|
|
TIME_NOW(&now);
|
|
|
|
t = &now;
|
|
|
|
|
|
|
|
init_msg(view->dtenv, &dm, dnstap_type(msgtype));
|
|
|
|
|
|
|
|
/* Query/response times */
|
|
|
|
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:
|
|
|
|
if (rtime != NULL)
|
|
|
|
t = rtime;
|
|
|
|
|
|
|
|
dm.m.response_time_sec = isc_time_seconds(t);
|
|
|
|
dm.m.has_response_time_sec = 1;
|
|
|
|
dm.m.response_time_nsec = isc_time_nanoseconds(t);
|
|
|
|
dm.m.has_response_time_nsec = 1;
|
|
|
|
|
|
|
|
cpbuf(buf, &dm.m.response_message, &dm.m.has_response_message);
|
|
|
|
|
|
|
|
/* Types RR and FR get both query and response times */
|
|
|
|
if (msgtype == DNS_DTTYPE_CR || msgtype == DNS_DTTYPE_AR)
|
|
|
|
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:
|
|
|
|
if (qtime != NULL)
|
|
|
|
t = qtime;
|
|
|
|
|
|
|
|
dm.m.query_time_sec = isc_time_seconds(t);
|
|
|
|
dm.m.has_query_time_sec = 1;
|
|
|
|
dm.m.query_time_nsec = isc_time_nanoseconds(t);
|
|
|
|
dm.m.has_query_time_nsec = 1;
|
|
|
|
|
|
|
|
cpbuf(buf, &dm.m.query_message, &dm.m.has_query_message);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP,
|
|
|
|
DNS_LOGMODULE_DNSTAP, ISC_LOG_ERROR,
|
|
|
|
"invalid dnstap message type %d", msgtype);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Zone/bailiwick */
|
|
|
|
switch (msgtype) {
|
|
|
|
case DNS_DTTYPE_AR:
|
|
|
|
case DNS_DTTYPE_RQ:
|
|
|
|
case DNS_DTTYPE_RR:
|
|
|
|
case DNS_DTTYPE_FQ:
|
|
|
|
case DNS_DTTYPE_FR:
|
|
|
|
if (zone != NULL && zone->base != NULL && zone->length != 0) {
|
|
|
|
dm.m.query_zone.data = zone->base;
|
|
|
|
dm.m.query_zone.len = zone->length;
|
|
|
|
dm.m.has_query_zone = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-02-03 17:05:58 -08:00
|
|
|
if (qaddr != NULL) {
|
|
|
|
setaddr(&dm, qaddr, tcp,
|
2015-10-02 12:32:42 -07:00
|
|
|
&dm.m.query_address, &dm.m.has_query_address,
|
|
|
|
&dm.m.query_port, &dm.m.has_query_port);
|
|
|
|
}
|
2017-02-03 17:05:58 -08:00
|
|
|
if (raddr != NULL) {
|
|
|
|
setaddr(&dm, raddr, tcp,
|
|
|
|
&dm.m.response_address, &dm.m.has_response_address,
|
|
|
|
&dm.m.response_port, &dm.m.has_response_port);
|
|
|
|
}
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
if (pack_dt(&dm.d, &dm.buf, &dm.len) == ISC_R_SUCCESS)
|
|
|
|
send_dt(view->dtenv, dm.buf, dm.len);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_dt_shutdown() {
|
|
|
|
if (dt_mctx != NULL)
|
|
|
|
isc_mem_detach(&dt_mctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
putstr(isc_buffer_t **b, const char *str) {
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
result = isc_buffer_reserve(b, strlen(str));
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (ISC_R_NOSPACE);
|
|
|
|
|
|
|
|
isc_buffer_putstr(*b, str);
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
putaddr(isc_buffer_t **b, isc_region_t *ip) {
|
|
|
|
char buf[64];
|
|
|
|
|
|
|
|
if (ip->length == 4) {
|
|
|
|
if (!inet_ntop(AF_INET, ip->base, buf, sizeof(buf)))
|
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
} else if (ip->length == 16) {
|
|
|
|
if (!inet_ntop(AF_INET6, ip->base, buf, sizeof(buf)))
|
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
} else
|
|
|
|
return (ISC_R_BADADDRESSFORM);
|
|
|
|
|
|
|
|
return (putstr(b, buf));
|
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
static bool
|
2015-10-02 12:32:42 -07:00
|
|
|
dnstap_file(struct fstrm_reader *r) {
|
|
|
|
fstrm_res res;
|
|
|
|
const struct fstrm_control *control = NULL;
|
2018-03-28 14:19:37 +02:00
|
|
|
const uint8_t *rtype = NULL;
|
2015-10-02 12:32:42 -07:00
|
|
|
size_t dlen = strlen(DNSTAP_CONTENT_TYPE), rlen = 0;
|
|
|
|
size_t n = 0;
|
|
|
|
|
|
|
|
res = fstrm_reader_get_control(r, FSTRM_CONTROL_START, &control);
|
|
|
|
if (res != fstrm_res_success)
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
res = fstrm_control_get_num_field_content_type(control, &n);
|
|
|
|
if (res != fstrm_res_success)
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2015-10-02 12:32:42 -07:00
|
|
|
if (n > 0) {
|
|
|
|
res = fstrm_control_get_field_content_type(control, 0,
|
|
|
|
&rtype, &rlen);
|
|
|
|
if (res != fstrm_res_success)
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
if (rlen != dlen)
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
if (memcmp(DNSTAP_CONTENT_TYPE, rtype, dlen) == 0)
|
2018-04-17 08:29:14 -07:00
|
|
|
return (true);
|
2015-10-02 12:32:42 -07:00
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2015-10-02 12:32:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2016-08-25 10:03:22 +10:00
|
|
|
dns_dt_open(const char *filename, dns_dtmode_t mode, isc_mem_t *mctx,
|
|
|
|
dns_dthandle_t **handlep)
|
|
|
|
{
|
2015-10-02 12:32:42 -07:00
|
|
|
isc_result_t result;
|
2016-08-25 10:03:22 +10:00
|
|
|
struct fstrm_file_options *fopt = NULL;
|
2015-10-02 12:32:42 -07:00
|
|
|
fstrm_res res;
|
2016-08-25 10:03:22 +10:00
|
|
|
dns_dthandle_t *handle;
|
2015-10-02 12:32:42 -07:00
|
|
|
|
2016-08-25 10:03:22 +10:00
|
|
|
REQUIRE(handlep != NULL && *handlep == NULL);
|
|
|
|
|
|
|
|
handle = isc_mem_get(mctx, sizeof(*handle));
|
|
|
|
if (handle == NULL)
|
|
|
|
CHECK(ISC_R_NOMEMORY);
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
handle->mode = mode;
|
2016-08-25 10:03:22 +10:00
|
|
|
handle->mctx = NULL;
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
switch(mode) {
|
|
|
|
case dns_dtmode_file:
|
|
|
|
fopt = fstrm_file_options_init();
|
|
|
|
if (fopt == NULL)
|
|
|
|
CHECK(ISC_R_NOMEMORY);
|
|
|
|
|
|
|
|
fstrm_file_options_set_file_path(fopt, filename);
|
|
|
|
|
|
|
|
handle->reader = fstrm_file_reader_init(fopt, NULL);
|
|
|
|
if (handle->reader == NULL)
|
|
|
|
CHECK(ISC_R_NOMEMORY);
|
|
|
|
|
|
|
|
res = fstrm_reader_open(handle->reader);
|
|
|
|
if (res != fstrm_res_success)
|
|
|
|
CHECK(ISC_R_FAILURE);
|
|
|
|
|
|
|
|
if (!dnstap_file(handle->reader))
|
|
|
|
CHECK(DNS_R_BADDNSTAP);
|
|
|
|
break;
|
|
|
|
case dns_dtmode_unix:
|
|
|
|
return (ISC_R_NOTIMPLEMENTED);
|
|
|
|
default:
|
|
|
|
INSIST(0);
|
|
|
|
}
|
|
|
|
|
2016-08-25 10:03:22 +10:00
|
|
|
isc_mem_attach(mctx, &handle->mctx);
|
2015-10-02 12:32:42 -07:00
|
|
|
result = ISC_R_SUCCESS;
|
2016-08-25 10:03:22 +10:00
|
|
|
*handlep = handle;
|
|
|
|
handle = NULL;
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (result != ISC_R_SUCCESS && handle->reader != NULL) {
|
|
|
|
fstrm_reader_destroy(&handle->reader);
|
|
|
|
handle->reader = NULL;
|
|
|
|
}
|
|
|
|
if (fopt != NULL)
|
|
|
|
fstrm_file_options_destroy(&fopt);
|
2016-08-25 10:03:22 +10:00
|
|
|
if (handle != NULL)
|
|
|
|
isc_mem_put(mctx, handle, sizeof(*handle));
|
2015-10-02 12:32:42 -07:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2018-03-28 14:19:37 +02:00
|
|
|
dns_dt_getframe(dns_dthandle_t *handle, uint8_t **bufp, size_t *sizep) {
|
|
|
|
const uint8_t *data;
|
2015-10-02 12:32:42 -07:00
|
|
|
fstrm_res res;
|
|
|
|
|
|
|
|
REQUIRE(handle != NULL);
|
|
|
|
REQUIRE(bufp != NULL);
|
|
|
|
REQUIRE(sizep != NULL);
|
|
|
|
|
2018-03-28 14:19:37 +02:00
|
|
|
data = (const uint8_t *) *bufp;
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
res = fstrm_reader_read(handle->reader, &data, sizep);
|
|
|
|
switch (res) {
|
|
|
|
case fstrm_res_success:
|
|
|
|
if (data == NULL)
|
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
DE_CONST(data, *bufp);
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
case fstrm_res_stop:
|
|
|
|
return (ISC_R_NOMORE);
|
|
|
|
default:
|
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-08-25 10:03:22 +10:00
|
|
|
dns_dt_close(dns_dthandle_t **handlep) {
|
|
|
|
dns_dthandle_t *handle;
|
|
|
|
|
|
|
|
REQUIRE(handlep != NULL && *handlep != NULL);
|
|
|
|
|
|
|
|
handle = *handlep;
|
|
|
|
*handlep = NULL;
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
if (handle->reader != NULL) {
|
|
|
|
fstrm_reader_destroy(&handle->reader);
|
|
|
|
handle->reader = NULL;
|
|
|
|
}
|
2016-08-25 10:03:22 +10:00
|
|
|
isc_mem_putanddetach(&handle->mctx, handle, sizeof(*handle));
|
2015-10-02 12:32:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_dt_parse(isc_mem_t *mctx, isc_region_t *src, dns_dtdata_t **destp) {
|
|
|
|
isc_result_t result;
|
|
|
|
Dnstap__Message *m;
|
|
|
|
dns_dtdata_t *d = NULL;
|
|
|
|
isc_buffer_t b;
|
|
|
|
|
|
|
|
REQUIRE(src != NULL);
|
|
|
|
REQUIRE(destp != NULL && *destp == NULL);
|
|
|
|
|
|
|
|
d = isc_mem_get(mctx, sizeof(*d));
|
|
|
|
if (d == NULL)
|
|
|
|
return (ISC_R_NOMEMORY);
|
|
|
|
|
|
|
|
memset(d, 0, sizeof(*d));
|
|
|
|
isc_mem_attach(mctx, &d->mctx);
|
|
|
|
|
|
|
|
d->frame = dnstap__dnstap__unpack(NULL, src->length, src->base);
|
|
|
|
if (d->frame == NULL)
|
|
|
|
CHECK(ISC_R_NOMEMORY);
|
|
|
|
|
|
|
|
if (d->frame->type != DNSTAP__DNSTAP__TYPE__MESSAGE)
|
|
|
|
CHECK(DNS_R_BADDNSTAP);
|
|
|
|
|
|
|
|
m = d->frame->message;
|
|
|
|
|
|
|
|
/* Message type */
|
|
|
|
switch (m->type) {
|
|
|
|
case DNSTAP__MESSAGE__TYPE__AUTH_QUERY:
|
|
|
|
d->type = DNS_DTTYPE_AQ;
|
|
|
|
break;
|
|
|
|
case DNSTAP__MESSAGE__TYPE__AUTH_RESPONSE:
|
|
|
|
d->type = DNS_DTTYPE_AR;
|
|
|
|
break;
|
|
|
|
case DNSTAP__MESSAGE__TYPE__CLIENT_QUERY:
|
|
|
|
d->type = DNS_DTTYPE_CQ;
|
|
|
|
break;
|
|
|
|
case DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE:
|
|
|
|
d->type = DNS_DTTYPE_CR;
|
|
|
|
break;
|
|
|
|
case DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY:
|
|
|
|
d->type = DNS_DTTYPE_FQ;
|
|
|
|
break;
|
|
|
|
case DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE:
|
|
|
|
d->type = DNS_DTTYPE_FR;
|
|
|
|
break;
|
|
|
|
case DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY:
|
|
|
|
d->type = DNS_DTTYPE_RQ;
|
|
|
|
break;
|
|
|
|
case DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE:
|
|
|
|
d->type = DNS_DTTYPE_RR;
|
|
|
|
break;
|
|
|
|
case DNSTAP__MESSAGE__TYPE__STUB_QUERY:
|
|
|
|
d->type = DNS_DTTYPE_SQ;
|
|
|
|
break;
|
|
|
|
case DNSTAP__MESSAGE__TYPE__STUB_RESPONSE:
|
|
|
|
d->type = DNS_DTTYPE_SR;
|
|
|
|
break;
|
|
|
|
case DNSTAP__MESSAGE__TYPE__TOOL_QUERY:
|
|
|
|
d->type = DNS_DTTYPE_TQ;
|
|
|
|
break;
|
|
|
|
case DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE:
|
|
|
|
d->type = DNS_DTTYPE_TR;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
CHECK(DNS_R_BADDNSTAP);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Query? */
|
2015-10-03 23:45:23 +00:00
|
|
|
if ((d->type & DNS_DTTYPE_QUERY) != 0)
|
2018-04-17 08:29:14 -07:00
|
|
|
d->query = true;
|
2015-10-02 12:32:42 -07:00
|
|
|
else
|
2018-04-17 08:29:14 -07:00
|
|
|
d->query = false;
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
/* Parse DNS message */
|
|
|
|
if (d->query && m->has_query_message) {
|
|
|
|
d->msgdata.base = m->query_message.data;
|
|
|
|
d->msgdata.length = m->query_message.len;
|
|
|
|
} else if (!d->query && m->has_response_message) {
|
|
|
|
d->msgdata.base = m->response_message.data;
|
|
|
|
d->msgdata.length = m->response_message.len;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_buffer_init(&b, d->msgdata.base, d->msgdata.length);
|
|
|
|
isc_buffer_add(&b, d->msgdata.length);
|
|
|
|
CHECK(dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &d->msg));
|
|
|
|
result = dns_message_parse(d->msg, &b, 0);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
if (result != DNS_R_RECOVERABLE)
|
|
|
|
dns_message_destroy(&d->msg);
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Timestamp */
|
|
|
|
if (d->query) {
|
|
|
|
if (m->has_query_time_sec && m->has_query_time_nsec)
|
|
|
|
isc_time_set(&d->qtime, m->query_time_sec,
|
|
|
|
m->query_time_nsec);
|
|
|
|
} else {
|
|
|
|
if (m->has_response_time_sec && m->has_response_time_nsec)
|
|
|
|
isc_time_set(&d->rtime, m->response_time_sec,
|
|
|
|
m->response_time_nsec);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Peer address */
|
|
|
|
if (m->has_query_address) {
|
|
|
|
d->qaddr.base = m->query_address.data;
|
|
|
|
d->qaddr.length = m->query_address.len;
|
|
|
|
}
|
2017-02-03 17:05:58 -08:00
|
|
|
if (m->has_query_port) {
|
|
|
|
d->qport = m->query_port;
|
|
|
|
}
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
if (m->has_response_address) {
|
|
|
|
d->raddr.base = m->response_address.data;
|
|
|
|
d->raddr.length = m->response_address.len;
|
|
|
|
}
|
2017-02-03 17:05:58 -08:00
|
|
|
if (m->has_response_port) {
|
|
|
|
d->rport = m->response_port;
|
|
|
|
}
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
/* Socket protocol */
|
|
|
|
if (m->has_socket_protocol) {
|
|
|
|
const ProtobufCEnumValue *type =
|
|
|
|
protobuf_c_enum_descriptor_get_value(
|
|
|
|
&dnstap__socket_protocol__descriptor,
|
|
|
|
m->socket_protocol);
|
2015-10-03 23:45:23 +00:00
|
|
|
if (type != NULL &&
|
2015-10-02 12:32:42 -07:00
|
|
|
type->value == DNSTAP__SOCKET_PROTOCOL__TCP)
|
2018-04-17 08:29:14 -07:00
|
|
|
d->tcp = true;
|
2015-10-03 23:45:23 +00:00
|
|
|
else
|
2018-04-17 08:29:14 -07:00
|
|
|
d->tcp = false;
|
2015-10-02 12:32:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Query tuple */
|
|
|
|
if (d->msg != NULL) {
|
|
|
|
dns_name_t *name = NULL;
|
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
|
|
|
|
CHECK(dns_message_firstname(d->msg, DNS_SECTION_QUESTION));
|
|
|
|
dns_message_currentname(d->msg, DNS_SECTION_QUESTION, &name);
|
|
|
|
rdataset = ISC_LIST_HEAD(name->list);
|
|
|
|
|
|
|
|
dns_name_format(name, d->namebuf, sizeof(d->namebuf));
|
|
|
|
dns_rdatatype_format(rdataset->type, d->typebuf,
|
|
|
|
sizeof(d->typebuf));
|
|
|
|
dns_rdataclass_format(rdataset->rdclass, d->classbuf,
|
|
|
|
sizeof(d->classbuf));
|
|
|
|
}
|
|
|
|
|
|
|
|
*destp = d;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
dns_dtdata_free(&d);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_dt_datatotext(dns_dtdata_t *d, isc_buffer_t **dest) {
|
|
|
|
isc_result_t result;
|
|
|
|
char buf[100];
|
|
|
|
|
|
|
|
REQUIRE(d != NULL);
|
|
|
|
REQUIRE(dest != NULL && *dest != NULL);
|
|
|
|
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
|
|
|
|
/* Timestamp */
|
|
|
|
if (d->query && !isc_time_isepoch(&d->qtime))
|
|
|
|
isc_time_formattimestamp(&d->qtime, buf, sizeof(buf));
|
|
|
|
else if (!d->query && !isc_time_isepoch(&d->rtime))
|
|
|
|
isc_time_formattimestamp(&d->rtime, buf, sizeof(buf));
|
|
|
|
|
|
|
|
if (buf[0] == '\0')
|
|
|
|
CHECK(putstr(dest, "???\?-?\?-?? ??:??:??.??? "));
|
|
|
|
else {
|
|
|
|
CHECK(putstr(dest, buf));
|
|
|
|
CHECK(putstr(dest, " "));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Type mnemonic */
|
|
|
|
switch (d->type) {
|
|
|
|
case DNS_DTTYPE_AQ:
|
|
|
|
CHECK(putstr(dest, "AQ "));
|
|
|
|
break;
|
|
|
|
case DNS_DTTYPE_AR:
|
|
|
|
CHECK(putstr(dest, "AR "));
|
|
|
|
break;
|
|
|
|
case DNS_DTTYPE_CQ:
|
|
|
|
CHECK(putstr(dest, "CQ "));
|
|
|
|
break;
|
|
|
|
case DNS_DTTYPE_CR:
|
|
|
|
CHECK(putstr(dest, "CR "));
|
|
|
|
break;
|
|
|
|
case DNS_DTTYPE_FQ:
|
|
|
|
CHECK(putstr(dest, "FQ "));
|
|
|
|
break;
|
|
|
|
case DNS_DTTYPE_FR:
|
|
|
|
CHECK(putstr(dest, "FR "));
|
|
|
|
break;
|
|
|
|
case DNS_DTTYPE_RQ:
|
|
|
|
CHECK(putstr(dest, "RQ "));
|
|
|
|
break;
|
|
|
|
case DNS_DTTYPE_RR:
|
|
|
|
CHECK(putstr(dest, "RR "));
|
|
|
|
break;
|
|
|
|
case DNS_DTTYPE_SQ:
|
|
|
|
CHECK(putstr(dest, "SQ "));
|
|
|
|
break;
|
|
|
|
case DNS_DTTYPE_SR:
|
|
|
|
CHECK(putstr(dest, "SR "));
|
|
|
|
break;
|
|
|
|
case DNS_DTTYPE_TQ:
|
|
|
|
CHECK(putstr(dest, "TQ "));
|
|
|
|
break;
|
|
|
|
case DNS_DTTYPE_TR:
|
|
|
|
CHECK(putstr(dest, "TR "));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return (DNS_R_BADDNSTAP);
|
|
|
|
}
|
|
|
|
|
2017-02-03 17:05:58 -08:00
|
|
|
/* Query and response addresses */
|
|
|
|
if (d->qaddr.length != 0) {
|
|
|
|
CHECK(putaddr(dest, &d->qaddr));
|
|
|
|
snprintf(buf, sizeof(buf), ":%u", d->qport);
|
|
|
|
CHECK(putstr(dest, buf));
|
|
|
|
} else {
|
|
|
|
CHECK(putstr(dest, "?"));
|
2015-10-02 12:32:42 -07:00
|
|
|
}
|
2017-02-03 17:05:58 -08:00
|
|
|
if ((d->type & DNS_DTTYPE_QUERY) != 0) {
|
|
|
|
CHECK(putstr(dest, " -> "));
|
|
|
|
} else {
|
|
|
|
CHECK(putstr(dest, " <- "));
|
|
|
|
}
|
|
|
|
if (d->raddr.length != 0) {
|
|
|
|
CHECK(putaddr(dest, &d->raddr));
|
|
|
|
snprintf(buf, sizeof(buf), ":%u", d->rport);
|
|
|
|
CHECK(putstr(dest, buf));
|
|
|
|
} else {
|
|
|
|
CHECK(putstr(dest, "?"));
|
|
|
|
}
|
2017-02-04 23:45:35 +00:00
|
|
|
|
2015-10-02 12:32:42 -07:00
|
|
|
CHECK(putstr(dest, " "));
|
|
|
|
|
|
|
|
/* Protocol */
|
|
|
|
if (d->tcp)
|
|
|
|
CHECK(putstr(dest, "TCP "));
|
|
|
|
else
|
|
|
|
CHECK(putstr(dest, "UDP "));
|
|
|
|
|
|
|
|
/* Message size */
|
|
|
|
if (d->msgdata.base != NULL) {
|
2018-02-15 12:04:33 +11:00
|
|
|
snprintf(buf, sizeof(buf), "%zub ", (size_t) d->msgdata.length);
|
2015-10-02 12:32:42 -07:00
|
|
|
CHECK(putstr(dest, buf));
|
|
|
|
} else
|
|
|
|
CHECK(putstr(dest, "0b "));
|
|
|
|
|
|
|
|
/* Query tuple */
|
|
|
|
if (d->namebuf[0] == '\0')
|
|
|
|
CHECK(putstr(dest, "?/"));
|
|
|
|
else {
|
|
|
|
CHECK(putstr(dest, d->namebuf));
|
|
|
|
CHECK(putstr(dest, "/"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (d->classbuf[0] == '\0')
|
|
|
|
CHECK(putstr(dest, "?/"));
|
|
|
|
else {
|
|
|
|
CHECK(putstr(dest, d->classbuf));
|
|
|
|
CHECK(putstr(dest, "/"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (d->typebuf[0] == '\0')
|
|
|
|
CHECK(putstr(dest, "?"));
|
2015-10-03 23:45:23 +00:00
|
|
|
else
|
2015-10-02 12:32:42 -07:00
|
|
|
CHECK(putstr(dest, d->typebuf));
|
|
|
|
|
|
|
|
CHECK(isc_buffer_reserve(dest, 1));
|
|
|
|
isc_buffer_putuint8(*dest, 0);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_dtdata_free(dns_dtdata_t **dp) {
|
|
|
|
dns_dtdata_t *d;
|
|
|
|
|
|
|
|
REQUIRE(dp != NULL && *dp != NULL);
|
|
|
|
|
|
|
|
d = *dp;
|
|
|
|
|
|
|
|
if (d->msg != NULL)
|
|
|
|
dns_message_destroy(&d->msg);
|
|
|
|
if (d->frame != NULL)
|
|
|
|
dnstap__dnstap__free_unpacked(d->frame, NULL);
|
|
|
|
|
|
|
|
isc_mem_putanddetach(&d->mctx, d, sizeof(*d));
|
|
|
|
|
|
|
|
*dp = NULL;
|
|
|
|
}
|