356 lines
14 KiB
PHP

<?php
/**
* Observium
*
* This file is part of Observium.
*
* @package observium
* @subpackage poller
* @copyright (C) Adam Armstrong
*
*/
if (!empty($agent_data['app']['bind']['global'])) {
$app_id = discover_app($device, 'bind');
// Prepare data arrays
// -------------------
$rrtypes = ['SOA', 'ANY', 'A', 'AAAA', 'NS', 'MX', 'CNAME', 'DNAME', 'TXT', 'SPF', 'SRV', 'SSHFP', 'TLSA', 'IPSECKEY', 'PTR', 'DNSKEY', 'RRSIG', 'NSEC', 'NSEC3', 'NSEC3PARAM', 'DS', 'DLV', 'IXFR', 'AXFR'];
// Requests incoming
$req_in = [
'QUERY' => 0,
'STATUS' => 0,
'NOTIFY' => 0,
'UPDATE' => 0,
];
// Query incoming
$query_in = [];
foreach ($rrtypes as $rrtype) {
$query_in[$rrtype] = 0;
}
// Query outgoing
$query_out = [];
// Name server statistics
$ns_stats_field_mapping = [
"IPv4 requests received" => 'Requestv4',
"IPv6 requests received" => 'Requestv6',
"requests with EDNS(0) received" => 'ReqEdns0',
"requests with unsupported EDNS version received" => 'ReqBadEDNSVer',
"requests with TSIG received" => 'ReqTSIG',
"requests with SIG(0) received" => 'ReqSIG0',
"requests with invalid signature" => 'ReqBadSIG',
"TCP requests received" => 'ReqTCP',
"auth queries rejected" => 'AuthQryRej',
"recursive queries rejected" => 'RecQryRej',
"transfer requests rejected" => 'XfrRej',
"update requests rejected" => 'UpdateRej',
"responses sent" => 'Response',
"truncated responses sent" => 'TruncatedResp',
"responses with EDNS(0) sent" => 'RespEDNS0',
"responses with TSIG sent" => 'RespTSIG',
"responses with SIG(0) sent" => 'RespSIG0',
"queries resulted in successful answer" => 'QrySuccess',
"queries resulted in authoritative answer" => 'QryAuthAns',
"queries resulted in non authoritative answer" => 'QryNoauthAns',
"queries resulted in referral answer" => 'QryReferral',
"queries resulted in nxrrset" => 'QryNxrrset',
"queries resulted in SERVFAIL" => 'QrySERVFAIL',
"queries resulted in FORMERR" => 'QryFORMERR',
"queries resulted in NXDOMAIN" => 'QryNXDOMAIN',
"queries caused recursion" => 'QryRecursion',
"duplicate queries received" => 'QryDuplicate',
"queries dropped" => 'QryDropped',
"other query failures" => 'QryFailure',
"requested transfers completed" => 'XfrReqDone',
"update requests forwarded" => 'UpdateReqFwd',
"update responses forwarded" => 'UpdateRespFwd',
"update forward failed" => 'UpdateFwdFail',
"updates completed" => 'UpdateDone',
"updates failed" => 'UpdateFail',
"updates rejected due to prerequisite failure" => 'UpdateBadPrereq',
"response policy zone rewrites" => 'RPZRewrites',
];
$ns_stats_fields = array_values($ns_stats_field_mapping);
array_sort($ns_stats_fields, 'Requestv4');
$ns_stats = [];
foreach ($ns_stats_fields as $field) {
$ns_stats[$field] = 0;
}
// Zone maintenance
$zone_maint_field_mapping = [
"IPv4 notifies sent" => 'NotifyOutv4',
"IPv6 notifies sent" => 'NotifyOutv6',
"IPv4 notifies received" => 'NotifyInv4',
"IPv6 notifies received" => 'NotifyInv6',
"notifies rejected" => 'NotifyRej',
"IPv4 SOA queries sent" => 'SOAOutv4',
"IPv6 SOA queries sent" => 'SOAOutv6',
"IPv4 AXFR requested" => 'AXFRReqv4',
"IPv6 AXFR requested" => 'AXFRReqv6',
"IPv4 IXFR requested" => 'IXFRReqv4',
"IPv6 IXFR requested" => 'IXFRReqv6',
"transfer requests succeeded" => 'XfrSuccess',
"transfer requests failed" => 'XfrFail',
];
$zone_maint_fields = array_values($zone_maint_field_mapping);
array_sort($zone_maint_fields, 'NotifyOutv4');
$zone_maint = [];
foreach ($zone_maint_fields as $field) {
$zone_maint[$field] = 0;
}
// Resolver
$resolver_field_mapping = [
"IPv4 queries sent" => 'Queryv4',
"IPv6 queries sent" => 'Queryv6',
"IPv4 responses received" => 'Responsev4',
"IPv6 responses received" => 'Responsev6',
"NXDOMAIN received" => 'NXDOMAIN',
"SERVFAIL received" => 'SERVFAIL',
"FORMERR received" => 'FORMERR',
"other errors received" => 'OtherError',
"EDNS(0) query failures" => 'EDNS0Fail',
"mismatch responses received" => 'Mismatch',
"truncated responses received" => 'Truncated',
"lame delegations received" => 'Lame',
"query retries" => 'Retry',
"queries aborted due to quota" => 'QueryAbort',
"failures in opening query sockets" => 'QuerySockFail',
"query timeouts" => 'QueryTimeout',
"IPv4 NS address fetches" => 'GlueFetchv4',
"IPv6 NS address fetches" => 'GlueFetchv6',
"IPv4 NS address fetch failed" => 'GlueFetchv4Fail',
"IPv6 NS address fetch failed" => 'GlueFetchv6Fail',
"DNSSEC validation attempted" => 'ValAttempt',
"DNSSEC validation succeeded" => 'ValOk',
"DNSSEC NX validation succeeded" => 'ValNegOk',
"DNSSEC validation failed" => 'ValFail',
"queries with RTT < 10ms" => 'QryRTT10',
"queries with RTT 10-100ms" => 'QryRTT100',
"queries with RTT 100-500ms" => 'QryRTT500',
"queries with RTT 500-800ms" => 'QryRTT800',
"queries with RTT 800-1600ms" => 'QryRTT1600',
"queries with RTT > 1600ms" => 'QryRTT1600plus',
];
$resolver_fields = array_values($resolver_field_mapping);
array_sort($resolver_fields, 'Queryv4');
$resolver = [];
// Cache
$cache = [];
// Store the data in arrays
// ------------------------
$lines = explode("\n", $agent_data['app']['bind']['global']);
foreach ($lines as $line) {
// Line format is "key:value"
[$key, $value] = explode(':', $line);
// Keys consist of "section,subkey"
[$section, $subkey] = explode(',', $key, 2);
// The subkey depends on the section
if ($section == 'req-in') {
// Subkey is the opcode
$req_in[$subkey] = (int)$value;
} elseif ($section == 'query-in') {
// Subkey is the RRType
$query_in[$subkey] = (int)$value;
} elseif ($section == 'ns-stats') {
// Subkey is description
if (isset($ns_stats_field_mapping[$subkey])) {
$subkey = $ns_stats_field_mapping[$subkey];
}
$ns_stats[$subkey] = (int)$value;
} elseif ($section == 'zone-maint') {
// Subkey is description
if (isset($zone_maint_field_mapping[$subkey])) {
$subkey = $zone_maint_field_mapping[$subkey];
}
$zone_maint[$subkey] = (int)$value;
}
}
// Done with the global stuff
unset($agent_data['app']['bind']['global']);
// The rest is views
foreach ($agent_data['app']['bind'] as $view => $view_data) {
$lines = explode("\n", $agent_data['app']['bind'][$view]);
foreach ($lines as $line) {
// Line format is "key:value"
[$key, $value] = explode(':', $line);
// Keys consist of "section,subkey"
[$section, $subkey] = explode(',', $key, 2);
// The subkey depends on the section
if ($section == 'query-out') {
// Create the view if it doesn't exist yet
if (!isset($query_out[$view])) {
foreach ($rrtypes as $rrtype) {
$query_out[$view][$rrtype] = 0;
}
}
// Subkey is the RRType
$query_out[$view][$subkey] = (int)$value;
} elseif ($section == 'resolver') {
// Create the view if it doesn't exist yet
if (!isset($resolver[$view])) {
foreach ($resolver_fields as $field) {
$resolver[$view][$field] = 0;
}
}
// Subkey is the description
if (isset($resolver_field_mapping[$subkey])) {
$subkey = $resolver_field_mapping[$subkey];
}
$resolver[$view][$subkey] = (int)$value;
} elseif ($section == 'cache') {
// Create the view if it doesn't exist yet
if (!isset($cache[$view])) {
foreach ($rrtypes as $rrtype) {
// Create fields for both positive and negative cache entries
$cache[$view][$field] = 0;
$cache[$view]['!' . $field] = 0;
}
}
// Subkey is the RRType
$cache[$view][$subkey] = (int)$value;
}
}
}
// Use the data from the arrays to build RRDs
// ------------------------------------------
// rrdcreate list of rrtypes
$rrdcreate_rrtypes = "";
foreach ($rrtypes as $rrtype) {
$rrdcreate_rrtypes .= " DS:$rrtype:DERIVE:600:0:7500000";
}
// req-in
rrdtool_update_ng($device, 'bind-req-in', [
'query' => $req_in['QUERY'],
'status' => $req_in['STATUS'],
'notify' => $req_in['NOTIFY'],
'update' => $req_in['UPDATE'],
], $app_id);
// query-in
$rrd_filename = "app-bind-$app_id-query-in.rrd";
rrdtool_create($device, $rrd_filename, " $rrdcreate_rrtypes ");
$rrd_data = "";
foreach ($rrtypes as $rrtype) {
$rrd_data .= ":" . (safe_empty($query_in[$rrtype]) ? 'U' : $query_in[$rrtype]);
}
rrdtool_update($device, $rrd_filename, "N" . $rrd_data);
// ns-stats
$rrd_filename = "app-bind-$app_id-ns-stats.rrd";
// rrdcreate list of fields
$rrdcreate_ns_stats = "";
foreach ($ns_stats_fields as $field) {
$rrdcreate_ns_stats .= " DS:$field:DERIVE:600:0:7500000";
}
rrdtool_create($device, $rrd_filename, " $rrdcreate_ns_stats ");
$rrd_data = "";
foreach ($ns_stats_fields as $field) {
$rrd_data .= ":" . (safe_empty($ns_stats[$field]) ? 'U' : $ns_stats[$field]);
}
rrdtool_update($device, $rrd_filename, "N" . $rrd_data);
// zone-maint
$rrd_filename = "app-bind-$app_id-zone-maint.rrd";
// rrdcreate list of fields
$rrdcreate_zone_maint = "";
foreach ($zone_maint_fields as $field) {
$rrdcreate_zone_maint .= " DS:$field:DERIVE:600:0:7500000";
}
rrdtool_create($device, $rrd_filename, " $rrdcreate_zone_maint ");
$rrd_data = "";
foreach ($zone_maint_fields as $field) {
$rrd_data .= ":" . (safe_empty($zone_maint[$field]) ? 'U' : $zone_maint[$field]);
}
rrdtool_update($device, $rrd_filename, "N" . $rrd_data);
// query-out
foreach ($query_out as $view => $view_data) {
$rrd_filename = "app-bind-$app_id-query-out-" . $view . ".rrd";
rrdtool_create($device, $rrd_filename, " $rrdcreate_rrtypes ");
$rrd_data = "";
foreach ($rrtypes as $rrtype) {
$rrd_data .= ":" . (safe_empty($view_data[$rrtype]) ? 'U' : $view_data[$rrtype]);
}
rrdtool_update($device, $rrd_filename, "N" . $rrd_data);
}
// resolver
foreach ($resolver as $view => $view_data) {
$rrd_filename = "app-bind-$app_id-resolver-$view.rrd";
// rrdcreate list of fields
$rrdcreate_resolver = "";
foreach ($resolver_fields as $field) {
$rrdcreate_resolver .= " DS:$field:DERIVE:600:0:7500000";
}
rrdtool_create($device, $rrd_filename, " $rrdcreate_resolver ");
$rrd_data = "";
foreach ($resolver_fields as $field) {
$rrd_data .= ":" . (safe_empty($view_data[$field]) ? 'U' : $view_data[$field]);
}
rrdtool_update($device, $rrd_filename, "N" . $rrd_data);
}
// cache
foreach ($cache as $view => $view_data) {
$rrd_filename = "app-bind-$app_id-cache-$view.rrd";
$rrdcreate_cache = "";
foreach ($rrtypes as $rrtype) {
$rrdcreate_cache .= " DS:$rrtype:GAUGE:600:0:1000000";
$rrdcreate_cache .= " DS:NEG_$rrtype:GAUGE:600:0:1000000";
}
rrdtool_create($device, $rrd_filename, " $rrdcreate_cache ");
$rrd_data = "";
foreach ($rrtypes as $rrtype) {
$rrd_data .= ":" . (safe_empty($view_data[$rrtype]) ? 'U' : $view_data[$rrtype]);
$rrd_data .= ":" . (safe_empty($view_data['!' . $rrtype]) ? 'U' : $view_data['!' . $rrtype]);
}
rrdtool_update($device, $rrd_filename, "N" . $rrd_data);
}
// FIXME
update_application($app_id, []);
}
// EOF