1 /* dnstap support for Unbound */
4 * Copyright (c) 2013-2014, Farsight Security, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the copyright holder nor the names of its
19 * contributors may be used to endorse or promote products derived from
20 * this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "dnstap/dnstap_config.h"
42 #include "ldns/sbuffer.h"
43 #include "util/config_file.h"
44 #include "util/net_help.h"
45 #include "util/netevent.h"
49 #include <protobuf-c/protobuf-c.h>
51 #include "dnstap/dnstap.h"
52 #include "dnstap/dnstap.pb-c.h"
54 #define DNSTAP_CONTENT_TYPE "protobuf:dnstap.Dnstap"
55 #define DNSTAP_INITIAL_BUF_SIZE 256
65 dt_pack(const Dnstap__Dnstap
*d
, void **buf
, size_t *sz
)
67 ProtobufCBufferSimple sbuf
;
69 memset(&sbuf
, 0, sizeof(sbuf
));
70 sbuf
.base
.append
= protobuf_c_buffer_simple_append
;
72 sbuf
.alloced
= DNSTAP_INITIAL_BUF_SIZE
;
73 sbuf
.data
= malloc(sbuf
.alloced
);
74 if (sbuf
.data
== NULL
)
76 sbuf
.must_free_data
= 1;
78 *sz
= dnstap__dnstap__pack_to_buffer(d
, (ProtobufCBuffer
*) &sbuf
);
79 if (sbuf
.data
== NULL
)
87 dt_send(const struct dt_env
*env
, void *buf
, size_t len_buf
)
92 res
= fstrm_iothr_submit(env
->iothr
, env
->ioq
, buf
, len_buf
,
93 fstrm_free_wrapper
, NULL
);
94 if (res
!= fstrm_res_success
)
99 dt_msg_init(const struct dt_env
*env
,
101 Dnstap__Message__Type mtype
)
103 memset(dm
, 0, sizeof(*dm
));
104 dm
->d
.base
.descriptor
= &dnstap__dnstap__descriptor
;
105 dm
->m
.base
.descriptor
= &dnstap__message__descriptor
;
106 dm
->d
.type
= DNSTAP__DNSTAP__TYPE__MESSAGE
;
107 dm
->d
.message
= &dm
->m
;
109 if (env
->identity
!= NULL
) {
110 dm
->d
.identity
.data
= (uint8_t *) env
->identity
;
111 dm
->d
.identity
.len
= (size_t) env
->len_identity
;
112 dm
->d
.has_identity
= 1;
114 if (env
->version
!= NULL
) {
115 dm
->d
.version
.data
= (uint8_t *) env
->version
;
116 dm
->d
.version
.len
= (size_t) env
->len_version
;
117 dm
->d
.has_version
= 1;
122 dt_create(const char *socket_path
, unsigned num_workers
)
126 struct fstrm_iothr_options
*fopt
;
127 struct fstrm_unix_writer_options
*fuwopt
;
128 struct fstrm_writer
*fw
;
129 struct fstrm_writer_options
*fwopt
;
131 verbose(VERB_OPS
, "opening dnstap socket %s", socket_path
);
132 log_assert(socket_path
!= NULL
);
133 log_assert(num_workers
> 0);
135 env
= (struct dt_env
*) calloc(1, sizeof(struct dt_env
));
139 fwopt
= fstrm_writer_options_init();
140 res
= fstrm_writer_options_add_content_type(fwopt
,
141 DNSTAP_CONTENT_TYPE
, sizeof(DNSTAP_CONTENT_TYPE
) - 1);
142 log_assert(res
== fstrm_res_success
);
144 fuwopt
= fstrm_unix_writer_options_init();
145 fstrm_unix_writer_options_set_socket_path(fuwopt
, socket_path
);
147 fw
= fstrm_unix_writer_init(fuwopt
, fwopt
);
148 log_assert(fw
!= NULL
);
150 fopt
= fstrm_iothr_options_init();
151 fstrm_iothr_options_set_num_input_queues(fopt
, num_workers
);
152 env
->iothr
= fstrm_iothr_init(fopt
, &fw
);
153 if (env
->iothr
== NULL
) {
154 verbose(VERB_DETAIL
, "dt_create: fstrm_iothr_init() failed");
155 fstrm_writer_destroy(&fw
);
159 fstrm_iothr_options_destroy(&fopt
);
160 fstrm_unix_writer_options_destroy(&fuwopt
);
161 fstrm_writer_options_destroy(&fwopt
);
167 dt_apply_identity(struct dt_env
*env
, struct config_file
*cfg
)
169 char buf
[MAXHOSTNAMELEN
+1];
170 if (!cfg
->dnstap_send_identity
)
173 if (cfg
->dnstap_identity
== NULL
|| cfg
->dnstap_identity
[0] == 0) {
174 if (gethostname(buf
, MAXHOSTNAMELEN
) == 0) {
175 buf
[MAXHOSTNAMELEN
] = 0;
176 env
->identity
= strdup(buf
);
178 fatal_exit("dt_apply_identity: gethostname() failed");
181 env
->identity
= strdup(cfg
->dnstap_identity
);
183 if (env
->identity
== NULL
)
184 fatal_exit("dt_apply_identity: strdup() failed");
185 env
->len_identity
= (unsigned int)strlen(env
->identity
);
186 verbose(VERB_OPS
, "dnstap identity field set to \"%s\"",
191 dt_apply_version(struct dt_env
*env
, struct config_file
*cfg
)
193 if (!cfg
->dnstap_send_version
)
196 if (cfg
->dnstap_version
== NULL
|| cfg
->dnstap_version
[0] == 0)
197 env
->version
= strdup(PACKAGE_STRING
);
199 env
->version
= strdup(cfg
->dnstap_version
);
200 if (env
->version
== NULL
)
201 fatal_exit("dt_apply_version: strdup() failed");
202 env
->len_version
= (unsigned int)strlen(env
->version
);
203 verbose(VERB_OPS
, "dnstap version field set to \"%s\"",
208 dt_apply_cfg(struct dt_env
*env
, struct config_file
*cfg
)
213 dt_apply_identity(env
, cfg
);
214 dt_apply_version(env
, cfg
);
215 if ((env
->log_resolver_query_messages
= (unsigned int)
216 cfg
->dnstap_log_resolver_query_messages
))
218 verbose(VERB_OPS
, "dnstap Message/RESOLVER_QUERY enabled");
220 if ((env
->log_resolver_response_messages
= (unsigned int)
221 cfg
->dnstap_log_resolver_response_messages
))
223 verbose(VERB_OPS
, "dnstap Message/RESOLVER_RESPONSE enabled");
225 if ((env
->log_client_query_messages
= (unsigned int)
226 cfg
->dnstap_log_client_query_messages
))
228 verbose(VERB_OPS
, "dnstap Message/CLIENT_QUERY enabled");
230 if ((env
->log_client_response_messages
= (unsigned int)
231 cfg
->dnstap_log_client_response_messages
))
233 verbose(VERB_OPS
, "dnstap Message/CLIENT_RESPONSE enabled");
235 if ((env
->log_forwarder_query_messages
= (unsigned int)
236 cfg
->dnstap_log_forwarder_query_messages
))
238 verbose(VERB_OPS
, "dnstap Message/FORWARDER_QUERY enabled");
240 if ((env
->log_forwarder_response_messages
= (unsigned int)
241 cfg
->dnstap_log_forwarder_response_messages
))
243 verbose(VERB_OPS
, "dnstap Message/FORWARDER_RESPONSE enabled");
248 dt_init(struct dt_env
*env
)
250 env
->ioq
= fstrm_iothr_get_input_queue(env
->iothr
);
251 if (env
->ioq
== NULL
)
257 dt_delete(struct dt_env
*env
)
261 verbose(VERB_OPS
, "closing dnstap socket");
262 fstrm_iothr_destroy(&env
->iothr
);
269 dt_fill_timeval(const struct timeval
*tv
,
270 uint64_t *time_sec
, protobuf_c_boolean
*has_time_sec
,
271 uint32_t *time_nsec
, protobuf_c_boolean
*has_time_nsec
)
274 *time_sec
= tv
->tv_sec
;
275 *time_nsec
= tv
->tv_usec
* 1000;
282 dt_fill_buffer(sldns_buffer
*b
, ProtobufCBinaryData
*p
, protobuf_c_boolean
*has
)
284 log_assert(b
!= NULL
);
285 p
->len
= sldns_buffer_limit(b
);
286 p
->data
= sldns_buffer_begin(b
);
291 dt_msg_fill_net(struct dt_msg
*dm
,
292 struct sockaddr_storage
*ss
,
293 enum comm_point_type cptype
,
294 ProtobufCBinaryData
*addr
, protobuf_c_boolean
*has_addr
,
295 uint32_t *port
, protobuf_c_boolean
*has_port
)
297 log_assert(ss
->ss_family
== AF_INET6
|| ss
->ss_family
== AF_INET
);
298 if (ss
->ss_family
== AF_INET6
) {
299 struct sockaddr_in6
*s
= (struct sockaddr_in6
*) ss
;
302 dm
->m
.socket_family
= DNSTAP__SOCKET_FAMILY__INET6
;
303 dm
->m
.has_socket_family
= 1;
305 /* addr: query_address or response_address */
306 addr
->data
= s
->sin6_addr
.s6_addr
;
307 addr
->len
= 16; /* IPv6 */
310 /* port: query_port or response_port */
311 *port
= ntohs(s
->sin6_port
);
313 } else if (ss
->ss_family
== AF_INET
) {
314 struct sockaddr_in
*s
= (struct sockaddr_in
*) ss
;
317 dm
->m
.socket_family
= DNSTAP__SOCKET_FAMILY__INET
;
318 dm
->m
.has_socket_family
= 1;
320 /* addr: query_address or response_address */
321 addr
->data
= (uint8_t *) &s
->sin_addr
.s_addr
;
322 addr
->len
= 4; /* IPv4 */
325 /* port: query_port or response_port */
326 *port
= ntohs(s
->sin_port
);
330 log_assert(cptype
== comm_udp
|| cptype
== comm_tcp
);
331 if (cptype
== comm_udp
) {
332 /* socket_protocol */
333 dm
->m
.socket_protocol
= DNSTAP__SOCKET_PROTOCOL__UDP
;
334 dm
->m
.has_socket_protocol
= 1;
335 } else if (cptype
== comm_tcp
) {
336 /* socket_protocol */
337 dm
->m
.socket_protocol
= DNSTAP__SOCKET_PROTOCOL__TCP
;
338 dm
->m
.has_socket_protocol
= 1;
343 dt_msg_send_client_query(struct dt_env
*env
,
344 struct sockaddr_storage
*qsock
,
345 enum comm_point_type cptype
,
349 struct timeval qtime
;
351 gettimeofday(&qtime
, NULL
);
354 dt_msg_init(env
, &dm
, DNSTAP__MESSAGE__TYPE__CLIENT_QUERY
);
357 dt_fill_timeval(&qtime
,
358 &dm
.m
.query_time_sec
, &dm
.m
.has_query_time_sec
,
359 &dm
.m
.query_time_nsec
, &dm
.m
.has_query_time_nsec
);
362 dt_fill_buffer(qmsg
, &dm
.m
.query_message
, &dm
.m
.has_query_message
);
364 /* socket_family, socket_protocol, query_address, query_port */
365 log_assert(cptype
== comm_udp
|| cptype
== comm_tcp
);
366 dt_msg_fill_net(&dm
, qsock
, cptype
,
367 &dm
.m
.query_address
, &dm
.m
.has_query_address
,
368 &dm
.m
.query_port
, &dm
.m
.has_query_port
);
370 if (dt_pack(&dm
.d
, &dm
.buf
, &dm
.len_buf
))
371 dt_send(env
, dm
.buf
, dm
.len_buf
);
375 dt_msg_send_client_response(struct dt_env
*env
,
376 struct sockaddr_storage
*qsock
,
377 enum comm_point_type cptype
,
381 struct timeval rtime
;
383 gettimeofday(&rtime
, NULL
);
386 dt_msg_init(env
, &dm
, DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE
);
389 dt_fill_timeval(&rtime
,
390 &dm
.m
.response_time_sec
, &dm
.m
.has_response_time_sec
,
391 &dm
.m
.response_time_nsec
, &dm
.m
.has_response_time_nsec
);
393 /* response_message */
394 dt_fill_buffer(rmsg
, &dm
.m
.response_message
, &dm
.m
.has_response_message
);
396 /* socket_family, socket_protocol, query_address, query_port */
397 log_assert(cptype
== comm_udp
|| cptype
== comm_tcp
);
398 dt_msg_fill_net(&dm
, qsock
, cptype
,
399 &dm
.m
.query_address
, &dm
.m
.has_query_address
,
400 &dm
.m
.query_port
, &dm
.m
.has_query_port
);
402 if (dt_pack(&dm
.d
, &dm
.buf
, &dm
.len_buf
))
403 dt_send(env
, dm
.buf
, dm
.len_buf
);
407 dt_msg_send_outside_query(struct dt_env
*env
,
408 struct sockaddr_storage
*rsock
,
409 enum comm_point_type cptype
,
410 uint8_t *zone
, size_t zone_len
,
414 struct timeval qtime
;
417 gettimeofday(&qtime
, NULL
);
418 qflags
= sldns_buffer_read_u16_at(qmsg
, 2);
421 if (qflags
& BIT_RD
) {
422 if (!env
->log_forwarder_query_messages
)
424 dt_msg_init(env
, &dm
, DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY
);
426 if (!env
->log_resolver_query_messages
)
428 dt_msg_init(env
, &dm
, DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY
);
432 dm
.m
.query_zone
.data
= zone
;
433 dm
.m
.query_zone
.len
= zone_len
;
434 dm
.m
.has_query_zone
= 1;
436 /* query_time_sec, query_time_nsec */
437 dt_fill_timeval(&qtime
,
438 &dm
.m
.query_time_sec
, &dm
.m
.has_query_time_sec
,
439 &dm
.m
.query_time_nsec
, &dm
.m
.has_query_time_nsec
);
442 dt_fill_buffer(qmsg
, &dm
.m
.query_message
, &dm
.m
.has_query_message
);
444 /* socket_family, socket_protocol, response_address, response_port */
445 log_assert(cptype
== comm_udp
|| cptype
== comm_tcp
);
446 dt_msg_fill_net(&dm
, rsock
, cptype
,
447 &dm
.m
.response_address
, &dm
.m
.has_response_address
,
448 &dm
.m
.response_port
, &dm
.m
.has_response_port
);
450 if (dt_pack(&dm
.d
, &dm
.buf
, &dm
.len_buf
))
451 dt_send(env
, dm
.buf
, dm
.len_buf
);
455 dt_msg_send_outside_response(struct dt_env
*env
,
456 struct sockaddr_storage
*rsock
,
457 enum comm_point_type cptype
,
458 uint8_t *zone
, size_t zone_len
,
459 uint8_t *qbuf
, size_t qbuf_len
,
460 const struct timeval
*qtime
,
461 const struct timeval
*rtime
,
467 log_assert(qbuf_len
>= sizeof(qflags
));
468 memcpy(&qflags
, qbuf
, sizeof(qflags
));
469 qflags
= ntohs(qflags
);
472 if (qflags
& BIT_RD
) {
473 if (!env
->log_forwarder_response_messages
)
475 dt_msg_init(env
, &dm
, DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE
);
477 if (!env
->log_resolver_query_messages
)
479 dt_msg_init(env
, &dm
, DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE
);
483 dm
.m
.query_zone
.data
= zone
;
484 dm
.m
.query_zone
.len
= zone_len
;
485 dm
.m
.has_query_zone
= 1;
487 /* query_time_sec, query_time_nsec */
488 dt_fill_timeval(qtime
,
489 &dm
.m
.query_time_sec
, &dm
.m
.has_query_time_sec
,
490 &dm
.m
.query_time_nsec
, &dm
.m
.has_query_time_nsec
);
492 /* response_time_sec, response_time_nsec */
493 dt_fill_timeval(rtime
,
494 &dm
.m
.response_time_sec
, &dm
.m
.has_response_time_sec
,
495 &dm
.m
.response_time_nsec
, &dm
.m
.has_response_time_nsec
);
497 /* response_message */
498 dt_fill_buffer(rmsg
, &dm
.m
.response_message
, &dm
.m
.has_response_message
);
500 /* socket_family, socket_protocol, response_address, response_port */
501 log_assert(cptype
== comm_udp
|| cptype
== comm_tcp
);
502 dt_msg_fill_net(&dm
, rsock
, cptype
,
503 &dm
.m
.response_address
, &dm
.m
.has_response_address
,
504 &dm
.m
.response_port
, &dm
.m
.has_response_port
);
506 if (dt_pack(&dm
.d
, &dm
.buf
, &dm
.len_buf
))
507 dt_send(env
, dm
.buf
, dm
.len_buf
);
510 #endif /* USE_DNSTAP */