1 /**
2 * collectd - src/named.c
3 * Copyright (C) 2006 Florian octo Forster
4 *
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.
9 *
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.
14 *
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
18 *
19 * Authors:
20 * Florian octo Forster <octo at verplant.org>
21 **/
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26 #include "configfile.h"
27 #include "utils_debug.h"
29 #if HAVE_SYS_POLL_H
30 # include <sys/poll.h>
31 #endif
33 #define MODULE_NAME "named"
35 #if HAVE_LIBPCAP
36 # define NAMED_HAVE_CONFIG 1
37 #else
38 # define NAMED_HAVE_CONFIG 0
39 #endif
41 #if HAVE_LIBPCAP
42 # include "dnstop.h"
43 # define NAMED_HAVE_READ 1
44 #else
45 # define NAMED_HAVE_READ 0
46 #endif
48 static char *qtype_file = "named/qtype-%s.rrd";
50 static char *qtype_ds_def[] =
51 {
52 "DS:value:COUNTER:"COLLECTD_HEARTBEAT":0:U",
53 NULL
54 };
55 static int qtype_ds_num = 1;
57 #if NAMED_HAVE_CONFIG
58 #if HAVE_LIBPCAP
59 static char *config_keys[] =
60 {
61 "Interface",
62 NULL
63 };
64 static int config_keys_num = 1;
65 #endif /* HAVE_LIBPCAP */
66 #endif /* NAMED_HAVE_CONFIG */
68 #if HAVE_LIBPCAP
69 #define PCAP_SNAPLEN 1460
70 static char *pcap_device = NULL;
71 static int pipe_fd;
72 #endif
74 #if NAMED_HAVE_CONFIG
75 static int named_config (char *key, char *value)
76 {
77 #if HAVE_LIBPCAP
78 if (strcasecmp (key, "Interface") == 0)
79 {
80 if (pcap_device != NULL)
81 free (pcap_device);
82 if ((pcap_device = strdup (value)) == NULL)
83 return (1);
84 }
85 else
86 {
87 return (-1);
88 }
90 return (0);
91 #endif /* HAVE_LIBPCAP */
92 }
93 #endif /* NAMED_HAVE_CONFIG */
95 static int named_child_send_data (void)
96 {
97 int values[2 * T_MAX];
98 int values_num;
99 int i;
101 values_num = 0;
102 for (i = 0; i < T_MAX; i++)
103 {
104 if (qtype_counts[i] != 0)
105 {
106 values[2 * values_num] = i;
107 values[(2 * values_num) + 1] = qtype_counts[i];
108 values_num++;
109 }
110 }
112 if (swrite (pipe_fd, (const void *) &values_num, sizeof (values_num)) != 0)
113 {
114 syslog (LOG_ERR, "named plugin: Writing to pipe failed: %s",
115 strerror (errno));
116 return (-1);
117 }
119 if (swrite (pipe_fd, (const void *) values, 2 * sizeof (int) * values_num) != 0)
120 {
121 syslog (LOG_ERR, "named plugin: Writing to pipe failed: %s",
122 strerror (errno));
123 return (-1);
124 }
126 return (values_num);
127 }
129 static void named_child_loop (void)
130 {
131 pcap_t *pcap_obj;
132 char pcap_error[PCAP_ERRBUF_SIZE];
134 struct pollfd poll_fds[2];
135 int status;
137 /* Passing `pcap_device == NULL' is okay and the same as passign "any" */
138 pcap_obj = pcap_open_live (pcap_device,
139 PCAP_SNAPLEN,
140 0 /* Not promiscuous */,
141 0 /* no read timeout */,
142 pcap_error);
143 if (pcap_obj == NULL)
144 {
145 syslog (LOG_ERR, "named plugin: Opening interface `%s' failed: %s",
146 (pcap_device != NULL) ? pcap_device : "any",
147 pcap_error);
148 close (pipe_fd);
149 return;
150 }
152 /* Set up pipe end */
153 poll_fds[0].fd = pipe_fd;
154 poll_fds[0].events = POLLOUT;
156 /* Set up pcap device */
157 poll_fds[1].fd = pcap_fileno (pcap_obj);
158 poll_fds[1].events = POLLIN | POLLPRI;
160 while (42)
161 {
162 status = poll (poll_fds, 2, -1 /* wait forever for a change */);
164 if (status < 0)
165 {
166 syslog (LOG_ERR, "named plugin: poll(2) failed: %s",
167 strerror (errno));
168 break;
169 }
171 if (poll_fds[0].revents & (POLLERR | POLLHUP | POLLNVAL))
172 {
173 syslog (LOG_NOTICE, "named plugin: Pipe closed. Exiting.");
174 break;
175 }
176 else if (poll_fds[0].revents & POLLOUT)
177 {
178 if (named_child_send_data () < 0)
179 {
180 break;
181 }
182 }
184 if (poll_fds[1].revents & (POLLERR | POLLHUP | POLLNVAL))
185 {
186 syslog (LOG_ERR, "named plugin: pcap-device closed. Exiting.");
187 break;
188 }
189 else if (poll_fds[1].revents & (POLLIN | POLLPRI))
190 {
191 /* TODO: Read and analyse packet */
192 status = pcap_dispatch (pcap_obj,
193 10 /* Only handle 10 packets at a time */,
194 handle_pcap /* callback */,
195 NULL /* Whatever this means.. */);
196 if (status < 0)
197 {
198 syslog (LOG_ERR, "named plugin: pcap_dispatch failed: %s",
199 pcap_geterr (pcap_obj));
200 break;
201 }
202 }
203 } /* while (42) */
205 close (pipe_fd);
206 pcap_close (pcap_obj);
207 } /* static void named_child_loop (void) */
209 static void named_init (void)
210 {
211 #if HAVE_LIBPCAP
212 int pipe_fds[2];
213 pid_t pid_child;
215 if (pipe (pipe_fds) != 0)
216 {
217 syslog (LOG_ERR, "named plugin: pipe(2) failed: %s",
218 strerror (errno));
219 return;
220 }
222 /* Fork off child */
223 pid_child = fork ();
224 if (pid_child < 0)
225 {
226 syslog (LOG_ERR, "named plugin: fork(2) failed: %s",
227 strerror (errno));
228 close (pipe_fds[0]);
229 close (pipe_fds[1]);
230 return;
231 }
232 else if (pid_child != 0)
233 {
234 /* parent: Close the writing end, keep the reading end. */
235 pipe_fd = pipe_fds[0];
236 close (pipe_fds[1]);
237 }
238 else
239 {
240 /* child: Close the reading end, keep the writing end. */
241 pipe_fd = pipe_fds[1];
242 close (pipe_fds[0]);
244 named_child_loop ();
245 exit (0);
246 }
248 fcntl (pipe_fd, F_SETFL, O_NONBLOCK);
249 #endif
250 }
252 #if NAMED_HAVE_READ
253 static void named_read (void)
254 {
255 int values[2 * T_MAX];
256 int values_num;
257 int qtype;
258 int counter;
259 int i;
261 if (sread (pipe_fd, (void *) &values_num, sizeof (values_num)) != 0)
262 {
263 syslog (LOG_ERR, "named plugin: Reading from the pipe failed: %s",
264 strerror (errno));
265 return;
266 }
268 assert ((values_num >= 0) && (values_num <= T_MAX));
270 if (sread (pipe_fd, (void *) values, 2 * sizeof (int) * values_num) != 0)
271 {
272 syslog (LOG_ERR, "named plugin: Reading from the pipe failed: %s",
273 strerror (errno));
274 return;
275 }
277 for (i = 0; i < values_num; i++)
278 {
279 qtype = values[2 * i];
280 counter = values[(2 * i) + 1];
282 DBG ("qtype = %i; counter = %i;", qtype, counter);
283 }
284 }
285 #else /* if !NAMED_HAVE_READ */
286 # define named_read NULL
287 #endif
289 void module_register (void)
290 {
291 plugin_register (MODULE_NAME, named_init, named_read, NULL);
292 /* TODO */
293 cf_register (MODULE_NAME, named_config, config_keys, config_keys_num);
294 }
296 #undef MODULE_NAME