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