1 /* $NetBSD: dnstap.c,v 1.1 2024/02/18 20:57:31 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16 /*
17 * Copyright (c) 2013-2014, Farsight Security, Inc.
18 * All rights reserved.
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions
22 * are met:
23 *
24 * 1. Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
26 *
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 *
31 * 3. Neither the name of the copyright holder nor the names of its
32 * contributors may be used to endorse or promote products derived from
33 * this software without specific prior written permission.
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
37 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
39 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
40 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
41 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
42 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
43 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
44 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
45 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 */
47
48 /*! \file */
49
50 #ifndef HAVE_DNSTAP
51 #error DNSTAP not configured.
52 #endif /* HAVE_DNSTAP */
53
54 #include <fstrm.h>
55 #include <inttypes.h>
56 #include <stdbool.h>
57 #include <stdlib.h>
58
59 #include <isc/buffer.h>
60 #include <isc/file.h>
61 #include <isc/log.h>
62 #include <isc/mem.h>
63 #include <isc/mutex.h>
64 #include <isc/once.h>
65 #include <isc/print.h>
66 #include <isc/sockaddr.h>
67 #include <isc/task.h>
68 #include <isc/thread.h>
69 #include <isc/time.h>
70 #include <isc/types.h>
71 #include <isc/util.h>
72
73 #include <dns/dnstap.h>
74 #include <dns/events.h>
75 #include <dns/log.h>
76 #include <dns/message.h>
77 #include <dns/name.h>
78 #include <dns/rdataset.h>
79 #include <dns/result.h>
80 #include <dns/stats.h>
81 #include <dns/types.h>
82 #include <dns/view.h>
83
84 #include "dnstap.pb-c.h"
85
86 #define DTENV_MAGIC ISC_MAGIC('D', 't', 'n', 'v')
87 #define VALID_DTENV(env) ISC_MAGIC_VALID(env, DTENV_MAGIC)
88
89 #define DNSTAP_CONTENT_TYPE "protobuf:dnstap.Dnstap"
90 #define DNSTAP_INITIAL_BUF_SIZE 256
91
92 struct dns_dtmsg {
93 void *buf;
94 size_t len;
95 Dnstap__Dnstap d;
96 Dnstap__Message m;
97 };
98
99 struct dns_dthandle {
100 dns_dtmode_t mode;
101 struct fstrm_reader *reader;
102 isc_mem_t *mctx;
103 };
104
105 struct dns_dtenv {
106 unsigned int magic;
107 isc_refcount_t refcount;
108
109 isc_mem_t *mctx;
110
111 struct fstrm_iothr *iothr;
112 struct fstrm_iothr_options *fopt;
113
114 isc_task_t *reopen_task;
115 isc_mutex_t reopen_lock; /* locks 'reopen_queued'
116 * */
117 bool reopen_queued;
118
119 isc_region_t identity;
120 isc_region_t version;
121 char *path;
122 dns_dtmode_t mode;
123 isc_offset_t max_size;
124 int rolls;
125 isc_log_rollsuffix_t suffix;
126 isc_stats_t *stats;
127 };
128
129 #define CHECK(x) \
130 do { \
131 result = (x); \
132 if (result != ISC_R_SUCCESS) \
133 goto cleanup; \
134 } while (0)
135
136 typedef struct ioq {
137 unsigned int generation;
138 struct fstrm_iothr_queue *ioq;
139 } dt__ioq_t;
140
141 ISC_THREAD_LOCAL dt__ioq_t dt_ioq = { 0 };
142
143 static atomic_uint_fast32_t global_generation;
144
145 isc_result_t
dns_dt_create(isc_mem_t * mctx,dns_dtmode_t mode,const char * path,struct fstrm_iothr_options ** foptp,isc_task_t * reopen_task,dns_dtenv_t ** envp)146 dns_dt_create(isc_mem_t *mctx, dns_dtmode_t mode, const char *path,
147 struct fstrm_iothr_options **foptp, isc_task_t *reopen_task,
148 dns_dtenv_t **envp) {
149 isc_result_t result = ISC_R_SUCCESS;
150 fstrm_res res;
151 struct fstrm_unix_writer_options *fuwopt = NULL;
152 struct fstrm_file_options *ffwopt = NULL;
153 struct fstrm_writer_options *fwopt = NULL;
154 struct fstrm_writer *fw = NULL;
155 dns_dtenv_t *env = NULL;
156
157 REQUIRE(path != NULL);
158 REQUIRE(envp != NULL && *envp == NULL);
159 REQUIRE(foptp != NULL && *foptp != NULL);
160
161 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP, DNS_LOGMODULE_DNSTAP,
162 ISC_LOG_INFO, "opening dnstap destination '%s'", path);
163
164 atomic_fetch_add_release(&global_generation, 1);
165
166 env = isc_mem_get(mctx, sizeof(dns_dtenv_t));
167
168 memset(env, 0, sizeof(dns_dtenv_t));
169 isc_mem_attach(mctx, &env->mctx);
170 env->reopen_task = reopen_task;
171 isc_mutex_init(&env->reopen_lock);
172 env->reopen_queued = false;
173 env->path = isc_mem_strdup(env->mctx, path);
174 isc_refcount_init(&env->refcount, 1);
175 CHECK(isc_stats_create(env->mctx, &env->stats, dns_dnstapcounter_max));
176
177 fwopt = fstrm_writer_options_init();
178 if (fwopt == NULL) {
179 CHECK(ISC_R_NOMEMORY);
180 }
181
182 res = fstrm_writer_options_add_content_type(
183 fwopt, DNSTAP_CONTENT_TYPE, sizeof(DNSTAP_CONTENT_TYPE) - 1);
184 if (res != fstrm_res_success) {
185 CHECK(ISC_R_FAILURE);
186 }
187
188 if (mode == dns_dtmode_file) {
189 ffwopt = fstrm_file_options_init();
190 if (ffwopt != NULL) {
191 fstrm_file_options_set_file_path(ffwopt, env->path);
192 fw = fstrm_file_writer_init(ffwopt, fwopt);
193 }
194 } else if (mode == dns_dtmode_unix) {
195 fuwopt = fstrm_unix_writer_options_init();
196 if (fuwopt != NULL) {
197 fstrm_unix_writer_options_set_socket_path(fuwopt,
198 env->path);
199 fw = fstrm_unix_writer_init(fuwopt, fwopt);
200 }
201 } else {
202 CHECK(ISC_R_FAILURE);
203 }
204
205 if (fw == NULL) {
206 CHECK(ISC_R_FAILURE);
207 }
208
209 env->iothr = fstrm_iothr_init(*foptp, &fw);
210 if (env->iothr == NULL) {
211 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP,
212 DNS_LOGMODULE_DNSTAP, ISC_LOG_WARNING,
213 "unable to initialize dnstap I/O thread");
214 fstrm_writer_destroy(&fw);
215 CHECK(ISC_R_FAILURE);
216 }
217 env->mode = mode;
218 env->max_size = 0;
219 env->rolls = ISC_LOG_ROLLINFINITE;
220 env->fopt = *foptp;
221 *foptp = NULL;
222
223 env->magic = DTENV_MAGIC;
224 *envp = env;
225
226 cleanup:
227 if (ffwopt != NULL) {
228 fstrm_file_options_destroy(&ffwopt);
229 }
230
231 if (fuwopt != NULL) {
232 fstrm_unix_writer_options_destroy(&fuwopt);
233 }
234
235 if (fwopt != NULL) {
236 fstrm_writer_options_destroy(&fwopt);
237 }
238
239 if (result != ISC_R_SUCCESS) {
240 isc_mutex_destroy(&env->reopen_lock);
241 isc_mem_free(env->mctx, env->path);
242 if (env->stats != NULL) {
243 isc_stats_detach(&env->stats);
244 }
245 isc_mem_putanddetach(&env->mctx, env, sizeof(dns_dtenv_t));
246 }
247
248 return (result);
249 }
250
251 isc_result_t
dns_dt_setupfile(dns_dtenv_t * env,uint64_t max_size,int rolls,isc_log_rollsuffix_t suffix)252 dns_dt_setupfile(dns_dtenv_t *env, uint64_t max_size, int rolls,
253 isc_log_rollsuffix_t suffix) {
254 REQUIRE(VALID_DTENV(env));
255
256 /*
257 * If we're using unix domain socket mode, then any
258 * change from the default values is invalid.
259 */
260 if (env->mode == dns_dtmode_unix) {
261 if (max_size == 0 && rolls == ISC_LOG_ROLLINFINITE &&
262 suffix == isc_log_rollsuffix_increment)
263 {
264 return (ISC_R_SUCCESS);
265 } else {
266 return (ISC_R_INVALIDFILE);
267 }
268 }
269
270 env->max_size = max_size;
271 env->rolls = rolls;
272 env->suffix = suffix;
273
274 return (ISC_R_SUCCESS);
275 }
276
277 isc_result_t
dns_dt_reopen(dns_dtenv_t * env,int roll)278 dns_dt_reopen(dns_dtenv_t *env, int roll) {
279 isc_result_t result = ISC_R_SUCCESS;
280 fstrm_res res;
281 isc_logfile_t file;
282 struct fstrm_unix_writer_options *fuwopt = NULL;
283 struct fstrm_file_options *ffwopt = NULL;
284 struct fstrm_writer_options *fwopt = NULL;
285 struct fstrm_writer *fw = NULL;
286
287 REQUIRE(VALID_DTENV(env));
288
289 /*
290 * Run in task-exclusive mode.
291 */
292 result = isc_task_beginexclusive(env->reopen_task);
293 RUNTIME_CHECK(result == ISC_R_SUCCESS);
294
295 /*
296 * Check that we can create a new fw object.
297 */
298 fwopt = fstrm_writer_options_init();
299 if (fwopt == NULL) {
300 CHECK(ISC_R_NOMEMORY);
301 }
302
303 res = fstrm_writer_options_add_content_type(
304 fwopt, DNSTAP_CONTENT_TYPE, sizeof(DNSTAP_CONTENT_TYPE) - 1);
305 if (res != fstrm_res_success) {
306 CHECK(ISC_R_FAILURE);
307 }
308
309 if (env->mode == dns_dtmode_file) {
310 ffwopt = fstrm_file_options_init();
311 if (ffwopt != NULL) {
312 fstrm_file_options_set_file_path(ffwopt, env->path);
313 fw = fstrm_file_writer_init(ffwopt, fwopt);
314 }
315 } else if (env->mode == dns_dtmode_unix) {
316 fuwopt = fstrm_unix_writer_options_init();
317 if (fuwopt != NULL) {
318 fstrm_unix_writer_options_set_socket_path(fuwopt,
319 env->path);
320 fw = fstrm_unix_writer_init(fuwopt, fwopt);
321 }
322 } else {
323 CHECK(ISC_R_NOTIMPLEMENTED);
324 }
325
326 if (fw == NULL) {
327 CHECK(ISC_R_FAILURE);
328 }
329
330 /*
331 * We are committed here.
332 */
333 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP, DNS_LOGMODULE_DNSTAP,
334 ISC_LOG_INFO, "%s dnstap destination '%s'",
335 (roll < 0) ? "reopening" : "rolling", env->path);
336
337 atomic_fetch_add_release(&global_generation, 1);
338
339 if (env->iothr != NULL) {
340 fstrm_iothr_destroy(&env->iothr);
341 }
342
343 if (roll == 0) {
344 roll = env->rolls;
345 }
346
347 if (env->mode == dns_dtmode_file && roll != 0) {
348 /*
349 * Create a temporary isc_logfile_t structure so we can
350 * take advantage of the logfile rolling facility.
351 */
352 char *filename = isc_mem_strdup(env->mctx, env->path);
353 file.name = filename;
354 file.stream = NULL;
355 file.versions = roll;
356 file.maximum_size = 0;
357 file.maximum_reached = false;
358 file.suffix = env->suffix;
359 result = isc_logfile_roll(&file);
360 isc_mem_free(env->mctx, filename);
361 CHECK(result);
362 }
363
364 env->iothr = fstrm_iothr_init(env->fopt, &fw);
365 if (env->iothr == NULL) {
366 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP,
367 DNS_LOGMODULE_DNSTAP, ISC_LOG_WARNING,
368 "unable to initialize dnstap I/O thread");
369 CHECK(ISC_R_FAILURE);
370 }
371
372 cleanup:
373 if (fw != NULL) {
374 fstrm_writer_destroy(&fw);
375 }
376
377 if (fuwopt != NULL) {
378 fstrm_unix_writer_options_destroy(&fuwopt);
379 }
380
381 if (ffwopt != NULL) {
382 fstrm_file_options_destroy(&ffwopt);
383 }
384
385 if (fwopt != NULL) {
386 fstrm_writer_options_destroy(&fwopt);
387 }
388
389 isc_task_endexclusive(env->reopen_task);
390
391 return (result);
392 }
393
394 static isc_result_t
toregion(dns_dtenv_t * env,isc_region_t * r,const char * str)395 toregion(dns_dtenv_t *env, isc_region_t *r, const char *str) {
396 unsigned char *p = NULL;
397
398 REQUIRE(r != NULL);
399
400 if (str != NULL) {
401 p = (unsigned char *)isc_mem_strdup(env->mctx, str);
402 }
403
404 if (r->base != NULL) {
405 isc_mem_free(env->mctx, r->base);
406 r->length = 0;
407 }
408
409 if (p != NULL) {
410 r->base = p;
411 r->length = strlen((char *)p);
412 }
413
414 return (ISC_R_SUCCESS);
415 }
416
417 isc_result_t
dns_dt_setidentity(dns_dtenv_t * env,const char * identity)418 dns_dt_setidentity(dns_dtenv_t *env, const char *identity) {
419 REQUIRE(VALID_DTENV(env));
420
421 return (toregion(env, &env->identity, identity));
422 }
423
424 isc_result_t
dns_dt_setversion(dns_dtenv_t * env,const char * version)425 dns_dt_setversion(dns_dtenv_t *env, const char *version) {
426 REQUIRE(VALID_DTENV(env));
427
428 return (toregion(env, &env->version, version));
429 }
430
431 static void
set_dt_ioq(unsigned int generation,struct fstrm_iothr_queue * ioq)432 set_dt_ioq(unsigned int generation, struct fstrm_iothr_queue *ioq) {
433 dt_ioq.generation = generation;
434 dt_ioq.ioq = ioq;
435 }
436
437 static struct fstrm_iothr_queue *
dt_queue(dns_dtenv_t * env)438 dt_queue(dns_dtenv_t *env) {
439 REQUIRE(VALID_DTENV(env));
440
441 unsigned int generation;
442
443 if (env->iothr == NULL) {
444 return (NULL);
445 }
446
447 generation = atomic_load_acquire(&global_generation);
448 if (dt_ioq.ioq != NULL && dt_ioq.generation != generation) {
449 set_dt_ioq(0, NULL);
450 }
451 if (dt_ioq.ioq == NULL) {
452 struct fstrm_iothr_queue *ioq =
453 fstrm_iothr_get_input_queue(env->iothr);
454 set_dt_ioq(generation, ioq);
455 }
456
457 return (dt_ioq.ioq);
458 }
459
460 void
dns_dt_attach(dns_dtenv_t * source,dns_dtenv_t ** destp)461 dns_dt_attach(dns_dtenv_t *source, dns_dtenv_t **destp) {
462 REQUIRE(VALID_DTENV(source));
463 REQUIRE(destp != NULL && *destp == NULL);
464
465 isc_refcount_increment(&source->refcount);
466 *destp = source;
467 }
468
469 isc_result_t
dns_dt_getstats(dns_dtenv_t * env,isc_stats_t ** statsp)470 dns_dt_getstats(dns_dtenv_t *env, isc_stats_t **statsp) {
471 REQUIRE(VALID_DTENV(env));
472 REQUIRE(statsp != NULL && *statsp == NULL);
473
474 if (env->stats == NULL) {
475 return (ISC_R_NOTFOUND);
476 }
477 isc_stats_attach(env->stats, statsp);
478 return (ISC_R_SUCCESS);
479 }
480
481 static void
destroy(dns_dtenv_t * env)482 destroy(dns_dtenv_t *env) {
483 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP, DNS_LOGMODULE_DNSTAP,
484 ISC_LOG_INFO, "closing dnstap");
485 env->magic = 0;
486
487 atomic_fetch_add(&global_generation, 1);
488
489 if (env->iothr != NULL) {
490 fstrm_iothr_destroy(&env->iothr);
491 }
492 if (env->fopt != NULL) {
493 fstrm_iothr_options_destroy(&env->fopt);
494 }
495
496 if (env->identity.base != NULL) {
497 isc_mem_free(env->mctx, env->identity.base);
498 env->identity.length = 0;
499 }
500 if (env->version.base != NULL) {
501 isc_mem_free(env->mctx, env->version.base);
502 env->version.length = 0;
503 }
504 if (env->path != NULL) {
505 isc_mem_free(env->mctx, env->path);
506 }
507 if (env->stats != NULL) {
508 isc_stats_detach(&env->stats);
509 }
510
511 isc_mem_putanddetach(&env->mctx, env, sizeof(*env));
512 }
513
514 void
dns_dt_detach(dns_dtenv_t ** envp)515 dns_dt_detach(dns_dtenv_t **envp) {
516 REQUIRE(envp != NULL && VALID_DTENV(*envp));
517 dns_dtenv_t *env = *envp;
518 *envp = NULL;
519
520 if (isc_refcount_decrement(&env->refcount) == 1) {
521 isc_refcount_destroy(&env->refcount);
522 destroy(env);
523 }
524 }
525
526 static isc_result_t
pack_dt(const Dnstap__Dnstap * d,void ** buf,size_t * sz)527 pack_dt(const Dnstap__Dnstap *d, void **buf, size_t *sz) {
528 ProtobufCBufferSimple sbuf;
529
530 REQUIRE(d != NULL);
531 REQUIRE(sz != NULL);
532
533 memset(&sbuf, 0, sizeof(sbuf));
534 sbuf.base.append = protobuf_c_buffer_simple_append;
535 sbuf.len = 0;
536 sbuf.alloced = DNSTAP_INITIAL_BUF_SIZE;
537
538 /* Need to use malloc() here because protobuf uses free() */
539 sbuf.data = malloc(sbuf.alloced);
540 if (sbuf.data == NULL) {
541 return (ISC_R_NOMEMORY);
542 }
543 sbuf.must_free_data = 1;
544
545 *sz = dnstap__dnstap__pack_to_buffer(d, (ProtobufCBuffer *)&sbuf);
546 if (sbuf.data == NULL) {
547 return (ISC_R_FAILURE);
548 }
549 *buf = sbuf.data;
550
551 return (ISC_R_SUCCESS);
552 }
553
554 static void
send_dt(dns_dtenv_t * env,void * buf,size_t len)555 send_dt(dns_dtenv_t *env, void *buf, size_t len) {
556 struct fstrm_iothr_queue *ioq;
557 fstrm_res res;
558
559 REQUIRE(env != NULL);
560
561 if (buf == NULL) {
562 return;
563 }
564
565 ioq = dt_queue(env);
566 if (ioq == NULL) {
567 free(buf);
568 return;
569 }
570
571 res = fstrm_iothr_submit(env->iothr, ioq, buf, len, fstrm_free_wrapper,
572 NULL);
573 if (res != fstrm_res_success) {
574 if (env->stats != NULL) {
575 isc_stats_increment(env->stats, dns_dnstapcounter_drop);
576 }
577 free(buf);
578 } else {
579 if (env->stats != NULL) {
580 isc_stats_increment(env->stats,
581 dns_dnstapcounter_success);
582 }
583 }
584 }
585
586 static void
init_msg(dns_dtenv_t * env,dns_dtmsg_t * dm,Dnstap__Message__Type mtype)587 init_msg(dns_dtenv_t *env, dns_dtmsg_t *dm, Dnstap__Message__Type mtype) {
588 memset(dm, 0, sizeof(*dm));
589 dm->d.base.descriptor = &dnstap__dnstap__descriptor;
590 dm->m.base.descriptor = &dnstap__message__descriptor;
591 dm->d.type = DNSTAP__DNSTAP__TYPE__MESSAGE;
592 dm->d.message = &dm->m;
593 dm->m.type = mtype;
594
595 if (env->identity.length != 0) {
596 dm->d.identity.data = env->identity.base;
597 dm->d.identity.len = env->identity.length;
598 dm->d.has_identity = true;
599 }
600
601 if (env->version.length != 0) {
602 dm->d.version.data = env->version.base;
603 dm->d.version.len = env->version.length;
604 dm->d.has_version = true;
605 }
606 }
607
608 static Dnstap__Message__Type
dnstap_type(dns_dtmsgtype_t msgtype)609 dnstap_type(dns_dtmsgtype_t msgtype) {
610 switch (msgtype) {
611 case DNS_DTTYPE_SQ:
612 return (DNSTAP__MESSAGE__TYPE__STUB_QUERY);
613 case DNS_DTTYPE_SR:
614 return (DNSTAP__MESSAGE__TYPE__STUB_RESPONSE);
615 case DNS_DTTYPE_CQ:
616 return (DNSTAP__MESSAGE__TYPE__CLIENT_QUERY);
617 case DNS_DTTYPE_CR:
618 return (DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE);
619 case DNS_DTTYPE_AQ:
620 return (DNSTAP__MESSAGE__TYPE__AUTH_QUERY);
621 case DNS_DTTYPE_AR:
622 return (DNSTAP__MESSAGE__TYPE__AUTH_RESPONSE);
623 case DNS_DTTYPE_RQ:
624 return (DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY);
625 case DNS_DTTYPE_RR:
626 return (DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE);
627 case DNS_DTTYPE_FQ:
628 return (DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY);
629 case DNS_DTTYPE_FR:
630 return (DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE);
631 case DNS_DTTYPE_TQ:
632 return (DNSTAP__MESSAGE__TYPE__TOOL_QUERY);
633 case DNS_DTTYPE_TR:
634 return (DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE);
635 case DNS_DTTYPE_UQ:
636 return (DNSTAP__MESSAGE__TYPE__UPDATE_QUERY);
637 case DNS_DTTYPE_UR:
638 return (DNSTAP__MESSAGE__TYPE__UPDATE_RESPONSE);
639 default:
640 UNREACHABLE();
641 }
642 }
643
644 static void
cpbuf(isc_buffer_t * buf,ProtobufCBinaryData * p,protobuf_c_boolean * has)645 cpbuf(isc_buffer_t *buf, ProtobufCBinaryData *p, protobuf_c_boolean *has) {
646 p->data = isc_buffer_base(buf);
647 p->len = isc_buffer_usedlength(buf);
648 *has = 1;
649 }
650
651 static void
setaddr(dns_dtmsg_t * dm,isc_sockaddr_t * sa,bool tcp,ProtobufCBinaryData * addr,protobuf_c_boolean * has_addr,uint32_t * port,protobuf_c_boolean * has_port)652 setaddr(dns_dtmsg_t *dm, isc_sockaddr_t *sa, bool tcp,
653 ProtobufCBinaryData *addr, protobuf_c_boolean *has_addr, uint32_t *port,
654 protobuf_c_boolean *has_port) {
655 int family = isc_sockaddr_pf(sa);
656
657 if (family != AF_INET6 && family != AF_INET) {
658 return;
659 }
660
661 if (family == AF_INET6) {
662 dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET6;
663 addr->data = sa->type.sin6.sin6_addr.s6_addr;
664 addr->len = 16;
665 *port = ntohs(sa->type.sin6.sin6_port);
666 } else {
667 dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET;
668 addr->data = (uint8_t *)&sa->type.sin.sin_addr.s_addr;
669 addr->len = 4;
670 *port = ntohs(sa->type.sin.sin_port);
671 }
672
673 if (tcp) {
674 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP;
675 } else {
676 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__UDP;
677 }
678
679 dm->m.has_socket_protocol = 1;
680 dm->m.has_socket_family = 1;
681 *has_addr = 1;
682 *has_port = 1;
683 }
684
685 /*%
686 * Invoke dns_dt_reopen() and re-allow dnstap output file rolling. This
687 * function is run in the context of the task stored in the 'reopen_task' field
688 * of the dnstap environment structure.
689 */
690 static void
perform_reopen(isc_task_t * task,isc_event_t * event)691 perform_reopen(isc_task_t *task, isc_event_t *event) {
692 dns_dtenv_t *env;
693
694 REQUIRE(event != NULL);
695 REQUIRE(event->ev_type == DNS_EVENT_FREESTORAGE);
696
697 env = (dns_dtenv_t *)event->ev_arg;
698
699 REQUIRE(VALID_DTENV(env));
700 REQUIRE(task == env->reopen_task);
701
702 /*
703 * Roll output file in the context of env->reopen_task.
704 */
705 dns_dt_reopen(env, env->rolls);
706
707 /*
708 * Clean up.
709 */
710 isc_event_free(&event);
711 isc_task_detach(&task);
712
713 /*
714 * Re-allow output file rolling.
715 */
716 LOCK(&env->reopen_lock);
717 env->reopen_queued = false;
718 UNLOCK(&env->reopen_lock);
719 }
720
721 /*%
722 * Check whether a dnstap output file roll is due and if so, initiate it (the
723 * actual roll happens asynchronously).
724 */
725 static void
check_file_size_and_maybe_reopen(dns_dtenv_t * env)726 check_file_size_and_maybe_reopen(dns_dtenv_t *env) {
727 isc_task_t *reopen_task = NULL;
728 isc_event_t *event;
729 struct stat statbuf;
730
731 /*
732 * If the task from which the output file should be reopened was not
733 * specified, abort.
734 */
735 if (env->reopen_task == NULL) {
736 return;
737 }
738
739 /*
740 * If an output file roll is not currently queued, check the current
741 * size of the output file to see whether a roll is needed. Return if
742 * it is not.
743 */
744 LOCK(&env->reopen_lock);
745 if (env->reopen_queued || stat(env->path, &statbuf) < 0 ||
746 statbuf.st_size <= env->max_size)
747 {
748 goto unlock_and_return;
749 }
750
751 /*
752 * We need to roll the output file, but it needs to be done in the
753 * context of env->reopen_task. Allocate and send an event to achieve
754 * that, then disallow output file rolling until the roll we queue is
755 * completed.
756 */
757 event = isc_event_allocate(env->mctx, NULL, DNS_EVENT_FREESTORAGE,
758 perform_reopen, env, sizeof(*event));
759 isc_task_attach(env->reopen_task, &reopen_task);
760 isc_task_send(reopen_task, &event);
761 env->reopen_queued = true;
762
763 unlock_and_return:
764 UNLOCK(&env->reopen_lock);
765 }
766
767 void
dns_dt_send(dns_view_t * view,dns_dtmsgtype_t msgtype,isc_sockaddr_t * qaddr,isc_sockaddr_t * raddr,bool tcp,isc_region_t * zone,isc_time_t * qtime,isc_time_t * rtime,isc_buffer_t * buf)768 dns_dt_send(dns_view_t *view, dns_dtmsgtype_t msgtype, isc_sockaddr_t *qaddr,
769 isc_sockaddr_t *raddr, bool tcp, isc_region_t *zone,
770 isc_time_t *qtime, isc_time_t *rtime, isc_buffer_t *buf) {
771 isc_time_t now, *t;
772 dns_dtmsg_t dm;
773
774 REQUIRE(DNS_VIEW_VALID(view));
775
776 if ((msgtype & view->dttypes) == 0) {
777 return;
778 }
779
780 if (view->dtenv == NULL) {
781 return;
782 }
783
784 REQUIRE(VALID_DTENV(view->dtenv));
785
786 if (view->dtenv->max_size != 0) {
787 check_file_size_and_maybe_reopen(view->dtenv);
788 }
789
790 TIME_NOW(&now);
791 t = &now;
792
793 init_msg(view->dtenv, &dm, dnstap_type(msgtype));
794
795 /* Query/response times */
796 switch (msgtype) {
797 case DNS_DTTYPE_AR:
798 case DNS_DTTYPE_CR:
799 case DNS_DTTYPE_RR:
800 case DNS_DTTYPE_FR:
801 case DNS_DTTYPE_SR:
802 case DNS_DTTYPE_TR:
803 case DNS_DTTYPE_UR:
804 if (rtime != NULL) {
805 t = rtime;
806 }
807
808 dm.m.response_time_sec = isc_time_seconds(t);
809 dm.m.has_response_time_sec = 1;
810 dm.m.response_time_nsec = isc_time_nanoseconds(t);
811 dm.m.has_response_time_nsec = 1;
812
813 /*
814 * Types RR and FR can fall through and get the query
815 * time set as well. Any other response type, break.
816 */
817 if (msgtype != DNS_DTTYPE_RR && msgtype != DNS_DTTYPE_FR) {
818 break;
819 }
820
821 FALLTHROUGH;
822 case DNS_DTTYPE_AQ:
823 case DNS_DTTYPE_CQ:
824 case DNS_DTTYPE_FQ:
825 case DNS_DTTYPE_RQ:
826 case DNS_DTTYPE_SQ:
827 case DNS_DTTYPE_TQ:
828 case DNS_DTTYPE_UQ:
829 if (qtime != NULL) {
830 t = qtime;
831 }
832
833 dm.m.query_time_sec = isc_time_seconds(t);
834 dm.m.has_query_time_sec = 1;
835 dm.m.query_time_nsec = isc_time_nanoseconds(t);
836 dm.m.has_query_time_nsec = 1;
837 break;
838 default:
839 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP,
840 DNS_LOGMODULE_DNSTAP, ISC_LOG_ERROR,
841 "invalid dnstap message type %d", msgtype);
842 return;
843 }
844
845 /* Query and response messages */
846 if ((msgtype & DNS_DTTYPE_QUERY) != 0) {
847 cpbuf(buf, &dm.m.query_message, &dm.m.has_query_message);
848 } else if ((msgtype & DNS_DTTYPE_RESPONSE) != 0) {
849 cpbuf(buf, &dm.m.response_message, &dm.m.has_response_message);
850 }
851
852 /* Zone/bailiwick */
853 switch (msgtype) {
854 case DNS_DTTYPE_AR:
855 case DNS_DTTYPE_RQ:
856 case DNS_DTTYPE_RR:
857 case DNS_DTTYPE_FQ:
858 case DNS_DTTYPE_FR:
859 if (zone != NULL && zone->base != NULL && zone->length != 0) {
860 dm.m.query_zone.data = zone->base;
861 dm.m.query_zone.len = zone->length;
862 dm.m.has_query_zone = 1;
863 }
864 break;
865 default:
866 break;
867 }
868
869 if (qaddr != NULL) {
870 setaddr(&dm, qaddr, tcp, &dm.m.query_address,
871 &dm.m.has_query_address, &dm.m.query_port,
872 &dm.m.has_query_port);
873 }
874 if (raddr != NULL) {
875 setaddr(&dm, raddr, tcp, &dm.m.response_address,
876 &dm.m.has_response_address, &dm.m.response_port,
877 &dm.m.has_response_port);
878 }
879
880 if (pack_dt(&dm.d, &dm.buf, &dm.len) == ISC_R_SUCCESS) {
881 send_dt(view->dtenv, dm.buf, dm.len);
882 }
883 }
884
885 static isc_result_t
putstr(isc_buffer_t ** b,const char * str)886 putstr(isc_buffer_t **b, const char *str) {
887 isc_result_t result;
888
889 result = isc_buffer_reserve(b, strlen(str));
890 if (result != ISC_R_SUCCESS) {
891 return (ISC_R_NOSPACE);
892 }
893
894 isc_buffer_putstr(*b, str);
895 return (ISC_R_SUCCESS);
896 }
897
898 static isc_result_t
putaddr(isc_buffer_t ** b,isc_region_t * ip)899 putaddr(isc_buffer_t **b, isc_region_t *ip) {
900 char buf[64];
901
902 if (ip->length == 4) {
903 if (!inet_ntop(AF_INET, ip->base, buf, sizeof(buf))) {
904 return (ISC_R_FAILURE);
905 }
906 } else if (ip->length == 16) {
907 if (!inet_ntop(AF_INET6, ip->base, buf, sizeof(buf))) {
908 return (ISC_R_FAILURE);
909 }
910 } else {
911 return (ISC_R_BADADDRESSFORM);
912 }
913
914 return (putstr(b, buf));
915 }
916
917 static bool
dnstap_file(struct fstrm_reader * r)918 dnstap_file(struct fstrm_reader *r) {
919 fstrm_res res;
920 const struct fstrm_control *control = NULL;
921 const uint8_t *rtype = NULL;
922 size_t dlen = strlen(DNSTAP_CONTENT_TYPE), rlen = 0;
923 size_t n = 0;
924
925 res = fstrm_reader_get_control(r, FSTRM_CONTROL_START, &control);
926 if (res != fstrm_res_success) {
927 return (false);
928 }
929
930 res = fstrm_control_get_num_field_content_type(control, &n);
931 if (res != fstrm_res_success) {
932 return (false);
933 }
934 if (n > 0) {
935 res = fstrm_control_get_field_content_type(control, 0, &rtype,
936 &rlen);
937 if (res != fstrm_res_success) {
938 return (false);
939 }
940
941 if (rlen != dlen) {
942 return (false);
943 }
944
945 if (memcmp(DNSTAP_CONTENT_TYPE, rtype, dlen) == 0) {
946 return (true);
947 }
948 }
949
950 return (false);
951 }
952
953 isc_result_t
dns_dt_open(const char * filename,dns_dtmode_t mode,isc_mem_t * mctx,dns_dthandle_t ** handlep)954 dns_dt_open(const char *filename, dns_dtmode_t mode, isc_mem_t *mctx,
955 dns_dthandle_t **handlep) {
956 isc_result_t result;
957 struct fstrm_file_options *fopt = NULL;
958 fstrm_res res;
959 dns_dthandle_t *handle;
960
961 REQUIRE(handlep != NULL && *handlep == NULL);
962
963 handle = isc_mem_get(mctx, sizeof(*handle));
964
965 handle->mode = mode;
966 handle->mctx = NULL;
967
968 switch (mode) {
969 case dns_dtmode_file:
970 fopt = fstrm_file_options_init();
971 if (fopt == NULL) {
972 CHECK(ISC_R_NOMEMORY);
973 }
974
975 fstrm_file_options_set_file_path(fopt, filename);
976
977 handle->reader = fstrm_file_reader_init(fopt, NULL);
978 if (handle->reader == NULL) {
979 CHECK(ISC_R_NOMEMORY);
980 }
981
982 res = fstrm_reader_open(handle->reader);
983 if (res != fstrm_res_success) {
984 CHECK(ISC_R_FAILURE);
985 }
986
987 if (!dnstap_file(handle->reader)) {
988 CHECK(DNS_R_BADDNSTAP);
989 }
990 break;
991 case dns_dtmode_unix:
992 result = ISC_R_NOTIMPLEMENTED;
993 goto cleanup;
994 default:
995 UNREACHABLE();
996 }
997
998 isc_mem_attach(mctx, &handle->mctx);
999 result = ISC_R_SUCCESS;
1000 *handlep = handle;
1001 handle = NULL;
1002
1003 cleanup:
1004 if (result != ISC_R_SUCCESS && handle->reader != NULL) {
1005 fstrm_reader_destroy(&handle->reader);
1006 handle->reader = NULL;
1007 }
1008 if (fopt != NULL) {
1009 fstrm_file_options_destroy(&fopt);
1010 }
1011 if (handle != NULL) {
1012 isc_mem_put(mctx, handle, sizeof(*handle));
1013 }
1014 return (result);
1015 }
1016
1017 isc_result_t
dns_dt_getframe(dns_dthandle_t * handle,uint8_t ** bufp,size_t * sizep)1018 dns_dt_getframe(dns_dthandle_t *handle, uint8_t **bufp, size_t *sizep) {
1019 const uint8_t *data;
1020 fstrm_res res;
1021
1022 REQUIRE(handle != NULL);
1023 REQUIRE(bufp != NULL);
1024 REQUIRE(sizep != NULL);
1025
1026 data = (const uint8_t *)*bufp;
1027
1028 res = fstrm_reader_read(handle->reader, &data, sizep);
1029 switch (res) {
1030 case fstrm_res_success:
1031 if (data == NULL) {
1032 return (ISC_R_FAILURE);
1033 }
1034 DE_CONST(data, *bufp);
1035 return (ISC_R_SUCCESS);
1036 case fstrm_res_stop:
1037 return (ISC_R_NOMORE);
1038 default:
1039 return (ISC_R_FAILURE);
1040 }
1041 }
1042
1043 void
dns_dt_close(dns_dthandle_t ** handlep)1044 dns_dt_close(dns_dthandle_t **handlep) {
1045 dns_dthandle_t *handle;
1046
1047 REQUIRE(handlep != NULL && *handlep != NULL);
1048
1049 handle = *handlep;
1050 *handlep = NULL;
1051
1052 if (handle->reader != NULL) {
1053 fstrm_reader_destroy(&handle->reader);
1054 handle->reader = NULL;
1055 }
1056 isc_mem_putanddetach(&handle->mctx, handle, sizeof(*handle));
1057 }
1058
1059 isc_result_t
dns_dt_parse(isc_mem_t * mctx,isc_region_t * src,dns_dtdata_t ** destp)1060 dns_dt_parse(isc_mem_t *mctx, isc_region_t *src, dns_dtdata_t **destp) {
1061 isc_result_t result;
1062 Dnstap__Dnstap *frame;
1063 Dnstap__Message *m;
1064 dns_dtdata_t *d = NULL;
1065 isc_buffer_t b;
1066
1067 REQUIRE(src != NULL);
1068 REQUIRE(destp != NULL && *destp == NULL);
1069
1070 d = isc_mem_get(mctx, sizeof(*d));
1071
1072 memset(d, 0, sizeof(*d));
1073 isc_mem_attach(mctx, &d->mctx);
1074
1075 d->frame = dnstap__dnstap__unpack(NULL, src->length, src->base);
1076 if (d->frame == NULL) {
1077 CHECK(ISC_R_NOMEMORY);
1078 }
1079
1080 frame = (Dnstap__Dnstap *)d->frame;
1081
1082 if (frame->type != DNSTAP__DNSTAP__TYPE__MESSAGE) {
1083 CHECK(DNS_R_BADDNSTAP);
1084 }
1085
1086 m = frame->message;
1087
1088 /* Message type */
1089 switch (m->type) {
1090 case DNSTAP__MESSAGE__TYPE__AUTH_QUERY:
1091 d->type = DNS_DTTYPE_AQ;
1092 break;
1093 case DNSTAP__MESSAGE__TYPE__AUTH_RESPONSE:
1094 d->type = DNS_DTTYPE_AR;
1095 break;
1096 case DNSTAP__MESSAGE__TYPE__CLIENT_QUERY:
1097 d->type = DNS_DTTYPE_CQ;
1098 break;
1099 case DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE:
1100 d->type = DNS_DTTYPE_CR;
1101 break;
1102 case DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY:
1103 d->type = DNS_DTTYPE_FQ;
1104 break;
1105 case DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE:
1106 d->type = DNS_DTTYPE_FR;
1107 break;
1108 case DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY:
1109 d->type = DNS_DTTYPE_RQ;
1110 break;
1111 case DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE:
1112 d->type = DNS_DTTYPE_RR;
1113 break;
1114 case DNSTAP__MESSAGE__TYPE__STUB_QUERY:
1115 d->type = DNS_DTTYPE_SQ;
1116 break;
1117 case DNSTAP__MESSAGE__TYPE__STUB_RESPONSE:
1118 d->type = DNS_DTTYPE_SR;
1119 break;
1120 case DNSTAP__MESSAGE__TYPE__TOOL_QUERY:
1121 d->type = DNS_DTTYPE_TQ;
1122 break;
1123 case DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE:
1124 d->type = DNS_DTTYPE_TR;
1125 break;
1126 case DNSTAP__MESSAGE__TYPE__UPDATE_QUERY:
1127 d->type = DNS_DTTYPE_UQ;
1128 break;
1129 case DNSTAP__MESSAGE__TYPE__UPDATE_RESPONSE:
1130 d->type = DNS_DTTYPE_UR;
1131 break;
1132 default:
1133 CHECK(DNS_R_BADDNSTAP);
1134 }
1135
1136 /* Query? */
1137 if ((d->type & DNS_DTTYPE_QUERY) != 0) {
1138 d->query = true;
1139 } else {
1140 d->query = false;
1141 }
1142
1143 /* Parse DNS message */
1144 if (d->query && m->has_query_message) {
1145 d->msgdata.base = m->query_message.data;
1146 d->msgdata.length = m->query_message.len;
1147 } else if (!d->query && m->has_response_message) {
1148 d->msgdata.base = m->response_message.data;
1149 d->msgdata.length = m->response_message.len;
1150 }
1151
1152 isc_buffer_init(&b, d->msgdata.base, d->msgdata.length);
1153 isc_buffer_add(&b, d->msgdata.length);
1154 dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &d->msg);
1155 result = dns_message_parse(d->msg, &b, 0);
1156 if (result != ISC_R_SUCCESS) {
1157 if (result != DNS_R_RECOVERABLE) {
1158 dns_message_detach(&d->msg);
1159 }
1160 result = ISC_R_SUCCESS;
1161 }
1162
1163 /* Timestamp */
1164 if (d->query) {
1165 if (m->has_query_time_sec && m->has_query_time_nsec) {
1166 isc_time_set(&d->qtime, m->query_time_sec,
1167 m->query_time_nsec);
1168 }
1169 } else {
1170 if (m->has_response_time_sec && m->has_response_time_nsec) {
1171 isc_time_set(&d->rtime, m->response_time_sec,
1172 m->response_time_nsec);
1173 }
1174 }
1175
1176 /* Peer address */
1177 if (m->has_query_address) {
1178 d->qaddr.base = m->query_address.data;
1179 d->qaddr.length = m->query_address.len;
1180 }
1181 if (m->has_query_port) {
1182 d->qport = m->query_port;
1183 }
1184
1185 if (m->has_response_address) {
1186 d->raddr.base = m->response_address.data;
1187 d->raddr.length = m->response_address.len;
1188 }
1189 if (m->has_response_port) {
1190 d->rport = m->response_port;
1191 }
1192
1193 /* Socket protocol */
1194 if (m->has_socket_protocol) {
1195 const ProtobufCEnumValue *type =
1196 protobuf_c_enum_descriptor_get_value(
1197 &dnstap__socket_protocol__descriptor,
1198 m->socket_protocol);
1199 if (type != NULL && type->value == DNSTAP__SOCKET_PROTOCOL__TCP)
1200 {
1201 d->tcp = true;
1202 } else {
1203 d->tcp = false;
1204 }
1205 }
1206
1207 /* Query tuple */
1208 if (d->msg != NULL) {
1209 dns_name_t *name = NULL;
1210 dns_rdataset_t *rdataset;
1211
1212 CHECK(dns_message_firstname(d->msg, DNS_SECTION_QUESTION));
1213 dns_message_currentname(d->msg, DNS_SECTION_QUESTION, &name);
1214 rdataset = ISC_LIST_HEAD(name->list);
1215
1216 dns_name_format(name, d->namebuf, sizeof(d->namebuf));
1217 dns_rdatatype_format(rdataset->type, d->typebuf,
1218 sizeof(d->typebuf));
1219 dns_rdataclass_format(rdataset->rdclass, d->classbuf,
1220 sizeof(d->classbuf));
1221 }
1222
1223 *destp = d;
1224
1225 cleanup:
1226 if (result != ISC_R_SUCCESS) {
1227 dns_dtdata_free(&d);
1228 }
1229
1230 return (result);
1231 }
1232
1233 isc_result_t
dns_dt_datatotext(dns_dtdata_t * d,isc_buffer_t ** dest)1234 dns_dt_datatotext(dns_dtdata_t *d, isc_buffer_t **dest) {
1235 isc_result_t result;
1236 char buf[100];
1237
1238 REQUIRE(d != NULL);
1239 REQUIRE(dest != NULL && *dest != NULL);
1240
1241 memset(buf, 0, sizeof(buf));
1242
1243 /* Timestamp */
1244 if (d->query && !isc_time_isepoch(&d->qtime)) {
1245 isc_time_formattimestamp(&d->qtime, buf, sizeof(buf));
1246 } else if (!d->query && !isc_time_isepoch(&d->rtime)) {
1247 isc_time_formattimestamp(&d->rtime, buf, sizeof(buf));
1248 }
1249
1250 if (buf[0] == '\0') {
1251 CHECK(putstr(dest, "???\?-?\?-?? ??:??:??.??? "));
1252 } else {
1253 CHECK(putstr(dest, buf));
1254 CHECK(putstr(dest, " "));
1255 }
1256
1257 /* Type mnemonic */
1258 switch (d->type) {
1259 case DNS_DTTYPE_AQ:
1260 CHECK(putstr(dest, "AQ "));
1261 break;
1262 case DNS_DTTYPE_AR:
1263 CHECK(putstr(dest, "AR "));
1264 break;
1265 case DNS_DTTYPE_CQ:
1266 CHECK(putstr(dest, "CQ "));
1267 break;
1268 case DNS_DTTYPE_CR:
1269 CHECK(putstr(dest, "CR "));
1270 break;
1271 case DNS_DTTYPE_FQ:
1272 CHECK(putstr(dest, "FQ "));
1273 break;
1274 case DNS_DTTYPE_FR:
1275 CHECK(putstr(dest, "FR "));
1276 break;
1277 case DNS_DTTYPE_RQ:
1278 CHECK(putstr(dest, "RQ "));
1279 break;
1280 case DNS_DTTYPE_RR:
1281 CHECK(putstr(dest, "RR "));
1282 break;
1283 case DNS_DTTYPE_SQ:
1284 CHECK(putstr(dest, "SQ "));
1285 break;
1286 case DNS_DTTYPE_SR:
1287 CHECK(putstr(dest, "SR "));
1288 break;
1289 case DNS_DTTYPE_TQ:
1290 CHECK(putstr(dest, "TQ "));
1291 break;
1292 case DNS_DTTYPE_TR:
1293 CHECK(putstr(dest, "TR "));
1294 break;
1295 case DNS_DTTYPE_UQ:
1296 CHECK(putstr(dest, "UQ "));
1297 break;
1298 case DNS_DTTYPE_UR:
1299 CHECK(putstr(dest, "UR "));
1300 break;
1301 default:
1302 return (DNS_R_BADDNSTAP);
1303 }
1304
1305 /* Query and response addresses */
1306 if (d->qaddr.length != 0) {
1307 CHECK(putaddr(dest, &d->qaddr));
1308 snprintf(buf, sizeof(buf), ":%u", d->qport);
1309 CHECK(putstr(dest, buf));
1310 } else {
1311 CHECK(putstr(dest, "?"));
1312 }
1313 if ((d->type & DNS_DTTYPE_QUERY) != 0) {
1314 CHECK(putstr(dest, " -> "));
1315 } else {
1316 CHECK(putstr(dest, " <- "));
1317 }
1318 if (d->raddr.length != 0) {
1319 CHECK(putaddr(dest, &d->raddr));
1320 snprintf(buf, sizeof(buf), ":%u", d->rport);
1321 CHECK(putstr(dest, buf));
1322 } else {
1323 CHECK(putstr(dest, "?"));
1324 }
1325
1326 CHECK(putstr(dest, " "));
1327
1328 /* Protocol */
1329 if (d->tcp) {
1330 CHECK(putstr(dest, "TCP "));
1331 } else {
1332 CHECK(putstr(dest, "UDP "));
1333 }
1334
1335 /* Message size */
1336 if (d->msgdata.base != NULL) {
1337 snprintf(buf, sizeof(buf), "%zub ", (size_t)d->msgdata.length);
1338 CHECK(putstr(dest, buf));
1339 } else {
1340 CHECK(putstr(dest, "0b "));
1341 }
1342
1343 /* Query tuple */
1344 if (d->namebuf[0] == '\0') {
1345 CHECK(putstr(dest, "?/"));
1346 } else {
1347 CHECK(putstr(dest, d->namebuf));
1348 CHECK(putstr(dest, "/"));
1349 }
1350
1351 if (d->classbuf[0] == '\0') {
1352 CHECK(putstr(dest, "?/"));
1353 } else {
1354 CHECK(putstr(dest, d->classbuf));
1355 CHECK(putstr(dest, "/"));
1356 }
1357
1358 if (d->typebuf[0] == '\0') {
1359 CHECK(putstr(dest, "?"));
1360 } else {
1361 CHECK(putstr(dest, d->typebuf));
1362 }
1363
1364 CHECK(isc_buffer_reserve(dest, 1));
1365 isc_buffer_putuint8(*dest, 0);
1366
1367 cleanup:
1368 return (result);
1369 }
1370
1371 void
dns_dtdata_free(dns_dtdata_t ** dp)1372 dns_dtdata_free(dns_dtdata_t **dp) {
1373 dns_dtdata_t *d;
1374
1375 REQUIRE(dp != NULL && *dp != NULL);
1376
1377 d = *dp;
1378 *dp = NULL;
1379
1380 if (d->msg != NULL) {
1381 dns_message_detach(&d->msg);
1382 }
1383 if (d->frame != NULL) {
1384 dnstap__dnstap__free_unpacked(d->frame, NULL);
1385 }
1386
1387 isc_mem_putanddetach(&d->mctx, d, sizeof(*d));
1388 }
1389