1 /* dnstap support for Unbound */ 2 3 /* 4 * Copyright (c) 2013-2014, Farsight Security, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 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. 17 * 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. 21 * 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. 33 */ 34 35 #include "dnstap/dnstap_config.h" 36 37 #ifdef USE_DNSTAP 38 39 #include "config.h" 40 #include <string.h> 41 #include <sys/time.h> 42 #ifdef HAVE_SYS_STAT_H 43 #include <sys/stat.h> 44 #endif 45 #include <errno.h> 46 #include "sldns/sbuffer.h" 47 #include "util/config_file.h" 48 #include "util/net_help.h" 49 #include "util/netevent.h" 50 #include "util/log.h" 51 52 #include <protobuf-c/protobuf-c.h> 53 54 #include "dnstap/dnstap.h" 55 #include "dnstap/dtstream.h" 56 #include "dnstap/dnstap.pb-c.h" 57 58 #define DNSTAP_INITIAL_BUF_SIZE 256 59 60 struct dt_msg { 61 void *buf; 62 size_t len_buf; 63 Dnstap__Dnstap d; 64 Dnstap__Message m; 65 }; 66 67 static int 68 dt_pack(const Dnstap__Dnstap *d, void **buf, size_t *sz) 69 { 70 ProtobufCBufferSimple sbuf; 71 72 memset(&sbuf, 0, sizeof(sbuf)); 73 sbuf.base.append = protobuf_c_buffer_simple_append; 74 sbuf.len = 0; 75 sbuf.alloced = DNSTAP_INITIAL_BUF_SIZE; 76 sbuf.data = malloc(sbuf.alloced); 77 if (sbuf.data == NULL) 78 return 0; 79 sbuf.must_free_data = 1; 80 81 *sz = dnstap__dnstap__pack_to_buffer(d, (ProtobufCBuffer *) &sbuf); 82 if (sbuf.data == NULL) 83 return 0; 84 *buf = sbuf.data; 85 86 return 1; 87 } 88 89 /** See if the message is sent due to dnstap sample rate */ 90 static int 91 dt_sample_rate_limited(struct dt_env* env) 92 { 93 lock_basic_lock(&env->sample_lock); 94 /* Sampling is every [n] packets. Where n==1, every packet is sent */ 95 if(env->sample_rate > 1) { 96 int submit = 0; 97 /* if sampling is engaged... */ 98 if (env->sample_rate_count > env->sample_rate) { 99 /* once the count passes the limit */ 100 /* submit the message */ 101 submit = 1; 102 /* and reset the count */ 103 env->sample_rate_count = 0; 104 } 105 /* increment count regardless */ 106 env->sample_rate_count++; 107 lock_basic_unlock(&env->sample_lock); 108 return !submit; 109 } 110 lock_basic_unlock(&env->sample_lock); 111 return 0; 112 } 113 114 static void 115 dt_send(const struct dt_env *env, void *buf, size_t len_buf) 116 { 117 dt_msg_queue_submit(env->msgqueue, buf, len_buf); 118 } 119 120 static void 121 dt_msg_init(const struct dt_env *env, 122 struct dt_msg *dm, 123 Dnstap__Message__Type mtype) 124 { 125 memset(dm, 0, sizeof(*dm)); 126 dm->d.base.descriptor = &dnstap__dnstap__descriptor; 127 dm->m.base.descriptor = &dnstap__message__descriptor; 128 dm->d.type = DNSTAP__DNSTAP__TYPE__MESSAGE; 129 dm->d.message = &dm->m; 130 dm->m.type = mtype; 131 if (env->identity != NULL) { 132 dm->d.identity.data = (uint8_t *) env->identity; 133 dm->d.identity.len = (size_t) env->len_identity; 134 dm->d.has_identity = 1; 135 } 136 if (env->version != NULL) { 137 dm->d.version.data = (uint8_t *) env->version; 138 dm->d.version.len = (size_t) env->len_version; 139 dm->d.has_version = 1; 140 } 141 } 142 143 /* check that the socket file can be opened and exists, print error if not */ 144 static void 145 check_socket_file(const char* socket_path) 146 { 147 struct stat statbuf; 148 memset(&statbuf, 0, sizeof(statbuf)); 149 if(stat(socket_path, &statbuf) < 0) { 150 log_warn("could not open dnstap-socket-path: %s, %s", 151 socket_path, strerror(errno)); 152 } 153 } 154 155 struct dt_env * 156 dt_create(struct config_file* cfg) 157 { 158 struct dt_env *env; 159 160 if(cfg->dnstap && cfg->dnstap_socket_path && cfg->dnstap_socket_path[0] && 161 (cfg->dnstap_ip==NULL || cfg->dnstap_ip[0]==0)) { 162 char* p = cfg->dnstap_socket_path; 163 if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(p, 164 cfg->chrootdir, strlen(cfg->chrootdir)) == 0) 165 p += strlen(cfg->chrootdir); 166 verbose(VERB_OPS, "attempting to connect to dnstap socket %s", 167 p); 168 check_socket_file(p); 169 } 170 171 env = (struct dt_env *) calloc(1, sizeof(struct dt_env)); 172 if (!env) 173 return NULL; 174 lock_basic_init(&env->sample_lock); 175 176 env->dtio = dt_io_thread_create(); 177 if(!env->dtio) { 178 log_err("malloc failure"); 179 free(env); 180 return NULL; 181 } 182 if(!dt_io_thread_apply_cfg(env->dtio, cfg)) { 183 dt_io_thread_delete(env->dtio); 184 free(env); 185 return NULL; 186 } 187 dt_apply_cfg(env, cfg); 188 return env; 189 } 190 191 static void 192 dt_apply_identity(struct dt_env *env, struct config_file *cfg) 193 { 194 char buf[MAXHOSTNAMELEN+1]; 195 if (!cfg->dnstap_send_identity) { 196 free(env->identity); 197 env->identity = NULL; 198 return; 199 } 200 free(env->identity); 201 if (cfg->dnstap_identity == NULL || cfg->dnstap_identity[0] == 0) { 202 if (gethostname(buf, MAXHOSTNAMELEN) == 0) { 203 buf[MAXHOSTNAMELEN] = 0; 204 env->identity = strdup(buf); 205 } else { 206 fatal_exit("dt_apply_identity: gethostname() failed"); 207 } 208 } else { 209 env->identity = strdup(cfg->dnstap_identity); 210 } 211 if (env->identity == NULL) 212 fatal_exit("dt_apply_identity: strdup() failed"); 213 env->len_identity = (unsigned int)strlen(env->identity); 214 verbose(VERB_OPS, "dnstap identity field set to \"%s\"", 215 env->identity); 216 } 217 218 static void 219 dt_apply_version(struct dt_env *env, struct config_file *cfg) 220 { 221 if (!cfg->dnstap_send_version) { 222 free(env->version); 223 env->version = NULL; 224 return; 225 } 226 free(env->version); 227 if (cfg->dnstap_version == NULL || cfg->dnstap_version[0] == 0) 228 env->version = strdup(PACKAGE_STRING); 229 else 230 env->version = strdup(cfg->dnstap_version); 231 if (env->version == NULL) 232 fatal_exit("dt_apply_version: strdup() failed"); 233 env->len_version = (unsigned int)strlen(env->version); 234 verbose(VERB_OPS, "dnstap version field set to \"%s\"", 235 env->version); 236 } 237 238 void 239 dt_apply_logcfg(struct dt_env *env, struct config_file *cfg) 240 { 241 if ((env->log_resolver_query_messages = (unsigned int) 242 cfg->dnstap_log_resolver_query_messages)) 243 { 244 verbose(VERB_OPS, "dnstap Message/RESOLVER_QUERY enabled"); 245 } 246 if ((env->log_resolver_response_messages = (unsigned int) 247 cfg->dnstap_log_resolver_response_messages)) 248 { 249 verbose(VERB_OPS, "dnstap Message/RESOLVER_RESPONSE enabled"); 250 } 251 if ((env->log_client_query_messages = (unsigned int) 252 cfg->dnstap_log_client_query_messages)) 253 { 254 verbose(VERB_OPS, "dnstap Message/CLIENT_QUERY enabled"); 255 } 256 if ((env->log_client_response_messages = (unsigned int) 257 cfg->dnstap_log_client_response_messages)) 258 { 259 verbose(VERB_OPS, "dnstap Message/CLIENT_RESPONSE enabled"); 260 } 261 if ((env->log_forwarder_query_messages = (unsigned int) 262 cfg->dnstap_log_forwarder_query_messages)) 263 { 264 verbose(VERB_OPS, "dnstap Message/FORWARDER_QUERY enabled"); 265 } 266 if ((env->log_forwarder_response_messages = (unsigned int) 267 cfg->dnstap_log_forwarder_response_messages)) 268 { 269 verbose(VERB_OPS, "dnstap Message/FORWARDER_RESPONSE enabled"); 270 } 271 lock_basic_lock(&env->sample_lock); 272 if((env->sample_rate = (unsigned int)cfg->dnstap_sample_rate)) 273 { 274 verbose(VERB_OPS, "dnstap SAMPLE_RATE enabled and set to \"%d\"", (int)env->sample_rate); 275 } 276 lock_basic_unlock(&env->sample_lock); 277 } 278 279 void 280 dt_apply_cfg(struct dt_env *env, struct config_file *cfg) 281 { 282 if (!cfg->dnstap) 283 return; 284 285 dt_apply_identity(env, cfg); 286 dt_apply_version(env, cfg); 287 dt_apply_logcfg(env, cfg); 288 } 289 290 int 291 dt_init(struct dt_env *env, struct comm_base* base) 292 { 293 env->msgqueue = dt_msg_queue_create(base); 294 if(!env->msgqueue) { 295 log_err("malloc failure"); 296 return 0; 297 } 298 if(!dt_io_thread_register_queue(env->dtio, env->msgqueue)) { 299 log_err("malloc failure"); 300 dt_msg_queue_delete(env->msgqueue); 301 env->msgqueue = NULL; 302 return 0; 303 } 304 return 1; 305 } 306 307 void 308 dt_deinit(struct dt_env* env) 309 { 310 dt_io_thread_unregister_queue(env->dtio, env->msgqueue); 311 dt_msg_queue_delete(env->msgqueue); 312 } 313 314 void 315 dt_delete(struct dt_env *env) 316 { 317 if (!env) 318 return; 319 dt_io_thread_delete(env->dtio); 320 lock_basic_destroy(&env->sample_lock); 321 free(env->identity); 322 free(env->version); 323 free(env); 324 } 325 326 static void 327 dt_fill_timeval(const struct timeval *tv, 328 uint64_t *time_sec, protobuf_c_boolean *has_time_sec, 329 uint32_t *time_nsec, protobuf_c_boolean *has_time_nsec) 330 { 331 #ifndef S_SPLINT_S 332 *time_sec = tv->tv_sec; 333 *time_nsec = tv->tv_usec * 1000; 334 #endif 335 *has_time_sec = 1; 336 *has_time_nsec = 1; 337 } 338 339 static void 340 dt_fill_buffer(sldns_buffer *b, ProtobufCBinaryData *p, protobuf_c_boolean *has) 341 { 342 log_assert(b != NULL); 343 p->len = sldns_buffer_limit(b); 344 p->data = sldns_buffer_begin(b); 345 *has = 1; 346 } 347 348 static void 349 dt_msg_fill_net(struct dt_msg *dm, 350 struct sockaddr_storage *qs, 351 struct sockaddr_storage *rs, 352 enum comm_point_type cptype, 353 void *cpssl, 354 ProtobufCBinaryData *qaddr, protobuf_c_boolean *has_qaddr, 355 uint32_t *qport, protobuf_c_boolean *has_qport, 356 ProtobufCBinaryData *raddr, protobuf_c_boolean *has_raddr, 357 uint32_t *rport, protobuf_c_boolean *has_rport) 358 { 359 log_assert(qs->ss_family == AF_INET6 || qs->ss_family == AF_INET); 360 if (qs->ss_family == AF_INET6) { 361 struct sockaddr_in6 *q = (struct sockaddr_in6 *) qs; 362 363 /* socket_family */ 364 dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET6; 365 dm->m.has_socket_family = 1; 366 367 /* addr: query_address or response_address */ 368 qaddr->data = q->sin6_addr.s6_addr; 369 qaddr->len = 16; /* IPv6 */ 370 *has_qaddr = 1; 371 372 /* port: query_port or response_port */ 373 *qport = ntohs(q->sin6_port); 374 *has_qport = 1; 375 } else if (qs->ss_family == AF_INET) { 376 struct sockaddr_in *q = (struct sockaddr_in *) qs; 377 378 /* socket_family */ 379 dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET; 380 dm->m.has_socket_family = 1; 381 382 /* addr: query_address or response_address */ 383 qaddr->data = (uint8_t *) &q->sin_addr.s_addr; 384 qaddr->len = 4; /* IPv4 */ 385 *has_qaddr = 1; 386 387 /* port: query_port or response_port */ 388 *qport = ntohs(q->sin_port); 389 *has_qport = 1; 390 } 391 392 /* 393 * This block is to fill second set of fields in DNSTAP-message defined as request_/response_ names. 394 * Additional responsive structure is: struct sockaddr_storage *rs 395 */ 396 if (rs && rs->ss_family == AF_INET6) { 397 struct sockaddr_in6 *r = (struct sockaddr_in6 *) rs; 398 399 /* addr: query_address or response_address */ 400 raddr->data = r->sin6_addr.s6_addr; 401 raddr->len = 16; /* IPv6 */ 402 *has_raddr = 1; 403 404 /* port: query_port or response_port */ 405 *rport = ntohs(r->sin6_port); 406 *has_rport = 1; 407 } else if (rs && rs->ss_family == AF_INET) { 408 struct sockaddr_in *r = (struct sockaddr_in *) rs; 409 410 /* addr: query_address or response_address */ 411 raddr->data = (uint8_t *) &r->sin_addr.s_addr; 412 raddr->len = 4; /* IPv4 */ 413 *has_raddr = 1; 414 415 /* port: query_port or response_port */ 416 *rport = ntohs(r->sin_port); 417 *has_rport = 1; 418 } 419 420 if (cptype == comm_udp) { 421 /* socket_protocol */ 422 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__UDP; 423 dm->m.has_socket_protocol = 1; 424 } else if (cptype == comm_tcp) { 425 if (cpssl == NULL) { 426 /* socket_protocol */ 427 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP; 428 dm->m.has_socket_protocol = 1; 429 } else { 430 /* socket_protocol */ 431 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__DOT; 432 dm->m.has_socket_protocol = 1; 433 } 434 } else if (cptype == comm_http) { 435 /* socket_protocol */ 436 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__DOH; 437 dm->m.has_socket_protocol = 1; 438 } else { 439 /* other socket protocol */ 440 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP; 441 dm->m.has_socket_protocol = 1; 442 } 443 } 444 445 void 446 dt_msg_send_client_query(struct dt_env *env, 447 struct sockaddr_storage *qsock, 448 struct sockaddr_storage *rsock, 449 enum comm_point_type cptype, 450 void *cpssl, 451 sldns_buffer *qmsg, 452 struct timeval* tstamp) 453 { 454 struct dt_msg dm; 455 struct timeval qtime; 456 457 if(dt_sample_rate_limited(env)) 458 return; 459 460 if(tstamp) 461 memcpy(&qtime, tstamp, sizeof(qtime)); 462 else gettimeofday(&qtime, NULL); 463 464 /* type */ 465 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__CLIENT_QUERY); 466 467 /* query_time */ 468 dt_fill_timeval(&qtime, 469 &dm.m.query_time_sec, &dm.m.has_query_time_sec, 470 &dm.m.query_time_nsec, &dm.m.has_query_time_nsec); 471 472 /* query_message */ 473 dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message); 474 475 /* socket_family, socket_protocol, query_address, query_port, response_address, response_port */ 476 dt_msg_fill_net(&dm, qsock, rsock, cptype, cpssl, 477 &dm.m.query_address, &dm.m.has_query_address, 478 &dm.m.query_port, &dm.m.has_query_port, 479 &dm.m.response_address, &dm.m.has_response_address, 480 &dm.m.response_port, &dm.m.has_response_port); 481 482 483 if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) 484 dt_send(env, dm.buf, dm.len_buf); 485 } 486 487 void 488 dt_msg_send_client_response(struct dt_env *env, 489 struct sockaddr_storage *qsock, 490 struct sockaddr_storage *rsock, 491 enum comm_point_type cptype, 492 void *cpssl, 493 sldns_buffer *rmsg) 494 { 495 struct dt_msg dm; 496 struct timeval rtime; 497 498 if(dt_sample_rate_limited(env)) 499 return; 500 501 gettimeofday(&rtime, NULL); 502 503 /* type */ 504 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE); 505 506 /* response_time */ 507 dt_fill_timeval(&rtime, 508 &dm.m.response_time_sec, &dm.m.has_response_time_sec, 509 &dm.m.response_time_nsec, &dm.m.has_response_time_nsec); 510 511 /* response_message */ 512 dt_fill_buffer(rmsg, &dm.m.response_message, &dm.m.has_response_message); 513 514 /* socket_family, socket_protocol, query_address, query_port, response_address, response_port */ 515 dt_msg_fill_net(&dm, qsock, rsock, cptype, cpssl, 516 &dm.m.query_address, &dm.m.has_query_address, 517 &dm.m.query_port, &dm.m.has_query_port, 518 &dm.m.response_address, &dm.m.has_response_address, 519 &dm.m.response_port, &dm.m.has_response_port); 520 521 if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) 522 dt_send(env, dm.buf, dm.len_buf); 523 } 524 525 void 526 dt_msg_send_outside_query(struct dt_env *env, 527 struct sockaddr_storage *rsock, 528 struct sockaddr_storage *qsock, 529 enum comm_point_type cptype, 530 void *cpssl, 531 uint8_t *zone, size_t zone_len, 532 sldns_buffer *qmsg) 533 { 534 struct dt_msg dm; 535 struct timeval qtime; 536 uint16_t qflags; 537 538 if(dt_sample_rate_limited(env)) 539 return; 540 541 gettimeofday(&qtime, NULL); 542 qflags = sldns_buffer_read_u16_at(qmsg, 2); 543 544 /* type */ 545 if (qflags & BIT_RD) { 546 if (!env->log_forwarder_query_messages) 547 return; 548 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY); 549 } else { 550 if (!env->log_resolver_query_messages) 551 return; 552 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY); 553 } 554 555 /* query_zone */ 556 dm.m.query_zone.data = zone; 557 dm.m.query_zone.len = zone_len; 558 dm.m.has_query_zone = 1; 559 560 /* query_time_sec, query_time_nsec */ 561 dt_fill_timeval(&qtime, 562 &dm.m.query_time_sec, &dm.m.has_query_time_sec, 563 &dm.m.query_time_nsec, &dm.m.has_query_time_nsec); 564 565 /* query_message */ 566 dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message); 567 568 /* socket_family, socket_protocol, response_address, response_port, query_address, query_port */ 569 dt_msg_fill_net(&dm, rsock, qsock, cptype, cpssl, 570 &dm.m.response_address, &dm.m.has_response_address, 571 &dm.m.response_port, &dm.m.has_response_port, 572 &dm.m.query_address, &dm.m.has_query_address, 573 &dm.m.query_port, &dm.m.has_query_port); 574 575 if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) 576 dt_send(env, dm.buf, dm.len_buf); 577 } 578 579 void 580 dt_msg_send_outside_response(struct dt_env *env, 581 struct sockaddr_storage *rsock, 582 struct sockaddr_storage *qsock, 583 enum comm_point_type cptype, 584 void *cpssl, 585 uint8_t *zone, size_t zone_len, 586 uint8_t *qbuf, size_t qbuf_len, 587 const struct timeval *qtime, 588 const struct timeval *rtime, 589 sldns_buffer *rmsg) 590 { 591 struct dt_msg dm; 592 uint16_t qflags; 593 594 if(dt_sample_rate_limited(env)) 595 return; 596 597 (void)qbuf_len; log_assert(qbuf_len >= sizeof(qflags)); 598 memcpy(&qflags, qbuf, sizeof(qflags)); 599 qflags = ntohs(qflags); 600 601 /* type */ 602 if (qflags & BIT_RD) { 603 if (!env->log_forwarder_response_messages) 604 return; 605 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE); 606 } else { 607 if (!env->log_resolver_response_messages) 608 return; 609 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE); 610 } 611 612 /* query_zone */ 613 dm.m.query_zone.data = zone; 614 dm.m.query_zone.len = zone_len; 615 dm.m.has_query_zone = 1; 616 617 /* query_time_sec, query_time_nsec */ 618 dt_fill_timeval(qtime, 619 &dm.m.query_time_sec, &dm.m.has_query_time_sec, 620 &dm.m.query_time_nsec, &dm.m.has_query_time_nsec); 621 622 /* response_time_sec, response_time_nsec */ 623 dt_fill_timeval(rtime, 624 &dm.m.response_time_sec, &dm.m.has_response_time_sec, 625 &dm.m.response_time_nsec, &dm.m.has_response_time_nsec); 626 627 /* response_message */ 628 dt_fill_buffer(rmsg, &dm.m.response_message, &dm.m.has_response_message); 629 630 /* socket_family, socket_protocol, response_address, response_port, query_address, query_port */ 631 dt_msg_fill_net(&dm, rsock, qsock, cptype, cpssl, 632 &dm.m.response_address, &dm.m.has_response_address, 633 &dm.m.response_port, &dm.m.has_response_port, 634 &dm.m.query_address, &dm.m.has_query_address, 635 &dm.m.query_port, &dm.m.has_query_port); 636 637 if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) 638 dt_send(env, dm.buf, dm.len_buf); 639 } 640 641 #endif /* USE_DNSTAP */ 642