Commit 94942ca5 authored by Robert Edmonds's avatar Robert Edmonds

Add initial dnstap implementation

parent 46d26d5a
......@@ -57,6 +57,12 @@
/src/knot/conf/libknotd_la-cf-parse.h
/src/zscanner/scanner.c
# dnstap
/src/dnstap/Makefile
/src/dnstap/Makefile.in
/src/dnstap/dnstap.pb-c.c
/src/dnstap/dnstap.pb-c.h
# zscanner
/src/zscanner/tests/tmp/
/src/zscanner/tests/unittests
......
......@@ -384,6 +384,7 @@ AC_CONFIG_FILES([Makefile
libtap/Makefile
src/Makefile
tests/Makefile
src/dnstap/Makefile
src/zscanner/Makefile
man/khost.1
man/knotc.8
......
ACLOCAL_AMFLAGS = -I $(top_srcdir)/m4
SUBDIRS = zscanner .
SUBDIRS = zscanner dnstap .
sbin_PROGRAMS = knotc knotd
bin_PROGRAMS = kdig khost knsupdate knsec3hash
......
ACLOCAL_AMFLAGS = -I $(top_srcdir)/m4
AM_CPPFLAGS = \
-include $(top_builddir)/src/config.h \
-I$(top_srcdir)/src
EXTRA_DIST = \
dnstap.proto
if HAVE_DNSTAP
SUFFIXES = .proto .pb-c.c .pb-c.h
.proto.pb-c.c:
$(AM_V_GEN)@PROTOC_C@ --c_out=. -I$(srcdir) $<
.proto.pb-c.h:
$(AM_V_GEN)@PROTOC_C@ --c_out=. -I$(srcdir) $<
noinst_LTLIBRARIES = libdnstap.la
libdnstap_la_CFLAGS = \
$(CODE_COVERAGE_CFLAGS) \
$(DNSTAP_CFLAGS)
libdnstap_la_LDFLAGS = \
$(CODE_COVERAGE_LDFLAGS) \
$(DNSTAP_LIBS)
libdnstap_la_SOURCES = \
dnstap.c \
message.c \
writer.c
nodist_libdnstap_la_SOURCES = \
dnstap.pb-c.c \
dnstap.pb-c.h
BUILT_SOURCES = $(nodist_libdnstap_la_SOURCES)
CLEANFILES = $(nodist_libdnstap_la_SOURCES)
endif
/* Copyright (C) 2014 Farsight Security, Inc. <software@farsightsecurity.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <stdlib.h>
#include "dnstap/dnstap.pb-c.h"
#define DNSTAP_INITIAL_BUF_SIZE 256
uint8_t* dt_pack(const Dnstap__Dnstap *d, uint8_t **buf, size_t *sz)
{
ProtobufCBufferSimple sbuf;
sbuf.base.append = protobuf_c_buffer_simple_append;
sbuf.len = 0;
sbuf.alloced = DNSTAP_INITIAL_BUF_SIZE;
sbuf.data = malloc(sbuf.alloced);
if (sbuf.data == NULL)
return NULL;
sbuf.must_free_data = 1;
*sz = dnstap__dnstap__pack_to_buffer(d, (ProtobufCBuffer *) &sbuf);
*buf = sbuf.data;
return *buf;
}
/* Copyright (C) 2014 Farsight Security, Inc. <software@farsightsecurity.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*!
* \file dnstap.h
*
* \author Robert Edmonds <edmonds@fsi.io>
*
* \brief Public interface for dnstap.
* @{
*/
#ifndef _DNSTAP__DNSTAP_H_
#define _DNSTAP__DNSTAP_H_
#include <stddef.h>
#include <stdint.h>
#include "dnstap/dnstap.pb-c.h"
/*! \brief Frame Streams "Content Type" value for dnstap. */
#define DNSTAP_CONTENT_TYPE "protobuf:dnstap.Dnstap"
/*!
* \brief Serializes a filled out dnstap protobuf struct. Dynamically allocates
* storage for the serialized frame.
*
* \note This function returns a copy of its parameter return value 'buf' to
* make error checking slightly easier.
*
* \param d dnstap protobuf struct.
* \param[out] buf Serialized frame.
* \param[out] sz Size in bytes of the serialized frame.
*
* \return Serialized frame.
* \retval NULL if error.
*/
uint8_t* dt_pack(const Dnstap__Dnstap *d, uint8_t **buf, size_t *sz);
#endif // _DNSTAP__DNSTAP_H_
/*! @} */
This diff is collapsed.
/* Copyright (C) 2014 Farsight Security, Inc. <software@farsightsecurity.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <netinet/in.h> // sockaddr_in
#include <stdint.h>
#include <stdlib.h>
#include <string.h> // memset
#include "common/errcode.h"
#include "dnstap/message.h"
int dt_message_fill(Dnstap__Message *m,
const Dnstap__Message__Type type,
const struct sockaddr *response_sa,
const int protocol,
const void *wire,
const size_t len_wire,
const struct timeval *qtime,
const struct timeval *rtime)
{
memset(m, 0, sizeof(*m));
m->base.descriptor = &dnstap__message__descriptor;
if (type != DNSTAP__MESSAGE__TYPE__TOOL_QUERY &&
type != DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE)
{
return KNOT_EINVAL;
}
// Message.type
m->type = type;
if (response_sa->sa_family == AF_INET) {
const struct sockaddr_in *sai =
(const struct sockaddr_in *)response_sa;
// Message.socket_family
m->has_socket_family = 1;
m->socket_family = DNSTAP__SOCKET_FAMILY__INET;
// Message.response_address
m->response_address.len = 4;
m->response_address.data = (uint8_t *)
&sai->sin_addr.s_addr;
m->has_response_address = 1;
// Message.response_port
m->has_response_port = 1;
m->response_port = ntohs(sai->sin_port);
} else if (response_sa->sa_family == AF_INET6) {
const struct sockaddr_in6 *sai6 =
(const struct sockaddr_in6 *)response_sa;
// Message.socket_family
m->socket_family = DNSTAP__SOCKET_FAMILY__INET6;
m->has_socket_family = 1;
// Message.response_address
m->response_address.len = 16;
m->response_address.data = (uint8_t *)
&sai6->sin6_addr.s6_addr;
m->has_response_address = 1;
// Message.response_port
m->has_response_port = 1;
m->response_port = ntohs(sai6->sin6_port);
} else {
return KNOT_EINVAL;
}
// Message.socket_protocol
if (protocol == IPPROTO_UDP) {
m->socket_protocol = DNSTAP__SOCKET_PROTOCOL__UDP;
} else if (protocol == IPPROTO_TCP) {
m->socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP;
} else {
return KNOT_EINVAL;
}
m->has_socket_protocol = 1;
if (type == DNSTAP__MESSAGE__TYPE__TOOL_QUERY) {
// Message.query_message
m->query_message.len = len_wire;
m->query_message.data = (uint8_t *)wire;
m->has_query_message = 1;
} else if (type == DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE) {
// Message.response_message
m->response_message.len = len_wire;
m->response_message.data = (uint8_t *)wire;
m->has_response_message = 1;
}
// Message.query_time_sec, Message.query_time_nsec
if (qtime != NULL) {
m->query_time_sec = qtime->tv_sec;
m->query_time_nsec = qtime->tv_usec * 1000;
m->has_query_time_sec = 1;
m->has_query_time_nsec = 1;
}
// Message.response_time_sec, Message.response_time_nsec
if (rtime != NULL) {
m->response_time_sec = rtime->tv_sec;
m->response_time_nsec = rtime->tv_usec * 1000;
m->has_response_time_sec = 1;
m->has_response_time_nsec = 1;
}
return KNOT_EOK;
}
/* Copyright (C) 2014 Farsight Security, Inc. <software@farsightsecurity.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*!
* \file message.h
*
* \author Robert Edmonds <edmonds@fsi.io>
*
* \brief dnstap message interface.
*
* \addtogroup dnstap
* @{
*/
#ifndef _DNSTAP__MESSAGE_H_
#define _DNSTAP__MESSAGE_H_
#include <sys/socket.h> // struct sockaddr
#include <sys/time.h> // struct timeval
#include <stddef.h> // size_t
#include "dnstap/dnstap.pb-c.h"
/*!
* \brief Fill a Dnstap__Message structure with the given parameters.
*
* Supported message types:
* \c DNSTAP__MESSAGE__TYPE__TOOL_QUERY
* \c DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE
*
* \param[out] m
* Dnstap__Message structure to fill. Will be zeroed first.
* \param type
* One of the supported message type values.
* \param response_sa
* sockaddr_in or sockaddr_in6 to use when filling the 'socket_family',
* 'response_address', 'response_port' fields.
* \param protocol
* \c IPPROTO_UDP or \c IPPROTO_TCP.
* \param wire
* Wire-format query message or response message (depending on 'type').
* \param len_wire
* Length in bytes of 'wire'.
* \param qtime
* Query time. May be NULL.
* \param rtime
* Response time. May be NULL.
*
* \retval KNOT_EOK
* \retval KNOT_EINVAL
*/
int dt_message_fill(Dnstap__Message *m,
const Dnstap__Message__Type type,
const struct sockaddr *response_sa,
const int protocol,
const void *wire,
const size_t len_wire,
const struct timeval *qtime,
const struct timeval *rtime);
#endif // _DNSTAP__MESSAGE_H_
/*! @} */
/* Copyright (C) 2014 Farsight Security, Inc. <software@farsightsecurity.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <arpa/inet.h> // htonl
#include <errno.h>
#include <stdint.h> // uint8_t, uint32_t
#include <stdio.h> // fopen, fwrite
#include <stdlib.h> // calloc, free
#include <string.h> // strdup
#include "common/errcode.h"
#include "libknot/common.h"
#include "dnstap/dnstap.pb-c.h"
#include "dnstap/dnstap.h"
#include "dnstap/writer.h"
#define DNSTAP_INITIAL_BUF_SIZE 256
static int dt_writer_write_control(dt_writer_t *writer,
fstrm_control_type type)
{
fstrm_res res;
// Encode the control frame.
res = fstrm_control_set_type(writer->control, type);
if (res != fstrm_res_success) {
return KNOT_ERROR;
}
// Write the control frame.
if (writer->fp != NULL) {
uint8_t frame[FSTRM_MAX_CONTROL_FRAME_LENGTH];
size_t len = sizeof(frame);
res = fstrm_control_encode(writer->control, frame, &len,
FSTRM_CONTROL_FLAG_WITH_HEADER);
if (res != fstrm_res_success) {
return KNOT_ERROR;
}
fwrite(frame, len, 1, writer->fp);
}
return KNOT_EOK;
}
dt_writer_t* dt_writer_create(const char *file_name, const char *version)
{
dt_writer_t *writer = NULL;
fstrm_res res;
writer = calloc(1, sizeof(dt_writer_t));
if (writer == NULL) {
goto fail;
}
// Set "version".
if (version != NULL) {
writer->len_version = strlen(version);
writer->version = (uint8_t *)strdup(version);
if (!writer->version) {
goto fail;
}
}
// Open file.
writer->fp = fopen(file_name, "w");
if (writer->fp == NULL) {
goto fail;
}
// Initialize the control frame object.
writer->control = fstrm_control_init();
res = fstrm_control_set_field_content_type(writer->control,
(const uint8_t *) DNSTAP_CONTENT_TYPE,
strlen(DNSTAP_CONTENT_TYPE));
if (res != fstrm_res_success) {
goto fail;
}
// Write the START control frame.
if (dt_writer_write_control(writer, FSTRM_CONTROL_START) != KNOT_EOK) {
goto fail;
}
return writer;
fail:
dt_writer_free(writer);
return NULL;
}
int dt_writer_close(dt_writer_t *writer)
{
FILE *fp;
int rv = KNOT_EOK;
// Write the STOP control frame.
if (writer->fp != NULL) {
rv = dt_writer_write_control(writer, FSTRM_CONTROL_STOP);
}
// Close file.
fp = writer->fp;
writer->fp = NULL;
if (fp != NULL) {
if (fclose(fp) != 0) {
return knot_map_errno(errno);
}
}
return rv;
}
int dt_writer_free(dt_writer_t *writer)
{
int rv = KNOT_EOK;
if (writer != NULL) {
rv = dt_writer_close(writer);
fstrm_control_destroy(&writer->control);
free(writer->version);
free(writer);
}
return rv;
}
int dt_writer_write(dt_writer_t *writer, const ProtobufCMessage *msg)
{
uint32_t be_len;
size_t len;
uint8_t *data;
Dnstap__Dnstap dnstap = DNSTAP__DNSTAP__INIT;
if (writer->fp == NULL)
return KNOT_EOK;
// Only handle dnstap/Message.
if (knot_unlikely(msg->descriptor != &dnstap__message__descriptor))
return KNOT_EINVAL;
// Fill out 'dnstap'.
if (writer->version) {
dnstap.version.data = writer->version;
dnstap.version.len = writer->len_version;
dnstap.has_version = 1;
}
dnstap.type = DNSTAP__DNSTAP__TYPE__MESSAGE;
dnstap.message = (Dnstap__Message *)msg;
// Serialize the dnstap frame.
if (!dt_pack(&dnstap, &data, &len))
return KNOT_ENOMEM;
// Write the dnstap frame to the output stream.
be_len = htonl(len);
fwrite(&be_len, sizeof(be_len), 1, writer->fp);
fwrite(data, len, 1, writer->fp);
// Cleanup.
free(data);
return KNOT_EOK;
}
/* Copyright (C) 2014 Farsight Security, Inc. <software@farsightsecurity.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*!
* \file writer.h
*
* \author Robert Edmonds <edmonds@fsi.io>
*
* \brief dnstap file writer.
*
* \addtogroup dnstap
* @{
*/
#ifndef _DNSTAP__WRITER_H_
#define _DNSTAP__WRITER_H_
#include <stdio.h> // FILE
#include <stdint.h> // uint8_t
#include <fstrm.h> // fstrm_control
#include <protobuf-c/protobuf-c.h> // ProtobufCMessage
/*! \brief Structure for dnstap file writer. */
typedef struct {
/*!< Output FILE. */
FILE *fp;
/*!< dnstap "version" field. */
uint8_t *version;
/*!< length of dnstap "version" field. */
size_t len_version;
/*!< Frame Streams control frame structure. */
struct fstrm_control *control;
} dt_writer_t;
/*!
* \brief Creates dnstap file writer structure.
*
* \param file_name Name of file to write output to.
* \param version Version string of software. May be NULL.
*
* \retval writer if success.
* \retval NULL if error.
*/
dt_writer_t* dt_writer_create(const char *file_name, const char *version);
/*!
* \brief Finish writing dnstap file writer and free resources.
*
* \param writer dnstap file writer structure.
*
* \retval KNOT_EOK
* \retval errcode if error.
*/
int dt_writer_free(dt_writer_t *writer);
/*!
* \brief Write a protobuf to the dnstap file writer.
*
* Supported protobuf types for the 'msg' parameter:
* \c Dnstap__Message
*
* \param writer dnstap file writer structure.
* \param msg dnstap protobuf. Must be a supported type.
*
* \retval KNOT_EOK
* \retval KNOT_EINVAL
* \retval KNOT_ENOMEM
*/
int dt_writer_write(dt_writer_t *writer, const ProtobufCMessage *msg);
#endif // _DNSTAP__DNSTAP_H_
/*! @} */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment