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 #include "sldns/sbuffer.h" 43 #include "util/config_file.h" 44 #include "util/net_help.h" 45 #include "util/netevent.h" 46 #include "util/log.h" 47 48 #include <fstrm.h> 49 #include <protobuf-c/protobuf-c.h> 50 51 #include "dnstap/dnstap.h" 52 #include "dnstap/dnstap.pb-c.h" 53 54 #define DNSTAP_CONTENT_TYPE "protobuf:dnstap.Dnstap" 55 #define DNSTAP_INITIAL_BUF_SIZE 256 56 57 struct dt_msg { 58 void *buf; 59 size_t len_buf; 60 Dnstap__Dnstap d; 61 Dnstap__Message m; 62 }; 63 64 static int 65 dt_pack(const Dnstap__Dnstap *d, void **buf, size_t *sz) 66 { 67 ProtobufCBufferSimple sbuf; 68 69 memset(&sbuf, 0, sizeof(sbuf)); 70 sbuf.base.append = protobuf_c_buffer_simple_append; 71 sbuf.len = 0; 72 sbuf.alloced = DNSTAP_INITIAL_BUF_SIZE; 73 sbuf.data = malloc(sbuf.alloced); 74 if (sbuf.data == NULL) 75 return 0; 76 sbuf.must_free_data = 1; 77 78 *sz = dnstap__dnstap__pack_to_buffer(d, (ProtobufCBuffer *) &sbuf); 79 if (sbuf.data == NULL) 80 return 0; 81 *buf = sbuf.data; 82 83 return 1; 84 } 85 86 static void 87 dt_send(const struct dt_env *env, void *buf, size_t len_buf) 88 { 89 fstrm_res res; 90 if (!buf) 91 return; 92 res = fstrm_iothr_submit(env->iothr, env->ioq, buf, len_buf, 93 fstrm_free_wrapper, NULL); 94 if (res != fstrm_res_success) 95 free(buf); 96 } 97 98 static void 99 dt_msg_init(const struct dt_env *env, 100 struct dt_msg *dm, 101 Dnstap__Message__Type mtype) 102 { 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; 108 dm->m.type = mtype; 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; 113 } 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; 118 } 119 } 120 121 struct dt_env * 122 dt_create(const char *socket_path, unsigned num_workers) 123 { 124 #ifdef UNBOUND_DEBUG 125 fstrm_res res; 126 #endif 127 struct dt_env *env; 128 struct fstrm_iothr_options *fopt; 129 struct fstrm_unix_writer_options *fuwopt; 130 struct fstrm_writer *fw; 131 struct fstrm_writer_options *fwopt; 132 133 verbose(VERB_OPS, "attempting to connect to dnstap socket %s", 134 socket_path); 135 log_assert(socket_path != NULL); 136 log_assert(num_workers > 0); 137 138 env = (struct dt_env *) calloc(1, sizeof(struct dt_env)); 139 if (!env) 140 return NULL; 141 142 fwopt = fstrm_writer_options_init(); 143 #ifdef UNBOUND_DEBUG 144 res = 145 #else 146 (void) 147 #endif 148 fstrm_writer_options_add_content_type(fwopt, 149 DNSTAP_CONTENT_TYPE, sizeof(DNSTAP_CONTENT_TYPE) - 1); 150 log_assert(res == fstrm_res_success); 151 152 fuwopt = fstrm_unix_writer_options_init(); 153 fstrm_unix_writer_options_set_socket_path(fuwopt, socket_path); 154 155 fw = fstrm_unix_writer_init(fuwopt, fwopt); 156 log_assert(fw != NULL); 157 158 fopt = fstrm_iothr_options_init(); 159 fstrm_iothr_options_set_num_input_queues(fopt, num_workers); 160 env->iothr = fstrm_iothr_init(fopt, &fw); 161 if (env->iothr == NULL) { 162 verbose(VERB_DETAIL, "dt_create: fstrm_iothr_init() failed"); 163 fstrm_writer_destroy(&fw); 164 free(env); 165 env = NULL; 166 } 167 fstrm_iothr_options_destroy(&fopt); 168 fstrm_unix_writer_options_destroy(&fuwopt); 169 fstrm_writer_options_destroy(&fwopt); 170 171 return env; 172 } 173 174 static void 175 dt_apply_identity(struct dt_env *env, struct config_file *cfg) 176 { 177 char buf[MAXHOSTNAMELEN+1]; 178 if (!cfg->dnstap_send_identity) 179 return; 180 free(env->identity); 181 if (cfg->dnstap_identity == NULL || cfg->dnstap_identity[0] == 0) { 182 if (gethostname(buf, MAXHOSTNAMELEN) == 0) { 183 buf[MAXHOSTNAMELEN] = 0; 184 env->identity = strdup(buf); 185 } else { 186 fatal_exit("dt_apply_identity: gethostname() failed"); 187 } 188 } else { 189 env->identity = strdup(cfg->dnstap_identity); 190 } 191 if (env->identity == NULL) 192 fatal_exit("dt_apply_identity: strdup() failed"); 193 env->len_identity = (unsigned int)strlen(env->identity); 194 verbose(VERB_OPS, "dnstap identity field set to \"%s\"", 195 env->identity); 196 } 197 198 static void 199 dt_apply_version(struct dt_env *env, struct config_file *cfg) 200 { 201 if (!cfg->dnstap_send_version) 202 return; 203 free(env->version); 204 if (cfg->dnstap_version == NULL || cfg->dnstap_version[0] == 0) 205 env->version = strdup(PACKAGE_STRING); 206 else 207 env->version = strdup(cfg->dnstap_version); 208 if (env->version == NULL) 209 fatal_exit("dt_apply_version: strdup() failed"); 210 env->len_version = (unsigned int)strlen(env->version); 211 verbose(VERB_OPS, "dnstap version field set to \"%s\"", 212 env->version); 213 } 214 215 void 216 dt_apply_cfg(struct dt_env *env, struct config_file *cfg) 217 { 218 if (!cfg->dnstap) 219 return; 220 221 dt_apply_identity(env, cfg); 222 dt_apply_version(env, cfg); 223 if ((env->log_resolver_query_messages = (unsigned int) 224 cfg->dnstap_log_resolver_query_messages)) 225 { 226 verbose(VERB_OPS, "dnstap Message/RESOLVER_QUERY enabled"); 227 } 228 if ((env->log_resolver_response_messages = (unsigned int) 229 cfg->dnstap_log_resolver_response_messages)) 230 { 231 verbose(VERB_OPS, "dnstap Message/RESOLVER_RESPONSE enabled"); 232 } 233 if ((env->log_client_query_messages = (unsigned int) 234 cfg->dnstap_log_client_query_messages)) 235 { 236 verbose(VERB_OPS, "dnstap Message/CLIENT_QUERY enabled"); 237 } 238 if ((env->log_client_response_messages = (unsigned int) 239 cfg->dnstap_log_client_response_messages)) 240 { 241 verbose(VERB_OPS, "dnstap Message/CLIENT_RESPONSE enabled"); 242 } 243 if ((env->log_forwarder_query_messages = (unsigned int) 244 cfg->dnstap_log_forwarder_query_messages)) 245 { 246 verbose(VERB_OPS, "dnstap Message/FORWARDER_QUERY enabled"); 247 } 248 if ((env->log_forwarder_response_messages = (unsigned int) 249 cfg->dnstap_log_forwarder_response_messages)) 250 { 251 verbose(VERB_OPS, "dnstap Message/FORWARDER_RESPONSE enabled"); 252 } 253 } 254 255 int 256 dt_init(struct dt_env *env) 257 { 258 env->ioq = fstrm_iothr_get_input_queue(env->iothr); 259 if (env->ioq == NULL) 260 return 0; 261 return 1; 262 } 263 264 void 265 dt_delete(struct dt_env *env) 266 { 267 if (!env) 268 return; 269 verbose(VERB_OPS, "closing dnstap socket"); 270 fstrm_iothr_destroy(&env->iothr); 271 free(env->identity); 272 free(env->version); 273 free(env); 274 } 275 276 static void 277 dt_fill_timeval(const struct timeval *tv, 278 uint64_t *time_sec, protobuf_c_boolean *has_time_sec, 279 uint32_t *time_nsec, protobuf_c_boolean *has_time_nsec) 280 { 281 #ifndef S_SPLINT_S 282 *time_sec = tv->tv_sec; 283 *time_nsec = tv->tv_usec * 1000; 284 #endif 285 *has_time_sec = 1; 286 *has_time_nsec = 1; 287 } 288 289 static void 290 dt_fill_buffer(sldns_buffer *b, ProtobufCBinaryData *p, protobuf_c_boolean *has) 291 { 292 log_assert(b != NULL); 293 p->len = sldns_buffer_limit(b); 294 p->data = sldns_buffer_begin(b); 295 *has = 1; 296 } 297 298 static void 299 dt_msg_fill_net(struct dt_msg *dm, 300 struct sockaddr_storage *ss, 301 enum comm_point_type cptype, 302 ProtobufCBinaryData *addr, protobuf_c_boolean *has_addr, 303 uint32_t *port, protobuf_c_boolean *has_port) 304 { 305 log_assert(ss->ss_family == AF_INET6 || ss->ss_family == AF_INET); 306 if (ss->ss_family == AF_INET6) { 307 struct sockaddr_in6 *s = (struct sockaddr_in6 *) ss; 308 309 /* socket_family */ 310 dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET6; 311 dm->m.has_socket_family = 1; 312 313 /* addr: query_address or response_address */ 314 addr->data = s->sin6_addr.s6_addr; 315 addr->len = 16; /* IPv6 */ 316 *has_addr = 1; 317 318 /* port: query_port or response_port */ 319 *port = ntohs(s->sin6_port); 320 *has_port = 1; 321 } else if (ss->ss_family == AF_INET) { 322 struct sockaddr_in *s = (struct sockaddr_in *) ss; 323 324 /* socket_family */ 325 dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET; 326 dm->m.has_socket_family = 1; 327 328 /* addr: query_address or response_address */ 329 addr->data = (uint8_t *) &s->sin_addr.s_addr; 330 addr->len = 4; /* IPv4 */ 331 *has_addr = 1; 332 333 /* port: query_port or response_port */ 334 *port = ntohs(s->sin_port); 335 *has_port = 1; 336 } 337 338 log_assert(cptype == comm_udp || cptype == comm_tcp); 339 if (cptype == comm_udp) { 340 /* socket_protocol */ 341 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__UDP; 342 dm->m.has_socket_protocol = 1; 343 } else if (cptype == comm_tcp) { 344 /* socket_protocol */ 345 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP; 346 dm->m.has_socket_protocol = 1; 347 } 348 } 349 350 void 351 dt_msg_send_client_query(struct dt_env *env, 352 struct sockaddr_storage *qsock, 353 enum comm_point_type cptype, 354 sldns_buffer *qmsg) 355 { 356 struct dt_msg dm; 357 struct timeval qtime; 358 359 gettimeofday(&qtime, NULL); 360 361 /* type */ 362 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__CLIENT_QUERY); 363 364 /* query_time */ 365 dt_fill_timeval(&qtime, 366 &dm.m.query_time_sec, &dm.m.has_query_time_sec, 367 &dm.m.query_time_nsec, &dm.m.has_query_time_nsec); 368 369 /* query_message */ 370 dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message); 371 372 /* socket_family, socket_protocol, query_address, query_port */ 373 log_assert(cptype == comm_udp || cptype == comm_tcp); 374 dt_msg_fill_net(&dm, qsock, cptype, 375 &dm.m.query_address, &dm.m.has_query_address, 376 &dm.m.query_port, &dm.m.has_query_port); 377 378 if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) 379 dt_send(env, dm.buf, dm.len_buf); 380 } 381 382 void 383 dt_msg_send_client_response(struct dt_env *env, 384 struct sockaddr_storage *qsock, 385 enum comm_point_type cptype, 386 sldns_buffer *rmsg) 387 { 388 struct dt_msg dm; 389 struct timeval rtime; 390 391 gettimeofday(&rtime, NULL); 392 393 /* type */ 394 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE); 395 396 /* response_time */ 397 dt_fill_timeval(&rtime, 398 &dm.m.response_time_sec, &dm.m.has_response_time_sec, 399 &dm.m.response_time_nsec, &dm.m.has_response_time_nsec); 400 401 /* response_message */ 402 dt_fill_buffer(rmsg, &dm.m.response_message, &dm.m.has_response_message); 403 404 /* socket_family, socket_protocol, query_address, query_port */ 405 log_assert(cptype == comm_udp || cptype == comm_tcp); 406 dt_msg_fill_net(&dm, qsock, cptype, 407 &dm.m.query_address, &dm.m.has_query_address, 408 &dm.m.query_port, &dm.m.has_query_port); 409 410 if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) 411 dt_send(env, dm.buf, dm.len_buf); 412 } 413 414 void 415 dt_msg_send_outside_query(struct dt_env *env, 416 struct sockaddr_storage *rsock, 417 enum comm_point_type cptype, 418 uint8_t *zone, size_t zone_len, 419 sldns_buffer *qmsg) 420 { 421 struct dt_msg dm; 422 struct timeval qtime; 423 uint16_t qflags; 424 425 gettimeofday(&qtime, NULL); 426 qflags = sldns_buffer_read_u16_at(qmsg, 2); 427 428 /* type */ 429 if (qflags & BIT_RD) { 430 if (!env->log_forwarder_query_messages) 431 return; 432 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY); 433 } else { 434 if (!env->log_resolver_query_messages) 435 return; 436 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY); 437 } 438 439 /* query_zone */ 440 dm.m.query_zone.data = zone; 441 dm.m.query_zone.len = zone_len; 442 dm.m.has_query_zone = 1; 443 444 /* query_time_sec, query_time_nsec */ 445 dt_fill_timeval(&qtime, 446 &dm.m.query_time_sec, &dm.m.has_query_time_sec, 447 &dm.m.query_time_nsec, &dm.m.has_query_time_nsec); 448 449 /* query_message */ 450 dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message); 451 452 /* socket_family, socket_protocol, response_address, response_port */ 453 log_assert(cptype == comm_udp || cptype == comm_tcp); 454 dt_msg_fill_net(&dm, rsock, cptype, 455 &dm.m.response_address, &dm.m.has_response_address, 456 &dm.m.response_port, &dm.m.has_response_port); 457 458 if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) 459 dt_send(env, dm.buf, dm.len_buf); 460 } 461 462 void 463 dt_msg_send_outside_response(struct dt_env *env, 464 struct sockaddr_storage *rsock, 465 enum comm_point_type cptype, 466 uint8_t *zone, size_t zone_len, 467 uint8_t *qbuf, size_t qbuf_len, 468 const struct timeval *qtime, 469 const struct timeval *rtime, 470 sldns_buffer *rmsg) 471 { 472 struct dt_msg dm; 473 uint16_t qflags; 474 475 log_assert(qbuf_len >= sizeof(qflags)); 476 memcpy(&qflags, qbuf, sizeof(qflags)); 477 qflags = ntohs(qflags); 478 479 /* type */ 480 if (qflags & BIT_RD) { 481 if (!env->log_forwarder_response_messages) 482 return; 483 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE); 484 } else { 485 if (!env->log_resolver_response_messages) 486 return; 487 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE); 488 } 489 490 /* query_zone */ 491 dm.m.query_zone.data = zone; 492 dm.m.query_zone.len = zone_len; 493 dm.m.has_query_zone = 1; 494 495 /* query_time_sec, query_time_nsec */ 496 dt_fill_timeval(qtime, 497 &dm.m.query_time_sec, &dm.m.has_query_time_sec, 498 &dm.m.query_time_nsec, &dm.m.has_query_time_nsec); 499 500 /* response_time_sec, response_time_nsec */ 501 dt_fill_timeval(rtime, 502 &dm.m.response_time_sec, &dm.m.has_response_time_sec, 503 &dm.m.response_time_nsec, &dm.m.has_response_time_nsec); 504 505 /* response_message */ 506 dt_fill_buffer(rmsg, &dm.m.response_message, &dm.m.has_response_message); 507 508 /* socket_family, socket_protocol, response_address, response_port */ 509 log_assert(cptype == comm_udp || cptype == comm_tcp); 510 dt_msg_fill_net(&dm, rsock, cptype, 511 &dm.m.response_address, &dm.m.has_response_address, 512 &dm.m.response_port, &dm.m.has_response_port); 513 514 if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) 515 dt_send(env, dm.buf, dm.len_buf); 516 } 517 518 #endif /* USE_DNSTAP */ 519