]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/unbound/dnstap/dnstap.c
unbound: Vendor import 1.19.1
[FreeBSD/FreeBSD.git] / contrib / unbound / dnstap / dnstap.c
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 static void
90 dt_send(const struct dt_env *env, void *buf, size_t len_buf)
91 {
92         dt_msg_queue_submit(env->msgqueue, buf, len_buf);
93 }
94
95 static void
96 dt_msg_init(const struct dt_env *env,
97             struct dt_msg *dm,
98             Dnstap__Message__Type mtype)
99 {
100         memset(dm, 0, sizeof(*dm));
101         dm->d.base.descriptor = &dnstap__dnstap__descriptor;
102         dm->m.base.descriptor = &dnstap__message__descriptor;
103         dm->d.type = DNSTAP__DNSTAP__TYPE__MESSAGE;
104         dm->d.message = &dm->m;
105         dm->m.type = mtype;
106         if (env->identity != NULL) {
107                 dm->d.identity.data = (uint8_t *) env->identity;
108                 dm->d.identity.len = (size_t) env->len_identity;
109                 dm->d.has_identity = 1;
110         }
111         if (env->version != NULL) {
112                 dm->d.version.data = (uint8_t *) env->version;
113                 dm->d.version.len = (size_t) env->len_version;
114                 dm->d.has_version = 1;
115         }
116 }
117
118 /* check that the socket file can be opened and exists, print error if not */
119 static void
120 check_socket_file(const char* socket_path)
121 {
122         struct stat statbuf;
123         memset(&statbuf, 0, sizeof(statbuf));
124         if(stat(socket_path, &statbuf) < 0) {
125                 log_warn("could not open dnstap-socket-path: %s, %s",
126                         socket_path, strerror(errno));
127         }
128 }
129
130 struct dt_env *
131 dt_create(struct config_file* cfg)
132 {
133         struct dt_env *env;
134
135         if(cfg->dnstap && cfg->dnstap_socket_path && cfg->dnstap_socket_path[0] &&
136                 (cfg->dnstap_ip==NULL || cfg->dnstap_ip[0]==0)) {
137                 char* p = cfg->dnstap_socket_path;
138                 if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(p,
139                         cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
140                         p += strlen(cfg->chrootdir);
141                 verbose(VERB_OPS, "attempting to connect to dnstap socket %s",
142                         p);
143                 check_socket_file(p);
144         }
145
146         env = (struct dt_env *) calloc(1, sizeof(struct dt_env));
147         if (!env)
148                 return NULL;
149
150         env->dtio = dt_io_thread_create();
151         if(!env->dtio) {
152                 log_err("malloc failure");
153                 free(env);
154                 return NULL;
155         }
156         if(!dt_io_thread_apply_cfg(env->dtio, cfg)) {
157                 dt_io_thread_delete(env->dtio);
158                 free(env);
159                 return NULL;
160         }
161         dt_apply_cfg(env, cfg);
162         return env;
163 }
164
165 static void
166 dt_apply_identity(struct dt_env *env, struct config_file *cfg)
167 {
168         char buf[MAXHOSTNAMELEN+1];
169         if (!cfg->dnstap_send_identity)
170                 return;
171         free(env->identity);
172         if (cfg->dnstap_identity == NULL || cfg->dnstap_identity[0] == 0) {
173                 if (gethostname(buf, MAXHOSTNAMELEN) == 0) {
174                         buf[MAXHOSTNAMELEN] = 0;
175                         env->identity = strdup(buf);
176                 } else {
177                         fatal_exit("dt_apply_identity: gethostname() failed");
178                 }
179         } else {
180                 env->identity = strdup(cfg->dnstap_identity);
181         }
182         if (env->identity == NULL)
183                 fatal_exit("dt_apply_identity: strdup() failed");
184         env->len_identity = (unsigned int)strlen(env->identity);
185         verbose(VERB_OPS, "dnstap identity field set to \"%s\"",
186                 env->identity);
187 }
188
189 static void
190 dt_apply_version(struct dt_env *env, struct config_file *cfg)
191 {
192         if (!cfg->dnstap_send_version)
193                 return;
194         free(env->version);
195         if (cfg->dnstap_version == NULL || cfg->dnstap_version[0] == 0)
196                 env->version = strdup(PACKAGE_STRING);
197         else
198                 env->version = strdup(cfg->dnstap_version);
199         if (env->version == NULL)
200                 fatal_exit("dt_apply_version: strdup() failed");
201         env->len_version = (unsigned int)strlen(env->version);
202         verbose(VERB_OPS, "dnstap version field set to \"%s\"",
203                 env->version);
204 }
205
206 void
207 dt_apply_cfg(struct dt_env *env, struct config_file *cfg)
208 {
209         if (!cfg->dnstap)
210                 return;
211
212         dt_apply_identity(env, cfg);
213         dt_apply_version(env, cfg);
214         if ((env->log_resolver_query_messages = (unsigned int)
215              cfg->dnstap_log_resolver_query_messages))
216         {
217                 verbose(VERB_OPS, "dnstap Message/RESOLVER_QUERY enabled");
218         }
219         if ((env->log_resolver_response_messages = (unsigned int)
220              cfg->dnstap_log_resolver_response_messages))
221         {
222                 verbose(VERB_OPS, "dnstap Message/RESOLVER_RESPONSE enabled");
223         }
224         if ((env->log_client_query_messages = (unsigned int)
225              cfg->dnstap_log_client_query_messages))
226         {
227                 verbose(VERB_OPS, "dnstap Message/CLIENT_QUERY enabled");
228         }
229         if ((env->log_client_response_messages = (unsigned int)
230              cfg->dnstap_log_client_response_messages))
231         {
232                 verbose(VERB_OPS, "dnstap Message/CLIENT_RESPONSE enabled");
233         }
234         if ((env->log_forwarder_query_messages = (unsigned int)
235              cfg->dnstap_log_forwarder_query_messages))
236         {
237                 verbose(VERB_OPS, "dnstap Message/FORWARDER_QUERY enabled");
238         }
239         if ((env->log_forwarder_response_messages = (unsigned int)
240              cfg->dnstap_log_forwarder_response_messages))
241         {
242                 verbose(VERB_OPS, "dnstap Message/FORWARDER_RESPONSE enabled");
243         }
244 }
245
246 int
247 dt_init(struct dt_env *env, struct comm_base* base)
248 {
249         env->msgqueue = dt_msg_queue_create(base);
250         if(!env->msgqueue) {
251                 log_err("malloc failure");
252                 return 0;
253         }
254         if(!dt_io_thread_register_queue(env->dtio, env->msgqueue)) {
255                 log_err("malloc failure");
256                 dt_msg_queue_delete(env->msgqueue);
257                 env->msgqueue = NULL;
258                 return 0;
259         }
260         return 1;
261 }
262
263 void
264 dt_deinit(struct dt_env* env)
265 {
266         dt_io_thread_unregister_queue(env->dtio, env->msgqueue);
267         dt_msg_queue_delete(env->msgqueue);
268 }
269
270 void
271 dt_delete(struct dt_env *env)
272 {
273         if (!env)
274                 return;
275         dt_io_thread_delete(env->dtio);
276         free(env->identity);
277         free(env->version);
278         free(env);
279 }
280
281 static void
282 dt_fill_timeval(const struct timeval *tv,
283                 uint64_t *time_sec, protobuf_c_boolean *has_time_sec,
284                 uint32_t *time_nsec, protobuf_c_boolean *has_time_nsec)
285 {
286 #ifndef S_SPLINT_S
287         *time_sec = tv->tv_sec;
288         *time_nsec = tv->tv_usec * 1000;
289 #endif
290         *has_time_sec = 1;
291         *has_time_nsec = 1;
292 }
293
294 static void
295 dt_fill_buffer(sldns_buffer *b, ProtobufCBinaryData *p, protobuf_c_boolean *has)
296 {
297         log_assert(b != NULL);
298         p->len = sldns_buffer_limit(b);
299         p->data = sldns_buffer_begin(b);
300         *has = 1;
301 }
302
303 static void
304 dt_msg_fill_net(struct dt_msg *dm,
305                 struct sockaddr_storage *qs,
306                 struct sockaddr_storage *rs,
307                 enum comm_point_type cptype,
308                 ProtobufCBinaryData *qaddr, protobuf_c_boolean *has_qaddr,
309                 uint32_t *qport, protobuf_c_boolean *has_qport,
310                 ProtobufCBinaryData *raddr, protobuf_c_boolean *has_raddr,
311                 uint32_t *rport, protobuf_c_boolean *has_rport)
312 {
313         log_assert(qs->ss_family == AF_INET6 || qs->ss_family == AF_INET);
314         if (qs->ss_family == AF_INET6) {
315                 struct sockaddr_in6 *q = (struct sockaddr_in6 *) qs;
316
317                 /* socket_family */
318                 dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET6;
319                 dm->m.has_socket_family = 1;
320
321                 /* addr: query_address or response_address */
322                 qaddr->data = q->sin6_addr.s6_addr;
323                 qaddr->len = 16; /* IPv6 */
324                 *has_qaddr = 1;
325
326                 /* port: query_port or response_port */
327                 *qport = ntohs(q->sin6_port);
328                 *has_qport = 1;
329         } else if (qs->ss_family == AF_INET) {
330                 struct sockaddr_in *q = (struct sockaddr_in *) qs;
331
332                 /* socket_family */
333                 dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET;
334                 dm->m.has_socket_family = 1;
335
336                 /* addr: query_address or response_address */
337                 qaddr->data = (uint8_t *) &q->sin_addr.s_addr;
338                 qaddr->len = 4; /* IPv4 */
339                 *has_qaddr = 1;
340
341                 /* port: query_port or response_port */
342                 *qport = ntohs(q->sin_port);
343                 *has_qport = 1;
344         }
345
346         /*
347          * This block is to fill second set of fields in DNSTAP-message defined as request_/response_ names.
348          * Additional responsive structure is: struct sockaddr_storage *rs
349          */
350         if (rs && rs->ss_family == AF_INET6) {
351                 struct sockaddr_in6 *r = (struct sockaddr_in6 *) rs;
352
353                 /* addr: query_address or response_address */
354                 raddr->data = r->sin6_addr.s6_addr;
355                 raddr->len = 16; /* IPv6 */
356                 *has_raddr = 1;
357
358                 /* port: query_port or response_port */
359                 *rport = ntohs(r->sin6_port);
360                 *has_rport = 1;
361         } else if (rs && rs->ss_family == AF_INET) {
362                 struct sockaddr_in *r = (struct sockaddr_in *) rs;
363
364                 /* addr: query_address or response_address */
365                 raddr->data = (uint8_t *) &r->sin_addr.s_addr;
366                 raddr->len = 4; /* IPv4 */
367                 *has_raddr = 1;
368
369                 /* port: query_port or response_port */
370                 *rport = ntohs(r->sin_port);
371                 *has_rport = 1;
372         }
373
374         log_assert(cptype == comm_udp || cptype == comm_tcp);
375         if (cptype == comm_udp) {
376                 /* socket_protocol */
377                 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__UDP;
378                 dm->m.has_socket_protocol = 1;
379         } else if (cptype == comm_tcp) {
380                 /* socket_protocol */
381                 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP;
382                 dm->m.has_socket_protocol = 1;
383         }
384 }
385
386 void
387 dt_msg_send_client_query(struct dt_env *env,
388                          struct sockaddr_storage *qsock,
389                          struct sockaddr_storage *rsock,
390                          enum comm_point_type cptype,
391                          sldns_buffer *qmsg,
392                          struct timeval* tstamp)
393 {
394         struct dt_msg dm;
395         struct timeval qtime;
396
397         if(tstamp)
398                 memcpy(&qtime, tstamp, sizeof(qtime));
399         else    gettimeofday(&qtime, NULL);
400
401         /* type */
402         dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__CLIENT_QUERY);
403
404         /* query_time */
405         dt_fill_timeval(&qtime,
406                         &dm.m.query_time_sec, &dm.m.has_query_time_sec,
407                         &dm.m.query_time_nsec, &dm.m.has_query_time_nsec);
408
409         /* query_message */
410         dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message);
411
412         /* socket_family, socket_protocol, query_address, query_port, response_address, response_port */
413         log_assert(cptype == comm_udp || cptype == comm_tcp);
414         dt_msg_fill_net(&dm, qsock, rsock, cptype,
415                         &dm.m.query_address, &dm.m.has_query_address,
416                         &dm.m.query_port, &dm.m.has_query_port,
417                         &dm.m.response_address, &dm.m.has_response_address,
418                         &dm.m.response_port, &dm.m.has_response_port);
419
420
421         if (dt_pack(&dm.d, &dm.buf, &dm.len_buf))
422                 dt_send(env, dm.buf, dm.len_buf);
423 }
424
425 void
426 dt_msg_send_client_response(struct dt_env *env,
427                             struct sockaddr_storage *qsock,
428                             struct sockaddr_storage *rsock,
429                             enum comm_point_type cptype,
430                             sldns_buffer *rmsg)
431 {
432         struct dt_msg dm;
433         struct timeval rtime;
434
435         gettimeofday(&rtime, NULL);
436
437         /* type */
438         dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE);
439
440         /* response_time */
441         dt_fill_timeval(&rtime,
442                         &dm.m.response_time_sec, &dm.m.has_response_time_sec,
443                         &dm.m.response_time_nsec, &dm.m.has_response_time_nsec);
444
445         /* response_message */
446         dt_fill_buffer(rmsg, &dm.m.response_message, &dm.m.has_response_message);
447
448         /* socket_family, socket_protocol, query_address, query_port, response_address, response_port */
449         log_assert(cptype == comm_udp || cptype == comm_tcp);
450         dt_msg_fill_net(&dm, qsock, rsock, cptype,
451                         &dm.m.query_address, &dm.m.has_query_address,
452                         &dm.m.query_port, &dm.m.has_query_port,
453                         &dm.m.response_address, &dm.m.has_response_address,
454                         &dm.m.response_port, &dm.m.has_response_port);
455
456         if (dt_pack(&dm.d, &dm.buf, &dm.len_buf))
457                 dt_send(env, dm.buf, dm.len_buf);
458 }
459
460 void
461 dt_msg_send_outside_query(struct dt_env *env,
462                           struct sockaddr_storage *rsock,
463                           struct sockaddr_storage *qsock,
464                           enum comm_point_type cptype,
465                           uint8_t *zone, size_t zone_len,
466                           sldns_buffer *qmsg)
467 {
468         struct dt_msg dm;
469         struct timeval qtime;
470         uint16_t qflags;
471
472         gettimeofday(&qtime, NULL);
473         qflags = sldns_buffer_read_u16_at(qmsg, 2);
474
475         /* type */
476         if (qflags & BIT_RD) {
477                 if (!env->log_forwarder_query_messages)
478                         return;
479                 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY);
480         } else {
481                 if (!env->log_resolver_query_messages)
482                         return;
483                 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY);
484         }
485
486         /* query_zone */
487         dm.m.query_zone.data = zone;
488         dm.m.query_zone.len = zone_len;
489         dm.m.has_query_zone = 1;
490
491         /* query_time_sec, query_time_nsec */
492         dt_fill_timeval(&qtime,
493                         &dm.m.query_time_sec, &dm.m.has_query_time_sec,
494                         &dm.m.query_time_nsec, &dm.m.has_query_time_nsec);
495
496         /* query_message */
497         dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message);
498
499         /* socket_family, socket_protocol, response_address, response_port, query_address, query_port */
500         log_assert(cptype == comm_udp || cptype == comm_tcp);
501         dt_msg_fill_net(&dm, rsock, qsock, cptype,
502                         &dm.m.response_address, &dm.m.has_response_address,
503                         &dm.m.response_port, &dm.m.has_response_port,
504                         &dm.m.query_address, &dm.m.has_query_address,
505                         &dm.m.query_port, &dm.m.has_query_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 void
512 dt_msg_send_outside_response(struct dt_env *env,
513         struct sockaddr_storage *rsock,
514         struct sockaddr_storage *qsock,
515         enum comm_point_type cptype,
516         uint8_t *zone, size_t zone_len,
517         uint8_t *qbuf, size_t qbuf_len,
518         const struct timeval *qtime,
519         const struct timeval *rtime,
520         sldns_buffer *rmsg)
521 {
522         struct dt_msg dm;
523         uint16_t qflags;
524
525         (void)qbuf_len; log_assert(qbuf_len >= sizeof(qflags));
526         memcpy(&qflags, qbuf, sizeof(qflags));
527         qflags = ntohs(qflags);
528
529         /* type */
530         if (qflags & BIT_RD) {
531                 if (!env->log_forwarder_response_messages)
532                         return;
533                 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE);
534         } else {
535                 if (!env->log_resolver_response_messages)
536                         return;
537                 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE);
538         }
539
540         /* query_zone */
541         dm.m.query_zone.data = zone;
542         dm.m.query_zone.len = zone_len;
543         dm.m.has_query_zone = 1;
544
545         /* query_time_sec, query_time_nsec */
546         dt_fill_timeval(qtime,
547                         &dm.m.query_time_sec, &dm.m.has_query_time_sec,
548                         &dm.m.query_time_nsec, &dm.m.has_query_time_nsec);
549
550         /* response_time_sec, response_time_nsec */
551         dt_fill_timeval(rtime,
552                         &dm.m.response_time_sec, &dm.m.has_response_time_sec,
553                         &dm.m.response_time_nsec, &dm.m.has_response_time_nsec);
554
555         /* response_message */
556         dt_fill_buffer(rmsg, &dm.m.response_message, &dm.m.has_response_message);
557
558         /* socket_family, socket_protocol, response_address, response_port, query_address, query_port */
559         log_assert(cptype == comm_udp || cptype == comm_tcp);
560         dt_msg_fill_net(&dm, rsock, qsock, cptype,
561                         &dm.m.response_address, &dm.m.has_response_address,
562                         &dm.m.response_port, &dm.m.has_response_port,
563                         &dm.m.query_address, &dm.m.has_query_address,
564                         &dm.m.query_port, &dm.m.has_query_port);
565
566         if (dt_pack(&dm.d, &dm.buf, &dm.len_buf))
567                 dt_send(env, dm.buf, dm.len_buf);
568 }
569
570 #endif /* USE_DNSTAP */