1e02bc0dfSflorian /*
2e02bc0dfSflorian * dnstap/dnstap_collector.c -- nsd collector process for dnstap information
3e02bc0dfSflorian *
4e02bc0dfSflorian * Copyright (c) 2018, NLnet Labs. All rights reserved.
5e02bc0dfSflorian *
6e02bc0dfSflorian * See LICENSE for the license.
7e02bc0dfSflorian *
8e02bc0dfSflorian */
9e02bc0dfSflorian
10e02bc0dfSflorian #include "config.h"
11e02bc0dfSflorian #include <sys/types.h>
12e02bc0dfSflorian #include <sys/socket.h>
13e02bc0dfSflorian #include <errno.h>
14e02bc0dfSflorian #include <fcntl.h>
15e02bc0dfSflorian #include <unistd.h>
16e02bc0dfSflorian #ifndef USE_MINI_EVENT
17e02bc0dfSflorian # ifdef HAVE_EVENT_H
18e02bc0dfSflorian # include <event.h>
19e02bc0dfSflorian # else
20e02bc0dfSflorian # include <event2/event.h>
21e02bc0dfSflorian # include "event2/event_struct.h"
22e02bc0dfSflorian # include "event2/event_compat.h"
23e02bc0dfSflorian # endif
24e02bc0dfSflorian #else
25e02bc0dfSflorian # include "mini_event.h"
26e02bc0dfSflorian #endif
27e02bc0dfSflorian #include "dnstap/dnstap_collector.h"
28e02bc0dfSflorian #include "dnstap/dnstap.h"
29e02bc0dfSflorian #include "util.h"
30e02bc0dfSflorian #include "nsd.h"
31e02bc0dfSflorian #include "region-allocator.h"
32e02bc0dfSflorian #include "buffer.h"
33e02bc0dfSflorian #include "namedb.h"
34e02bc0dfSflorian #include "options.h"
353efee2e1Sflorian #include "remote.h"
36e02bc0dfSflorian
37063644e9Sflorian #include "udb.h"
38063644e9Sflorian #include "rrl.h"
39063644e9Sflorian
dt_collector_create(struct nsd * nsd)40e02bc0dfSflorian struct dt_collector* dt_collector_create(struct nsd* nsd)
41e02bc0dfSflorian {
42e02bc0dfSflorian int i, sv[2];
43e02bc0dfSflorian struct dt_collector* dt_col = (struct dt_collector*)xalloc_zero(
44e02bc0dfSflorian sizeof(*dt_col));
45063644e9Sflorian dt_col->count = nsd->child_count * 2;
46e02bc0dfSflorian dt_col->dt_env = NULL;
47e02bc0dfSflorian dt_col->region = region_create(xalloc, free);
48e02bc0dfSflorian dt_col->send_buffer = buffer_create(dt_col->region,
493aefc4aaSsthen /* msglen + is_response + addrlen + is_tcp + packetlen + packet + zonelen + zone + spare + local_addr + addr */
50e02bc0dfSflorian 4+1+4+1+4+TCP_MAX_MESSAGE_LEN+4+MAXHOSTNAMELEN + 32 +
51e02bc0dfSflorian #ifdef INET6
523aefc4aaSsthen sizeof(struct sockaddr_storage) + sizeof(struct sockaddr_storage)
53e02bc0dfSflorian #else
543aefc4aaSsthen sizeof(struct sockaddr_in) + sizeof(struct sockaddr_in)
55e02bc0dfSflorian #endif
56e02bc0dfSflorian );
57e02bc0dfSflorian
58063644e9Sflorian /* open communication channels in struct nsd */
59e02bc0dfSflorian nsd->dt_collector_fd_send = (int*)xalloc_array_zero(dt_col->count,
60e02bc0dfSflorian sizeof(int));
61e02bc0dfSflorian nsd->dt_collector_fd_recv = (int*)xalloc_array_zero(dt_col->count,
62e02bc0dfSflorian sizeof(int));
63e02bc0dfSflorian for(i=0; i<dt_col->count; i++) {
64063644e9Sflorian int sv[2];
65063644e9Sflorian int bufsz = buffer_capacity(dt_col->send_buffer);
66063644e9Sflorian sv[0] = -1; /* For receiving by parent (dnstap-collector) */
67063644e9Sflorian sv[1] = -1; /* For sending by child (server childs) */
68*b71395eaSflorian if(socketpair(AF_UNIX, SOCK_DGRAM
69*b71395eaSflorian #ifdef SOCK_NONBLOCK
70*b71395eaSflorian | SOCK_NONBLOCK
71*b71395eaSflorian #endif
72*b71395eaSflorian , 0, sv) < 0) {
73063644e9Sflorian error("dnstap_collector: cannot create communication channel: %s",
74e02bc0dfSflorian strerror(errno));
75e02bc0dfSflorian }
76*b71395eaSflorian #ifndef SOCK_NONBLOCK
77*b71395eaSflorian if (fcntl(sv[0], F_SETFL, O_NONBLOCK) == -1) {
78*b71395eaSflorian log_msg(LOG_ERR, "dnstap_collector receive fd fcntl "
79*b71395eaSflorian "failed: %s", strerror(errno));
80*b71395eaSflorian }
81*b71395eaSflorian if (fcntl(sv[1], F_SETFL, O_NONBLOCK) == -1) {
82*b71395eaSflorian log_msg(LOG_ERR, "dnstap_collector send fd fcntl "
83*b71395eaSflorian "failed: %s", strerror(errno));
84*b71395eaSflorian }
85*b71395eaSflorian #endif
86063644e9Sflorian if(setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &bufsz, sizeof(bufsz))) {
87063644e9Sflorian log_msg(LOG_ERR, "setting dnstap_collector "
88063644e9Sflorian "receive buffer size failed: %s", strerror(errno));
89e02bc0dfSflorian }
90063644e9Sflorian if(setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &bufsz, sizeof(bufsz))) {
91063644e9Sflorian log_msg(LOG_ERR, "setting dnstap_collector "
92063644e9Sflorian "send buffer size failed: %s", strerror(errno));
93e02bc0dfSflorian }
94063644e9Sflorian nsd->dt_collector_fd_recv[i] = sv[0];
95063644e9Sflorian nsd->dt_collector_fd_send[i] = sv[1];
96e02bc0dfSflorian }
97063644e9Sflorian nsd->dt_collector_fd_swap = nsd->dt_collector_fd_send + nsd->child_count;
98e02bc0dfSflorian
99e02bc0dfSflorian /* open socketpair */
100e02bc0dfSflorian if(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
101e02bc0dfSflorian error("dnstap_collector: cannot create socketpair: %s",
102e02bc0dfSflorian strerror(errno));
103e02bc0dfSflorian }
104e02bc0dfSflorian if(fcntl(sv[0], F_SETFL, O_NONBLOCK) == -1) {
105e02bc0dfSflorian log_msg(LOG_ERR, "fcntl failed: %s", strerror(errno));
106e02bc0dfSflorian }
107e02bc0dfSflorian if(fcntl(sv[1], F_SETFL, O_NONBLOCK) == -1) {
108e02bc0dfSflorian log_msg(LOG_ERR, "fcntl failed: %s", strerror(errno));
109e02bc0dfSflorian }
110e02bc0dfSflorian dt_col->cmd_socket_dt = sv[0];
111e02bc0dfSflorian dt_col->cmd_socket_nsd = sv[1];
112e02bc0dfSflorian
113e02bc0dfSflorian return dt_col;
114e02bc0dfSflorian }
115e02bc0dfSflorian
dt_collector_destroy(struct dt_collector * dt_col,struct nsd * nsd)116e02bc0dfSflorian void dt_collector_destroy(struct dt_collector* dt_col, struct nsd* nsd)
117e02bc0dfSflorian {
118e02bc0dfSflorian if(!dt_col) return;
119e02bc0dfSflorian free(nsd->dt_collector_fd_recv);
120e02bc0dfSflorian nsd->dt_collector_fd_recv = NULL;
121063644e9Sflorian if (nsd->dt_collector_fd_send < nsd->dt_collector_fd_swap)
122e02bc0dfSflorian free(nsd->dt_collector_fd_send);
123063644e9Sflorian else
124063644e9Sflorian free(nsd->dt_collector_fd_swap);
125e02bc0dfSflorian nsd->dt_collector_fd_send = NULL;
126063644e9Sflorian nsd->dt_collector_fd_swap = NULL;
127e02bc0dfSflorian region_destroy(dt_col->region);
128e02bc0dfSflorian free(dt_col);
129e02bc0dfSflorian }
130e02bc0dfSflorian
dt_collector_close(struct dt_collector * dt_col,struct nsd * nsd)131e02bc0dfSflorian void dt_collector_close(struct dt_collector* dt_col, struct nsd* nsd)
132e02bc0dfSflorian {
133063644e9Sflorian int i, *fd_send;
134e02bc0dfSflorian if(!dt_col) return;
135e02bc0dfSflorian if(dt_col->cmd_socket_dt != -1) {
136e02bc0dfSflorian close(dt_col->cmd_socket_dt);
137e02bc0dfSflorian dt_col->cmd_socket_dt = -1;
138e02bc0dfSflorian }
139e02bc0dfSflorian if(dt_col->cmd_socket_nsd != -1) {
140e02bc0dfSflorian close(dt_col->cmd_socket_nsd);
141e02bc0dfSflorian dt_col->cmd_socket_nsd = -1;
142e02bc0dfSflorian }
143063644e9Sflorian fd_send = nsd->dt_collector_fd_send < nsd->dt_collector_fd_swap
144063644e9Sflorian ? nsd->dt_collector_fd_send : nsd->dt_collector_fd_swap;
145e02bc0dfSflorian for(i=0; i<dt_col->count; i++) {
146e02bc0dfSflorian if(nsd->dt_collector_fd_recv[i] != -1) {
147e02bc0dfSflorian close(nsd->dt_collector_fd_recv[i]);
148e02bc0dfSflorian nsd->dt_collector_fd_recv[i] = -1;
149e02bc0dfSflorian }
150063644e9Sflorian if(fd_send[i] != -1) {
151063644e9Sflorian close(fd_send[i]);
152063644e9Sflorian fd_send[i] = -1;
153e02bc0dfSflorian }
154e02bc0dfSflorian }
155e02bc0dfSflorian }
156e02bc0dfSflorian
157e02bc0dfSflorian /* handle command from nsd to dt collector.
158e02bc0dfSflorian * mostly, check for fd closed, this means we have to exit */
159e02bc0dfSflorian void
dt_handle_cmd_from_nsd(int ATTR_UNUSED (fd),short event,void * arg)160e02bc0dfSflorian dt_handle_cmd_from_nsd(int ATTR_UNUSED(fd), short event, void* arg)
161e02bc0dfSflorian {
162e02bc0dfSflorian struct dt_collector* dt_col = (struct dt_collector*)arg;
163e02bc0dfSflorian if((event&EV_READ) != 0) {
164e02bc0dfSflorian event_base_loopexit(dt_col->event_base, NULL);
165e02bc0dfSflorian }
166e02bc0dfSflorian }
167e02bc0dfSflorian
168063644e9Sflorian /* receive data from fd into buffer, 1 when message received, -1 on error */
recv_into_buffer(int fd,struct buffer * buf)169063644e9Sflorian static int recv_into_buffer(int fd, struct buffer* buf)
170e02bc0dfSflorian {
171e02bc0dfSflorian size_t msglen;
172e02bc0dfSflorian ssize_t r;
173e02bc0dfSflorian
174063644e9Sflorian assert(buffer_position(buf) == 0);
175063644e9Sflorian r = recv(fd, buffer_current(buf), buffer_capacity(buf), MSG_DONTWAIT);
176063644e9Sflorian if(r == -1) {
177063644e9Sflorian if(errno == EAGAIN || errno == EINTR || errno == EMSGSIZE) {
178063644e9Sflorian /* continue to receive a message later */
179063644e9Sflorian return 0;
180063644e9Sflorian }
181063644e9Sflorian log_msg(LOG_ERR, "dnstap collector: receive failed: %s",
182063644e9Sflorian strerror(errno));
183063644e9Sflorian return -1;
184063644e9Sflorian }
185063644e9Sflorian if(r == 0) {
186063644e9Sflorian /* Remote end closed the connection? */
187063644e9Sflorian log_msg(LOG_ERR, "dnstap collector: remote closed connection");
188063644e9Sflorian return -1;
189063644e9Sflorian }
190063644e9Sflorian assert(r > 4);
191e02bc0dfSflorian msglen = buffer_read_u32_at(buf, 0);
192063644e9Sflorian if(msglen != (size_t)(r - 4)) {
193063644e9Sflorian /* Is this still possible now the communication channel is of
194063644e9Sflorian * type SOCK_DGRAM? I think not, but better safe than sorry. */
195063644e9Sflorian log_msg(LOG_ERR, "dnstap collector: out of sync (msglen: %u)",
196063644e9Sflorian (unsigned int) msglen);
197e02bc0dfSflorian return 0;
198e02bc0dfSflorian }
199e02bc0dfSflorian buffer_skip(buf, r);
200e02bc0dfSflorian buffer_flip(buf);
201e02bc0dfSflorian return 1;
202e02bc0dfSflorian }
203e02bc0dfSflorian
204e02bc0dfSflorian /* submit the content of the buffer received to dnstap */
205e02bc0dfSflorian static void
dt_submit_content(struct dt_env * dt_env,struct buffer * buf)206e02bc0dfSflorian dt_submit_content(struct dt_env* dt_env, struct buffer* buf)
207e02bc0dfSflorian {
208e02bc0dfSflorian uint8_t is_response, is_tcp;
209e02bc0dfSflorian #ifdef INET6
2103aefc4aaSsthen struct sockaddr_storage local_addr, addr;
211e02bc0dfSflorian #else
2123aefc4aaSsthen struct sockaddr_in local_addr, addr;
213e02bc0dfSflorian #endif
214e02bc0dfSflorian socklen_t addrlen;
215e02bc0dfSflorian size_t pktlen;
216e02bc0dfSflorian uint8_t* data;
217e02bc0dfSflorian size_t zonelen;
218e02bc0dfSflorian uint8_t* zone;
219e02bc0dfSflorian
220e02bc0dfSflorian /* parse content from buffer */
221e02bc0dfSflorian if(!buffer_available(buf, 4+1+4)) return;
222e02bc0dfSflorian buffer_skip(buf, 4); /* skip msglen */
223e02bc0dfSflorian is_response = buffer_read_u8(buf);
224e02bc0dfSflorian addrlen = buffer_read_u32(buf);
2253aefc4aaSsthen if(addrlen > sizeof(local_addr) || addrlen > sizeof(addr)) return;
2263aefc4aaSsthen if(!buffer_available(buf, 2*addrlen)) return;
2273aefc4aaSsthen buffer_read(buf, &local_addr, addrlen);
228e02bc0dfSflorian buffer_read(buf, &addr, addrlen);
229e02bc0dfSflorian if(!buffer_available(buf, 1+4)) return;
230e02bc0dfSflorian is_tcp = buffer_read_u8(buf);
231e02bc0dfSflorian pktlen = buffer_read_u32(buf);
232e02bc0dfSflorian if(!buffer_available(buf, pktlen)) return;
233e02bc0dfSflorian data = buffer_current(buf);
234e02bc0dfSflorian buffer_skip(buf, pktlen);
235e02bc0dfSflorian if(!buffer_available(buf, 4)) return;
236e02bc0dfSflorian zonelen = buffer_read_u32(buf);
237e02bc0dfSflorian if(zonelen == 0) {
238e02bc0dfSflorian zone = NULL;
239e02bc0dfSflorian } else {
240e02bc0dfSflorian if(zonelen > MAXDOMAINLEN) return;
241e02bc0dfSflorian if(!buffer_available(buf, zonelen)) return;
242e02bc0dfSflorian zone = buffer_current(buf);
243e02bc0dfSflorian buffer_skip(buf, zonelen);
244e02bc0dfSflorian }
245e02bc0dfSflorian
246e02bc0dfSflorian /* submit it */
247e02bc0dfSflorian if(is_response) {
2483aefc4aaSsthen dt_msg_send_auth_response(dt_env, &local_addr, &addr, is_tcp, zone,
249e02bc0dfSflorian zonelen, data, pktlen);
250e02bc0dfSflorian } else {
2513aefc4aaSsthen dt_msg_send_auth_query(dt_env, &local_addr, &addr, is_tcp, zone,
252e02bc0dfSflorian zonelen, data, pktlen);
253e02bc0dfSflorian }
254e02bc0dfSflorian }
255e02bc0dfSflorian
256e02bc0dfSflorian /* handle input from worker for dnstap */
257e02bc0dfSflorian void
dt_handle_input(int fd,short event,void * arg)258e02bc0dfSflorian dt_handle_input(int fd, short event, void* arg)
259e02bc0dfSflorian {
260e02bc0dfSflorian struct dt_collector_input* dt_input = (struct dt_collector_input*)arg;
261e02bc0dfSflorian if((event&EV_READ) != 0) {
262063644e9Sflorian /* receive */
263063644e9Sflorian int r = recv_into_buffer(fd, dt_input->buffer);
264063644e9Sflorian if(r == 0)
265e02bc0dfSflorian return;
266063644e9Sflorian else if(r < 0) {
267063644e9Sflorian event_base_loopexit(dt_input->dt_collector->event_base, NULL);
268063644e9Sflorian return;
269063644e9Sflorian }
270063644e9Sflorian /* once data is complete, send it to dnstap */
271e02bc0dfSflorian VERBOSITY(4, (LOG_INFO, "dnstap collector: received msg len %d",
272e02bc0dfSflorian (int)buffer_remaining(dt_input->buffer)));
273e02bc0dfSflorian if(dt_input->dt_collector->dt_env) {
274e02bc0dfSflorian dt_submit_content(dt_input->dt_collector->dt_env,
275e02bc0dfSflorian dt_input->buffer);
276e02bc0dfSflorian }
277e02bc0dfSflorian
278e02bc0dfSflorian /* clear buffer for next message */
279e02bc0dfSflorian buffer_clear(dt_input->buffer);
280e02bc0dfSflorian }
281e02bc0dfSflorian }
282e02bc0dfSflorian
283e02bc0dfSflorian /* init dnstap */
dt_init_dnstap(struct dt_collector * dt_col,struct nsd * nsd)284e02bc0dfSflorian static void dt_init_dnstap(struct dt_collector* dt_col, struct nsd* nsd)
285e02bc0dfSflorian {
286e02bc0dfSflorian int num_workers = 1;
287e02bc0dfSflorian #ifdef HAVE_CHROOT
288e02bc0dfSflorian if(nsd->chrootdir && nsd->chrootdir[0]) {
289e02bc0dfSflorian int l = strlen(nsd->chrootdir)-1; /* ends in trailing slash */
290e02bc0dfSflorian if (nsd->options->dnstap_socket_path &&
291e02bc0dfSflorian nsd->options->dnstap_socket_path[0] == '/' &&
292e02bc0dfSflorian strncmp(nsd->options->dnstap_socket_path,
293e02bc0dfSflorian nsd->chrootdir, l) == 0)
294e02bc0dfSflorian nsd->options->dnstap_socket_path += l;
295e02bc0dfSflorian }
296e02bc0dfSflorian #endif
2973efee2e1Sflorian dt_col->dt_env = dt_create(nsd->options->dnstap_socket_path,
2983efee2e1Sflorian nsd->options->dnstap_ip, num_workers, nsd->options->dnstap_tls,
2993efee2e1Sflorian nsd->options->dnstap_tls_server_name,
3003efee2e1Sflorian nsd->options->dnstap_tls_cert_bundle,
3013efee2e1Sflorian nsd->options->dnstap_tls_client_key_file,
3023efee2e1Sflorian nsd->options->dnstap_tls_client_cert_file);
303e02bc0dfSflorian if(!dt_col->dt_env) {
304e02bc0dfSflorian log_msg(LOG_ERR, "could not create dnstap env");
305e02bc0dfSflorian return;
306e02bc0dfSflorian }
307e02bc0dfSflorian dt_apply_cfg(dt_col->dt_env, nsd->options);
308e02bc0dfSflorian dt_init(dt_col->dt_env);
309e02bc0dfSflorian }
310e02bc0dfSflorian
311e02bc0dfSflorian /* cleanup dt collector process for exit */
dt_collector_cleanup(struct dt_collector * dt_col,struct nsd * nsd)312e02bc0dfSflorian static void dt_collector_cleanup(struct dt_collector* dt_col, struct nsd* nsd)
313e02bc0dfSflorian {
314e02bc0dfSflorian int i;
315e02bc0dfSflorian dt_delete(dt_col->dt_env);
316e02bc0dfSflorian event_del(dt_col->cmd_event);
317e02bc0dfSflorian for(i=0; i<dt_col->count; i++) {
318e02bc0dfSflorian event_del(dt_col->inputs[i].event);
319e02bc0dfSflorian }
320e02bc0dfSflorian dt_collector_close(dt_col, nsd);
321e02bc0dfSflorian event_base_free(dt_col->event_base);
322e02bc0dfSflorian #ifdef MEMCLEAN
323e02bc0dfSflorian free(dt_col->cmd_event);
324e02bc0dfSflorian if(dt_col->inputs) {
325e02bc0dfSflorian for(i=0; i<dt_col->count; i++) {
326e02bc0dfSflorian free(dt_col->inputs[i].event);
327e02bc0dfSflorian }
328e02bc0dfSflorian free(dt_col->inputs);
329e02bc0dfSflorian }
330e02bc0dfSflorian dt_collector_destroy(dt_col, nsd);
3313efee2e1Sflorian daemon_remote_delete(nsd->rc); /* ssl-delete secret keys */
3323efee2e1Sflorian nsd_options_destroy(nsd->options);
3333efee2e1Sflorian region_destroy(nsd->region);
334e02bc0dfSflorian #endif
335e02bc0dfSflorian }
336e02bc0dfSflorian
337e02bc0dfSflorian /* attach events to the event base to listen to the workers and cmd channel */
dt_attach_events(struct dt_collector * dt_col,struct nsd * nsd)338e02bc0dfSflorian static void dt_attach_events(struct dt_collector* dt_col, struct nsd* nsd)
339e02bc0dfSflorian {
340e02bc0dfSflorian int i;
341e02bc0dfSflorian /* create event base */
342e02bc0dfSflorian dt_col->event_base = nsd_child_event_base();
343e02bc0dfSflorian if(!dt_col->event_base) {
344e02bc0dfSflorian error("dnstap collector: event_base create failed");
345e02bc0dfSflorian }
346e02bc0dfSflorian
347e02bc0dfSflorian /* add command handler */
348e02bc0dfSflorian dt_col->cmd_event = (struct event*)xalloc_zero(
349e02bc0dfSflorian sizeof(*dt_col->cmd_event));
350e02bc0dfSflorian event_set(dt_col->cmd_event, dt_col->cmd_socket_dt,
351e02bc0dfSflorian EV_PERSIST|EV_READ, dt_handle_cmd_from_nsd, dt_col);
352e02bc0dfSflorian if(event_base_set(dt_col->event_base, dt_col->cmd_event) != 0)
353e02bc0dfSflorian log_msg(LOG_ERR, "dnstap collector: event_base_set failed");
354e02bc0dfSflorian if(event_add(dt_col->cmd_event, NULL) != 0)
355e02bc0dfSflorian log_msg(LOG_ERR, "dnstap collector: event_add failed");
356e02bc0dfSflorian
357e02bc0dfSflorian /* add worker input handlers */
358e02bc0dfSflorian dt_col->inputs = xalloc_array_zero(dt_col->count,
359e02bc0dfSflorian sizeof(*dt_col->inputs));
360e02bc0dfSflorian for(i=0; i<dt_col->count; i++) {
361e02bc0dfSflorian dt_col->inputs[i].dt_collector = dt_col;
362e02bc0dfSflorian dt_col->inputs[i].event = (struct event*)xalloc_zero(
363e02bc0dfSflorian sizeof(struct event));
364e02bc0dfSflorian event_set(dt_col->inputs[i].event,
365e02bc0dfSflorian nsd->dt_collector_fd_recv[i], EV_PERSIST|EV_READ,
366e02bc0dfSflorian dt_handle_input, &dt_col->inputs[i]);
367e02bc0dfSflorian if(event_base_set(dt_col->event_base,
368e02bc0dfSflorian dt_col->inputs[i].event) != 0)
369e02bc0dfSflorian log_msg(LOG_ERR, "dnstap collector: event_base_set failed");
370e02bc0dfSflorian if(event_add(dt_col->inputs[i].event, NULL) != 0)
371e02bc0dfSflorian log_msg(LOG_ERR, "dnstap collector: event_add failed");
372e02bc0dfSflorian
373e02bc0dfSflorian dt_col->inputs[i].buffer = buffer_create(dt_col->region,
3743aefc4aaSsthen /* msglen + is_response + addrlen + is_tcp + packetlen + packet + zonelen + zone + spare + local_addr + addr */
375e02bc0dfSflorian 4+1+4+1+4+TCP_MAX_MESSAGE_LEN+4+MAXHOSTNAMELEN + 32 +
376e02bc0dfSflorian #ifdef INET6
3773aefc4aaSsthen sizeof(struct sockaddr_storage) + sizeof(struct sockaddr_storage)
378e02bc0dfSflorian #else
3793aefc4aaSsthen sizeof(struct sockaddr_in) + sizeof(struct sockaddr_in)
380e02bc0dfSflorian #endif
381e02bc0dfSflorian );
382e02bc0dfSflorian assert(buffer_capacity(dt_col->inputs[i].buffer) ==
383e02bc0dfSflorian buffer_capacity(dt_col->send_buffer));
384e02bc0dfSflorian }
385e02bc0dfSflorian }
386e02bc0dfSflorian
387e02bc0dfSflorian /* the dnstap collector process main routine */
dt_collector_run(struct dt_collector * dt_col,struct nsd * nsd)388e02bc0dfSflorian static void dt_collector_run(struct dt_collector* dt_col, struct nsd* nsd)
389e02bc0dfSflorian {
390e02bc0dfSflorian /* init dnstap */
391e02bc0dfSflorian VERBOSITY(1, (LOG_INFO, "dnstap collector started"));
392e02bc0dfSflorian dt_init_dnstap(dt_col, nsd);
393e02bc0dfSflorian dt_attach_events(dt_col, nsd);
394e02bc0dfSflorian
395e02bc0dfSflorian /* run */
396e02bc0dfSflorian if(event_base_loop(dt_col->event_base, 0) == -1) {
397e02bc0dfSflorian error("dnstap collector: event_base_loop failed");
398e02bc0dfSflorian }
399e02bc0dfSflorian
400e02bc0dfSflorian /* cleanup and done */
401e02bc0dfSflorian VERBOSITY(1, (LOG_INFO, "dnstap collector stopped"));
402e02bc0dfSflorian dt_collector_cleanup(dt_col, nsd);
403e02bc0dfSflorian exit(0);
404e02bc0dfSflorian }
405e02bc0dfSflorian
dt_collector_start(struct dt_collector * dt_col,struct nsd * nsd)406e02bc0dfSflorian void dt_collector_start(struct dt_collector* dt_col, struct nsd* nsd)
407e02bc0dfSflorian {
408063644e9Sflorian int i, *fd_send;
409e02bc0dfSflorian /* fork */
410e02bc0dfSflorian dt_col->dt_pid = fork();
411e02bc0dfSflorian if(dt_col->dt_pid == -1) {
412e02bc0dfSflorian error("dnstap_collector: fork failed: %s", strerror(errno));
413e02bc0dfSflorian }
414e02bc0dfSflorian if(dt_col->dt_pid == 0) {
415e02bc0dfSflorian /* the dt collector process is this */
416e02bc0dfSflorian /* close the nsd side of the command channel */
417e02bc0dfSflorian close(dt_col->cmd_socket_nsd);
418e02bc0dfSflorian dt_col->cmd_socket_nsd = -1;
419063644e9Sflorian
420063644e9Sflorian /* close the send side of the communication channels */
421063644e9Sflorian assert(nsd->dt_collector_fd_send < nsd->dt_collector_fd_swap);
422063644e9Sflorian fd_send = nsd->dt_collector_fd_send < nsd->dt_collector_fd_swap
423063644e9Sflorian ? nsd->dt_collector_fd_send : nsd->dt_collector_fd_swap;
424063644e9Sflorian for(i=0; i<dt_col->count; i++) {
425063644e9Sflorian if(fd_send[i] != -1) {
426063644e9Sflorian close(fd_send[i]);
427063644e9Sflorian fd_send[i] = -1;
428063644e9Sflorian }
429063644e9Sflorian }
430063644e9Sflorian #ifdef HAVE_SETPROCTITLE
431063644e9Sflorian setproctitle("dnstap_collector");
432063644e9Sflorian #endif
433063644e9Sflorian /* Free serve process specific memory pages */
434063644e9Sflorian #ifdef RATELIMIT
435063644e9Sflorian rrl_mmap_deinit_keep_mmap();
436063644e9Sflorian #endif
437063644e9Sflorian udb_base_free_keep_mmap(nsd->task[0]);
438063644e9Sflorian udb_base_free_keep_mmap(nsd->task[1]);
439063644e9Sflorian namedb_close(nsd->db);
440063644e9Sflorian
441e02bc0dfSflorian dt_collector_run(dt_col, nsd);
442e02bc0dfSflorian /* NOTREACH */
443e02bc0dfSflorian exit(0);
444e02bc0dfSflorian } else {
445e02bc0dfSflorian /* the parent continues on, with starting NSD */
446e02bc0dfSflorian /* close the dt side of the command channel */
447e02bc0dfSflorian close(dt_col->cmd_socket_dt);
448e02bc0dfSflorian dt_col->cmd_socket_dt = -1;
449063644e9Sflorian
450063644e9Sflorian /* close the receive side of the communication channels */
451063644e9Sflorian for(i=0; i<dt_col->count; i++) {
452063644e9Sflorian if(nsd->dt_collector_fd_recv[i] != -1) {
453063644e9Sflorian close(nsd->dt_collector_fd_recv[i]);
454063644e9Sflorian nsd->dt_collector_fd_recv[i] = -1;
455063644e9Sflorian }
456063644e9Sflorian }
457e02bc0dfSflorian }
458e02bc0dfSflorian }
459e02bc0dfSflorian
460e02bc0dfSflorian /* put data for sending to the collector process into the buffer */
461e02bc0dfSflorian static int
prep_send_data(struct buffer * buf,uint8_t is_response,struct sockaddr_storage * local_addr,struct sockaddr_storage * addr,socklen_t addrlen,int is_tcp,struct buffer * packet,struct zone * zone)462e02bc0dfSflorian prep_send_data(struct buffer* buf, uint8_t is_response,
463e02bc0dfSflorian #ifdef INET6
4643aefc4aaSsthen struct sockaddr_storage* local_addr,
465e02bc0dfSflorian struct sockaddr_storage* addr,
466e02bc0dfSflorian #else
4673aefc4aaSsthen struct sockaddr_in* local_addr,
468e02bc0dfSflorian struct sockaddr_in* addr,
469e02bc0dfSflorian #endif
470e02bc0dfSflorian socklen_t addrlen, int is_tcp, struct buffer* packet,
471e02bc0dfSflorian struct zone* zone)
472e02bc0dfSflorian {
473e02bc0dfSflorian buffer_clear(buf);
4743aefc4aaSsthen #ifdef INET6
4753aefc4aaSsthen if(local_addr->ss_family != addr->ss_family)
4763aefc4aaSsthen return 0; /* must be same length to send */
4773aefc4aaSsthen #else
4783aefc4aaSsthen if(local_addr->sin_family != addr->sin_family)
4793aefc4aaSsthen return 0; /* must be same length to send */
4803aefc4aaSsthen #endif
4813aefc4aaSsthen if(!buffer_available(buf, 4+1+4+2*addrlen+1+4+buffer_remaining(packet)))
482e02bc0dfSflorian return 0; /* does not fit in send_buffer, log is dropped */
483e02bc0dfSflorian buffer_skip(buf, 4); /* the length of the message goes here */
484e02bc0dfSflorian buffer_write_u8(buf, is_response);
485e02bc0dfSflorian buffer_write_u32(buf, addrlen);
4863aefc4aaSsthen buffer_write(buf, local_addr, (size_t)addrlen);
487e02bc0dfSflorian buffer_write(buf, addr, (size_t)addrlen);
488e02bc0dfSflorian buffer_write_u8(buf, (is_tcp?1:0));
489e02bc0dfSflorian buffer_write_u32(buf, buffer_remaining(packet));
490e02bc0dfSflorian buffer_write(buf, buffer_begin(packet), buffer_remaining(packet));
491e02bc0dfSflorian if(zone && zone->apex && domain_dname(zone->apex)) {
492e02bc0dfSflorian if(!buffer_available(buf, 4 + domain_dname(zone->apex)->name_size))
493e02bc0dfSflorian return 0;
494e02bc0dfSflorian buffer_write_u32(buf, domain_dname(zone->apex)->name_size);
495e02bc0dfSflorian buffer_write(buf, dname_name(domain_dname(zone->apex)),
496e02bc0dfSflorian domain_dname(zone->apex)->name_size);
497e02bc0dfSflorian } else {
498e02bc0dfSflorian if(!buffer_available(buf, 4))
499e02bc0dfSflorian return 0;
500e02bc0dfSflorian buffer_write_u32(buf, 0);
501e02bc0dfSflorian }
502e02bc0dfSflorian
503e02bc0dfSflorian buffer_flip(buf);
504e02bc0dfSflorian /* write length of message */
505e02bc0dfSflorian buffer_write_u32_at(buf, 0, buffer_remaining(buf)-4);
506e02bc0dfSflorian return 1;
507e02bc0dfSflorian }
508e02bc0dfSflorian
509063644e9Sflorian /* attempt to send buffer to socket, if it blocks do not send it.
510063644e9Sflorian * return 0 on success, -1 on error */
attempt_to_send(int s,uint8_t * data,size_t len)511063644e9Sflorian static int attempt_to_send(int s, uint8_t* data, size_t len)
512e02bc0dfSflorian {
513e02bc0dfSflorian ssize_t r;
514063644e9Sflorian if(len == 0)
515063644e9Sflorian return 0;
516063644e9Sflorian r = send(s, data, len, MSG_DONTWAIT | MSG_NOSIGNAL);
517e02bc0dfSflorian if(r == -1) {
518063644e9Sflorian if(errno == EAGAIN || errno == EINTR ||
519063644e9Sflorian errno == ENOBUFS || errno == EMSGSIZE) {
520063644e9Sflorian /* check if pipe is full, if the nonblocking fd blocks,
521063644e9Sflorian * then drop the message */
522063644e9Sflorian return 0;
523e02bc0dfSflorian }
524063644e9Sflorian /* some sort of error, print it */
525063644e9Sflorian log_msg(LOG_ERR, "dnstap collector: send failed: %s",
526e02bc0dfSflorian strerror(errno));
527063644e9Sflorian return -1;
528e02bc0dfSflorian }
529063644e9Sflorian assert(r > 0);
530063644e9Sflorian if(r > 0) {
531063644e9Sflorian assert((size_t)r == len);
532063644e9Sflorian return 0;
533e02bc0dfSflorian }
534063644e9Sflorian /* Other end closed the channel? */
535063644e9Sflorian log_msg(LOG_ERR, "dnstap collector: server child closed the channel");
536063644e9Sflorian return -1;
537e02bc0dfSflorian }
538e02bc0dfSflorian
dt_collector_submit_auth_query(struct nsd * nsd,struct sockaddr_storage * local_addr,struct sockaddr_storage * addr,socklen_t addrlen,int is_tcp,struct buffer * packet)539e02bc0dfSflorian void dt_collector_submit_auth_query(struct nsd* nsd,
540e02bc0dfSflorian #ifdef INET6
5413aefc4aaSsthen struct sockaddr_storage* local_addr,
542e02bc0dfSflorian struct sockaddr_storage* addr,
543e02bc0dfSflorian #else
5443aefc4aaSsthen struct sockaddr_in* local_addr,
545e02bc0dfSflorian struct sockaddr_in* addr,
546e02bc0dfSflorian #endif
547e02bc0dfSflorian socklen_t addrlen, int is_tcp, struct buffer* packet)
548e02bc0dfSflorian {
549e02bc0dfSflorian if(!nsd->dt_collector) return;
550e02bc0dfSflorian if(!nsd->options->dnstap_log_auth_query_messages) return;
551063644e9Sflorian if(nsd->dt_collector_fd_send[nsd->this_child->child_num] == -1) return;
552e02bc0dfSflorian VERBOSITY(4, (LOG_INFO, "dnstap submit auth query"));
553e02bc0dfSflorian
554e02bc0dfSflorian /* marshal data into send buffer */
5553aefc4aaSsthen if(!prep_send_data(nsd->dt_collector->send_buffer, 0, local_addr, addr, addrlen,
556e02bc0dfSflorian is_tcp, packet, NULL))
557e02bc0dfSflorian return; /* probably did not fit in buffer */
558e02bc0dfSflorian
559e02bc0dfSflorian /* attempt to send data; do not block */
560063644e9Sflorian if(attempt_to_send(nsd->dt_collector_fd_send[nsd->this_child->child_num],
561e02bc0dfSflorian buffer_begin(nsd->dt_collector->send_buffer),
562063644e9Sflorian buffer_remaining(nsd->dt_collector->send_buffer))) {
563063644e9Sflorian /* Something went wrong sending to the socket. Don't send to
564063644e9Sflorian * this socket again. */
565063644e9Sflorian close(nsd->dt_collector_fd_send[nsd->this_child->child_num]);
566063644e9Sflorian nsd->dt_collector_fd_send[nsd->this_child->child_num] = -1;
567063644e9Sflorian }
568e02bc0dfSflorian }
569e02bc0dfSflorian
dt_collector_submit_auth_response(struct nsd * nsd,struct sockaddr_storage * local_addr,struct sockaddr_storage * addr,socklen_t addrlen,int is_tcp,struct buffer * packet,struct zone * zone)570e02bc0dfSflorian void dt_collector_submit_auth_response(struct nsd* nsd,
571e02bc0dfSflorian #ifdef INET6
5723aefc4aaSsthen struct sockaddr_storage* local_addr,
573e02bc0dfSflorian struct sockaddr_storage* addr,
574e02bc0dfSflorian #else
5753aefc4aaSsthen struct sockaddr_in* local_addr,
576e02bc0dfSflorian struct sockaddr_in* addr,
577e02bc0dfSflorian #endif
578e02bc0dfSflorian socklen_t addrlen, int is_tcp, struct buffer* packet,
579e02bc0dfSflorian struct zone* zone)
580e02bc0dfSflorian {
581e02bc0dfSflorian if(!nsd->dt_collector) return;
582e02bc0dfSflorian if(!nsd->options->dnstap_log_auth_response_messages) return;
583063644e9Sflorian if(nsd->dt_collector_fd_send[nsd->this_child->child_num] == -1) return;
584e02bc0dfSflorian VERBOSITY(4, (LOG_INFO, "dnstap submit auth response"));
585e02bc0dfSflorian
586e02bc0dfSflorian /* marshal data into send buffer */
5873aefc4aaSsthen if(!prep_send_data(nsd->dt_collector->send_buffer, 1, local_addr, addr, addrlen,
588e02bc0dfSflorian is_tcp, packet, zone))
589e02bc0dfSflorian return; /* probably did not fit in buffer */
590e02bc0dfSflorian
591e02bc0dfSflorian /* attempt to send data; do not block */
592063644e9Sflorian if(attempt_to_send(nsd->dt_collector_fd_send[nsd->this_child->child_num],
593e02bc0dfSflorian buffer_begin(nsd->dt_collector->send_buffer),
594063644e9Sflorian buffer_remaining(nsd->dt_collector->send_buffer))) {
595063644e9Sflorian /* Something went wrong sending to the socket. Don't send to
596063644e9Sflorian * this socket again. */
597063644e9Sflorian close(nsd->dt_collector_fd_send[nsd->this_child->child_num]);
598063644e9Sflorian nsd->dt_collector_fd_send[nsd->this_child->child_num] = -1;
599063644e9Sflorian }
600e02bc0dfSflorian }
601