]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/unbound/dnstap/dnstap.c
MFV r367082:
[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 = fname_after_chroot(cfg->dnstap_socket_path, cfg, 1);
138                 if(!p) {
139                         log_err("malloc failure");
140                         return NULL;
141                 }
142                 verbose(VERB_OPS, "attempting to connect to dnstap socket %s",
143                         p);
144                 check_socket_file(p);
145                 free(p);
146         }
147
148         env = (struct dt_env *) calloc(1, sizeof(struct dt_env));
149         if (!env)
150                 return NULL;
151
152         env->dtio = dt_io_thread_create();
153         if(!env->dtio) {
154                 log_err("malloc failure");
155                 free(env);
156                 return NULL;
157         }
158         if(!dt_io_thread_apply_cfg(env->dtio, cfg)) {
159                 dt_io_thread_delete(env->dtio);
160                 free(env);
161                 return NULL;
162         }
163         dt_apply_cfg(env, cfg);
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, struct comm_base* base)
250 {
251         env->msgqueue = dt_msg_queue_create(base);
252         if(!env->msgqueue) {
253                 log_err("malloc failure");
254                 return 0;
255         }
256         if(!dt_io_thread_register_queue(env->dtio, env->msgqueue)) {
257                 log_err("malloc failure");
258                 dt_msg_queue_delete(env->msgqueue);
259                 env->msgqueue = NULL;
260                 return 0;
261         }
262         return 1;
263 }
264
265 void
266 dt_deinit(struct dt_env* env)
267 {
268         dt_io_thread_unregister_queue(env->dtio, env->msgqueue);
269         dt_msg_queue_delete(env->msgqueue);
270 }
271
272 void
273 dt_delete(struct dt_env *env)
274 {
275         if (!env)
276                 return;
277         dt_io_thread_delete(env->dtio);
278         free(env->identity);
279         free(env->version);
280         free(env);
281 }
282
283 static void
284 dt_fill_timeval(const struct timeval *tv,
285                 uint64_t *time_sec, protobuf_c_boolean *has_time_sec,
286                 uint32_t *time_nsec, protobuf_c_boolean *has_time_nsec)
287 {
288 #ifndef S_SPLINT_S
289         *time_sec = tv->tv_sec;
290         *time_nsec = tv->tv_usec * 1000;
291 #endif
292         *has_time_sec = 1;
293         *has_time_nsec = 1;
294 }
295
296 static void
297 dt_fill_buffer(sldns_buffer *b, ProtobufCBinaryData *p, protobuf_c_boolean *has)
298 {
299         log_assert(b != NULL);
300         p->len = sldns_buffer_limit(b);
301         p->data = sldns_buffer_begin(b);
302         *has = 1;
303 }
304
305 static void
306 dt_msg_fill_net(struct dt_msg *dm,
307                 struct sockaddr_storage *ss,
308                 enum comm_point_type cptype,
309                 ProtobufCBinaryData *addr, protobuf_c_boolean *has_addr,
310                 uint32_t *port, protobuf_c_boolean *has_port)
311 {
312         log_assert(ss->ss_family == AF_INET6 || ss->ss_family == AF_INET);
313         if (ss->ss_family == AF_INET6) {
314                 struct sockaddr_in6 *s = (struct sockaddr_in6 *) ss;
315
316                 /* socket_family */
317                 dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET6;
318                 dm->m.has_socket_family = 1;
319
320                 /* addr: query_address or response_address */
321                 addr->data = s->sin6_addr.s6_addr;
322                 addr->len = 16; /* IPv6 */
323                 *has_addr = 1;
324
325                 /* port: query_port or response_port */
326                 *port = ntohs(s->sin6_port);
327                 *has_port = 1;
328         } else if (ss->ss_family == AF_INET) {
329                 struct sockaddr_in *s = (struct sockaddr_in *) ss;
330
331                 /* socket_family */
332                 dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET;
333                 dm->m.has_socket_family = 1;
334
335                 /* addr: query_address or response_address */
336                 addr->data = (uint8_t *) &s->sin_addr.s_addr;
337                 addr->len = 4; /* IPv4 */
338                 *has_addr = 1;
339
340                 /* port: query_port or response_port */
341                 *port = ntohs(s->sin_port);
342                 *has_port = 1;
343         }
344
345         log_assert(cptype == comm_udp || cptype == comm_tcp);
346         if (cptype == comm_udp) {
347                 /* socket_protocol */
348                 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__UDP;
349                 dm->m.has_socket_protocol = 1;
350         } else if (cptype == comm_tcp) {
351                 /* socket_protocol */
352                 dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP;
353                 dm->m.has_socket_protocol = 1;
354         }
355 }
356
357 void
358 dt_msg_send_client_query(struct dt_env *env,
359                          struct sockaddr_storage *qsock,
360                          enum comm_point_type cptype,
361                          sldns_buffer *qmsg)
362 {
363         struct dt_msg dm;
364         struct timeval qtime;
365
366         gettimeofday(&qtime, NULL);
367
368         /* type */
369         dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__CLIENT_QUERY);
370
371         /* query_time */
372         dt_fill_timeval(&qtime,
373                         &dm.m.query_time_sec, &dm.m.has_query_time_sec,
374                         &dm.m.query_time_nsec, &dm.m.has_query_time_nsec);
375
376         /* query_message */
377         dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message);
378
379         /* socket_family, socket_protocol, query_address, query_port */
380         log_assert(cptype == comm_udp || cptype == comm_tcp);
381         dt_msg_fill_net(&dm, qsock, cptype,
382                         &dm.m.query_address, &dm.m.has_query_address,
383                         &dm.m.query_port, &dm.m.has_query_port);
384
385         if (dt_pack(&dm.d, &dm.buf, &dm.len_buf))
386                 dt_send(env, dm.buf, dm.len_buf);
387 }
388
389 void
390 dt_msg_send_client_response(struct dt_env *env,
391                             struct sockaddr_storage *qsock,
392                             enum comm_point_type cptype,
393                             sldns_buffer *rmsg)
394 {
395         struct dt_msg dm;
396         struct timeval rtime;
397
398         gettimeofday(&rtime, NULL);
399
400         /* type */
401         dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE);
402
403         /* response_time */
404         dt_fill_timeval(&rtime,
405                         &dm.m.response_time_sec, &dm.m.has_response_time_sec,
406                         &dm.m.response_time_nsec, &dm.m.has_response_time_nsec);
407
408         /* response_message */
409         dt_fill_buffer(rmsg, &dm.m.response_message, &dm.m.has_response_message);
410
411         /* socket_family, socket_protocol, query_address, query_port */
412         log_assert(cptype == comm_udp || cptype == comm_tcp);
413         dt_msg_fill_net(&dm, qsock, cptype,
414                         &dm.m.query_address, &dm.m.has_query_address,
415                         &dm.m.query_port, &dm.m.has_query_port);
416
417         if (dt_pack(&dm.d, &dm.buf, &dm.len_buf))
418                 dt_send(env, dm.buf, dm.len_buf);
419 }
420
421 void
422 dt_msg_send_outside_query(struct dt_env *env,
423                           struct sockaddr_storage *rsock,
424                           enum comm_point_type cptype,
425                           uint8_t *zone, size_t zone_len,
426                           sldns_buffer *qmsg)
427 {
428         struct dt_msg dm;
429         struct timeval qtime;
430         uint16_t qflags;
431
432         gettimeofday(&qtime, NULL);
433         qflags = sldns_buffer_read_u16_at(qmsg, 2);
434
435         /* type */
436         if (qflags & BIT_RD) {
437                 if (!env->log_forwarder_query_messages)
438                         return;
439                 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY);
440         } else {
441                 if (!env->log_resolver_query_messages)
442                         return;
443                 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY);
444         }
445
446         /* query_zone */
447         dm.m.query_zone.data = zone;
448         dm.m.query_zone.len = zone_len;
449         dm.m.has_query_zone = 1;
450
451         /* query_time_sec, query_time_nsec */
452         dt_fill_timeval(&qtime,
453                         &dm.m.query_time_sec, &dm.m.has_query_time_sec,
454                         &dm.m.query_time_nsec, &dm.m.has_query_time_nsec);
455
456         /* query_message */
457         dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message);
458
459         /* socket_family, socket_protocol, response_address, response_port */
460         log_assert(cptype == comm_udp || cptype == comm_tcp);
461         dt_msg_fill_net(&dm, rsock, cptype,
462                         &dm.m.response_address, &dm.m.has_response_address,
463                         &dm.m.response_port, &dm.m.has_response_port);
464
465         if (dt_pack(&dm.d, &dm.buf, &dm.len_buf))
466                 dt_send(env, dm.buf, dm.len_buf);
467 }
468
469 void
470 dt_msg_send_outside_response(struct dt_env *env,
471                              struct sockaddr_storage *rsock,
472                              enum comm_point_type cptype,
473                              uint8_t *zone, size_t zone_len,
474                              uint8_t *qbuf, size_t qbuf_len,
475                              const struct timeval *qtime,
476                              const struct timeval *rtime,
477                              sldns_buffer *rmsg)
478 {
479         struct dt_msg dm;
480         uint16_t qflags;
481
482         log_assert(qbuf_len >= sizeof(qflags));
483         memcpy(&qflags, qbuf, sizeof(qflags));
484         qflags = ntohs(qflags);
485
486         /* type */
487         if (qflags & BIT_RD) {
488                 if (!env->log_forwarder_response_messages)
489                         return;
490                 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE);
491         } else {
492                 if (!env->log_resolver_response_messages)
493                         return;
494                 dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE);
495         }
496
497         /* query_zone */
498         dm.m.query_zone.data = zone;
499         dm.m.query_zone.len = zone_len;
500         dm.m.has_query_zone = 1;
501
502         /* query_time_sec, query_time_nsec */
503         dt_fill_timeval(qtime,
504                         &dm.m.query_time_sec, &dm.m.has_query_time_sec,
505                         &dm.m.query_time_nsec, &dm.m.has_query_time_nsec);
506
507         /* response_time_sec, response_time_nsec */
508         dt_fill_timeval(rtime,
509                         &dm.m.response_time_sec, &dm.m.has_response_time_sec,
510                         &dm.m.response_time_nsec, &dm.m.has_response_time_nsec);
511
512         /* response_message */
513         dt_fill_buffer(rmsg, &dm.m.response_message, &dm.m.has_response_message);
514
515         /* socket_family, socket_protocol, response_address, response_port */
516         log_assert(cptype == comm_udp || cptype == comm_tcp);
517         dt_msg_fill_net(&dm, rsock, cptype,
518                         &dm.m.response_address, &dm.m.has_response_address,
519                         &dm.m.response_port, &dm.m.has_response_port);
520
521         if (dt_pack(&dm.d, &dm.buf, &dm.len_buf))
522                 dt_send(env, dm.buf, dm.len_buf);
523 }
524
525 #endif /* USE_DNSTAP */