2 * collectd - src/powerdns.c
3 * Copyright (C) 2007-2008 C-Ware, Inc.
4 * Copyright (C) 2008 Florian Forster
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; only version 2 of the License is applicable.
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 * Luke Heberling <lukeh at c-ware.com>
21 * Florian Forster <octo at verplant.org>
24 * Queries a PowerDNS control socket for statistics
30 #include "configfile.h"
31 #include "utils_llist.h"
39 #include <sys/types.h>
40 #include <sys/socket.h>
45 # define UNIX_PATH_MAX sizeof (((struct sockaddr_un *)0)->sun_path)
47 #define FUNC_ERROR(func) ERROR ("powerdns plugin: `%s' failed\n", func)
49 #define SERVER_SOCKET "/var/run/pdns.controlsocket"
50 #define SERVER_COMMAND "SHOW *"
52 #define RECURSOR_SOCKET "/var/run/pdns_recursor.controlsocket"
53 #define RECURSOR_COMMAND "get all-outqueries answers0-1 answers100-1000 answers10-100 answers1-10 answers-slow cache-entries cache-hits cache-misses chain-resends client-parse-errors concurrent-queries dlg-only-drops ipv6-outqueries negcache-entries noerror-answers nsset-invalidations nsspeeds-entries nxdomain-answers outgoing-timeouts qa-latency questions resource-limits server-parse-errors servfail-answers spoof-prevents sys-msec tcp-client-overflow tcp-outqueries tcp-questions throttled-out throttled-outqueries throttle-entries unauthorized-tcp unauthorized-udp unexpected-packets unreachables user-msec"
56 typedef struct list_item_s list_item_t;
60 int (*func) (list_item_t *item);
63 struct sockaddr_un sockaddr;
67 static llist_t *list = NULL;
69 static void submit (const char *plugin_instance, const char *type, const char *value)
71 value_list_t vl = VALUE_LIST_INIT;
77 ERROR ("powerdns plugin: submit: TODO: Translate the passed-in `key' to a reasonable type (and type_instance).");
79 ds = plugin_get_ds (type);
82 ERROR( "%s: DS %s not defined\n", "powerdns", type );
87 if (ds->ds->type == DS_TYPE_GAUGE)
92 ERROR ("%s: atof failed (%s->%s)", "powerdns", type, value);
97 values[0].gauge = f<0?-f:f;
105 ERROR ("%s: atol failed (%s->%s)", "powerdns", type, value);
110 values[0].counter = l < 0 ? -l : l;
116 vl.time = time (NULL);
117 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
118 sstrncpy (vl.plugin, "powerdns", sizeof (vl.plugin));
119 sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
120 sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
122 plugin_dispatch_values (type, &vl);
123 } /* static void submit */
125 static int powerdns_get_data (list_item_t *item, char **ret_buffer,
126 size_t *ret_buffer_size)
133 size_t buffer_size = 0;
135 sd = socket (AF_UNIX, item->socktype, 0);
138 FUNC_ERROR ("socket");
142 status = connect (sd, (struct sockaddr *) &item->sockaddr,
143 sizeof(item->sockaddr));
146 FUNC_ERROR ("connect");
151 status = send (sd, item->command, strlen (item->command), 0);
163 status = recv (sd, temp, sizeof (temp), 0);
169 else if (status == 0)
172 buffer_new = (char *) realloc (buffer, buffer_size + status);
173 if (buffer_new == NULL)
175 FUNC_ERROR ("realloc");
181 memcpy (buffer + buffer_size, temp, status);
182 buffer_size += status;
193 *ret_buffer = buffer;
194 *ret_buffer_size = buffer_size;
198 } /* int powerdns_get_data */
200 static int powerdns_read_server (list_item_t *item)
203 size_t buffer_size = 0;
212 status = powerdns_get_data (item, &buffer, &buffer_size);
218 while ((key = strtok_r (dummy, ",", &saveptr)) != NULL)
222 value = strchr (key, '=');
229 if (value[0] == '\0')
232 submit (item->instance, key, value);
233 } /* while (strtok_r) */
238 } /* int powerdns_read_server */
240 static int powerdns_read_recursor (list_item_t *item)
243 size_t buffer_size = 0;
254 status = powerdns_get_data (item, &buffer, &buffer_size);
258 keys_list = strdup (item->command);
259 if (keys_list == NULL)
261 FUNC_ERROR ("strdup");
267 value_saveptr = NULL;
269 /* Skip the `get' at the beginning */
270 strtok_r (keys_list, " \t", &key_saveptr);
273 while ((value = strtok_r (dummy, " \t\n\r", &value_saveptr)) != NULL)
277 key = strtok_r (NULL, " \t", &key_saveptr);
281 submit (item->instance, key, value);
282 } /* while (strtok_r) */
288 } /* int powerdns_read_recursor */
290 static int powerdns_config_add_string (const char *name, char **dest,
293 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
295 WARNING ("powerdns plugin: `%s' needs exactly one string argument.",
301 *dest = strdup (ci->values[0].value.string);
306 } /* int ctail_config_add_string */
308 static int powerdns_config_add_server (oconfig_item_t *ci)
316 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
318 WARNING ("powerdns plugin: `%s' needs exactly one string argument.",
323 item = (list_item_t *) malloc (sizeof (list_item_t));
326 ERROR ("powerdns plugin: malloc failed.");
329 memset (item, '\0', sizeof (list_item_t));
331 item->instance = strdup (ci->values[0].value.string);
332 if (item->instance == NULL)
334 ERROR ("powerdns plugin: strdup failed.");
340 * Set default values for the members of list_item_t
342 if (strcasecmp ("Server", ci->key) == 0)
344 item->func = powerdns_read_server;
345 item->command = strdup (SERVER_COMMAND);
346 item->socktype = SOCK_STREAM;
347 socket_temp = strdup (SERVER_SOCKET);
349 else if (strcasecmp ("Recursor", ci->key) == 0)
351 item->func = powerdns_read_recursor;
352 item->command = strdup (RECURSOR_COMMAND);
353 item->socktype = SOCK_DGRAM;
354 socket_temp = strdup (RECURSOR_SOCKET);
358 for (i = 0; i < ci->children_num; i++)
360 oconfig_item_t *option = ci->children + i;
362 if (strcasecmp ("Command", option->key) == 0)
363 status = powerdns_config_add_string ("Command", &item->command, option);
364 else if (strcasecmp ("Socket", option->key) == 0)
365 status = powerdns_config_add_string ("Socket", &socket_temp, option);
368 ERROR ("powerdns plugin: Option `%s' not allowed here.", option->key);
380 if (socket_temp == NULL)
382 ERROR ("powerdns plugin: socket_temp == NULL.");
387 if (item->command == NULL)
389 ERROR ("powerdns plugin: item->command == NULL.");
394 item->sockaddr.sun_family = AF_UNIX;
395 sstrncpy (item->sockaddr.sun_path, socket_temp, UNIX_PATH_MAX);
397 e = llentry_create (item->instance, item);
400 ERROR ("powerdns plugin: llentry_create failed.");
404 llist_append (list, e);
416 } /* int powerdns_config_add_server */
418 static int powerdns_config (oconfig_item_t *ci)
424 list = llist_create ();
428 ERROR ("powerdns plugin: `llist_create' failed.");
433 for (i = 0; i < ci->children_num; i++)
435 oconfig_item_t *option = ci->children + i;
437 if ((strcasecmp ("Server", ci->key) == 0)
438 || (strcasecmp ("Recursor", ci->key) == 0))
439 powerdns_config_add_server (option);
442 ERROR ("powerdns plugin: Option `%s' not allowed here.", option->key);
444 } /* for (i = 0; i < ci->children_num; i++) */
447 } /* int powerdns_config */
449 static int powerdns_read (void)
453 for (e = llist_head (list); e != NULL; e = e->next)
455 list_item_t *item = e->value;
460 } /* static int powerdns_read */
462 static int powerdns_shutdown (void)
469 for (e = llist_head (list); e != NULL; e = e->next)
471 list_item_t *item = (list_item_t *) e->value;
474 sfree (item->instance);
475 sfree (item->command);
479 llist_destroy (list);
483 } /* static int powerdns_shutdown */
485 void module_register (void)
487 plugin_register_complex_config ("powerdns", powerdns_config);
488 plugin_register_read ("powerdns", powerdns_read);
489 plugin_register_shutdown ("powerdns", powerdns_shutdown );
490 } /* void module_register */
492 /* vim: set sw=2 sts=2 ts=8 : */