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