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 return; 197 free(env->identity); 198 if (cfg->dnstap_identity == NULL || cfg->dnstap_identity[0] == 0) { 199 if (gethostname(buf, MAXHOSTNAMELEN) == 0) { 200 buf[MAXHOSTNAMELEN] = 0; 201 env->identity = strdup(buf); 202 } else { 203 fatal_exit("dt_apply_identity: gethostname() failed"); 204 } 205 } else { 206 env->identity = strdup(cfg->dnstap_identity); 207 } 208 if (env->identity == NULL) 209 fatal_exit("dt_apply_identity: strdup() failed"); 210 env->len_identity = (unsigned int)strlen(env->identity); 211 verbose(VERB_OPS, "dnstap identity field set to \"%s\"", 212 env->identity); 213 } 214 215 static void 216 dt_apply_version(struct dt_env *env, struct config_file *cfg) 217 { 218 if (!cfg->dnstap_send_version) 219 return; 220 free(env->version); 221 if (cfg->dnstap_version == NULL || cfg->dnstap_version[0] == 0) 222 env->version = strdup(PACKAGE_STRING); 223 else 224 env->version = strdup(cfg->dnstap_version); 225 if (env->version == NULL) 226 fatal_exit("dt_apply_version: strdup() failed"); 227 env->len_version = (unsigned int)strlen(env->version); 228 verbose(VERB_OPS, "dnstap version field set to \"%s\"", 229 env->version); 230 } 231 232 void 233 dt_apply_cfg(struct dt_env *env, struct config_file *cfg) 234 { 235 if (!cfg->dnstap) 236 return; 237 238 dt_apply_identity(env, cfg); 239 dt_apply_version(env, cfg); 240 if ((env->log_resolver_query_messages = (unsigned int) 241 cfg->dnstap_log_resolver_query_messages)) 242 { 243 verbose(VERB_OPS, "dnstap Message/RESOLVER_QUERY enabled"); 244 } 245 if ((env->log_resolver_response_messages = (unsigned int) 246 cfg->dnstap_log_resolver_response_messages)) 247 { 248 verbose(VERB_OPS, "dnstap Message/RESOLVER_RESPONSE enabled"); 249 } 250 if ((env->log_client_query_messages = (unsigned int) 251 cfg->dnstap_log_client_query_messages)) 252 { 253 verbose(VERB_OPS, "dnstap Message/CLIENT_QUERY enabled"); 254 } 255 if ((env->log_client_response_messages = (unsigned int) 256 cfg->dnstap_log_client_response_messages)) 257 { 258 verbose(VERB_OPS, "dnstap Message/CLIENT_RESPONSE enabled"); 259 } 260 if ((env->log_forwarder_query_messages = (unsigned int) 261 cfg->dnstap_log_forwarder_query_messages)) 262 { 263 verbose(VERB_OPS, "dnstap Message/FORWARDER_QUERY enabled"); 264 } 265 if ((env->log_forwarder_response_messages = (unsigned int) 266 cfg->dnstap_log_forwarder_response_messages)) 267 { 268 verbose(VERB_OPS, "dnstap Message/FORWARDER_RESPONSE enabled"); 269 } 270 lock_basic_lock(&env->sample_lock); 271 if((env->sample_rate = (unsigned int)cfg->dnstap_sample_rate)) 272 { 273 verbose(VERB_OPS, "dnstap SAMPLE_RATE enabled and set to \"%d\"", (int)env->sample_rate); 274 } 275 lock_basic_unlock(&env->sample_lock); 276 } 277 278 int 279 dt_init(struct dt_env *env, struct comm_base* base) 280 { 281 env->msgqueue = dt_msg_queue_create(base); 282 if(!env->msgqueue) { 283 log_err("malloc failure"); 284 return 0; 285 } 286 if(!dt_io_thread_register_queue(env->dtio, env->msgqueue)) { 287 log_err("malloc failure"); 288 dt_msg_queue_delete(env->msgqueue); 289 env->msgqueue = NULL; 290 return 0; 291 } 292 return 1; 293 } 294 295 void 296 dt_deinit(struct dt_env* env) 297 { 298 dt_io_thread_unregister_queue(env->dtio, env->msgqueue); 299 dt_msg_queue_delete(env->msgqueue); 300 } 301 302 void 303 dt_delete(struct dt_env *env) 304 { 305 if (!env) 306 return; 307 dt_io_thread_delete(env->dtio); 308 lock_basic_destroy(&env->sample_lock); 309 free(env->identity); 310 free(env->version); 311 free(env); 312 } 313 314 static void 315 dt_fill_timeval(const struct timeval *tv, 316 uint64_t *time_sec, protobuf_c_boolean *has_time_sec, 317 uint32_t *time_nsec, protobuf_c_boolean *has_time_nsec) 318 { 319 #ifndef S_SPLINT_S 320 *time_sec = tv->tv_sec; 321 *time_nsec = tv->tv_usec * 1000; 322 #endif 323 *has_time_sec = 1; 324 *has_time_nsec = 1; 325 } 326 327 static void 328 dt_fill_buffer(sldns_buffer *b, ProtobufCBinaryData *p, protobuf_c_boolean *has) 329 { 330 log_assert(b != NULL); 331 p->len = sldns_buffer_limit(b); 332 p->data = sldns_buffer_begin(b); 333 *has = 1; 334 } 335 336 static void 337 dt_msg_fill_net(struct dt_msg *dm, 338 struct sockaddr_storage *qs, 339 struct sockaddr_storage *rs, 340 enum comm_point_type cptype, 341 void *cpssl, 342 ProtobufCBinaryData *qaddr, protobuf_c_boolean *has_qaddr, 343 uint32_t *qport, protobuf_c_boolean *has_qport, 344 ProtobufCBinaryData *raddr, protobuf_c_boolean *has_raddr, 345 uint32_t *rport, protobuf_c_boolean *has_rport) 346 { 347 log_assert(qs->ss_family == AF_INET6 || qs->ss_family == AF_INET); 348 if (qs->ss_family == AF_INET6) { 349 struct sockaddr_in6 *q = (struct sockaddr_in6 *) qs; 350 351 /* socket_family */ 352 dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET6; 353 dm->m.has_socket_family = 1; 354 355 /* addr: query_address or response_address */ 356 qaddr->data = q->sin6_addr.s6_addr; 357 qaddr->len = 16; /* IPv6 */ 358 *has_qaddr = 1; 359 360 /* port: query_port or response_port */ 361 *qport = ntohs(q->sin6_port); 362 *has_qport = 1; 363 } else if (qs->ss_family == AF_INET) { 364 struct sockaddr_in *q = (struct sockaddr_in *) qs; 365 366 /* socket_family */ 367 dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET; 368 dm->m.has_socket_family = 1; 369 370 /* addr: query_address or response_address */ 371 qaddr->data = (uint8_t *) &q->sin_addr.s_addr; 372 qaddr->len = 4; /* IPv4 */ 373 *has_qaddr = 1; 374 375 /* port: query_port or response_port */ 376 *qport = ntohs(q->sin_port); 377 *has_qport = 1; 378 } 379 380 /* 381 * This block is to fill second set of fields in DNSTAP-message defined as request_/response_ names. 382 * Additional responsive structure is: struct sockaddr_storage *rs 383 */ 384 if (rs && rs->ss_family == AF_INET6) { 385 struct sockaddr_in6 *r = (struct sockaddr_in6 *) rs; 386 387 /* addr: query_address or response_address */ 388 raddr->data = r->sin6_addr.s6_addr; 389 raddr->len = 16; /* IPv6 */ 390 *has_raddr = 1; 391 392 /* port: query_port or response_port */ 393 *rport = ntohs(r->sin6_port); 394 *has_rport = 1; 395 } else if (rs && rs->ss_family == AF_INET) { 396 struct sockaddr_in *r = (struct sockaddr_in *) rs; 397 398 /* addr: query_address or response_address */ 399 raddr->data = (uint8_t *) &r->sin_addr.s_addr; 400 raddr->len = 4; /* IPv4 */ 401 *has_raddr = 1; 402 403 /* port: query_port or response_port */ 404 *rport = ntohs(r->sin_port); 405 *has_rport = 1; 406 } 407 408 if (cptype == comm_udp) { 409 /* socket_protocol */ 410 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__UDP; 411 dm->m.has_socket_protocol = 1; 412 } else if (cptype == comm_tcp) { 413 if (cpssl == NULL) { 414 /* socket_protocol */ 415 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP; 416 dm->m.has_socket_protocol = 1; 417 } else { 418 /* socket_protocol */ 419 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__DOT; 420 dm->m.has_socket_protocol = 1; 421 } 422 } else if (cptype == comm_http) { 423 /* socket_protocol */ 424 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__DOH; 425 dm->m.has_socket_protocol = 1; 426 } else { 427 /* other socket protocol */ 428 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP; 429 dm->m.has_socket_protocol = 1; 430 } 431 } 432 433 void 434 dt_msg_send_client_query(struct dt_env *env, 435 struct sockaddr_storage *qsock, 436 struct sockaddr_storage *rsock, 437 enum comm_point_type cptype, 438 void *cpssl, 439 sldns_buffer *qmsg, 440 struct timeval* tstamp) 441 { 442 struct dt_msg dm; 443 struct timeval qtime; 444 445 if(dt_sample_rate_limited(env)) 446 return; 447 448 if(tstamp) 449 memcpy(&qtime, tstamp, sizeof(qtime)); 450 else gettimeofday(&qtime, NULL); 451 452 /* type */ 453 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__CLIENT_QUERY); 454 455 /* query_time */ 456 dt_fill_timeval(&qtime, 457 &dm.m.query_time_sec, &dm.m.has_query_time_sec, 458 &dm.m.query_time_nsec, &dm.m.has_query_time_nsec); 459 460 /* query_message */ 461 dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message); 462 463 /* socket_family, socket_protocol, query_address, query_port, response_address, response_port */ 464 dt_msg_fill_net(&dm, qsock, rsock, cptype, cpssl, 465 &dm.m.query_address, &dm.m.has_query_address, 466 &dm.m.query_port, &dm.m.has_query_port, 467 &dm.m.response_address, &dm.m.has_response_address, 468 &dm.m.response_port, &dm.m.has_response_port); 469 470 471 if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) 472 dt_send(env, dm.buf, dm.len_buf); 473 } 474 475 void 476 dt_msg_send_client_response(struct dt_env *env, 477 struct sockaddr_storage *qsock, 478 struct sockaddr_storage *rsock, 479 enum comm_point_type cptype, 480 void *cpssl, 481 sldns_buffer *rmsg) 482 { 483 struct dt_msg dm; 484 struct timeval rtime; 485 486 if(dt_sample_rate_limited(env)) 487 return; 488 489 gettimeofday(&rtime, NULL); 490 491 /* type */ 492 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE); 493 494 /* response_time */ 495 dt_fill_timeval(&rtime, 496 &dm.m.response_time_sec, &dm.m.has_response_time_sec, 497 &dm.m.response_time_nsec, &dm.m.has_response_time_nsec); 498 499 /* response_message */ 500 dt_fill_buffer(rmsg, &dm.m.response_message, &dm.m.has_response_message); 501 502 /* socket_family, socket_protocol, query_address, query_port, response_address, response_port */ 503 dt_msg_fill_net(&dm, qsock, rsock, cptype, cpssl, 504 &dm.m.query_address, &dm.m.has_query_address, 505 &dm.m.query_port, &dm.m.has_query_port, 506 &dm.m.response_address, &dm.m.has_response_address, 507 &dm.m.response_port, &dm.m.has_response_port); 508 509 if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) 510 dt_send(env, dm.buf, dm.len_buf); 511 } 512 513 void 514 dt_msg_send_outside_query(struct dt_env *env, 515 struct sockaddr_storage *rsock, 516 struct sockaddr_storage *qsock, 517 enum comm_point_type cptype, 518 void *cpssl, 519 uint8_t *zone, size_t zone_len, 520 sldns_buffer *qmsg) 521 { 522 struct dt_msg dm; 523 struct timeval qtime; 524 uint16_t qflags; 525 526 if(dt_sample_rate_limited(env)) 527 return; 528 529 gettimeofday(&qtime, NULL); 530 qflags = sldns_buffer_read_u16_at(qmsg, 2); 531 532 /* type */ 533 if (qflags & BIT_RD) { 534 if (!env->log_forwarder_query_messages) 535 return; 536 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY); 537 } else { 538 if (!env->log_resolver_query_messages) 539 return; 540 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY); 541 } 542 543 /* query_zone */ 544 dm.m.query_zone.data = zone; 545 dm.m.query_zone.len = zone_len; 546 dm.m.has_query_zone = 1; 547 548 /* query_time_sec, query_time_nsec */ 549 dt_fill_timeval(&qtime, 550 &dm.m.query_time_sec, &dm.m.has_query_time_sec, 551 &dm.m.query_time_nsec, &dm.m.has_query_time_nsec); 552 553 /* query_message */ 554 dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message); 555 556 /* socket_family, socket_protocol, response_address, response_port, query_address, query_port */ 557 dt_msg_fill_net(&dm, rsock, qsock, cptype, cpssl, 558 &dm.m.response_address, &dm.m.has_response_address, 559 &dm.m.response_port, &dm.m.has_response_port, 560 &dm.m.query_address, &dm.m.has_query_address, 561 &dm.m.query_port, &dm.m.has_query_port); 562 563 if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) 564 dt_send(env, dm.buf, dm.len_buf); 565 } 566 567 void 568 dt_msg_send_outside_response(struct dt_env *env, 569 struct sockaddr_storage *rsock, 570 struct sockaddr_storage *qsock, 571 enum comm_point_type cptype, 572 void *cpssl, 573 uint8_t *zone, size_t zone_len, 574 uint8_t *qbuf, size_t qbuf_len, 575 const struct timeval *qtime, 576 const struct timeval *rtime, 577 sldns_buffer *rmsg) 578 { 579 struct dt_msg dm; 580 uint16_t qflags; 581 582 if(dt_sample_rate_limited(env)) 583 return; 584 585 (void)qbuf_len; log_assert(qbuf_len >= sizeof(qflags)); 586 memcpy(&qflags, qbuf, sizeof(qflags)); 587 qflags = ntohs(qflags); 588 589 /* type */ 590 if (qflags & BIT_RD) { 591 if (!env->log_forwarder_response_messages) 592 return; 593 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE); 594 } else { 595 if (!env->log_resolver_response_messages) 596 return; 597 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE); 598 } 599 600 /* query_zone */ 601 dm.m.query_zone.data = zone; 602 dm.m.query_zone.len = zone_len; 603 dm.m.has_query_zone = 1; 604 605 /* query_time_sec, query_time_nsec */ 606 dt_fill_timeval(qtime, 607 &dm.m.query_time_sec, &dm.m.has_query_time_sec, 608 &dm.m.query_time_nsec, &dm.m.has_query_time_nsec); 609 610 /* response_time_sec, response_time_nsec */ 611 dt_fill_timeval(rtime, 612 &dm.m.response_time_sec, &dm.m.has_response_time_sec, 613 &dm.m.response_time_nsec, &dm.m.has_response_time_nsec); 614 615 /* response_message */ 616 dt_fill_buffer(rmsg, &dm.m.response_message, &dm.m.has_response_message); 617 618 /* socket_family, socket_protocol, response_address, response_port, query_address, query_port */ 619 dt_msg_fill_net(&dm, rsock, qsock, cptype, cpssl, 620 &dm.m.response_address, &dm.m.has_response_address, 621 &dm.m.response_port, &dm.m.has_response_port, 622 &dm.m.query_address, &dm.m.has_query_address, 623 &dm.m.query_port, &dm.m.has_query_port); 624 625 if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) 626 dt_send(env, dm.buf, dm.len_buf); 627 } 628 629 #endif /* USE_DNSTAP */ 630