diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 00:55:53 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 00:55:53 +0000 |
commit | 3d0386f27ca66379acf50199e1d1298386eeeeb8 (patch) | |
tree | f87bd4a126b3a843858eb447e8fd5893c3ee3882 /modules/dnstap | |
parent | Initial commit. (diff) | |
download | knot-resolver-3d0386f27ca66379acf50199e1d1298386eeeeb8.tar.xz knot-resolver-3d0386f27ca66379acf50199e1d1298386eeeeb8.zip |
Adding upstream version 3.2.1.upstream/3.2.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'modules/dnstap')
-rw-r--r-- | modules/dnstap/README.rst | 24 | ||||
-rw-r--r-- | modules/dnstap/dnstap.c | 382 | ||||
-rw-r--r-- | modules/dnstap/dnstap.mk | 8 | ||||
-rw-r--r-- | modules/dnstap/dnstap.pb-c.c | 523 | ||||
-rw-r--r-- | modules/dnstap/dnstap.pb-c.h | 343 | ||||
-rw-r--r-- | modules/dnstap/dnstap.proto | 269 |
6 files changed, 1549 insertions, 0 deletions
diff --git a/modules/dnstap/README.rst b/modules/dnstap/README.rst new file mode 100644 index 0000000..442b4cf --- /dev/null +++ b/modules/dnstap/README.rst @@ -0,0 +1,24 @@ +.. _mod-dnstap: + +Dnstap +------ + +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. + +Configuration +^^^^^^^^^^^^^ +Tunables: + +* ``socket_path``: the the unix socket file where dnstap messages will be sent +* ``log_responses``: if true responses in wire format will be logged + +.. code-block:: lua + + modules = { + dnstap = { + socket_path = "/tmp/dnstap.sock", + log_responses = true + } + } diff --git a/modules/dnstap/dnstap.c b/modules/dnstap/dnstap.c new file mode 100644 index 0000000..0918426 --- /dev/null +++ b/modules/dnstap/dnstap.c @@ -0,0 +1,382 @@ +/* + * 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 + * + */ + +#include "lib/module.h" +#include "lib/layer.h" +#include "lib/resolve.h" +#include "modules/dnstap/dnstap.pb-c.h" +#include <ccan/json/json.h> +#include <fstrm.h> +#include "contrib/cleanup.h" + +#define DEBUG_MSG(fmt, ...) kr_log_verbose("[dnstap] " fmt, ##__VA_ARGS__); +#define CFG_SOCK_PATH "socket_path" +#define CFG_LOG_RESP_PKT "log_responses" +#define DEFAULT_SOCK_PATH "/tmp/dnstap.sock" +#define DNSTAP_CONTENT_TYPE "protobuf:dnstap.Dnstap" +#define DNSTAP_INITIAL_BUF_SIZE 256 + +#define auto_destroy_uopts __attribute__((cleanup(fstrm_unix_writer_options_destroy))) +#define auto_destroy_wopts __attribute__((cleanup(fstrm_writer_options_destroy))) + +/* 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/knot/knot-dns/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 detail in dnstap_message + * https://gitlab.labs.nic.cz/knot/knot-dns/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) { + const char *saddr = kr_inaddr(sockaddr); + if (saddr == NULL) { + *has_addr = false; + *has_port = false; + return; + } + + addr->data = (uint8_t *)(saddr); + addr->len = kr_inaddr_len(sockaddr); + *has_addr = true; + *port = kr_inaddr_port(sockaddr); + *has_port = true; +} + +/* dnstap_log prepares dnstap message and sent it to fstrm */ +static int dnstap_log(kr_layer_t *ctx) { + const struct kr_request *req = ctx->req; + const struct kr_module *module = ctx->api->data; + const struct kr_rplan *rplan = &req->rplan; + const 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.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) { + if (req->qsource.flags.tcp) { + m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP; + } else { + m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__UDP; + } + m.has_socket_protocol = true; + + 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_usec * 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_usec * 1000; + m.has_response_time_nsec = true; + + /* Query Zone */ + if (rplan->resolved.len > 0) { + struct kr_query *last = array_tail(rplan->resolved); + /* Only add query_zone when not answered from cache */ + if (!(last->flags.CACHED)) { + const knot_dname_t *zone_cut_name = last->zone_cut.name; + if (zone_cut_name != NULL) { + m.query_zone.data = (uint8_t *)zone_cut_name; + m.query_zone.len = knot_dname_size(zone_cut_name); + 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) { + /* 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) { + 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/knot/knot-dns/blob/master/src/knot/modules/dnstap.c#L159 + */ +static struct fstrm_writer* dnstap_unix_writer(const char *path) { + + auto_destroy_uopts struct fstrm_unix_writer_options *opt = fstrm_unix_writer_options_init(); + if (!opt) { + return NULL; + } + fstrm_unix_writer_options_set_socket_path(opt, path); + + auto_destroy_wopts struct fstrm_writer_options *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)); + + struct fstrm_writer *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_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; + auto_free char *sock_path = NULL; + + /* 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); + struct fstrm_writer *writer = dnstap_unix_writer(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) { + fstrm_iothr_destroy(&data->iothread); + DEBUG_MSG("can't get fstrm queue\n"); + return kr_error(EBUSY); + } + + return kr_ok(); +} + +KR_EXPORT +const kr_layer_api_t *dnstap_layer(struct kr_module *module) { + static kr_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 index 0000000..9a44dc2 --- /dev/null +++ b/modules/dnstap/dnstap.mk @@ -0,0 +1,8 @@ +dnstap_CFLAGS := -fPIC +dnstap_SOURCES := modules/dnstap/dnstap.pb-c.c modules/dnstap/dnstap.c +dnstap_DEPEND := $(libkres) modules/dnstap/dnstap.pb-c.c # because of generated *.h +dnstap_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS) $(libprotobuf-c_LIBS) $(libfstrm_LIBS) +$(call make_c_module,dnstap) + +modules/dnstap/dnstap.pb-c.c: modules/dnstap/dnstap.proto + protoc-c $< --c_out=. diff --git a/modules/dnstap/dnstap.pb-c.c b/modules/dnstap/dnstap.pb-c.c new file mode 100644 index 0000000..94d11c3 --- /dev/null +++ b/modules/dnstap/dnstap.pb-c.c @@ -0,0 +1,523 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: modules/dnstap/dnstap.proto */ + +/* Do not generate deprecated warnings for self */ +#ifndef PROTOBUF_C__NO_DEPRECATED +#define PROTOBUF_C__NO_DEPRECATED +#endif + +#include "modules/dnstap/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/modules/dnstap/dnstap.pb-c.h b/modules/dnstap/dnstap.pb-c.h new file mode 100644 index 0000000..51d5fee --- /dev/null +++ b/modules/dnstap/dnstap.pb-c.h @@ -0,0 +1,343 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: modules/dnstap/dnstap.proto */ + +#ifndef PROTOBUF_C_modules_2fdnstap_2fdnstap_2eproto__INCLUDED +#define PROTOBUF_C_modules_2fdnstap_2fdnstap_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_modules_2fdnstap_2fdnstap_2eproto__INCLUDED */ diff --git a/modules/dnstap/dnstap.proto b/modules/dnstap/dnstap.proto new file mode 100644 index 0000000..ed87c65 --- /dev/null +++ b/modules/dnstap/dnstap.proto @@ -0,0 +1,269 @@ +// 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/>. + +syntax = "proto2"; +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 |