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