1<?php
2
3/**
4 * Observium
5 *
6 *   This file is part of Observium.
7 *
8 * @package    observium
9 * @subpackage poller
10 * @copyright  (C) 2006-2013 Adam Armstrong, (C) 2013-2019 Observium Limited
11 *
12 */
13
14if (!empty($agent_data['app']['bind']['global']))
15{
16  $app_id = discover_app($device, 'bind');
17
18  // Prepare data arrays
19  // -------------------
20  $rrtypes = array('SOA', 'ANY', 'A', 'AAAA', 'NS', 'MX', 'CNAME', 'DNAME', 'TXT', 'SPF', 'SRV', 'SSHFP', 'TLSA', 'IPSECKEY', 'PTR', 'DNSKEY', 'RRSIG', 'NSEC', 'NSEC3', 'NSEC3PARAM', 'DS', 'DLV', 'IXFR', 'AXFR');
21
22  // Requests incoming
23  $req_in = array(
24    'QUERY' => 0,
25    'STATUS' => 0,
26    'NOTIFY' => 0,
27    'UPDATE' => 0,
28  );
29
30  // Query incoming
31  $query_in = array();
32  foreach ($rrtypes as $rrtype)
33  {
34    $query_in[$rrtype] = 0;
35  }
36
37  // Query outgoing
38  $query_out = array();
39
40  // Name server statistics
41  $ns_stats_field_mapping = array(
42    "IPv4 requests received" => 'Requestv4',
43    "IPv6 requests received" => 'Requestv6',
44    "requests with EDNS(0) received" => 'ReqEdns0',
45    "requests with unsupported EDNS version received" => 'ReqBadEDNSVer',
46    "requests with TSIG received" => 'ReqTSIG',
47    "requests with SIG(0) received" => 'ReqSIG0',
48    "requests with invalid signature" => 'ReqBadSIG',
49    "TCP requests received" => 'ReqTCP',
50    "auth queries rejected" => 'AuthQryRej',
51    "recursive queries rejected" => 'RecQryRej',
52    "transfer requests rejected" => 'XfrRej',
53    "update requests rejected" => 'UpdateRej',
54    "responses sent" => 'Response',
55    "truncated responses sent" => 'TruncatedResp',
56    "responses with EDNS(0) sent" => 'RespEDNS0',
57    "responses with TSIG sent" => 'RespTSIG',
58    "responses with SIG(0) sent" => 'RespSIG0',
59    "queries resulted in successful answer" => 'QrySuccess',
60    "queries resulted in authoritative answer" => 'QryAuthAns',
61    "queries resulted in non authoritative answer" => 'QryNoauthAns',
62    "queries resulted in referral answer" => 'QryReferral',
63    "queries resulted in nxrrset" => 'QryNxrrset',
64    "queries resulted in SERVFAIL" => 'QrySERVFAIL',
65    "queries resulted in FORMERR" => 'QryFORMERR',
66    "queries resulted in NXDOMAIN" => 'QryNXDOMAIN',
67    "queries caused recursion" => 'QryRecursion',
68    "duplicate queries received" => 'QryDuplicate',
69    "queries dropped" => 'QryDropped',
70    "other query failures" => 'QryFailure',
71    "requested transfers completed" => 'XfrReqDone',
72    "update requests forwarded" => 'UpdateReqFwd',
73    "update responses forwarded" => 'UpdateRespFwd',
74    "update forward failed" => 'UpdateFwdFail',
75    "updates completed" => 'UpdateDone',
76    "updates failed" => 'UpdateFail',
77    "updates rejected due to prerequisite failure" => 'UpdateBadPrereq',
78    "response policy zone rewrites" => 'RPZRewrites',
79  );
80
81  $ns_stats_fields = array_values($ns_stats_field_mapping);
82  array_sort($ns_stats_fields, 'Requestv4');
83
84  $ns_stats = array();
85  foreach ($ns_stats_fields as $field)
86  {
87    $ns_stats[$field] = 0;
88  }
89
90  // Zone maintenance
91  $zone_maint_field_mapping = array(
92    "IPv4 notifies sent" => 'NotifyOutv4',
93    "IPv6 notifies sent" => 'NotifyOutv6',
94    "IPv4 notifies received" => 'NotifyInv4',
95    "IPv6 notifies received" => 'NotifyInv6',
96    "notifies rejected" => 'NotifyRej',
97    "IPv4 SOA queries sent" => 'SOAOutv4',
98    "IPv6 SOA queries sent" => 'SOAOutv6',
99    "IPv4 AXFR requested" => 'AXFRReqv4',
100    "IPv6 AXFR requested" => 'AXFRReqv6',
101    "IPv4 IXFR requested" => 'IXFRReqv4',
102    "IPv6 IXFR requested" => 'IXFRReqv6',
103    "transfer requests succeeded" => 'XfrSuccess',
104    "transfer requests failed" => 'XfrFail',
105  );
106
107  $zone_maint_fields = array_values($zone_maint_field_mapping);
108  array_sort($zone_maint_fields, 'NotifyOutv4');
109
110  $zone_maint = array();
111  foreach ($zone_maint_fields as $field)
112  {
113    $zone_maint[$field] = 0;
114  }
115
116  // Resolver
117  $resolver_field_mapping = array(
118    "IPv4 queries sent" => 'Queryv4',
119    "IPv6 queries sent" => 'Queryv6',
120    "IPv4 responses received" => 'Responsev4',
121    "IPv6 responses received" => 'Responsev6',
122    "NXDOMAIN received" => 'NXDOMAIN',
123    "SERVFAIL received" => 'SERVFAIL',
124    "FORMERR received" => 'FORMERR',
125    "other errors received" => 'OtherError',
126    "EDNS(0) query failures" => 'EDNS0Fail',
127    "mismatch responses received" => 'Mismatch',
128    "truncated responses received" => 'Truncated',
129    "lame delegations received" => 'Lame',
130    "query retries" => 'Retry',
131    "queries aborted due to quota" => 'QueryAbort',
132    "failures in opening query sockets" => 'QuerySockFail',
133    "query timeouts" => 'QueryTimeout',
134    "IPv4 NS address fetches" => 'GlueFetchv4',
135    "IPv6 NS address fetches" => 'GlueFetchv6',
136    "IPv4 NS address fetch failed" => 'GlueFetchv4Fail',
137    "IPv6 NS address fetch failed" => 'GlueFetchv6Fail',
138    "DNSSEC validation attempted" => 'ValAttempt',
139    "DNSSEC validation succeeded" => 'ValOk',
140    "DNSSEC NX validation succeeded" => 'ValNegOk',
141    "DNSSEC validation failed" => 'ValFail',
142    "queries with RTT < 10ms" => 'QryRTT10',
143    "queries with RTT 10-100ms" => 'QryRTT100',
144    "queries with RTT 100-500ms" => 'QryRTT500',
145    "queries with RTT 500-800ms" => 'QryRTT800',
146    "queries with RTT 800-1600ms" => 'QryRTT1600',
147    "queries with RTT > 1600ms" => 'QryRTT1600plus',
148  );
149
150  $resolver_fields = array_values($resolver_field_mapping);
151  array_sort($resolver_fields, 'Queryv4');
152
153  $resolver = array();
154
155  // Cache
156  $cache = array();
157
158  // Store the data in arrays
159  // ------------------------
160  $lines = explode("\n", $agent_data['app']['bind']['global']);
161  foreach ($lines as $line) {
162    // Line format is "key:value"
163    list ($key, $value) = explode(':', $line);
164
165    // Keys consist of "section,subkey"
166    list ($section, $subkey) = explode(',', $key, 2);
167
168    // The subkey depends on the section
169    if ($section == 'req-in')
170    {
171      // Subkey is the opcode
172      $req_in[$subkey] = (int) $value;
173    }
174    elseif ($section == 'query-in')
175    {
176      // Subkey is the RRType
177      $query_in[$subkey] = (int) $value;
178    }
179    elseif ($section == 'ns-stats')
180    {
181      // Subkey is description
182      if (isset($ns_stats_field_mapping[$subkey]))
183      {
184        $subkey = $ns_stats_field_mapping[$subkey];
185      }
186      $ns_stats[$subkey] = (int) $value;
187    }
188    elseif ($section == 'zone-maint')
189    {
190      // Subkey is description
191      if (isset($zone_maint_field_mapping[$subkey]))
192      {
193        $subkey = $zone_maint_field_mapping[$subkey];
194      }
195      $zone_maint[$subkey] = (int) $value;
196    }
197  }
198
199  // Done with the global stuff
200  unset($agent_data['app']['bind']['global']);
201
202  // The rest is views
203  foreach ($agent_data['app']['bind'] as $view => $view_data)
204  {
205    $lines = explode("\n", $agent_data['app']['bind'][$view]);
206    foreach ($lines as $line) {
207      // Line format is "key:value"
208      list ($key, $value) = explode(':', $line);
209
210      // Keys consist of "section,subkey"
211      list ($section, $subkey) = explode(',', $key, 2);
212
213      // The subkey depends on the section
214      if ($section == 'query-out')
215      {
216        // Create the view if it doesn't exist yet
217        if (!isset($query_out[$view]))
218        {
219          foreach ($rrtypes as $rrtype)
220          {
221            $query_out[$view][$rrtype] = 0;
222          }
223        }
224
225        // Subkey is the RRType
226        $query_out[$view][$subkey] = (int) $value;
227      }
228      elseif ($section == 'resolver')
229      {
230        // Create the view if it doesn't exist yet
231        if (!isset($resolver[$view]))
232        {
233          foreach ($resolver_fields as $field)
234          {
235            $resolver[$view][$field] = 0;
236          }
237        }
238
239        // Subkey is the description
240        if (isset($resolver_field_mapping[$subkey]))
241        {
242          $subkey = $resolver_field_mapping[$subkey];
243        }
244        $resolver[$view][$subkey] = (int) $value;
245      }
246      elseif ($section == 'cache')
247      {
248        // Create the view if it doesn't exist yet
249        if (!isset($cache[$view]))
250        {
251          foreach ($rrtypes as $rrtype)
252          {
253            // Create fields for both positive and negative cache entries
254            $cache[$view][$field] = 0;
255            $cache[$view]['!'.$field] = 0;
256          }
257        }
258        // Subkey is the RRType
259        $cache[$view][$subkey] = (int) $value;
260      }
261    }
262  }
263
264  // Use the data from the arrays to build RRDs
265  // ------------------------------------------
266
267  // rrdcreate list of rrtypes
268  $rrdcreate_rrtypes = "";
269  foreach ($rrtypes as $rrtype)
270  {
271    $rrdcreate_rrtypes .= " DS:$rrtype:DERIVE:600:0:7500000";
272  }
273
274  // req-in
275  rrdtool_update_ng($device, 'bind-req-in', array(
276    'query'  => $req_in['QUERY'],
277    'status' => $req_in['STATUS'],
278    'notify' => $req_in['NOTIFY'],
279    'update' => $req_in['UPDATE'],
280  ), $app_id);
281
282  // query-in
283  $rrd_filename = "app-bind-$app_id-query-in.rrd";
284
285  rrdtool_create($device, $rrd_filename, " $rrdcreate_rrtypes ");
286
287  $rrd_data = "";
288  foreach ($rrtypes as $rrtype)
289  {
290    $rrd_data .= ":".$query_in[$rrtype];
291  }
292  rrdtool_update($device, $rrd_filename,  "N".$rrd_data);
293
294  // ns-stats
295  $rrd_filename = "app-bind-$app_id-ns-stats.rrd";
296
297  // rrdcreate list of fields
298  $rrdcreate_ns_stats = "";
299  foreach ($ns_stats_fields as $field)
300  {
301    $rrdcreate_ns_stats .= " DS:$field:DERIVE:600:0:7500000";
302  }
303
304  rrdtool_create($device, $rrd_filename, " $rrdcreate_ns_stats ");
305
306  $rrd_data = "";
307  foreach ($ns_stats_fields as $field)
308  {
309    $rrd_data .= ":".$ns_stats[$field];
310  }
311  rrdtool_update($device, $rrd_filename,  "N".$rrd_data);
312
313  // zone-maint
314  $rrd_filename = "app-bind-$app_id-zone-maint.rrd";
315
316  // rrdcreate list of fields
317  $rrdcreate_zone_maint = "";
318  foreach ($zone_maint_fields as $field)
319  {
320    $rrdcreate_zone_maint .= " DS:$field:DERIVE:600:0:7500000";
321  }
322  rrdtool_create($device, $rrd_filename, " $rrdcreate_zone_maint ");
323
324  $rrd_data = "";
325  foreach ($zone_maint_fields as $field)
326  {
327    $rrd_data .= ":".$zone_maint[$field];
328  }
329  rrdtool_update($device, $rrd_filename,  "N".$rrd_data);
330
331  // query-out
332  foreach ($query_out as $view => $view_data)
333  {
334    $rrd_filename = "app-bind-$app_id-query-out-".$view.".rrd";
335
336    rrdtool_create($device, $rrd_filename, " $rrdcreate_rrtypes ");
337
338    $rrd_data = "";
339    foreach ($rrtypes as $rrtype)
340    {
341      $rrd_data .= ":".$view_data[$rrtype];
342    }
343    rrdtool_update($device, $rrd_filename,  "N".$rrd_data);
344  }
345
346  // resolver
347  foreach ($resolver as $view => $view_data)
348  {
349    $rrd_filename = "app-bind-$app_id-resolver-$view.rrd";
350
351    // rrdcreate list of fields
352    $rrdcreate_resolver = "";
353    foreach ($resolver_fields as $field)
354    {
355      $rrdcreate_resolver .= " DS:$field:DERIVE:600:0:7500000";
356    }
357    rrdtool_create($device, $rrd_filename, " $rrdcreate_resolver ");
358
359    $rrd_data = "";
360    foreach ($resolver_fields as $field)
361    {
362      $rrd_data .= ":".$view_data[$field];
363    }
364    rrdtool_update($device, $rrd_filename,  "N".$rrd_data);
365  }
366
367  // cache
368  foreach ($cache as $view => $view_data)
369  {
370    $rrd_filename = "app-bind-$app_id-cache-$view.rrd";
371
372    $rrdcreate_cache = "";
373    foreach ($rrtypes as $rrtype)
374    {
375      $rrdcreate_cache .= " DS:$rrtype:GAUGE:600:0:1000000";
376      $rrdcreate_cache .= " DS:NEG_$rrtype:GAUGE:600:0:1000000";
377    }
378    rrdtool_create($device, $rrd_filename, " $rrdcreate_cache ");
379
380    $rrd_data = "";
381    foreach ($rrtypes as $rrtype)
382    {
383      $rrd_data .= ":".$view_data[$rrtype];
384      $rrd_data .= ":".$view_data['!'.$rrtype];
385    }
386    rrdtool_update($device, $rrd_filename,  "N".$rrd_data);
387  }
388
389
390  // FIXME
391  update_application($app_id, array());
392
393}
394
395// EOF
396