3 * Copyright (C) 2006 Florian octo Forster
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * Florian octo Forster <octo at verplant.org>
26 #include "configfile.h"
27 #include "utils_debug.h"
30 # include <sys/poll.h>
33 #define MODULE_NAME "dns"
36 # define NAMED_HAVE_CONFIG 1
38 # define NAMED_HAVE_CONFIG 0
42 # include "utils_dns.h"
43 # define NAMED_HAVE_READ 1
45 # define NAMED_HAVE_READ 0
52 struct counter_list_s *next;
54 typedef struct counter_list_s counter_list_t;
56 static char *traffic_file = "dns/dns_traffic.rrd";
57 static char *qtype_file = "dns/qtype-%s.rrd";
58 static char *opcode_file = "dns/opcode-%s.rrd";
59 static char *rcode_file = "dns/rcode-%s.rrd";
61 static char *traffic_ds_def[] =
63 /* Limit to 1GBit/s */
64 "DS:queries:COUNTER:"COLLECTD_HEARTBEAT":0:125000000",
65 "DS:responses:COUNTER:"COLLECTD_HEARTBEAT":0:125000000",
68 static int traffic_ds_num = 2;
70 static char *qtype_ds_def[] =
72 "DS:value:COUNTER:"COLLECTD_HEARTBEAT":0:65535",
75 static int qtype_ds_num = 1;
77 static char *opcode_ds_def[] =
79 "DS:value:COUNTER:"COLLECTD_HEARTBEAT":0:65535",
82 static int opcode_ds_num = 1;
84 static char *rcode_ds_def[] =
86 "DS:value:COUNTER:"COLLECTD_HEARTBEAT":0:65535",
89 static int rcode_ds_num = 1;
93 static char *config_keys[] =
99 static int config_keys_num = 2;
100 #endif /* HAVE_LIBPCAP */
101 #endif /* NAMED_HAVE_CONFIG */
104 #define PCAP_SNAPLEN 1460
105 static char *pcap_device = NULL;
106 static int pipe_fd = -1;
108 static unsigned int tr_queries;
109 static unsigned int tr_responses;
110 static counter_list_t *qtype_list;
111 static counter_list_t *opcode_list;
112 static counter_list_t *rcode_list;
115 static counter_list_t *counter_list_search (counter_list_t **list, unsigned int key)
117 counter_list_t *entry;
119 DBG ("counter_list_search (list = %p, key = %u)",
120 (void *) *list, key);
122 for (entry = *list; entry != NULL; entry = entry->next)
123 if (entry->key == key)
126 DBG ("return (%p)", (void *) entry);
130 static counter_list_t *counter_list_create (counter_list_t **list,
131 unsigned int key, unsigned int value)
133 counter_list_t *entry;
135 DBG ("counter_list_create (list = %p, key = %u, value = %u)",
136 (void *) *list, key, value);
138 entry = (counter_list_t *) malloc (sizeof (counter_list_t));
142 memset (entry, 0, sizeof (counter_list_t));
144 entry->value = value;
152 counter_list_t *last;
155 while (last->next != NULL)
161 DBG ("return (%p)", (void *) entry);
165 static void counter_list_add (counter_list_t **list,
166 unsigned int key, unsigned int increment)
168 counter_list_t *entry;
170 DBG ("counter_list_add (list = %p, key = %u, increment = %u)",
171 (void *) *list, key, increment);
173 entry = counter_list_search (list, key);
177 entry->value += increment;
181 counter_list_create (list, key, increment);
186 static int counter_list_send (counter_list_t *list, int fd)
189 unsigned int values[2 * T_MAX];
190 unsigned int values_num;
198 (cl != NULL) && (values_num < T_MAX);
201 values[2 * values_num] = cl->key;
202 values[(2 * values_num) + 1] = cl->value;
206 DBG ("swrite (fd = %i, values_num = %i)", fd, values_num);
207 if (swrite (fd, (const void *) &values_num, sizeof (values_num)) != 0)
209 DBG ("Writing to fd failed: %s", strerror (errno));
210 syslog (LOG_ERR, "dns plugin: Writing to fd failed: %s",
218 DBG ("swrite (fd = %i, values = %p, size = %i)",
219 fd, (void *) values, (int) (sizeof (int) * values_num));
220 if (swrite (fd, (const void *) values, 2 * sizeof (int) * values_num) != 0)
222 DBG ("Writing to pipe failed: %s", strerror (errno));
223 syslog (LOG_ERR, "dns plugin: Writing to pipe failed: %s",
230 #if NAMED_HAVE_CONFIG
231 static int dns_config (char *key, char *value)
234 if (strcasecmp (key, "Interface") == 0)
236 if (pcap_device != NULL)
238 if ((pcap_device = strdup (value)) == NULL)
241 else if (strcasecmp (key, "IgnoreSource") == 0)
244 ignore_list_add_name (value);
252 #endif /* HAVE_LIBPCAP */
254 #endif /* NAMED_HAVE_CONFIG */
256 static void dns_child_callback (const rfc1035_header_t *dns)
260 /* This is a query */
261 tr_queries += dns->length;
262 counter_list_add (&qtype_list, dns->qtype, 1);
266 /* This is a reply */
267 tr_responses += dns->length;
268 counter_list_add (&rcode_list, dns->rcode, 1);
271 /* FIXME: Are queries, replies or both interesting? */
272 counter_list_add (&opcode_list, dns->opcode, 1);
275 static void dns_child_loop (void)
278 char pcap_error[PCAP_ERRBUF_SIZE];
279 struct bpf_program fp;
281 struct pollfd poll_fds[2];
284 /* Don't catch these signals */
285 signal (SIGINT, SIG_DFL);
286 signal (SIGTERM, SIG_DFL);
288 /* Passing `pcap_device == NULL' is okay and the same as passign "any" */
289 DBG ("Creating PCAP object..");
290 pcap_obj = pcap_open_live (pcap_device,
292 0 /* Not promiscuous */,
293 0 /* no read timeout */,
295 if (pcap_obj == NULL)
297 syslog (LOG_ERR, "dns plugin: Opening interface `%s' failed: %s",
298 (pcap_device != NULL) ? pcap_device : "any",
305 memset (&fp, 0, sizeof (fp));
306 if (pcap_compile (pcap_obj, &fp, "udp port 53", 1, 0) < 0)
308 DBG ("pcap_compile failed");
309 syslog (LOG_ERR, "dns plugin: pcap_compile failed");
314 if (pcap_setfilter (pcap_obj, &fp) < 0)
316 DBG ("pcap_setfilter failed");
317 syslog (LOG_ERR, "dns plugin: pcap_setfilter failed");
323 DBG ("PCAP object created.");
325 dnstop_set_pcap_obj (pcap_obj);
326 dnstop_set_callback (dns_child_callback);
328 /* Set up pipe end */
329 poll_fds[0].fd = pipe_fd;
330 poll_fds[0].events = POLLOUT;
332 /* Set up pcap device */
333 poll_fds[1].fd = pcap_fileno (pcap_obj);
334 poll_fds[1].events = POLLIN | POLLPRI;
339 status = poll (poll_fds, 2, -1 /* wait forever for a change */);
341 /* Signals are not caught, but this is very handy when
342 * attaching to the process with a debugger. -octo */
343 if ((status < 0) && (errno == EINTR))
351 syslog (LOG_ERR, "dns plugin: poll(2) failed: %s",
356 if (poll_fds[0].revents & (POLLERR | POLLHUP | POLLNVAL))
358 DBG ("Pipe closed. Exiting.");
359 syslog (LOG_NOTICE, "dns plugin: Pipe closed. Exiting.");
362 else if (poll_fds[0].revents & POLLOUT)
364 DBG ("Sending data..");
366 DBG ("swrite (pipe_fd = %i, tr_queries = %i)", pipe_fd, tr_queries);
367 if (swrite (pipe_fd, (const void *) &tr_queries, sizeof (tr_queries)) != 0)
369 DBG ("Writing to pipe_fd failed: %s", strerror (errno));
370 syslog (LOG_ERR, "dns plugin: Writing to pipe_fd failed: %s",
375 DBG ("swrite (pipe_fd = %i, tr_responses = %i)", pipe_fd, tr_responses);
376 if (swrite (pipe_fd, (const void *) &tr_responses, sizeof (tr_responses)) != 0)
378 DBG ("Writing to pipe_fd failed: %s", strerror (errno));
379 syslog (LOG_ERR, "dns plugin: Writing to pipe_fd failed: %s",
384 counter_list_send (qtype_list, pipe_fd);
385 counter_list_send (opcode_list, pipe_fd);
386 counter_list_send (rcode_list, pipe_fd);
389 if (poll_fds[1].revents & (POLLERR | POLLHUP | POLLNVAL))
391 DBG ("pcap-device closed. Exiting.");
392 syslog (LOG_ERR, "dns plugin: pcap-device closed. Exiting.");
395 else if (poll_fds[1].revents & (POLLIN | POLLPRI))
397 status = pcap_dispatch (pcap_obj,
398 10 /* Only handle 10 packets at a time */,
399 handle_pcap /* callback */,
400 NULL /* Whatever this means.. */);
403 DBG ("pcap_dispatch failed: %s", pcap_geterr (pcap_obj));
404 syslog (LOG_ERR, "dns plugin: pcap_dispatch failed: %s",
405 pcap_geterr (pcap_obj));
411 DBG ("child is exiting");
415 pcap_close (pcap_obj);
416 } /* static void dns_child_loop (void) */
418 static void dns_init (void)
427 if (pipe (pipe_fds) != 0)
429 syslog (LOG_ERR, "dns plugin: pipe(2) failed: %s",
438 syslog (LOG_ERR, "dns plugin: fork(2) failed: %s",
444 else if (pid_child != 0)
446 /* parent: Close the writing end, keep the reading end. */
447 pipe_fd = pipe_fds[0];
452 /* child: Close the reading end, keep the writing end. */
453 pipe_fd = pipe_fds[1];
460 /* fcntl (pipe_fd, F_SETFL, O_NONBLOCK); */
464 static void traffic_write (char *host, char *inst, char *val)
466 rrd_update_file (host, traffic_file, val,
467 traffic_ds_def, traffic_ds_num);
470 static void qtype_write (char *host, char *inst, char *val)
475 status = snprintf (file, 512, qtype_file, inst);
478 else if (status >= 512)
481 rrd_update_file (host, file, val, qtype_ds_def, qtype_ds_num);
484 static void rcode_write (char *host, char *inst, char *val)
489 status = snprintf (file, 512, rcode_file, inst);
492 else if (status >= 512)
495 rrd_update_file (host, file, val, rcode_ds_def, rcode_ds_num);
498 static void opcode_write (char *host, char *inst, char *val)
503 status = snprintf (file, 512, opcode_file, inst);
506 else if (status >= 512)
509 rrd_update_file (host, file, val, opcode_ds_def, opcode_ds_num);
512 static void traffic_submit (unsigned int queries, unsigned int replies)
517 status = snprintf (buffer, 64, "N:%u:%u", queries, replies);
518 if ((status < 1) || (status >= 64))
521 plugin_submit ("dns_traffic", "-", buffer);
524 static void qtype_submit (int qtype, unsigned int counter)
530 strncpy (inst, qtype_str (qtype), 32);
533 status = snprintf (buffer, 32, "N:%u", counter);
534 if ((status < 1) || (status >= 32))
537 plugin_submit ("dns_qtype", inst, buffer);
540 static void rcode_submit (int rcode, unsigned int counter)
546 strncpy (inst, rcode_str (rcode), 32);
549 status = snprintf (buffer, 32, "N:%u", counter);
550 if ((status < 1) || (status >= 32))
553 plugin_submit ("dns_rcode", inst, buffer);
556 static void opcode_submit (int opcode, unsigned int counter)
562 strncpy (inst, opcode_str (opcode), 32);
565 status = snprintf (buffer, 32, "N:%u", counter);
566 if ((status < 1) || (status >= 32))
569 plugin_submit ("dns_opcode", inst, buffer);
573 static unsigned int dns_read_array (unsigned int *values)
575 unsigned int values_num;
580 if (sread (pipe_fd, (void *) &values_num, sizeof (values_num)) != 0)
582 DBG ("Reading from the pipe failed: %s",
584 syslog (LOG_ERR, "dns plugin: Reading from the pipe failed: %s",
589 DBG ("sread (pipe_fd = %i, values_num = %u)", pipe_fd, values_num);
591 assert (values_num <= T_MAX);
596 if (sread (pipe_fd, (void *) values, 2 * sizeof (unsigned int) * values_num) != 0)
598 DBG ("Reading from the pipe failed: %s",
600 syslog (LOG_ERR, "dns plugin: Reading from the pipe failed: %s",
609 static void dns_read (void)
611 unsigned int values[2 * T_MAX];
612 unsigned int values_num;
618 if (sread (pipe_fd, (void *) &tr_queries, sizeof (tr_queries)) != 0)
620 DBG ("Reading from the pipe failed: %s",
622 syslog (LOG_ERR, "dns plugin: Reading from the pipe failed: %s",
627 DBG ("sread (pipe_fd = %i, tr_queries = %u)", pipe_fd, tr_queries);
629 if (sread (pipe_fd, (void *) &tr_responses, sizeof (tr_responses)) != 0)
631 DBG ("Reading from the pipe failed: %s",
633 syslog (LOG_ERR, "dns plugin: Reading from the pipe failed: %s",
638 DBG ("sread (pipe_fd = %i, tr_responses = %u)", pipe_fd, tr_responses);
640 traffic_submit (tr_queries, tr_responses);
642 values_num = dns_read_array (values);
643 for (i = 0; i < values_num; i++)
645 DBG ("qtype = %u; counter = %u;", values[2 * i], values[(2 * i) + 1]);
646 qtype_submit (values[2 * i], values[(2 * i) + 1]);
649 values_num = dns_read_array (values);
650 for (i = 0; i < values_num; i++)
652 DBG ("opcode = %u; counter = %u;", values[2 * i], values[(2 * i) + 1]);
653 opcode_submit (values[2 * i], values[(2 * i) + 1]);
656 values_num = dns_read_array (values);
657 for (i = 0; i < values_num; i++)
659 DBG ("rcode = %u; counter = %u;", values[2 * i], values[(2 * i) + 1]);
660 rcode_submit (values[2 * i], values[(2 * i) + 1]);
663 #else /* if !NAMED_HAVE_READ */
664 # define dns_read NULL
667 void module_register (void)
669 plugin_register (MODULE_NAME, dns_init, dns_read, NULL);
670 plugin_register ("dns_traffic", NULL, NULL, traffic_write);
671 plugin_register ("dns_qtype", NULL, NULL, qtype_write);
672 plugin_register ("dns_rcode", NULL, NULL, rcode_write);
673 plugin_register ("dns_opcode", NULL, NULL, opcode_write);
674 cf_register (MODULE_NAME, dns_config, config_keys, config_keys_num);