X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fbind.c;h=9703c0a5cc5b9d5181e289382919c0ba9e15f876;hb=ec43e8a33bdcb116e75310c7bd9daae3bc912834;hp=28d28b68e5fa56fd1584c24f5c2ead252df5dc03;hpb=c1219a1c9db2e8400e2ee94b87f86ccd441485d5;p=collectd.git diff --git a/src/bind.c b/src/bind.c index 28d28b68..9703c0a5 100644 --- a/src/bind.c +++ b/src/bind.c @@ -36,9 +36,9 @@ #endif /* STRPTIME_NEEDS_STANDARDS */ #include "collectd.h" + #include "common.h" #include "plugin.h" -#include "configfile.h" /* Some versions of libcurl don't include this themselves and then don't have * fd_set available. */ @@ -54,7 +54,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 +109,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; @@ -246,16 +247,12 @@ static int memsummary_translation_table_length = static void submit (time_t ts, const char *plugin_instance, /* {{{ */ const char *type, const char *type_instance, value_t value) { - value_t values[1]; value_list_t vl = VALUE_LIST_INIT; - values[0] = value; - - vl.values = values; + vl.values = &value; vl.values_len = 1; if (config_parse_time) vl.time = TIME_T_TO_CDTIME_T (ts); - sstrncpy(vl.host, hostname_g, sizeof(vl.host)); sstrncpy(vl.plugin, "bind", sizeof(vl.plugin)); if (plugin_instance) { sstrncpy(vl.plugin_instance, plugin_instance, @@ -276,14 +273,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 +305,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 +365,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 +412,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 +453,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 +468,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 +485,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 +496,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 +551,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 +570,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 +581,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 +619,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 +748,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 +759,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 +768,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 +802,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 +818,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 +837,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 +918,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 +946,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 +993,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 +1009,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 +1027,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 +1186,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 +1210,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 +1240,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 +1262,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 +1286,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 +1308,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 +1333,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 +1354,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 +1423,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 +1439,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 +1514,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 +1594,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 +1617,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 +1624,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 +1648,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 +1673,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 +1703,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 +1729,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 */