]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
Adding dnstap module
authorVicky Shrestha <vicky@geeks.net.np>
Thu, 22 Sep 2016 22:32:27 +0000 (15:32 -0700)
committerOndřej Surý <ondrej@sury.org>
Mon, 6 Mar 2017 11:48:21 +0000 (12:48 +0100)
Makefile
contrib/contrib.mk
contrib/dnstap/dnstap.pb-c.c [new file with mode: 0644]
contrib/dnstap/dnstap.pb-c.h [new file with mode: 0644]
contrib/dnstap/dnstap.proto [new file with mode: 0644]
daemon/worker.c
lib/resolve.h
modules/dnstap/dnstap.c [new file with mode: 0644]
modules/dnstap/dnstap.mk [new file with mode: 0644]
modules/modules.mk

index ecd964cba195d377520926825b5c16a2cbf9137a..167fbde704dbc46022f969374bc9215e387bb38d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -35,6 +35,8 @@ $(eval $(call find_lib,socket_wrapper))
 $(eval $(call find_lib,libsystemd,227))
 $(eval $(call find_lib,gnutls))
 $(eval $(call find_lib,libedit))
+$(eval $(call find_lib,libprotobuf-c,1.2.1))
+$(eval $(call find_lib,libfstrm,0.2))
 
 # Lookup SONAME
 $(eval $(call find_soname,libknot))
@@ -71,6 +73,12 @@ endif
 endif
 endif
 
+# check for fstrm and protobuf for dnstap
+ifeq ($(HAS_libfstrm)&$(HAS_libprotobuf-c),yes&yes)
+BUILD_CFLAGS += -DENABLE_DNSTAP
+ENABLE_DNSTAP := yes
+endif
+
 # Overview
 info:
        $(info Target:     Knot DNS Resolver $(VERSION)-$(PLATFORM))
@@ -112,6 +120,8 @@ info:
        $(info [$(HAS_ltn12)] Lua socket ltn12 (trust anchor bootstrapping))
        $(info [$(HAS_ssl.https)] Lua ssl.https (trust anchor bootstrapping))
        $(info [$(HAS_libedit)] libedit (client))
+       $(info [$(HAS_libfstrm)] libfstrm (modules/dnstap))
+       $(info [$(HAS_libprotobuf-c)] libprotobuf-c (modules/dnstap))
        $(info )
 
 # Verify required dependencies are met, as listed above
index 1753b530fb1382739aa5c577f737886c71d0e3f8..3cb685c5b78c3ed21e43802c1837b1050e4ebd7f 100644 (file)
@@ -6,7 +6,8 @@ contrib_SOURCES := \
        contrib/ucw/mempool.c \
        contrib/murmurhash3/murmurhash3.c \
        contrib/base32hex.c \
-       contrib/base64.c
+       contrib/base64.c \
+       contrib/dnstap/dnstap.pb-c.c
 contrib_CFLAGS := -fPIC
 contrib_TARGET := $(abspath contrib)/contrib$(AREXT)
 
diff --git a/contrib/dnstap/dnstap.pb-c.c b/contrib/dnstap/dnstap.pb-c.c
new file mode 100644 (file)
index 0000000..50000bd
--- /dev/null
@@ -0,0 +1,523 @@
+/* Generated by the protocol buffer compiler.  DO NOT EDIT! */
+/* Generated from: dnstap.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "dnstap.pb-c.h"
+void   dnstap__dnstap__init
+                     (Dnstap__Dnstap         *message)
+{
+  static Dnstap__Dnstap init_value = DNSTAP__DNSTAP__INIT;
+  *message = init_value;
+}
+size_t dnstap__dnstap__get_packed_size
+                     (const Dnstap__Dnstap *message)
+{
+  assert(message->base.descriptor == &dnstap__dnstap__descriptor);
+  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t dnstap__dnstap__pack
+                     (const Dnstap__Dnstap *message,
+                      uint8_t       *out)
+{
+  assert(message->base.descriptor == &dnstap__dnstap__descriptor);
+  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t dnstap__dnstap__pack_to_buffer
+                     (const Dnstap__Dnstap *message,
+                      ProtobufCBuffer *buffer)
+{
+  assert(message->base.descriptor == &dnstap__dnstap__descriptor);
+  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+Dnstap__Dnstap *
+       dnstap__dnstap__unpack
+                     (ProtobufCAllocator  *allocator,
+                      size_t               len,
+                      const uint8_t       *data)
+{
+  return (Dnstap__Dnstap *)
+     protobuf_c_message_unpack (&dnstap__dnstap__descriptor,
+                                allocator, len, data);
+}
+void   dnstap__dnstap__free_unpacked
+                     (Dnstap__Dnstap *message,
+                      ProtobufCAllocator *allocator)
+{
+  assert(message->base.descriptor == &dnstap__dnstap__descriptor);
+  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+void   dnstap__message__init
+                     (Dnstap__Message         *message)
+{
+  static Dnstap__Message init_value = DNSTAP__MESSAGE__INIT;
+  *message = init_value;
+}
+size_t dnstap__message__get_packed_size
+                     (const Dnstap__Message *message)
+{
+  assert(message->base.descriptor == &dnstap__message__descriptor);
+  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t dnstap__message__pack
+                     (const Dnstap__Message *message,
+                      uint8_t       *out)
+{
+  assert(message->base.descriptor == &dnstap__message__descriptor);
+  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t dnstap__message__pack_to_buffer
+                     (const Dnstap__Message *message,
+                      ProtobufCBuffer *buffer)
+{
+  assert(message->base.descriptor == &dnstap__message__descriptor);
+  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+Dnstap__Message *
+       dnstap__message__unpack
+                     (ProtobufCAllocator  *allocator,
+                      size_t               len,
+                      const uint8_t       *data)
+{
+  return (Dnstap__Message *)
+     protobuf_c_message_unpack (&dnstap__message__descriptor,
+                                allocator, len, data);
+}
+void   dnstap__message__free_unpacked
+                     (Dnstap__Message *message,
+                      ProtobufCAllocator *allocator)
+{
+  assert(message->base.descriptor == &dnstap__message__descriptor);
+  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCEnumValue dnstap__dnstap__type__enum_values_by_number[1] =
+{
+  { "MESSAGE", "DNSTAP__DNSTAP__TYPE__MESSAGE", 1 },
+};
+static const ProtobufCIntRange dnstap__dnstap__type__value_ranges[] = {
+{1, 0},{0, 1}
+};
+static const ProtobufCEnumValueIndex dnstap__dnstap__type__enum_values_by_name[1] =
+{
+  { "MESSAGE", 0 },
+};
+const ProtobufCEnumDescriptor dnstap__dnstap__type__descriptor =
+{
+  PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
+  "dnstap.Dnstap.Type",
+  "Type",
+  "Dnstap__Dnstap__Type",
+  "dnstap",
+  1,
+  dnstap__dnstap__type__enum_values_by_number,
+  1,
+  dnstap__dnstap__type__enum_values_by_name,
+  1,
+  dnstap__dnstap__type__value_ranges,
+  NULL,NULL,NULL,NULL   /* reserved[1234] */
+};
+static const ProtobufCFieldDescriptor dnstap__dnstap__field_descriptors[5] =
+{
+  {
+    "identity",
+    1,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_BYTES,
+    offsetof(Dnstap__Dnstap, has_identity),
+    offsetof(Dnstap__Dnstap, identity),
+    NULL,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "version",
+    2,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_BYTES,
+    offsetof(Dnstap__Dnstap, has_version),
+    offsetof(Dnstap__Dnstap, version),
+    NULL,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "extra",
+    3,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_BYTES,
+    offsetof(Dnstap__Dnstap, has_extra),
+    offsetof(Dnstap__Dnstap, extra),
+    NULL,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "message",
+    14,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_MESSAGE,
+    0,   /* quantifier_offset */
+    offsetof(Dnstap__Dnstap, message),
+    &dnstap__message__descriptor,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "type",
+    15,
+    PROTOBUF_C_LABEL_REQUIRED,
+    PROTOBUF_C_TYPE_ENUM,
+    0,   /* quantifier_offset */
+    offsetof(Dnstap__Dnstap, type),
+    &dnstap__dnstap__type__descriptor,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+};
+static const unsigned dnstap__dnstap__field_indices_by_name[] = {
+  2,   /* field[2] = extra */
+  0,   /* field[0] = identity */
+  3,   /* field[3] = message */
+  4,   /* field[4] = type */
+  1,   /* field[1] = version */
+};
+static const ProtobufCIntRange dnstap__dnstap__number_ranges[2 + 1] =
+{
+  { 1, 0 },
+  { 14, 3 },
+  { 0, 5 }
+};
+const ProtobufCMessageDescriptor dnstap__dnstap__descriptor =
+{
+  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+  "dnstap.Dnstap",
+  "Dnstap",
+  "Dnstap__Dnstap",
+  "dnstap",
+  sizeof(Dnstap__Dnstap),
+  5,
+  dnstap__dnstap__field_descriptors,
+  dnstap__dnstap__field_indices_by_name,
+  2,  dnstap__dnstap__number_ranges,
+  (ProtobufCMessageInit) dnstap__dnstap__init,
+  NULL,NULL,NULL    /* reserved[123] */
+};
+static const ProtobufCEnumValue dnstap__message__type__enum_values_by_number[12] =
+{
+  { "AUTH_QUERY", "DNSTAP__MESSAGE__TYPE__AUTH_QUERY", 1 },
+  { "AUTH_RESPONSE", "DNSTAP__MESSAGE__TYPE__AUTH_RESPONSE", 2 },
+  { "RESOLVER_QUERY", "DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY", 3 },
+  { "RESOLVER_RESPONSE", "DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE", 4 },
+  { "CLIENT_QUERY", "DNSTAP__MESSAGE__TYPE__CLIENT_QUERY", 5 },
+  { "CLIENT_RESPONSE", "DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE", 6 },
+  { "FORWARDER_QUERY", "DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY", 7 },
+  { "FORWARDER_RESPONSE", "DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE", 8 },
+  { "STUB_QUERY", "DNSTAP__MESSAGE__TYPE__STUB_QUERY", 9 },
+  { "STUB_RESPONSE", "DNSTAP__MESSAGE__TYPE__STUB_RESPONSE", 10 },
+  { "TOOL_QUERY", "DNSTAP__MESSAGE__TYPE__TOOL_QUERY", 11 },
+  { "TOOL_RESPONSE", "DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE", 12 },
+};
+static const ProtobufCIntRange dnstap__message__type__value_ranges[] = {
+{1, 0},{0, 12}
+};
+static const ProtobufCEnumValueIndex dnstap__message__type__enum_values_by_name[12] =
+{
+  { "AUTH_QUERY", 0 },
+  { "AUTH_RESPONSE", 1 },
+  { "CLIENT_QUERY", 4 },
+  { "CLIENT_RESPONSE", 5 },
+  { "FORWARDER_QUERY", 6 },
+  { "FORWARDER_RESPONSE", 7 },
+  { "RESOLVER_QUERY", 2 },
+  { "RESOLVER_RESPONSE", 3 },
+  { "STUB_QUERY", 8 },
+  { "STUB_RESPONSE", 9 },
+  { "TOOL_QUERY", 10 },
+  { "TOOL_RESPONSE", 11 },
+};
+const ProtobufCEnumDescriptor dnstap__message__type__descriptor =
+{
+  PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
+  "dnstap.Message.Type",
+  "Type",
+  "Dnstap__Message__Type",
+  "dnstap",
+  12,
+  dnstap__message__type__enum_values_by_number,
+  12,
+  dnstap__message__type__enum_values_by_name,
+  1,
+  dnstap__message__type__value_ranges,
+  NULL,NULL,NULL,NULL   /* reserved[1234] */
+};
+static const ProtobufCFieldDescriptor dnstap__message__field_descriptors[14] =
+{
+  {
+    "type",
+    1,
+    PROTOBUF_C_LABEL_REQUIRED,
+    PROTOBUF_C_TYPE_ENUM,
+    0,   /* quantifier_offset */
+    offsetof(Dnstap__Message, type),
+    &dnstap__message__type__descriptor,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "socket_family",
+    2,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_ENUM,
+    offsetof(Dnstap__Message, has_socket_family),
+    offsetof(Dnstap__Message, socket_family),
+    &dnstap__socket_family__descriptor,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "socket_protocol",
+    3,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_ENUM,
+    offsetof(Dnstap__Message, has_socket_protocol),
+    offsetof(Dnstap__Message, socket_protocol),
+    &dnstap__socket_protocol__descriptor,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "query_address",
+    4,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_BYTES,
+    offsetof(Dnstap__Message, has_query_address),
+    offsetof(Dnstap__Message, query_address),
+    NULL,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "response_address",
+    5,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_BYTES,
+    offsetof(Dnstap__Message, has_response_address),
+    offsetof(Dnstap__Message, response_address),
+    NULL,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "query_port",
+    6,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_UINT32,
+    offsetof(Dnstap__Message, has_query_port),
+    offsetof(Dnstap__Message, query_port),
+    NULL,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "response_port",
+    7,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_UINT32,
+    offsetof(Dnstap__Message, has_response_port),
+    offsetof(Dnstap__Message, response_port),
+    NULL,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "query_time_sec",
+    8,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_UINT64,
+    offsetof(Dnstap__Message, has_query_time_sec),
+    offsetof(Dnstap__Message, query_time_sec),
+    NULL,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "query_time_nsec",
+    9,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_FIXED32,
+    offsetof(Dnstap__Message, has_query_time_nsec),
+    offsetof(Dnstap__Message, query_time_nsec),
+    NULL,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "query_message",
+    10,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_BYTES,
+    offsetof(Dnstap__Message, has_query_message),
+    offsetof(Dnstap__Message, query_message),
+    NULL,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "query_zone",
+    11,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_BYTES,
+    offsetof(Dnstap__Message, has_query_zone),
+    offsetof(Dnstap__Message, query_zone),
+    NULL,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "response_time_sec",
+    12,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_UINT64,
+    offsetof(Dnstap__Message, has_response_time_sec),
+    offsetof(Dnstap__Message, response_time_sec),
+    NULL,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "response_time_nsec",
+    13,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_FIXED32,
+    offsetof(Dnstap__Message, has_response_time_nsec),
+    offsetof(Dnstap__Message, response_time_nsec),
+    NULL,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+  {
+    "response_message",
+    14,
+    PROTOBUF_C_LABEL_OPTIONAL,
+    PROTOBUF_C_TYPE_BYTES,
+    offsetof(Dnstap__Message, has_response_message),
+    offsetof(Dnstap__Message, response_message),
+    NULL,
+    NULL,
+    0,             /* flags */
+    0,NULL,NULL    /* reserved1,reserved2, etc */
+  },
+};
+static const unsigned dnstap__message__field_indices_by_name[] = {
+  3,   /* field[3] = query_address */
+  9,   /* field[9] = query_message */
+  5,   /* field[5] = query_port */
+  8,   /* field[8] = query_time_nsec */
+  7,   /* field[7] = query_time_sec */
+  10,   /* field[10] = query_zone */
+  4,   /* field[4] = response_address */
+  13,   /* field[13] = response_message */
+  6,   /* field[6] = response_port */
+  12,   /* field[12] = response_time_nsec */
+  11,   /* field[11] = response_time_sec */
+  1,   /* field[1] = socket_family */
+  2,   /* field[2] = socket_protocol */
+  0,   /* field[0] = type */
+};
+static const ProtobufCIntRange dnstap__message__number_ranges[1 + 1] =
+{
+  { 1, 0 },
+  { 0, 14 }
+};
+const ProtobufCMessageDescriptor dnstap__message__descriptor =
+{
+  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+  "dnstap.Message",
+  "Message",
+  "Dnstap__Message",
+  "dnstap",
+  sizeof(Dnstap__Message),
+  14,
+  dnstap__message__field_descriptors,
+  dnstap__message__field_indices_by_name,
+  1,  dnstap__message__number_ranges,
+  (ProtobufCMessageInit) dnstap__message__init,
+  NULL,NULL,NULL    /* reserved[123] */
+};
+static const ProtobufCEnumValue dnstap__socket_family__enum_values_by_number[2] =
+{
+  { "INET", "DNSTAP__SOCKET_FAMILY__INET", 1 },
+  { "INET6", "DNSTAP__SOCKET_FAMILY__INET6", 2 },
+};
+static const ProtobufCIntRange dnstap__socket_family__value_ranges[] = {
+{1, 0},{0, 2}
+};
+static const ProtobufCEnumValueIndex dnstap__socket_family__enum_values_by_name[2] =
+{
+  { "INET", 0 },
+  { "INET6", 1 },
+};
+const ProtobufCEnumDescriptor dnstap__socket_family__descriptor =
+{
+  PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
+  "dnstap.SocketFamily",
+  "SocketFamily",
+  "Dnstap__SocketFamily",
+  "dnstap",
+  2,
+  dnstap__socket_family__enum_values_by_number,
+  2,
+  dnstap__socket_family__enum_values_by_name,
+  1,
+  dnstap__socket_family__value_ranges,
+  NULL,NULL,NULL,NULL   /* reserved[1234] */
+};
+static const ProtobufCEnumValue dnstap__socket_protocol__enum_values_by_number[2] =
+{
+  { "UDP", "DNSTAP__SOCKET_PROTOCOL__UDP", 1 },
+  { "TCP", "DNSTAP__SOCKET_PROTOCOL__TCP", 2 },
+};
+static const ProtobufCIntRange dnstap__socket_protocol__value_ranges[] = {
+{1, 0},{0, 2}
+};
+static const ProtobufCEnumValueIndex dnstap__socket_protocol__enum_values_by_name[2] =
+{
+  { "TCP", 1 },
+  { "UDP", 0 },
+};
+const ProtobufCEnumDescriptor dnstap__socket_protocol__descriptor =
+{
+  PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
+  "dnstap.SocketProtocol",
+  "SocketProtocol",
+  "Dnstap__SocketProtocol",
+  "dnstap",
+  2,
+  dnstap__socket_protocol__enum_values_by_number,
+  2,
+  dnstap__socket_protocol__enum_values_by_name,
+  1,
+  dnstap__socket_protocol__value_ranges,
+  NULL,NULL,NULL,NULL   /* reserved[1234] */
+};
diff --git a/contrib/dnstap/dnstap.pb-c.h b/contrib/dnstap/dnstap.pb-c.h
new file mode 100644 (file)
index 0000000..520d55e
--- /dev/null
@@ -0,0 +1,343 @@
+/* Generated by the protocol buffer compiler.  DO NOT EDIT! */
+/* Generated from: dnstap.proto */
+
+#ifndef PROTOBUF_C_dnstap_2eproto__INCLUDED
+#define PROTOBUF_C_dnstap_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1000000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1002001 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+
+typedef struct _Dnstap__Dnstap Dnstap__Dnstap;
+typedef struct _Dnstap__Message Dnstap__Message;
+
+
+/* --- enums --- */
+
+/*
+ * Identifies which field below is filled in.
+ */
+typedef enum _Dnstap__Dnstap__Type {
+  DNSTAP__DNSTAP__TYPE__MESSAGE = 1
+    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(DNSTAP__DNSTAP__TYPE)
+} Dnstap__Dnstap__Type;
+typedef enum _Dnstap__Message__Type {
+  /*
+   * AUTH_QUERY is a DNS query message received from a resolver by an
+   * authoritative name server, from the perspective of the authoritative
+   * name server.
+   */
+  DNSTAP__MESSAGE__TYPE__AUTH_QUERY = 1,
+  /*
+   * AUTH_RESPONSE is a DNS response message sent from an authoritative
+   * name server to a resolver, from the perspective of the authoritative
+   * name server.
+   */
+  DNSTAP__MESSAGE__TYPE__AUTH_RESPONSE = 2,
+  /*
+   * RESOLVER_QUERY is a DNS query message sent from a resolver to an
+   * authoritative name server, from the perspective of the resolver.
+   * Resolvers typically clear the RD (recursion desired) bit when
+   * sending queries.
+   */
+  DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY = 3,
+  /*
+   * RESOLVER_RESPONSE is a DNS response message received from an
+   * authoritative name server by a resolver, from the perspective of
+   * the resolver.
+   */
+  DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE = 4,
+  /*
+   * CLIENT_QUERY is a DNS query message sent from a client to a DNS
+   * server which is expected to perform further recursion, from the
+   * perspective of the DNS server. The client may be a stub resolver or
+   * forwarder or some other type of software which typically sets the RD
+   * (recursion desired) bit when querying the DNS server. The DNS server
+   * may be a simple forwarding proxy or it may be a full recursive
+   * resolver.
+   */
+  DNSTAP__MESSAGE__TYPE__CLIENT_QUERY = 5,
+  /*
+   * CLIENT_RESPONSE is a DNS response message sent from a DNS server to
+   * a client, from the perspective of the DNS server. The DNS server
+   * typically sets the RA (recursion available) bit when responding.
+   */
+  DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE = 6,
+  /*
+   * FORWARDER_QUERY is a DNS query message sent from a downstream DNS
+   * server to an upstream DNS server which is expected to perform
+   * further recursion, from the perspective of the downstream DNS
+   * server.
+   */
+  DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY = 7,
+  /*
+   * FORWARDER_RESPONSE is a DNS response message sent from an upstream
+   * DNS server performing recursion to a downstream DNS server, from the
+   * perspective of the downstream DNS server.
+   */
+  DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE = 8,
+  /*
+   * STUB_QUERY is a DNS query message sent from a stub resolver to a DNS
+   * server, from the perspective of the stub resolver.
+   */
+  DNSTAP__MESSAGE__TYPE__STUB_QUERY = 9,
+  /*
+   * STUB_RESPONSE is a DNS response message sent from a DNS server to a
+   * stub resolver, from the perspective of the stub resolver.
+   */
+  DNSTAP__MESSAGE__TYPE__STUB_RESPONSE = 10,
+  /*
+   * TOOL_QUERY is a DNS query message sent from a DNS software tool to a
+   * DNS server, from the perspective of the tool.
+   */
+  DNSTAP__MESSAGE__TYPE__TOOL_QUERY = 11,
+  /*
+   * TOOL_RESPONSE is a DNS response message received by a DNS software
+   * tool from a DNS server, from the perspective of the tool.
+   */
+  DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE = 12
+    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(DNSTAP__MESSAGE__TYPE)
+} Dnstap__Message__Type;
+/*
+ * SocketFamily: the network protocol family of a socket. This specifies how
+ * to interpret "network address" fields.
+ */
+typedef enum _Dnstap__SocketFamily {
+  /*
+   * IPv4 (RFC 791)
+   */
+  DNSTAP__SOCKET_FAMILY__INET = 1,
+  /*
+   * IPv6 (RFC 2460)
+   */
+  DNSTAP__SOCKET_FAMILY__INET6 = 2
+    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(DNSTAP__SOCKET_FAMILY)
+} Dnstap__SocketFamily;
+/*
+ * SocketProtocol: the transport protocol of a socket. This specifies how to
+ * interpret "transport port" fields.
+ */
+typedef enum _Dnstap__SocketProtocol {
+  /*
+   * User Datagram Protocol (RFC 768)
+   */
+  DNSTAP__SOCKET_PROTOCOL__UDP = 1,
+  /*
+   * Transmission Control Protocol (RFC 793)
+   */
+  DNSTAP__SOCKET_PROTOCOL__TCP = 2
+    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(DNSTAP__SOCKET_PROTOCOL)
+} Dnstap__SocketProtocol;
+
+/* --- messages --- */
+
+/*
+ * "Dnstap": this is the top-level dnstap type, which is a "union" type that
+ * contains other kinds of dnstap payloads, although currently only one type
+ * of dnstap payload is defined.
+ * See: https://developers.google.com/protocol-buffers/docs/techniques#union
+ */
+struct  _Dnstap__Dnstap
+{
+  ProtobufCMessage base;
+  /*
+   * DNS server identity.
+   * If enabled, this is the identity string of the DNS server which generated
+   * this message. Typically this would be the same string as returned by an
+   * "NSID" (RFC 5001) query.
+   */
+  protobuf_c_boolean has_identity;
+  ProtobufCBinaryData identity;
+  /*
+   * DNS server version.
+   * If enabled, this is the version string of the DNS server which generated
+   * this message. Typically this would be the same string as returned by a
+   * "version.bind" query.
+   */
+  protobuf_c_boolean has_version;
+  ProtobufCBinaryData version;
+  /*
+   * Extra data for this payload.
+   * This field can be used for adding an arbitrary byte-string annotation to
+   * the payload. No encoding or interpretation is applied or enforced.
+   */
+  protobuf_c_boolean has_extra;
+  ProtobufCBinaryData extra;
+  Dnstap__Dnstap__Type type;
+  /*
+   * One of the following will be filled in.
+   */
+  Dnstap__Message *message;
+};
+#define DNSTAP__DNSTAP__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&dnstap__dnstap__descriptor) \
+    , 0,{0,NULL}, 0,{0,NULL}, 0,{0,NULL}, 0, NULL }
+
+
+/*
+ * Message: a wire-format (RFC 1035 section 4) DNS message and associated
+ * metadata. Applications generating "Message" payloads should follow
+ * certain requirements based on the MessageType, see below.
+ */
+struct  _Dnstap__Message
+{
+  ProtobufCMessage base;
+  /*
+   * One of the Type values described above.
+   */
+  Dnstap__Message__Type type;
+  /*
+   * One of the SocketFamily values described above.
+   */
+  protobuf_c_boolean has_socket_family;
+  Dnstap__SocketFamily socket_family;
+  /*
+   * One of the SocketProtocol values described above.
+   */
+  protobuf_c_boolean has_socket_protocol;
+  Dnstap__SocketProtocol socket_protocol;
+  /*
+   * The network address of the message initiator.
+   * For SocketFamily INET, this field is 4 octets (IPv4 address).
+   * For SocketFamily INET6, this field is 16 octets (IPv6 address).
+   */
+  protobuf_c_boolean has_query_address;
+  ProtobufCBinaryData query_address;
+  /*
+   * The network address of the message responder.
+   * For SocketFamily INET, this field is 4 octets (IPv4 address).
+   * For SocketFamily INET6, this field is 16 octets (IPv6 address).
+   */
+  protobuf_c_boolean has_response_address;
+  ProtobufCBinaryData response_address;
+  /*
+   * The transport port of the message initiator.
+   * This is a 16-bit UDP or TCP port number, depending on SocketProtocol.
+   */
+  protobuf_c_boolean has_query_port;
+  uint32_t query_port;
+  /*
+   * The transport port of the message responder.
+   * This is a 16-bit UDP or TCP port number, depending on SocketProtocol.
+   */
+  protobuf_c_boolean has_response_port;
+  uint32_t response_port;
+  /*
+   * The time at which the DNS query message was sent or received, depending
+   * on whether this is an AUTH_QUERY, RESOLVER_QUERY, or CLIENT_QUERY.
+   * This is the number of seconds since the UNIX epoch.
+   */
+  protobuf_c_boolean has_query_time_sec;
+  uint64_t query_time_sec;
+  /*
+   * The time at which the DNS query message was sent or received.
+   * This is the seconds fraction, expressed as a count of nanoseconds.
+   */
+  protobuf_c_boolean has_query_time_nsec;
+  uint32_t query_time_nsec;
+  /*
+   * The initiator's original wire-format DNS query message, verbatim.
+   */
+  protobuf_c_boolean has_query_message;
+  ProtobufCBinaryData query_message;
+  /*
+   * The "zone" or "bailiwick" pertaining to the DNS query message.
+   * This is a wire-format DNS domain name.
+   */
+  protobuf_c_boolean has_query_zone;
+  ProtobufCBinaryData query_zone;
+  /*
+   * The time at which the DNS response message was sent or received,
+   * depending on whether this is an AUTH_RESPONSE, RESOLVER_RESPONSE, or
+   * CLIENT_RESPONSE.
+   * This is the number of seconds since the UNIX epoch.
+   */
+  protobuf_c_boolean has_response_time_sec;
+  uint64_t response_time_sec;
+  /*
+   * The time at which the DNS response message was sent or received.
+   * This is the seconds fraction, expressed as a count of nanoseconds.
+   */
+  protobuf_c_boolean has_response_time_nsec;
+  uint32_t response_time_nsec;
+  /*
+   * The responder's original wire-format DNS response message, verbatim.
+   */
+  protobuf_c_boolean has_response_message;
+  ProtobufCBinaryData response_message;
+};
+#define DNSTAP__MESSAGE__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&dnstap__message__descriptor) \
+    , 0, 0,0, 0,0, 0,{0,NULL}, 0,{0,NULL}, 0,0, 0,0, 0,0, 0,0, 0,{0,NULL}, 0,{0,NULL}, 0,0, 0,0, 0,{0,NULL} }
+
+
+/* Dnstap__Dnstap methods */
+void   dnstap__dnstap__init
+                     (Dnstap__Dnstap         *message);
+size_t dnstap__dnstap__get_packed_size
+                     (const Dnstap__Dnstap   *message);
+size_t dnstap__dnstap__pack
+                     (const Dnstap__Dnstap   *message,
+                      uint8_t             *out);
+size_t dnstap__dnstap__pack_to_buffer
+                     (const Dnstap__Dnstap   *message,
+                      ProtobufCBuffer     *buffer);
+Dnstap__Dnstap *
+       dnstap__dnstap__unpack
+                     (ProtobufCAllocator  *allocator,
+                      size_t               len,
+                      const uint8_t       *data);
+void   dnstap__dnstap__free_unpacked
+                     (Dnstap__Dnstap *message,
+                      ProtobufCAllocator *allocator);
+/* Dnstap__Message methods */
+void   dnstap__message__init
+                     (Dnstap__Message         *message);
+size_t dnstap__message__get_packed_size
+                     (const Dnstap__Message   *message);
+size_t dnstap__message__pack
+                     (const Dnstap__Message   *message,
+                      uint8_t             *out);
+size_t dnstap__message__pack_to_buffer
+                     (const Dnstap__Message   *message,
+                      ProtobufCBuffer     *buffer);
+Dnstap__Message *
+       dnstap__message__unpack
+                     (ProtobufCAllocator  *allocator,
+                      size_t               len,
+                      const uint8_t       *data);
+void   dnstap__message__free_unpacked
+                     (Dnstap__Message *message,
+                      ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*Dnstap__Dnstap_Closure)
+                 (const Dnstap__Dnstap *message,
+                  void *closure_data);
+typedef void (*Dnstap__Message_Closure)
+                 (const Dnstap__Message *message,
+                  void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCEnumDescriptor    dnstap__socket_family__descriptor;
+extern const ProtobufCEnumDescriptor    dnstap__socket_protocol__descriptor;
+extern const ProtobufCMessageDescriptor dnstap__dnstap__descriptor;
+extern const ProtobufCEnumDescriptor    dnstap__dnstap__type__descriptor;
+extern const ProtobufCMessageDescriptor dnstap__message__descriptor;
+extern const ProtobufCEnumDescriptor    dnstap__message__type__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif  /* PROTOBUF_C_dnstap_2eproto__INCLUDED */
diff --git a/contrib/dnstap/dnstap.proto b/contrib/dnstap/dnstap.proto
new file mode 100644 (file)
index 0000000..22784cd
--- /dev/null
@@ -0,0 +1,268 @@
+// dnstap: flexible, structured event replication format for DNS software
+//
+// This file contains the protobuf schemas for the "dnstap" structured event
+// replication format for DNS software.
+
+// Written in 2013-2014 by Farsight Security, Inc.
+//
+// To the extent possible under law, the author(s) have dedicated all
+// copyright and related and neighboring rights to this file to the public
+// domain worldwide. This file is distributed without any warranty.
+//
+// You should have received a copy of the CC0 Public Domain Dedication along
+// with this file. If not, see:
+//
+// <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+package dnstap;
+
+// "Dnstap": this is the top-level dnstap type, which is a "union" type that
+// contains other kinds of dnstap payloads, although currently only one type
+// of dnstap payload is defined.
+// See: https://developers.google.com/protocol-buffers/docs/techniques#union
+message Dnstap {
+    // DNS server identity.
+    // If enabled, this is the identity string of the DNS server which generated
+    // this message. Typically this would be the same string as returned by an
+    // "NSID" (RFC 5001) query.
+    optional bytes      identity = 1;
+
+    // DNS server version.
+    // If enabled, this is the version string of the DNS server which generated
+    // this message. Typically this would be the same string as returned by a
+    // "version.bind" query.
+    optional bytes      version = 2;
+
+    // Extra data for this payload.
+    // This field can be used for adding an arbitrary byte-string annotation to
+    // the payload. No encoding or interpretation is applied or enforced.
+    optional bytes      extra = 3;
+
+    // Identifies which field below is filled in.
+    enum Type {
+        MESSAGE = 1;
+    }
+    required Type       type = 15;
+
+    // One of the following will be filled in.
+    optional Message    message = 14;
+}
+
+// SocketFamily: the network protocol family of a socket. This specifies how
+// to interpret "network address" fields.
+enum SocketFamily {
+    INET = 1;   // IPv4 (RFC 791)
+    INET6 = 2;  // IPv6 (RFC 2460)
+}
+
+// SocketProtocol: the transport protocol of a socket. This specifies how to
+// interpret "transport port" fields.
+enum SocketProtocol {
+    UDP = 1;    // User Datagram Protocol (RFC 768)
+    TCP = 2;    // Transmission Control Protocol (RFC 793)
+}
+
+// Message: a wire-format (RFC 1035 section 4) DNS message and associated
+// metadata. Applications generating "Message" payloads should follow
+// certain requirements based on the MessageType, see below.
+message Message {
+
+    // There are eight types of "Message" defined that correspond to the
+    // four arrows in the following diagram, slightly modified from RFC 1035
+    // section 2:
+
+    //    +---------+               +----------+           +--------+
+    //    |         |     query     |          |   query   |        |
+    //    | Stub    |-SQ--------CQ->| Recursive|-RQ----AQ->| Auth.  |
+    //    | Resolver|               | Server   |           | Name   |
+    //    |         |<-SR--------CR-|          |<-RR----AR-| Server |
+    //    +---------+    response   |          |  response |        |
+    //                              +----------+           +--------+
+
+    // Each arrow has two Type values each, one for each "end" of each arrow,
+    // because these are considered to be distinct events. Each end of each
+    // arrow on the diagram above has been marked with a two-letter Type
+    // mnemonic. Clockwise from upper left, these mnemonic values are:
+    //
+    //   SQ:        STUB_QUERY
+    //   CQ:      CLIENT_QUERY
+    //   RQ:    RESOLVER_QUERY
+    //   AQ:        AUTH_QUERY
+    //   AR:        AUTH_RESPONSE
+    //   RR:    RESOLVER_RESPONSE
+    //   CR:      CLIENT_RESPONSE
+    //   SR:        STUB_RESPONSE
+
+    // Two additional types of "Message" have been defined for the
+    // "forwarding" case where an upstream DNS server is responsible for
+    // further recursion. These are not shown on the diagram above, but have
+    // the following mnemonic values:
+
+    //   FQ:   FORWARDER_QUERY
+    //   FR:   FORWARDER_RESPONSE
+
+    // The "Message" Type values are defined below.
+
+    enum Type {
+        // AUTH_QUERY is a DNS query message received from a resolver by an
+        // authoritative name server, from the perspective of the authoritative
+        // name server.
+        AUTH_QUERY = 1;
+
+        // AUTH_RESPONSE is a DNS response message sent from an authoritative
+        // name server to a resolver, from the perspective of the authoritative
+        // name server.
+        AUTH_RESPONSE = 2;
+
+        // RESOLVER_QUERY is a DNS query message sent from a resolver to an
+        // authoritative name server, from the perspective of the resolver.
+        // Resolvers typically clear the RD (recursion desired) bit when
+        // sending queries.
+        RESOLVER_QUERY = 3;
+
+        // RESOLVER_RESPONSE is a DNS response message received from an
+        // authoritative name server by a resolver, from the perspective of
+        // the resolver.
+        RESOLVER_RESPONSE = 4;
+
+        // CLIENT_QUERY is a DNS query message sent from a client to a DNS
+        // server which is expected to perform further recursion, from the
+        // perspective of the DNS server. The client may be a stub resolver or
+        // forwarder or some other type of software which typically sets the RD
+        // (recursion desired) bit when querying the DNS server. The DNS server
+        // may be a simple forwarding proxy or it may be a full recursive
+        // resolver.
+        CLIENT_QUERY = 5;
+
+        // CLIENT_RESPONSE is a DNS response message sent from a DNS server to
+        // a client, from the perspective of the DNS server. The DNS server
+        // typically sets the RA (recursion available) bit when responding.
+        CLIENT_RESPONSE = 6;
+
+        // FORWARDER_QUERY is a DNS query message sent from a downstream DNS
+        // server to an upstream DNS server which is expected to perform
+        // further recursion, from the perspective of the downstream DNS
+        // server.
+        FORWARDER_QUERY = 7;
+
+        // FORWARDER_RESPONSE is a DNS response message sent from an upstream
+        // DNS server performing recursion to a downstream DNS server, from the
+        // perspective of the downstream DNS server.
+        FORWARDER_RESPONSE = 8;
+
+        // STUB_QUERY is a DNS query message sent from a stub resolver to a DNS
+        // server, from the perspective of the stub resolver.
+        STUB_QUERY = 9;
+
+        // STUB_RESPONSE is a DNS response message sent from a DNS server to a
+        // stub resolver, from the perspective of the stub resolver.
+        STUB_RESPONSE = 10;
+
+        // TOOL_QUERY is a DNS query message sent from a DNS software tool to a
+        // DNS server, from the perspective of the tool.
+        TOOL_QUERY = 11;
+
+        // TOOL_RESPONSE is a DNS response message received by a DNS software
+        // tool from a DNS server, from the perspective of the tool.
+        TOOL_RESPONSE = 12;
+    }
+
+    // One of the Type values described above.
+    required Type               type = 1;
+
+    // One of the SocketFamily values described above.
+    optional SocketFamily       socket_family = 2;
+
+    // One of the SocketProtocol values described above.
+    optional SocketProtocol     socket_protocol = 3;
+
+    // The network address of the message initiator.
+    // For SocketFamily INET, this field is 4 octets (IPv4 address).
+    // For SocketFamily INET6, this field is 16 octets (IPv6 address).
+    optional bytes              query_address = 4;
+
+    // The network address of the message responder.
+    // For SocketFamily INET, this field is 4 octets (IPv4 address).
+    // For SocketFamily INET6, this field is 16 octets (IPv6 address).
+    optional bytes              response_address = 5;
+
+    // The transport port of the message initiator.
+    // This is a 16-bit UDP or TCP port number, depending on SocketProtocol.
+    optional uint32             query_port = 6;
+
+    // The transport port of the message responder.
+    // This is a 16-bit UDP or TCP port number, depending on SocketProtocol.
+    optional uint32             response_port = 7;
+
+    // The time at which the DNS query message was sent or received, depending
+    // on whether this is an AUTH_QUERY, RESOLVER_QUERY, or CLIENT_QUERY.
+    // This is the number of seconds since the UNIX epoch.
+    optional uint64             query_time_sec = 8;
+
+    // The time at which the DNS query message was sent or received.
+    // This is the seconds fraction, expressed as a count of nanoseconds.
+    optional fixed32            query_time_nsec = 9;
+
+    // The initiator's original wire-format DNS query message, verbatim.
+    optional bytes              query_message = 10;
+
+    // The "zone" or "bailiwick" pertaining to the DNS query message.
+    // This is a wire-format DNS domain name.
+    optional bytes              query_zone = 11;
+
+    // The time at which the DNS response message was sent or received,
+    // depending on whether this is an AUTH_RESPONSE, RESOLVER_RESPONSE, or
+    // CLIENT_RESPONSE.
+    // This is the number of seconds since the UNIX epoch.
+    optional uint64             response_time_sec = 12;
+
+    // The time at which the DNS response message was sent or received.
+    // This is the seconds fraction, expressed as a count of nanoseconds.
+    optional fixed32            response_time_nsec = 13;
+
+    // The responder's original wire-format DNS response message, verbatim.
+    optional bytes              response_message = 14;
+}
+
+// All fields except for 'type' in the Message schema are optional.
+// It is recommended that at least the following fields be filled in for
+// particular types of Messages.
+
+// AUTH_QUERY:
+//      socket_family, socket_protocol
+//      query_address, query_port
+//      query_message
+//      query_time_sec, query_time_nsec
+
+// AUTH_RESPONSE:
+//      socket_family, socket_protocol
+//      query_address, query_port
+//      query_time_sec, query_time_nsec
+//      response_message
+//      response_time_sec, response_time_nsec
+
+// RESOLVER_QUERY:
+//      socket_family, socket_protocol
+//      query_message
+//      query_time_sec, query_time_nsec
+//      query_zone
+//      response_address, response_port
+
+// RESOLVER_RESPONSE:
+//      socket_family, socket_protocol
+//      query_time_sec, query_time_nsec
+//      query_zone
+//      response_address, response_port
+//      response_message
+//      response_time_sec, response_time_nsec
+
+// CLIENT_QUERY:
+//      socket_family, socket_protocol
+//      query_message
+//      query_time_sec, query_time_nsec
+
+// CLIENT_RESPONSE:
+//      socket_family, socket_protocol
+//      query_time_sec, query_time_nsec
+//      response_message
+//      response_time_sec, response_time_nsec
index e31264729df7ea8d260923a72536ea0e24c3b305..21efd306baa7effd3af46ed1c68d3e0bc0ff1cc9 100644 (file)
@@ -303,10 +303,12 @@ static struct qr_task *qr_task_create(struct worker_ctx *worker, uv_handle_t *ha
                        if (uv_udp_getsockname((uv_udp_t *)handle, dst_addr, &addr_len) == 0) {
                                task->req.qsource.dst_addr = dst_addr;
                        }
+                       task->req.qsource.tcp = false;
                } else if (handle->type == UV_TCP) {
                        if (uv_tcp_getsockname((uv_tcp_t *)handle, dst_addr, &addr_len) == 0) {
                                task->req.qsource.dst_addr = dst_addr;
                        }
+                       task->req.qsource.tcp = true;
                }
        }
        worker->stats.concurrent += 1;
index d8e409112f07b3da0c7d09f13b5cd877a2072148..c5c31cad224b77c374146c6a3ea0f29c6834b4de 100644 (file)
@@ -133,6 +133,7 @@ struct kr_request {
                const struct sockaddr *dst_addr;
                const knot_pkt_t *packet;
                const knot_rrset_t *opt;
+               bool tcp; /* true if the query is on tcp */
        } qsource;
        struct {
                unsigned rtt;                  /**< Current upstream RTT */
diff --git a/modules/dnstap/dnstap.c b/modules/dnstap/dnstap.c
new file mode 100644 (file)
index 0000000..818a8c5
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * @file dnstap.c
+ * @brief dnstap based query logging support
+ *
+ * dnstap module currently supports logging dns responses to a unix socket
+ * in dnstap format using fstrm framing library. The unix socket and the
+ * socket reader should be present before starting kresd
+ *
+ * Tunables:
+ * sockpath: is the the unix socket file where dnstap messages will be send
+ * logRespPkt: if true responses in wire format will be logged
+ *
+ * sample configuration for dnstap
+ * dnstap = {
+ *     sockPath = "/tmp/dnstap.sock",
+ *     logRespPkt = true
+ * }
+ *
+ */
+
+#include "lib/module.h"
+#include "lib/layer.h"
+#include "lib/resolve.h"
+#include "contrib/dnstap/dnstap.pb-c.h"
+#include <ccan/json/json.h>
+#include <fstrm.h>
+
+#define DEBUG_MSG(fmt, ...) kr_log_debug("[dnstap] " fmt, ##__VA_ARGS__);
+#define CFG_SOCK_PATH "sockPath"
+#define CFG_LOG_RESP_PKT "logRespPkt"
+#define DEFAULT_SOCK_PATH "/tmp/dnstap.sock"
+#define DNSTAP_CONTENT_TYPE "protobuf:dnstap.Dnstap"
+#define DNSTAP_INITIAL_BUF_SIZE         256
+
+/* Internal data structure */
+struct dnstap_data {
+       bool log_resp_pkt;
+       struct fstrm_iothr *iothread;
+       struct fstrm_iothr_queue *ioq;
+};
+
+/*
+ * dt_pack packs the dnstap message for transport
+ * https://gitlab.labs.nic.cz/labs/knot/blob/master/src/contrib/dnstap/dnstap.c#L24
+ * */
+uint8_t* dt_pack(const Dnstap__Dnstap *d, uint8_t **buf, size_t *sz)
+{
+       ProtobufCBufferSimple sbuf = { { NULL } };
+
+       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 = true;
+
+       *sz = dnstap__dnstap__pack_to_buffer(d, (ProtobufCBuffer *) &sbuf);
+       *buf = sbuf.data;
+       return *buf;
+}
+
+/* set_address fills in address deatail in dnstap_message 
+ * https://gitlab.labs.nic.cz/labs/knot/blob/master/src/contrib/dnstap/message.c#L28
+ */
+static void set_address(const struct sockaddr *sockaddr,
+               ProtobufCBinaryData   *addr,
+               protobuf_c_boolean    *has_addr,
+               uint32_t              *port,
+               protobuf_c_boolean    *has_port) {
+       if (sockaddr == NULL) {
+               *has_addr = 0;
+               *has_port = 0;
+               return;
+       }
+
+       *has_addr = true;
+       *has_port = true;
+
+       if (sockaddr->sa_family == AF_INET) {
+               const struct sockaddr_in *sai;
+               sai = (const struct sockaddr_in *)sockaddr;
+               addr->len = sizeof(sai->sin_addr);
+               addr->data = (uint8_t *)&sai->sin_addr.s_addr;
+               *port = ntohs(sai->sin_port);
+       } else if (sockaddr->sa_family == AF_INET6) {
+               const struct sockaddr_in6 *sai6;
+               sai6 = (const struct sockaddr_in6 *)sockaddr;
+               addr->len = sizeof(sai6->sin6_addr);
+               addr->data = (uint8_t *)&sai6->sin6_addr.s6_addr;
+               *port = ntohs(sai6->sin6_port);
+       }
+}
+
+/* dnstap_log prepares dnstap message and sent it to fstrm */
+static int dnstap_log(knot_layer_t *ctx) {
+       struct kr_request *req = ctx->data;
+       struct kr_module *module = ctx->api->data;
+       struct kr_rplan *rplan = &req->rplan;
+       struct dnstap_data *dnstap_dt = module->data;
+
+       /* check if we have a valid iothread */
+       if (!dnstap_dt->iothread || !dnstap_dt->ioq ) {
+               DEBUG_MSG("dnstap_dt->iothread or dnstap_dt->ioq is NULL\n");
+               return kr_error(EFAULT);
+       }
+
+       /* current time */
+       struct timeval now;
+       gettimeofday(&now, NULL);
+
+       /* Create dnstap message */
+       Dnstap__Message m;
+
+       memset(&m, 0, sizeof(m));
+
+       m.base.descriptor = &dnstap__message__descriptor;
+       /* Only handling response */
+       m.type = DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE;
+
+       if (req->qsource.tcp) {
+               m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP;
+       } else {
+               m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__UDP;
+       }
+       m.has_socket_protocol = true;
+
+       if (req->qsource.addr) {
+               set_address(req->qsource.addr,
+                               &m.query_address,
+                               &m.has_query_address,
+                               &m.query_port,
+                               &m.has_query_port);
+       }
+
+       if (req->qsource.dst_addr) {
+               set_address(req->qsource.dst_addr,
+                               &m.response_address,
+                               &m.has_response_address,
+                               &m.response_port,
+                               &m.has_response_port);
+               switch (req->qsource.dst_addr->sa_family) {
+                       case AF_INET:
+                               m.socket_family = DNSTAP__SOCKET_FAMILY__INET;
+                               m.has_socket_family = true;
+                               break;
+                       case AF_INET6:
+                               m.socket_family = DNSTAP__SOCKET_FAMILY__INET6;
+                               m.has_socket_family = true;
+                               break;
+               }
+       }
+
+       if (dnstap_dt->log_resp_pkt) {
+               const knot_pkt_t *rpkt = req->answer;
+               m.response_message.len = rpkt->size;
+               m.response_message.data = (uint8_t *)rpkt->wire;
+               m.has_response_message = true;
+       }
+
+       /* set query time to the timestamp of the first kr_query
+        * set response time to now
+        */
+       if (rplan->resolved.len > 0 ) {
+               struct kr_query *first = rplan->resolved.at[0];
+
+               m.query_time_sec = first->timestamp.tv_sec;
+               m.has_query_time_sec = true;
+               m.query_time_nsec = first->timestamp.tv_sec * 1000;
+               m.has_query_time_nsec = true;
+       }
+
+       /* Response time */
+       m.response_time_sec = now.tv_sec;
+       m.has_response_time_sec = true;
+       m.response_time_nsec = now.tv_sec * 1000;
+       m.has_response_time_nsec = true;
+
+       /* Qname */
+       m.query_zone.data = (uint8_t *)knot_pkt_qname(req->answer);
+       m.query_zone.len = req->answer->qname_size;
+       m.has_query_zone = true;
+
+       /* Create a dnstap Message */
+       Dnstap__Dnstap dnstap = DNSTAP__DNSTAP__INIT;
+       dnstap.type = DNSTAP__DNSTAP__TYPE__MESSAGE;
+       dnstap.message = (Dnstap__Message *)&m;
+
+       /* Pack the message */
+       uint8_t *frame = NULL;
+       size_t size = 0;
+       dt_pack(&dnstap, &frame, &size);
+       if (!frame) {
+               return kr_error(ENOMEM);
+       }
+
+       /* Submit a request to send message to fstrm_iothr*/
+       fstrm_res res = fstrm_iothr_submit(dnstap_dt->iothread, dnstap_dt->ioq, frame, size,
+                       fstrm_free_wrapper, NULL);
+       if (res != fstrm_res_success) {
+               DEBUG_MSG("Error submitting dnstap message to iothr\n");
+               free(frame);
+               return kr_error(EBUSY);
+       }
+
+       return ctx->state;
+}
+
+KR_EXPORT
+int dnstap_init(struct kr_module *module) {
+       DEBUG_MSG("loading\n");
+       /* allocated memory for internal data */
+       struct dnstap_data *data = malloc(sizeof(*data));
+       if (!data) {
+               return kr_error(ENOMEM);
+       }
+       memset(data, 0, sizeof(*data));
+
+       /* save pointer to internal struct in module for future reference */
+       module->data = data;
+       return kr_ok();
+}
+
+KR_EXPORT
+int dnstap_deinit(struct kr_module *module) {
+       DEBUG_MSG("unloading\n");
+       struct dnstap_data *data = module->data;
+       /* Free allocated memory */
+       if (data) {
+               fstrm_iothr_destroy(&data->iothread);
+               DEBUG_MSG("fstrm iothread destroyed\n");
+               free(data);
+       }
+       return kr_ok();
+}
+
+/* dnstap_unix_writer returns a unix fstream writer
+ * https://gitlab.labs.nic.cz/labs/knot/blob/master/src/knot/modules/dnstap.c#L159
+ */
+static struct fstrm_writer* dnstap_unix_writer(const char *path) {
+       struct fstrm_unix_writer_options *opt = NULL;
+       struct fstrm_writer_options *wopt = NULL;
+       struct fstrm_writer *writer = NULL;
+
+       opt = fstrm_unix_writer_options_init();
+       if (!opt) {
+               return NULL;
+       }
+       fstrm_unix_writer_options_set_socket_path(opt, path);
+
+       wopt = fstrm_writer_options_init();
+       if (!wopt) {
+               fstrm_unix_writer_options_destroy(&opt);
+               return NULL;
+       }
+       fstrm_writer_options_add_content_type(wopt, DNSTAP_CONTENT_TYPE,
+                       strlen(DNSTAP_CONTENT_TYPE));
+
+       writer = fstrm_unix_writer_init(opt, wopt);
+       fstrm_unix_writer_options_destroy(&opt);
+       fstrm_writer_options_destroy(&wopt);
+       if (!writer) {
+               return NULL;
+       }
+
+       fstrm_res res = fstrm_writer_open(writer);
+       if (res != fstrm_res_success) {
+               DEBUG_MSG("fstrm_writer_open returned %d\n", res);
+               fstrm_writer_destroy(&writer);
+               return NULL;
+       }
+
+       return writer;
+}
+
+/* find_string 
+ * create a new string from json
+ * *var is set to pointer of new string
+ * node must of type JSON_STRING
+ * new string can be at most len bytes
+ */
+static int find_string(const JsonNode *node, char **val, size_t len) {
+       if (!node || !node->key ) {
+               return kr_error(EINVAL);
+       }
+       assert(node->tag == JSON_STRING);
+       *val = strndup(node->string_, len);
+       assert(*val != NULL);
+       return kr_ok();
+}
+
+/* find_int copies json int into val
+ * node must be of type JSON_NUMBER */
+static int find_int(const JsonNode *node, int *val) {
+       if (!node || !node->key || !val ) {
+               return kr_error(EINVAL);
+       }
+       assert(node->tag == JSON_NUMBER);
+       *val = node->number_;
+       return kr_ok();
+}
+
+/* find_bool returns bool from json */
+static bool find_bool(const JsonNode *node) {
+       if (!node || !node->key ) {
+               return false;
+       }
+       assert(node->tag == JSON_BOOL);
+       return node->bool_;
+}
+
+/* parse config */
+KR_EXPORT
+int dnstap_config(struct kr_module *module, const char *conf) {
+       struct dnstap_data *data = module->data;
+       char *sock_path = NULL;
+       struct fstrm_writer *writer;
+
+       /* Empty conf passed, set default */
+       if (!conf || strlen(conf) < 1) {
+               sock_path = strndup(DEFAULT_SOCK_PATH, PATH_MAX);
+       } else {
+
+               JsonNode *root_node = json_decode(conf);
+               if (!root_node) {
+                       DEBUG_MSG("error parsing json\n");
+                       return kr_error(EINVAL);
+               }
+
+               JsonNode *node;
+               /* dnstapPath key */
+               node = json_find_member(root_node, CFG_SOCK_PATH);
+               if (!node || find_string(node, &sock_path, PATH_MAX) != kr_ok() ) {
+                       sock_path = strndup(DEFAULT_SOCK_PATH, PATH_MAX);
+               }
+
+               /* logRespPkt key */
+               node = json_find_member(root_node, CFG_LOG_RESP_PKT);
+               if (node) {
+                       data->log_resp_pkt = find_bool(node);
+               } else {
+                       data->log_resp_pkt = false;
+               }
+
+               /* clean up json, we don't need it no more */
+               json_delete(root_node);
+       }
+
+       DEBUG_MSG("opening sock file %s\n",sock_path);
+       writer = dnstap_unix_writer(sock_path);
+       free(sock_path);
+       if (!writer) {
+               DEBUG_MSG("can't create unix writer\n");
+               return kr_error(EINVAL);
+       }
+
+       struct fstrm_iothr_options *opt = fstrm_iothr_options_init();
+       if (!opt) {
+               DEBUG_MSG("can't init fstrm options\n");
+               fstrm_writer_destroy(&writer);
+               return kr_error(EINVAL);
+       }
+
+       /* Create the I/O thread. */
+       data->iothread = fstrm_iothr_init(opt, &writer);
+       fstrm_iothr_options_destroy(&opt);
+       if (!data->iothread) {
+               DEBUG_MSG("can't init fstrm_iothr\n");
+               fstrm_writer_destroy(&writer);
+               return kr_error(ENOMEM);
+       }
+
+       /* Get fstrm thread handle
+        * We only have one input queue, hence idx=0
+        */
+       data->ioq = fstrm_iothr_get_input_queue_idx(data->iothread, 0);
+       if (!data->ioq) {
+               DEBUG_MSG("can't get fstrm queue\n");
+               return kr_error(EBUSY);
+       }
+
+       return kr_ok();
+}
+
+KR_EXPORT
+const knot_layer_api_t *dnstap_layer(struct kr_module *module) {
+       static knot_layer_api_t _layer = {
+               .finish = &dnstap_log,
+       };
+       /* Store module reference */
+       _layer.data = module;
+       return &_layer;
+}
+
+KR_MODULE_EXPORT(dnstap);
+
diff --git a/modules/dnstap/dnstap.mk b/modules/dnstap/dnstap.mk
new file mode 100644 (file)
index 0000000..2de1230
--- /dev/null
@@ -0,0 +1,5 @@
+dnstap_CFLAGS := -fvisibility=hidden -fPIC
+dnstap_SOURCES := modules/dnstap/dnstap.c
+dnstap_DEPEND := $(libkres)
+dnstap_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS) $(libprotobuf-c_LIBS) $(libfstrm_LIBS)
+$(call make_c_module,dnstap)
index 4687bc41ca88d33cd0c008c80231902857095007..3a77ab6081ad85c900217fe6df7338b35ed306dd 100644 (file)
@@ -7,6 +7,10 @@ ifeq ($(ENABLE_COOKIES),yes)
 modules_TARGETS += cookies
 endif
 
+ifeq ($(ENABLE_DNSTAP),yes)
+modules_TARGETS += dnstap
+endif
+
 # Memcached
 ifeq ($(HAS_libmemcached),yes)
 modules_TARGETS += kmemcached