X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fbind.c;h=7fda034968ffe5217a3a24bd493974c271124db7;hb=99db6e480437d6dd6cf80580d19a65855768a727;hp=28d28b68e5fa56fd1584c24f5c2ead252df5dc03;hpb=f634a0a8751f51560b065c5041cf457c9a5e7472;p=collectd.git
diff --git a/src/bind.c b/src/bind.c
index 28d28b68..7fda0349 100644
--- a/src/bind.c
+++ b/src/bind.c
@@ -36,6 +36,7 @@
#endif /* STRPTIME_NEEDS_STANDARDS */
#include "collectd.h"
+
#include "common.h"
#include "plugin.h"
#include "configfile.h"
@@ -54,7 +55,7 @@
# define BIND_DEFAULT_URL "http://localhost:8053/"
#endif
-/*
+/*
* Some types used for the callback functions. `translation_table_ptr_t' and
* `list_info_ptr_t' are passed to the callbacks in the `void *user_data'
* pointer.
@@ -109,6 +110,7 @@ static int global_server_stats = 1;
static int global_zone_maint_stats = 1;
static int global_resolver_stats = 0;
static int global_memory_stats = 1;
+static int timeout = -1;
static cb_view_t *views = NULL;
static size_t views_num = 0;
@@ -276,14 +278,14 @@ static size_t bind_curl_callback (void *buf, size_t size, /* {{{ */
{
size_t len = size * nmemb;
- if (len <= 0)
+ if (len == 0)
return (len);
if ((bind_buffer_fill + len) >= bind_buffer_size)
{
char *temp;
- temp = realloc(bind_buffer, bind_buffer_fill + len + 1);
+ temp = realloc (bind_buffer, bind_buffer_fill + len + 1);
if (temp == NULL)
{
ERROR ("bind plugin: realloc failed.");
@@ -308,12 +310,11 @@ static int bind_xml_table_callback (const char *name, value_t value, /* {{{ */
time_t current_time, void *user_data)
{
translation_table_ptr_t *table = (translation_table_ptr_t *) user_data;
- size_t i;
if (table == NULL)
return (-1);
- for (i = 0; i < table->table_length; i++)
+ for (size_t i = 0; i < table->table_length; i++)
{
if (strcmp (table->table[i].xml_name, name) != 0)
continue;
@@ -369,9 +370,11 @@ static int bind_xml_read_derive (xmlDoc *doc, xmlNode *node, /* {{{ */
{
ERROR ("bind plugin: Parsing string \"%s\" to derive value failed.",
str_ptr);
+ xmlFree(str_ptr);
return (-1);
}
+ xmlFree(str_ptr);
*ret_value = value.derive;
return (0);
} /* }}} int bind_xml_read_derive */
@@ -414,7 +417,7 @@ static int bind_xml_read_timestamp (const char *xpath_expression, /* {{{ */
xmlNode *node;
char *str_ptr;
char *tmp;
- struct tm tm;
+ struct tm tm = { 0 };
xpathObj = xmlXPathEvalExpression (BAD_CAST xpath_expression, xpathCtx);
if (xpathObj == NULL)
@@ -455,7 +458,6 @@ static int bind_xml_read_timestamp (const char *xpath_expression, /* {{{ */
return (-1);
}
- memset (&tm, 0, sizeof(tm));
tmp = strptime (str_ptr, "%Y-%m-%dT%T", &tm);
xmlFree(str_ptr);
if (tmp == NULL)
@@ -471,7 +473,7 @@ static int bind_xml_read_timestamp (const char *xpath_expression, /* {{{ */
return (0);
} /* }}} int bind_xml_read_timestamp */
-/*
+/*
* bind_parse_generic_name_value
*
* Reads statistics in the form:
@@ -488,7 +490,6 @@ static int bind_parse_generic_name_value (const char *xpath_expression, /* {{{ *
{
xmlXPathObject *xpathObj = NULL;
int num_entries;
- int i;
xpathObj = xmlXPathEvalExpression(BAD_CAST xpath_expression, xpathCtx);
if (xpathObj == NULL)
@@ -500,19 +501,18 @@ static int bind_parse_generic_name_value (const char *xpath_expression, /* {{{ *
num_entries = 0;
/* Iterate over all matching nodes. */
- for (i = 0; xpathObj->nodesetval && (i < xpathObj->nodesetval->nodeNr); i++)
+ for (int i = 0; xpathObj->nodesetval && (i < xpathObj->nodesetval->nodeNr); i++)
{
xmlNode *name_node = NULL;
xmlNode *counter = NULL;
xmlNode *parent;
- xmlNode *child;
parent = xpathObj->nodesetval->nodeTab[i];
DEBUG ("bind plugin: bind_parse_generic_name_value: parent->name = %s;",
(char *) parent->name);
/* Iterate over all child nodes. */
- for (child = parent->xmlChildrenNode;
+ for (xmlNode *child = parent->xmlChildrenNode;
child != NULL;
child = child->next)
{
@@ -556,7 +556,7 @@ static int bind_parse_generic_name_value (const char *xpath_expression, /* {{{ *
return (0);
} /* }}} int bind_parse_generic_name_value */
-/*
+/*
* bind_parse_generic_value_list
*
* Reads statistics in the form:
@@ -575,7 +575,6 @@ static int bind_parse_generic_value_list (const char *xpath_expression, /* {{{ *
{
xmlXPathObject *xpathObj = NULL;
int num_entries;
- int i;
xpathObj = xmlXPathEvalExpression(BAD_CAST xpath_expression, xpathCtx);
if (xpathObj == NULL)
@@ -587,12 +586,10 @@ static int bind_parse_generic_value_list (const char *xpath_expression, /* {{{ *
num_entries = 0;
/* Iterate over all matching nodes. */
- for (i = 0; xpathObj->nodesetval && (i < xpathObj->nodesetval->nodeNr); i++)
+ for (int i = 0; xpathObj->nodesetval && (i < xpathObj->nodesetval->nodeNr); i++)
{
- xmlNode *child;
-
/* Iterate over all child nodes. */
- for (child = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
+ for (xmlNode *child = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
child != NULL;
child = child->next)
{
@@ -627,34 +624,123 @@ static int bind_parse_generic_value_list (const char *xpath_expression, /* {{{ *
return (0);
} /* }}} int bind_parse_generic_value_list */
+/*
+ * bind_parse_generic_name_attr_value_list
+ *
+ * Reads statistics in the form:
+ *
+ * 123
+ * 234
+ * 345
+ * :
+ *
+ */
+static int bind_parse_generic_name_attr_value_list (const char *xpath_expression, /* {{{ */
+ list_callback_t list_callback,
+ void *user_data,
+ xmlDoc *doc, xmlXPathContext *xpathCtx,
+ time_t current_time, int ds_type)
+{
+ xmlXPathObject *xpathObj = NULL;
+ int num_entries;
+
+ xpathObj = xmlXPathEvalExpression(BAD_CAST xpath_expression, xpathCtx);
+ if (xpathObj == NULL)
+ {
+ ERROR("bind plugin: Unable to evaluate XPath expression `%s'.",
+ xpath_expression);
+ return (-1);
+ }
+
+ num_entries = 0;
+ /* Iterate over all matching nodes. */
+ for (int i = 0; xpathObj->nodesetval && (i < xpathObj->nodesetval->nodeNr); i++)
+ {
+ /* Iterate over all child nodes. */
+ for (xmlNode *child = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
+ child != NULL;
+ child = child->next)
+ {
+ if (child->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (strncmp ("counter", (char *) child->name, strlen ("counter")) != 0)
+ continue;
+
+ char *attr_name;
+ value_t value;
+ int status;
+
+ attr_name = (char *) xmlGetProp (child, BAD_CAST "name");
+ if (attr_name == NULL)
+ {
+ DEBUG ("bind plugin: found without name.");
+ continue;
+ }
+ if (ds_type == DS_TYPE_GAUGE)
+ status = bind_xml_read_gauge (doc, child, &value.gauge);
+ else
+ status = bind_xml_read_derive (doc, child, &value.derive);
+ if (status != 0)
+ continue;
+
+ status = (*list_callback) (attr_name, value, current_time, user_data);
+ if (status == 0)
+ num_entries++;
+ }
+ }
+
+ DEBUG ("bind plugin: Found %d %s for XPath expression `%s'",
+ num_entries, (num_entries == 1) ? "entry" : "entries",
+ xpath_expression);
+
+ xmlXPathFreeObject(xpathObj);
+
+ return (0);
+} /* }}} int bind_parse_generic_name_attr_value_list */
+
static int bind_xml_stats_handle_zone (int version, xmlDoc *doc, /* {{{ */
xmlXPathContext *path_ctx, xmlNode *node, cb_view_t *view,
time_t current_time)
{
xmlXPathObject *path_obj;
char *zone_name = NULL;
- int i;
size_t j;
- path_obj = xmlXPathEvalExpression (BAD_CAST "name", path_ctx);
- if (path_obj == NULL)
+ if (version >= 3)
{
- ERROR ("bind plugin: xmlXPathEvalExpression failed.");
- return (-1);
+ char *n = (char *) xmlGetProp (node, BAD_CAST "name");
+ char *c = (char *) xmlGetProp (node, BAD_CAST "rdataclass");
+ if (n && c)
+ {
+ zone_name = (char *) xmlMalloc(strlen(n) + strlen(c) + 2);
+ snprintf(zone_name, strlen(n) + strlen(c) + 2, "%s/%s", n, c);
+ }
+ xmlFree(n);
+ xmlFree(c);
}
-
- for (i = 0; path_obj->nodesetval && (i < path_obj->nodesetval->nodeNr); i++)
+ else
{
- zone_name = (char *) xmlNodeListGetString (doc,
- path_obj->nodesetval->nodeTab[i]->xmlChildrenNode, 1);
- if (zone_name != NULL)
- break;
+ path_obj = xmlXPathEvalExpression (BAD_CAST "name", path_ctx);
+ if (path_obj == NULL)
+ {
+ ERROR ("bind plugin: xmlXPathEvalExpression failed.");
+ return (-1);
+ }
+
+ for (int i = 0; path_obj->nodesetval && (i < path_obj->nodesetval->nodeNr); i++)
+ {
+ zone_name = (char *) xmlNodeListGetString (doc,
+ path_obj->nodesetval->nodeTab[i]->xmlChildrenNode, 1);
+ if (zone_name != NULL)
+ break;
+ }
+ xmlXPathFreeObject (path_obj);
}
if (zone_name == NULL)
{
ERROR ("bind plugin: Could not determine zone name.");
- xmlXPathFreeObject (path_obj);
return (-1);
}
@@ -667,11 +753,8 @@ static int bind_xml_stats_handle_zone (int version, xmlDoc *doc, /* {{{ */
xmlFree (zone_name);
zone_name = NULL;
- if (j >= views_num)
- {
- xmlXPathFreeObject (path_obj);
+ if (j >= view->zones_num)
return (0);
- }
zone_name = view->zones[j];
@@ -681,7 +764,7 @@ static int bind_xml_stats_handle_zone (int version, xmlDoc *doc, /* {{{ */
{ /* Parse the tag {{{ */
char plugin_instance[DATA_MAX_NAME_LEN];
translation_table_ptr_t table_ptr =
- {
+ {
nsstats_translation_table,
nsstats_translation_table_length,
plugin_instance
@@ -690,14 +773,31 @@ static int bind_xml_stats_handle_zone (int version, xmlDoc *doc, /* {{{ */
ssnprintf (plugin_instance, sizeof (plugin_instance), "%s-zone-%s",
view->name, zone_name);
- bind_parse_generic_value_list (/* xpath = */ "counters",
+ if (version == 3)
+ {
+ list_info_ptr_t list_info =
+ {
+ plugin_instance,
+ /* type = */ "dns_qtype"
+ };
+ bind_parse_generic_name_attr_value_list (/* xpath = */ "counters[@type='rcode']",
/* callback = */ bind_xml_table_callback,
/* user_data = */ &table_ptr,
doc, path_ctx, current_time, DS_TYPE_COUNTER);
+ bind_parse_generic_name_attr_value_list (/* xpath = */ "counters[@type='qtype']",
+ /* callback = */ bind_xml_list_callback,
+ /* user_data = */ &list_info,
+ doc, path_ctx, current_time, DS_TYPE_COUNTER);
+ }
+ else
+ {
+ bind_parse_generic_value_list (/* xpath = */ "counters",
+ /* callback = */ bind_xml_table_callback,
+ /* user_data = */ &table_ptr,
+ doc, path_ctx, current_time, DS_TYPE_COUNTER);
+ }
} /* }}} */
- xmlXPathFreeObject (path_obj);
-
return (0);
} /* }}} int bind_xml_stats_handle_zone */
@@ -707,7 +807,6 @@ static int bind_xml_stats_search_zones (int version, xmlDoc *doc, /* {{{ */
{
xmlXPathObject *zone_nodes = NULL;
xmlXPathContext *zone_path_context;
- int i;
zone_path_context = xmlXPathNewContext (doc);
if (zone_path_context == NULL)
@@ -724,7 +823,7 @@ static int bind_xml_stats_search_zones (int version, xmlDoc *doc, /* {{{ */
return (-1);
}
- for (i = 0; i < zone_nodes->nodesetval->nodeNr; i++)
+ for (int i = 0; i < zone_nodes->nodesetval->nodeNr; i++)
{
node = zone_nodes->nodesetval->nodeTab[i];
assert (node != NULL);
@@ -743,45 +842,67 @@ static int bind_xml_stats_search_zones (int version, xmlDoc *doc, /* {{{ */
static int bind_xml_stats_handle_view (int version, xmlDoc *doc, /* {{{ */
xmlXPathContext *path_ctx, xmlNode *node, time_t current_time)
{
- xmlXPathObject *path_obj;
char *view_name = NULL;
cb_view_t *view;
- int i;
size_t j;
- path_obj = xmlXPathEvalExpression (BAD_CAST "name", path_ctx);
- if (path_obj == NULL)
+ if (version == 3)
{
- ERROR ("bind plugin: xmlXPathEvalExpression failed.");
- return (-1);
- }
+ view_name = (char*) xmlGetProp(node, BAD_CAST "name");
- for (i = 0; path_obj->nodesetval && (i < path_obj->nodesetval->nodeNr); i++)
- {
- view_name = (char *) xmlNodeListGetString (doc,
- path_obj->nodesetval->nodeTab[i]->xmlChildrenNode, 1);
- if (view_name != NULL)
- break;
- }
+ if (view_name == NULL)
+ {
+ ERROR ("bind plugin: Could not determine view name.");
+ return (-1);
+ }
- if (view_name == NULL)
+ for (j = 0; j < views_num; j++)
+ {
+ if (strcasecmp (view_name, views[j].name) == 0)
+ break;
+ }
+
+ xmlFree (view_name);
+ view_name = NULL;
+ }
+ else
{
- ERROR ("bind plugin: Could not determine view name.");
+ xmlXPathObject *path_obj;
+ path_obj = xmlXPathEvalExpression (BAD_CAST "name", path_ctx);
+ if (path_obj == NULL)
+ {
+ ERROR ("bind plugin: xmlXPathEvalExpression failed.");
+ return (-1);
+ }
+
+ for (int i = 0; path_obj->nodesetval && (i < path_obj->nodesetval->nodeNr); i++)
+ {
+ view_name = (char *) xmlNodeListGetString (doc,
+ path_obj->nodesetval->nodeTab[i]->xmlChildrenNode, 1);
+ if (view_name != NULL)
+ break;
+ }
+
+ if (view_name == NULL)
+ {
+ ERROR ("bind plugin: Could not determine view name.");
+ xmlXPathFreeObject (path_obj);
+ return (-1);
+ }
+
+ for (j = 0; j < views_num; j++)
+ {
+ if (strcasecmp (view_name, views[j].name) == 0)
+ break;
+ }
+
+ xmlFree (view_name);
xmlXPathFreeObject (path_obj);
- return (-1);
- }
- for (j = 0; j < views_num; j++)
- {
- if (strcasecmp (view_name, views[j].name) == 0)
- break;
+ view_name = NULL;
+ path_obj = NULL;
}
- xmlFree (view_name);
- xmlXPathFreeObject (path_obj);
-
- view_name = NULL;
- path_obj = NULL;
if (j >= views_num)
return (0);
@@ -802,18 +923,27 @@ static int bind_xml_stats_handle_view (int version, xmlDoc *doc, /* {{{ */
ssnprintf (plugin_instance, sizeof (plugin_instance), "%s-qtypes",
view->name);
-
- bind_parse_generic_name_value (/* xpath = */ "rdtype",
+ if (version == 3)
+ {
+ bind_parse_generic_name_attr_value_list (/* xpath = */ "counters[@type='resqtype']",
+ /* callback = */ bind_xml_list_callback,
+ /* user_data = */ &list_info,
+ doc, path_ctx, current_time, DS_TYPE_COUNTER);
+ }
+ else
+ {
+ bind_parse_generic_name_value (/* xpath = */ "rdtype",
/* callback = */ bind_xml_list_callback,
/* user_data = */ &list_info,
doc, path_ctx, current_time, DS_TYPE_COUNTER);
+ }
} /* }}} */
if (view->resolver_stats != 0) /* {{{ */
{
char plugin_instance[DATA_MAX_NAME_LEN];
translation_table_ptr_t table_ptr =
- {
+ {
resstats_translation_table,
resstats_translation_table_length,
plugin_instance
@@ -821,11 +951,20 @@ static int bind_xml_stats_handle_view (int version, xmlDoc *doc, /* {{{ */
ssnprintf (plugin_instance, sizeof (plugin_instance),
"%s-resolver_stats", view->name);
-
- bind_parse_generic_name_value ("resstat",
- /* callback = */ bind_xml_table_callback,
- /* user_data = */ &table_ptr,
- doc, path_ctx, current_time, DS_TYPE_COUNTER);
+ if (version == 3)
+ {
+ bind_parse_generic_name_attr_value_list ("counters[@type='resstats']",
+ /* callback = */ bind_xml_table_callback,
+ /* user_data = */ &table_ptr,
+ doc, path_ctx, current_time, DS_TYPE_COUNTER);
+ }
+ else
+ {
+ bind_parse_generic_name_value ("resstat",
+ /* callback = */ bind_xml_table_callback,
+ /* user_data = */ &table_ptr,
+ doc, path_ctx, current_time, DS_TYPE_COUNTER);
+ }
} /* }}} */
/* Record types in the cache */
@@ -859,7 +998,6 @@ static int bind_xml_stats_search_views (int version, xmlDoc *doc, /* {{{ */
{
xmlXPathObject *view_nodes = NULL;
xmlXPathContext *view_path_context;
- int i;
view_path_context = xmlXPathNewContext (doc);
if (view_path_context == NULL)
@@ -876,7 +1014,7 @@ static int bind_xml_stats_search_views (int version, xmlDoc *doc, /* {{{ */
return (-1);
}
- for (i = 0; i < view_nodes->nodesetval->nodeNr; i++)
+ for (int i = 0; i < view_nodes->nodesetval->nodeNr; i++)
{
xmlNode *node;
@@ -894,28 +1032,145 @@ static int bind_xml_stats_search_views (int version, xmlDoc *doc, /* {{{ */
return (0);
} /* }}} int bind_xml_stats_search_views */
-static int bind_xml_stats (int version, xmlDoc *doc, /* {{{ */
- xmlXPathContext *xpathCtx, xmlNode *statsnode)
+static void bind_xml_stats_v3 (xmlDoc *doc, /* {{{ */
+ xmlXPathContext *xpathCtx, xmlNode *statsnode, time_t current_time)
{
- time_t current_time = 0;
- int status;
+ /* XPath: server/counters[@type='opcode']
+ * Variables: QUERY, IQUERY, NOTIFY, UPDATE, ...
+ * Layout v3:
+ *
+ * 1
+ * :
+ *
+ */
+ if (global_opcodes != 0)
+ {
+ list_info_ptr_t list_info =
+ {
+ /* plugin instance = */ "global-opcodes",
+ /* type = */ "dns_opcode"
+ };
+ bind_parse_generic_name_attr_value_list (/* xpath = */ "server/counters[@type='opcode']",
+ /* callback = */ bind_xml_list_callback,
+ /* user_data = */ &list_info,
+ doc, xpathCtx, current_time, DS_TYPE_COUNTER);
+ }
- xpathCtx->node = statsnode;
+ /* XPath: server/counters[@type='qtype']
+ * Variables: RESERVED0, A, NS, CNAME, SOA, MR, PTR, HINFO, MX, TXT, RP,
+ * X25, PX, AAAA, LOC, SRV, NAPTR, A6, DS, RRSIG, NSEC, DNSKEY,
+ * SPF, TKEY, IXFR, AXFR, ANY, ..., Others
+ * Layout v3:
+ *
+ * 1
+ * :
+ *
+ */
+ if (global_qtypes != 0)
+ {
+ list_info_ptr_t list_info =
+ {
+ /* plugin instance = */ "global-qtypes",
+ /* type = */ "dns_qtype"
+ };
- /* TODO: Check `server/boot-time' to recognize server restarts. */
+ bind_parse_generic_name_attr_value_list (/* xpath = */ "server/counters[@type='qtype']",
+ /* callback = */ bind_xml_list_callback,
+ /* user_data = */ &list_info,
+ doc, xpathCtx, current_time, DS_TYPE_COUNTER);
+ }
- status = bind_xml_read_timestamp ("server/current-time",
- doc, xpathCtx, ¤t_time);
- if (status != 0)
+ /* XPath: server/counters[@type='nsstat']
+ * Variables: Requestv4, Requestv6, ReqEdns0, ReqBadEDNSVer, ReqTSIG,
+ * ReqSIG0, ReqBadSIG, ReqTCP, AuthQryRej, RecQryRej, XfrRej,
+ * UpdateRej, Response, TruncatedResp, RespEDNS0, RespTSIG,
+ * RespSIG0, QrySuccess, QryAuthAns, QryNoauthAns, QryReferral,
+ * QryNxrrset, QrySERVFAIL, QryFORMERR, QryNXDOMAIN, QryRecursion,
+ * QryDuplicate, QryDropped, QryFailure, XfrReqDone, UpdateReqFwd,
+ * UpdateRespFwd, UpdateFwdFail, UpdateDone, UpdateFail,
+ * UpdateBadPrereq
+ * Layout v3:
+ * 1
+ * 0
+ * :
+ *
+ */
+ if (global_server_stats)
{
- ERROR ("bind plugin: Reading `server/current-time' failed.");
- return (-1);
+ translation_table_ptr_t table_ptr =
+ {
+ nsstats_translation_table,
+ nsstats_translation_table_length,
+ /* plugin_instance = */ "global-server_stats"
+ };
+
+ bind_parse_generic_name_attr_value_list ("server/counters[@type='nsstat']",
+ /* callback = */ bind_xml_table_callback,
+ /* user_data = */ &table_ptr,
+ doc, xpathCtx, current_time, DS_TYPE_COUNTER);
}
- DEBUG ("bind plugin: Current server time is %i.", (int) current_time);
- /* XPath: server/requests/opcode
+ /* XPath: server/zonestats, server/zonestat, server/counters[@type='zonestat']
+ * Variables: NotifyOutv4, NotifyOutv6, NotifyInv4, NotifyInv6, NotifyRej,
+ * SOAOutv4, SOAOutv6, AXFRReqv4, AXFRReqv6, IXFRReqv4, IXFRReqv6,
+ * XfrSuccess, XfrFail
+ * Layout v3:
+ * 0
+ * 0
+ * :
+ *
+ */
+ if (global_zone_maint_stats)
+ {
+ translation_table_ptr_t table_ptr =
+ {
+ zonestats_translation_table,
+ zonestats_translation_table_length,
+ /* plugin_instance = */ "global-zone_maint_stats"
+ };
+
+ bind_parse_generic_name_attr_value_list ("server/counters[@type='zonestat']",
+ /* callback = */ bind_xml_table_callback,
+ /* user_data = */ &table_ptr,
+ doc, xpathCtx, current_time, DS_TYPE_COUNTER);
+ }
+
+ /* XPath: server/resstats, server/counters[@type='resstat']
+ * Variables: Queryv4, Queryv6, Responsev4, Responsev6, NXDOMAIN, SERVFAIL,
+ * FORMERR, OtherError, EDNS0Fail, Mismatch, Truncated, Lame,
+ * Retry, GlueFetchv4, GlueFetchv6, GlueFetchv4Fail,
+ * GlueFetchv6Fail, ValAttempt, ValOk, ValNegOk, ValFail
+ * Layout v3:
+ * 0
+ * 0
+ * :
+ *
+ */
+ if (global_resolver_stats != 0)
+ {
+ translation_table_ptr_t table_ptr =
+ {
+ resstats_translation_table,
+ resstats_translation_table_length,
+ /* plugin_instance = */ "global-resolver_stats"
+ };
+
+ bind_parse_generic_name_attr_value_list ("server/counters[@type='resstat']",
+ /* callback = */ bind_xml_table_callback,
+ /* user_data = */ &table_ptr,
+ doc, xpathCtx, current_time, DS_TYPE_COUNTER);
+ }
+} /* }}} bind_xml_stats_v3 */
+
+static void bind_xml_stats_v1_v2 (int version, xmlDoc *doc, /* {{{ */
+ xmlXPathContext *xpathCtx, xmlNode *statsnode, time_t current_time)
+{
+ /* XPath: server/requests/opcode, server/counters[@type='opcode']
* Variables: QUERY, IQUERY, NOTIFY, UPDATE, ...
- * Layout:
+ * Layout V1 and V2:
*
* A
* 1
@@ -936,11 +1191,11 @@ static int bind_xml_stats (int version, xmlDoc *doc, /* {{{ */
doc, xpathCtx, current_time, DS_TYPE_COUNTER);
}
- /* XPath: server/queries-in/rdtype
+ /* XPath: server/queries-in/rdtype, server/counters[@type='qtype']
* Variables: RESERVED0, A, NS, CNAME, SOA, MR, PTR, HINFO, MX, TXT, RP,
* X25, PX, AAAA, LOC, SRV, NAPTR, A6, DS, RRSIG, NSEC, DNSKEY,
* SPF, TKEY, IXFR, AXFR, ANY, ..., Others
- * Layout:
+ * Layout v1 or v2:
*
* A
* 1
@@ -960,8 +1215,8 @@ static int bind_xml_stats (int version, xmlDoc *doc, /* {{{ */
/* user_data = */ &list_info,
doc, xpathCtx, current_time, DS_TYPE_COUNTER);
}
-
- /* XPath: server/nsstats, server/nsstat
+
+ /* XPath: server/nsstats, server/nsstat, server/counters[@type='nsstat']
* Variables: Requestv4, Requestv6, ReqEdns0, ReqBadEDNSVer, ReqTSIG,
* ReqSIG0, ReqBadSIG, ReqTCP, AuthQryRej, RecQryRej, XfrRej,
* UpdateRej, Response, TruncatedResp, RespEDNS0, RespTSIG,
@@ -990,7 +1245,7 @@ static int bind_xml_stats (int version, xmlDoc *doc, /* {{{ */
if (global_server_stats)
{
translation_table_ptr_t table_ptr =
- {
+ {
nsstats_translation_table,
nsstats_translation_table_length,
/* plugin_instance = */ "global-server_stats"
@@ -1012,7 +1267,7 @@ static int bind_xml_stats (int version, xmlDoc *doc, /* {{{ */
}
}
- /* XPath: server/zonestats, server/zonestat
+ /* XPath: server/zonestats, server/zonestat, server/counters[@type='zonestat']
* Variables: NotifyOutv4, NotifyOutv6, NotifyInv4, NotifyInv6, NotifyRej,
* SOAOutv4, SOAOutv6, AXFRReqv4, AXFRReqv6, IXFRReqv4, IXFRReqv6,
* XfrSuccess, XfrFail
@@ -1036,7 +1291,7 @@ static int bind_xml_stats (int version, xmlDoc *doc, /* {{{ */
if (global_zone_maint_stats)
{
translation_table_ptr_t table_ptr =
- {
+ {
zonestats_translation_table,
zonestats_translation_table_length,
/* plugin_instance = */ "global-zone_maint_stats"
@@ -1058,7 +1313,7 @@ static int bind_xml_stats (int version, xmlDoc *doc, /* {{{ */
}
}
- /* XPath: server/resstats
+ /* XPath: server/resstats, server/counters[@type='resstat']
* Variables: Queryv4, Queryv6, Responsev4, Responsev6, NXDOMAIN, SERVFAIL,
* FORMERR, OtherError, EDNS0Fail, Mismatch, Truncated, Lame,
* Retry, GlueFetchv4, GlueFetchv6, GlueFetchv4Fail,
@@ -1083,7 +1338,7 @@ static int bind_xml_stats (int version, xmlDoc *doc, /* {{{ */
if (global_resolver_stats != 0)
{
translation_table_ptr_t table_ptr =
- {
+ {
resstats_translation_table,
resstats_translation_table_length,
/* plugin_instance = */ "global-resolver_stats"
@@ -1104,10 +1359,39 @@ static int bind_xml_stats (int version, xmlDoc *doc, /* {{{ */
doc, xpathCtx, current_time, DS_TYPE_COUNTER);
}
}
+} /* }}} bind_xml_stats_v1_v2 */
+
+static int bind_xml_stats (int version, xmlDoc *doc, /* {{{ */
+ xmlXPathContext *xpathCtx, xmlNode *statsnode)
+{
+ time_t current_time = 0;
+ int status;
+
+ xpathCtx->node = statsnode;
+
+ /* TODO: Check `server/boot-time' to recognize server restarts. */
+
+ status = bind_xml_read_timestamp ("server/current-time",
+ doc, xpathCtx, ¤t_time);
+ if (status != 0)
+ {
+ ERROR ("bind plugin: Reading `server/current-time' failed.");
+ return (-1);
+ }
+ DEBUG ("bind plugin: Current server time is %i.", (int) current_time);
+
+ if (version == 3)
+ {
+ bind_xml_stats_v3(doc, xpathCtx, statsnode, current_time);
+ }
+ else
+ {
+ bind_xml_stats_v1_v2(version, doc, xpathCtx, statsnode, current_time);
+ }
/* XPath: memory/summary
* Variables: TotalUse, InUse, BlockSize, ContextSize, Lost
- * Layout: v2:
+ * Layout: v2 and v3:
*
* 6587096
* 1345424
@@ -1144,7 +1428,6 @@ static int bind_xml (const char *data) /* {{{ */
xmlXPathContext *xpathCtx = NULL;
xmlXPathObject *xpathObj = NULL;
int ret = -1;
- int i;
doc = xmlParseMemory (data, strlen (data));
if (doc == NULL)
@@ -1161,6 +1444,64 @@ static int bind_xml (const char *data) /* {{{ */
return (-1);
}
+ //
+ // version 3.* of statistics XML (since BIND9.9)
+ //
+
+ xpathObj = xmlXPathEvalExpression (BAD_CAST "/statistics", xpathCtx);
+ if (xpathObj == NULL || xpathObj->nodesetval == NULL || xpathObj->nodesetval->nodeNr == 0)
+ {
+ DEBUG ("bind plugin: Statistics appears not to be v3");
+ // we will fallback to v1 or v2 detection
+ if (xpathObj != NULL) { xmlXPathFreeObject (xpathObj); }
+ }
+ else
+ {
+ for (int i = 0; i < xpathObj->nodesetval->nodeNr; i++)
+ {
+ xmlNode *node;
+ char *attr_version;
+
+ node = xpathObj->nodesetval->nodeTab[i];
+ assert (node != NULL);
+
+ attr_version = (char *) xmlGetProp (node, BAD_CAST "version");
+ if (attr_version == NULL)
+ {
+ NOTICE ("bind plugin: Found tag doesn't have a "
+ "`version' attribute.");
+ continue;
+ }
+ DEBUG ("bind plugin: Found: ", attr_version);
+
+ if (strncmp ("3.", attr_version, strlen ("3.")) != 0)
+ {
+ /* TODO: Use the complaint mechanism here. */
+ NOTICE ("bind plugin: Found tag with version `%s'. "
+ "Unfortunately I have no clue how to parse that. "
+ "Please open a bug report for this.", attr_version);
+ xmlFree (attr_version);
+ continue;
+ }
+ ret = bind_xml_stats (3, doc, xpathCtx, node);
+
+ xmlFree (attr_version);
+ /* One node ought to be enough. */
+ break;
+ }
+
+ // we are finished, early-return
+ xmlXPathFreeObject (xpathObj);
+ xmlXPathFreeContext (xpathCtx);
+ xmlFreeDoc (doc);
+
+ return (ret);
+ }
+
+ //
+ // versions 1.* or 2.* of statistics XML
+ //
+
xpathObj = xmlXPathEvalExpression (BAD_CAST "/isc/bind/statistics", xpathCtx);
if (xpathObj == NULL)
{
@@ -1178,7 +1519,7 @@ static int bind_xml (const char *data) /* {{{ */
return (-1);
}
- for (i = 0; i < xpathObj->nodesetval->nodeNr; i++)
+ for (int i = 0; i < xpathObj->nodesetval->nodeNr; i++)
{
xmlNode *node;
char *attr_version;
@@ -1258,7 +1599,7 @@ static int bind_config_add_view_zone (cb_view_t *view, /* {{{ */
return (-1);
}
- tmp = (char **) realloc (view->zones,
+ tmp = realloc (view->zones,
sizeof (char *) * (view->zones_num + 1));
if (tmp == NULL)
{
@@ -1281,7 +1622,6 @@ static int bind_config_add_view_zone (cb_view_t *view, /* {{{ */
static int bind_config_add_view (oconfig_item_t *ci) /* {{{ */
{
cb_view_t *tmp;
- int i;
if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
{
@@ -1289,7 +1629,7 @@ static int bind_config_add_view (oconfig_item_t *ci) /* {{{ */
return (-1);
}
- tmp = (cb_view_t *) realloc (views, sizeof (*views) * (views_num + 1));
+ tmp = realloc (views, sizeof (*views) * (views_num + 1));
if (tmp == NULL)
{
ERROR ("bind plugin: realloc failed.");
@@ -1313,7 +1653,7 @@ static int bind_config_add_view (oconfig_item_t *ci) /* {{{ */
return (-1);
}
- for (i = 0; i < ci->children_num; i++)
+ for (int i = 0; i < ci->children_num; i++)
{
oconfig_item_t *child = ci->children + i;
@@ -1338,9 +1678,7 @@ static int bind_config_add_view (oconfig_item_t *ci) /* {{{ */
static int bind_config (oconfig_item_t *ci) /* {{{ */
{
- int i;
-
- for (i = 0; i < ci->children_num; i++)
+ for (int i = 0; i < ci->children_num; i++)
{
oconfig_item_t *child = ci->children + i;
@@ -1370,6 +1708,8 @@ static int bind_config (oconfig_item_t *ci) /* {{{ */
bind_config_add_view (child);
else if (strcasecmp ("ParseTime", child->key) == 0)
cf_util_get_boolean (child, &config_parse_time);
+ else if (strcasecmp ("Timeout", child->key) == 0)
+ cf_util_get_int (child, &timeout);
else
{
WARNING ("bind plugin: Unknown configuration option "
@@ -1394,11 +1734,16 @@ static int bind_init (void) /* {{{ */
curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, bind_curl_callback);
- curl_easy_setopt (curl, CURLOPT_USERAGENT, PACKAGE_NAME"/"PACKAGE_VERSION);
+ curl_easy_setopt (curl, CURLOPT_USERAGENT, COLLECTD_USERAGENT);
curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, bind_curl_error);
curl_easy_setopt (curl, CURLOPT_URL, (url != NULL) ? url : BIND_DEFAULT_URL);
curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt (curl, CURLOPT_MAXREDIRS, 50L);
+#ifdef HAVE_CURLOPT_TIMEOUT_MS
+ curl_easy_setopt (curl, CURLOPT_TIMEOUT_MS, (timeout >= 0) ?
+ (long) timeout : (long) CDTIME_T_TO_MS(plugin_get_interval()));
+#endif
+
return (0);
} /* }}} int bind_init */