etc/services - sync with NetBSD-8
[minix.git] / external / bsd / bind / dist / bin / named / statschannel.c
blob816f0eb7c14787862f4c8fd43ac9392c1db91790
1 /* $NetBSD: statschannel.c,v 1.10 2014/12/10 04:37:52 christos Exp $ */
3 /*
4 * Copyright (C) 2008-2014 Internet Systems Consortium, Inc. ("ISC")
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
19 /* Id: statschannel.c,v 1.28.224.1 2011/12/22 07:48:27 marka Exp */
21 /*! \file */
23 #include <config.h>
25 #include <isc/buffer.h>
26 #include <isc/httpd.h>
27 #include <isc/mem.h>
28 #include <isc/once.h>
29 #include <isc/print.h>
30 #include <isc/socket.h>
31 #include <isc/stats.h>
32 #include <isc/string.h>
33 #include <isc/task.h>
35 #include <dns/cache.h>
36 #include <dns/db.h>
37 #include <dns/opcode.h>
38 #include <dns/resolver.h>
39 #include <dns/rdataclass.h>
40 #include <dns/rdatatype.h>
41 #include <dns/stats.h>
42 #include <dns/view.h>
43 #include <dns/zt.h>
45 #include <named/log.h>
46 #include <named/server.h>
47 #include <named/statschannel.h>
49 #ifdef HAVE_JSON_H
50 #include <json/json.h>
51 #endif
53 #include "bind9.xsl.h"
55 struct ns_statschannel {
56 /* Unlocked */
57 isc_httpdmgr_t *httpdmgr;
58 isc_sockaddr_t address;
59 isc_mem_t *mctx;
62 * Locked by channel lock: can be referenced and modified by both
63 * the server task and the channel task.
65 isc_mutex_t lock;
66 dns_acl_t *acl;
68 /* Locked by server task */
69 ISC_LINK(struct ns_statschannel) link;
72 typedef struct
73 stats_dumparg {
74 isc_statsformat_t type;
75 void *arg; /* type dependent argument */
76 int ncounters; /* for general statistics */
77 int *counterindices; /* for general statistics */
78 isc_uint64_t *countervalues; /* for general statistics */
79 isc_result_t result;
80 } stats_dumparg_t;
82 static isc_once_t once = ISC_ONCE_INIT;
84 #if defined(HAVE_LIBXML2) || defined(HAVE_JSON)
85 #define EXTENDED_STATS
86 #else
87 #undef EXTENDED_STATS
88 #endif
90 /*%
91 * Statistics descriptions. These could be statistically initialized at
92 * compile time, but we configure them run time in the init_desc() function
93 * below so that they'll be less susceptible to counter name changes.
95 static const char *nsstats_desc[dns_nsstatscounter_max];
96 static const char *resstats_desc[dns_resstatscounter_max];
97 static const char *adbstats_desc[dns_adbstats_max];
98 static const char *zonestats_desc[dns_zonestatscounter_max];
99 static const char *sockstats_desc[isc_sockstatscounter_max];
100 static const char *dnssecstats_desc[dns_dnssecstats_max];
101 #if defined(EXTENDED_STATS)
102 static const char *nsstats_xmldesc[dns_nsstatscounter_max];
103 static const char *resstats_xmldesc[dns_resstatscounter_max];
104 static const char *adbstats_xmldesc[dns_adbstats_max];
105 static const char *zonestats_xmldesc[dns_zonestatscounter_max];
106 static const char *sockstats_xmldesc[isc_sockstatscounter_max];
107 static const char *dnssecstats_xmldesc[dns_dnssecstats_max];
108 #else
109 #define nsstats_xmldesc NULL
110 #define resstats_xmldesc NULL
111 #define adbstats_xmldesc NULL
112 #define zonestats_xmldesc NULL
113 #define sockstats_xmldesc NULL
114 #define dnssecstats_xmldesc NULL
115 #endif /* EXTENDED_STATS */
117 #define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(/*CONSTCOND*/0)
120 * Mapping arrays to represent statistics counters in the order of our
121 * preference, regardless of the order of counter indices. For example,
122 * nsstats_desc[nsstats_index[0]] will be the description that is shown first.
124 static int nsstats_index[dns_nsstatscounter_max];
125 static int resstats_index[dns_resstatscounter_max];
126 static int adbstats_index[dns_adbstats_max];
127 static int zonestats_index[dns_zonestatscounter_max];
128 static int sockstats_index[isc_sockstatscounter_max];
129 static int dnssecstats_index[dns_dnssecstats_max];
131 static inline void
132 set_desc(int counter, int maxcounter, const char *fdesc, const char **fdescs,
133 const char *xdesc, const char **xdescs)
135 REQUIRE(counter < maxcounter);
136 REQUIRE(fdescs != NULL && fdescs[counter] == NULL);
137 #if defined(EXTENDED_STATS)
138 REQUIRE(xdescs != NULL && xdescs[counter] == NULL);
139 #endif
141 fdescs[counter] = fdesc;
142 #if defined(EXTENDED_STATS)
143 xdescs[counter] = xdesc;
144 #else
145 UNUSED(xdesc);
146 UNUSED(xdescs);
147 #endif
150 static void
151 init_desc(void) {
152 int i;
154 /* Initialize name server statistics */
155 for (i = 0; i < dns_nsstatscounter_max; i++)
156 nsstats_desc[i] = NULL;
157 #if defined(EXTENDED_STATS)
158 for (i = 0; i < dns_nsstatscounter_max; i++)
159 nsstats_xmldesc[i] = NULL;
160 #endif
162 #define SET_NSSTATDESC(counterid, desc, xmldesc) \
163 do { \
164 set_desc(dns_nsstatscounter_ ## counterid, \
165 dns_nsstatscounter_max, \
166 desc, nsstats_desc, xmldesc, nsstats_xmldesc); \
167 nsstats_index[i++] = dns_nsstatscounter_ ## counterid; \
168 } while (/*CONSTCOND*/0)
170 i = 0;
171 SET_NSSTATDESC(requestv4, "IPv4 requests received", "Requestv4");
172 SET_NSSTATDESC(requestv6, "IPv6 requests received", "Requestv6");
173 SET_NSSTATDESC(edns0in, "requests with EDNS(0) received", "ReqEdns0");
174 SET_NSSTATDESC(badednsver,
175 "requests with unsupported EDNS version received",
176 "ReqBadEDNSVer");
177 SET_NSSTATDESC(tsigin, "requests with TSIG received", "ReqTSIG");
178 SET_NSSTATDESC(sig0in, "requests with SIG(0) received", "ReqSIG0");
179 SET_NSSTATDESC(invalidsig, "requests with invalid signature",
180 "ReqBadSIG");
181 SET_NSSTATDESC(requesttcp, "TCP requests received", "ReqTCP");
182 SET_NSSTATDESC(authrej, "auth queries rejected", "AuthQryRej");
183 SET_NSSTATDESC(recurserej, "recursive queries rejected", "RecQryRej");
184 SET_NSSTATDESC(xfrrej, "transfer requests rejected", "XfrRej");
185 SET_NSSTATDESC(updaterej, "update requests rejected", "UpdateRej");
186 SET_NSSTATDESC(response, "responses sent", "Response");
187 SET_NSSTATDESC(truncatedresp, "truncated responses sent",
188 "TruncatedResp");
189 SET_NSSTATDESC(edns0out, "responses with EDNS(0) sent", "RespEDNS0");
190 SET_NSSTATDESC(tsigout, "responses with TSIG sent", "RespTSIG");
191 SET_NSSTATDESC(sig0out, "responses with SIG(0) sent", "RespSIG0");
192 SET_NSSTATDESC(success, "queries resulted in successful answer",
193 "QrySuccess");
194 SET_NSSTATDESC(authans, "queries resulted in authoritative answer",
195 "QryAuthAns");
196 SET_NSSTATDESC(nonauthans,
197 "queries resulted in non authoritative answer",
198 "QryNoauthAns");
199 SET_NSSTATDESC(referral, "queries resulted in referral answer",
200 "QryReferral");
201 SET_NSSTATDESC(nxrrset, "queries resulted in nxrrset", "QryNxrrset");
202 SET_NSSTATDESC(servfail, "queries resulted in SERVFAIL", "QrySERVFAIL");
203 SET_NSSTATDESC(formerr, "queries resulted in FORMERR", "QryFORMERR");
204 SET_NSSTATDESC(nxdomain, "queries resulted in NXDOMAIN", "QryNXDOMAIN");
205 SET_NSSTATDESC(recursion, "queries caused recursion", "QryRecursion");
206 SET_NSSTATDESC(duplicate, "duplicate queries received", "QryDuplicate");
207 SET_NSSTATDESC(dropped, "queries dropped", "QryDropped");
208 SET_NSSTATDESC(failure, "other query failures", "QryFailure");
209 SET_NSSTATDESC(xfrdone, "requested transfers completed", "XfrReqDone");
210 SET_NSSTATDESC(updatereqfwd, "update requests forwarded",
211 "UpdateReqFwd");
212 SET_NSSTATDESC(updaterespfwd, "update responses forwarded",
213 "UpdateRespFwd");
214 SET_NSSTATDESC(updatefwdfail, "update forward failed", "UpdateFwdFail");
215 SET_NSSTATDESC(updatedone, "updates completed", "UpdateDone");
216 SET_NSSTATDESC(updatefail, "updates failed", "UpdateFail");
217 SET_NSSTATDESC(updatebadprereq,
218 "updates rejected due to prerequisite failure",
219 "UpdateBadPrereq");
220 SET_NSSTATDESC(recursclients, "recursing clients",
221 "RecursClients");
222 SET_NSSTATDESC(dns64, "queries answered by DNS64", "DNS64");
223 SET_NSSTATDESC(ratedropped, "responses dropped for rate limits",
224 "RateDropped");
225 SET_NSSTATDESC(rateslipped, "responses truncated for rate limits",
226 "RateSlipped");
227 SET_NSSTATDESC(rpz_rewrites, "response policy zone rewrites",
228 "RPZRewrites");
229 SET_NSSTATDESC(udp, "UDP queries received", "QryUDP");
230 SET_NSSTATDESC(tcp, "TCP queries received", "QryTCP");
231 SET_NSSTATDESC(nsidopt, "NSID option received", "NSIDOpt");
232 SET_NSSTATDESC(expireopt, "Expire option recieved", "ExpireOpt");
233 SET_NSSTATDESC(otheropt, "Other EDNS option recieved", "OtherOpt");
234 #ifdef ISC_PLATFORM_USESIT
235 SET_NSSTATDESC(sitopt, "source identity token option received",
236 "SitOpt");
237 SET_NSSTATDESC(sitnew, "new source identity token requested",
238 "SitNew");
239 SET_NSSTATDESC(sitbadsize, "source identity token - bad size",
240 "SitBadSize");
241 SET_NSSTATDESC(sitbadtime, "source identity token - bad time",
242 "SitBadTime");
243 SET_NSSTATDESC(sitnomatch, "source identity token - no match",
244 "SitNoMatch");
245 SET_NSSTATDESC(sitmatch, "source identity token - match", "SitMatch");
246 #endif
247 INSIST(i == dns_nsstatscounter_max);
249 /* Initialize resolver statistics */
250 for (i = 0; i < dns_resstatscounter_max; i++)
251 resstats_desc[i] = NULL;
252 #if defined(EXTENDED_STATS)
253 for (i = 0; i < dns_resstatscounter_max; i++)
254 resstats_xmldesc[i] = NULL;
255 #endif
257 #define SET_RESSTATDESC(counterid, desc, xmldesc) \
258 do { \
259 set_desc(dns_resstatscounter_ ## counterid, \
260 dns_resstatscounter_max, \
261 desc, resstats_desc, xmldesc, resstats_xmldesc); \
262 resstats_index[i++] = dns_resstatscounter_ ## counterid; \
263 } while (/*CONSTCOND*/0)
265 i = 0;
266 SET_RESSTATDESC(queryv4, "IPv4 queries sent", "Queryv4");
267 SET_RESSTATDESC(queryv6, "IPv6 queries sent", "Queryv6");
268 SET_RESSTATDESC(responsev4, "IPv4 responses received", "Responsev4");
269 SET_RESSTATDESC(responsev6, "IPv6 responses received", "Responsev6");
270 SET_RESSTATDESC(nxdomain, "NXDOMAIN received", "NXDOMAIN");
271 SET_RESSTATDESC(servfail, "SERVFAIL received", "SERVFAIL");
272 SET_RESSTATDESC(formerr, "FORMERR received", "FORMERR");
273 SET_RESSTATDESC(othererror, "other errors received", "OtherError");
274 SET_RESSTATDESC(edns0fail, "EDNS(0) query failures", "EDNS0Fail");
275 SET_RESSTATDESC(mismatch, "mismatch responses received", "Mismatch");
276 SET_RESSTATDESC(truncated, "truncated responses received", "Truncated");
277 SET_RESSTATDESC(lame, "lame delegations received", "Lame");
278 SET_RESSTATDESC(retry, "query retries", "Retry");
279 SET_RESSTATDESC(dispabort, "queries aborted due to quota",
280 "QueryAbort");
281 SET_RESSTATDESC(dispsockfail, "failures in opening query sockets",
282 "QuerySockFail");
283 SET_RESSTATDESC(disprequdp, "UDP queries in progress", "QueryCurUDP");
284 SET_RESSTATDESC(dispreqtcp, "TCP queries in progress", "QueryCurTCP");
285 SET_RESSTATDESC(querytimeout, "query timeouts", "QueryTimeout");
286 SET_RESSTATDESC(gluefetchv4, "IPv4 NS address fetches", "GlueFetchv4");
287 SET_RESSTATDESC(gluefetchv6, "IPv6 NS address fetches", "GlueFetchv6");
288 SET_RESSTATDESC(gluefetchv4fail, "IPv4 NS address fetch failed",
289 "GlueFetchv4Fail");
290 SET_RESSTATDESC(gluefetchv6fail, "IPv6 NS address fetch failed",
291 "GlueFetchv6Fail");
292 SET_RESSTATDESC(val, "DNSSEC validation attempted", "ValAttempt");
293 SET_RESSTATDESC(valsuccess, "DNSSEC validation succeeded", "ValOk");
294 SET_RESSTATDESC(valnegsuccess, "DNSSEC NX validation succeeded",
295 "ValNegOk");
296 SET_RESSTATDESC(valfail, "DNSSEC validation failed", "ValFail");
297 SET_RESSTATDESC(queryrtt0, "queries with RTT < "
298 DNS_RESOLVER_QRYRTTCLASS0STR "ms",
299 "QryRTT" DNS_RESOLVER_QRYRTTCLASS0STR);
300 SET_RESSTATDESC(queryrtt1, "queries with RTT "
301 DNS_RESOLVER_QRYRTTCLASS0STR "-"
302 DNS_RESOLVER_QRYRTTCLASS1STR "ms",
303 "QryRTT" DNS_RESOLVER_QRYRTTCLASS1STR);
304 SET_RESSTATDESC(queryrtt2, "queries with RTT "
305 DNS_RESOLVER_QRYRTTCLASS1STR "-"
306 DNS_RESOLVER_QRYRTTCLASS2STR "ms",
307 "QryRTT" DNS_RESOLVER_QRYRTTCLASS2STR);
308 SET_RESSTATDESC(queryrtt3, "queries with RTT "
309 DNS_RESOLVER_QRYRTTCLASS2STR "-"
310 DNS_RESOLVER_QRYRTTCLASS3STR "ms",
311 "QryRTT" DNS_RESOLVER_QRYRTTCLASS3STR);
312 SET_RESSTATDESC(queryrtt4, "queries with RTT "
313 DNS_RESOLVER_QRYRTTCLASS3STR "-"
314 DNS_RESOLVER_QRYRTTCLASS4STR "ms",
315 "QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR);
316 SET_RESSTATDESC(queryrtt5, "queries with RTT > "
317 DNS_RESOLVER_QRYRTTCLASS4STR "ms",
318 "QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR "+");
319 SET_RESSTATDESC(nfetch, "active fetches", "NumFetch");
320 SET_RESSTATDESC(buckets, "bucket size", "BucketSize");
321 SET_RESSTATDESC(refused, "REFUSED received", "REFUSED");
322 #ifdef ISC_PLATFORM_USESIT
323 SET_RESSTATDESC(sitcc, "SIT sent client cookie only",
324 "SitClientOut");
325 SET_RESSTATDESC(sitout, "SIT sent with client and server cookie",
326 "SitOut");
327 SET_RESSTATDESC(sitin, "SIT replies received", "SitIn");
328 SET_RESSTATDESC(sitok, "SIT client cookie ok", "SitClientOk");
329 #endif
330 SET_RESSTATDESC(badvers, "bad EDNS version", "BadEDNSVersion");
332 INSIST(i == dns_resstatscounter_max);
334 /* Initialize adb statistics */
335 for (i = 0; i < dns_adbstats_max; i++)
336 adbstats_desc[i] = NULL;
337 #if defined(EXTENDED_STATS)
338 for (i = 0; i < dns_adbstats_max; i++)
339 adbstats_xmldesc[i] = NULL;
340 #endif
342 #define SET_ADBSTATDESC(id, desc, xmldesc) \
343 do { \
344 set_desc(dns_adbstats_ ## id, dns_adbstats_max, \
345 desc, adbstats_desc, xmldesc, adbstats_xmldesc); \
346 adbstats_index[i++] = dns_adbstats_ ## id; \
347 } while (/*CONSTCOND*/0)
348 i = 0;
349 SET_ADBSTATDESC(nentries, "Address hash table size", "nentries");
350 SET_ADBSTATDESC(entriescnt, "Addresses in hash table", "entriescnt");
351 SET_ADBSTATDESC(nnames, "Name hash table size", "nnames");
352 SET_ADBSTATDESC(namescnt, "Names in hash table", "namescnt");
354 INSIST(i == dns_adbstats_max);
356 /* Initialize zone statistics */
357 for (i = 0; i < dns_zonestatscounter_max; i++)
358 zonestats_desc[i] = NULL;
359 #if defined(EXTENDED_STATS)
360 for (i = 0; i < dns_zonestatscounter_max; i++)
361 zonestats_xmldesc[i] = NULL;
362 #endif
364 #define SET_ZONESTATDESC(counterid, desc, xmldesc) \
365 do { \
366 set_desc(dns_zonestatscounter_ ## counterid, \
367 dns_zonestatscounter_max, \
368 desc, zonestats_desc, xmldesc, zonestats_xmldesc); \
369 zonestats_index[i++] = dns_zonestatscounter_ ## counterid; \
370 } while (/*CONSTCOND*/0)
372 i = 0;
373 SET_ZONESTATDESC(notifyoutv4, "IPv4 notifies sent", "NotifyOutv4");
374 SET_ZONESTATDESC(notifyoutv6, "IPv6 notifies sent", "NotifyOutv6");
375 SET_ZONESTATDESC(notifyinv4, "IPv4 notifies received", "NotifyInv4");
376 SET_ZONESTATDESC(notifyinv6, "IPv6 notifies received", "NotifyInv6");
377 SET_ZONESTATDESC(notifyrej, "notifies rejected", "NotifyRej");
378 SET_ZONESTATDESC(soaoutv4, "IPv4 SOA queries sent", "SOAOutv4");
379 SET_ZONESTATDESC(soaoutv6, "IPv6 SOA queries sent", "SOAOutv6");
380 SET_ZONESTATDESC(axfrreqv4, "IPv4 AXFR requested", "AXFRReqv4");
381 SET_ZONESTATDESC(axfrreqv6, "IPv6 AXFR requested", "AXFRReqv6");
382 SET_ZONESTATDESC(ixfrreqv4, "IPv4 IXFR requested", "IXFRReqv4");
383 SET_ZONESTATDESC(ixfrreqv6, "IPv6 IXFR requested", "IXFRReqv6");
384 SET_ZONESTATDESC(xfrsuccess, "transfer requests succeeded",
385 "XfrSuccess");
386 SET_ZONESTATDESC(xfrfail, "transfer requests failed", "XfrFail");
387 INSIST(i == dns_zonestatscounter_max);
389 /* Initialize socket statistics */
390 for (i = 0; i < isc_sockstatscounter_max; i++)
391 sockstats_desc[i] = NULL;
392 #if defined(EXTENDED_STATS)
393 for (i = 0; i < isc_sockstatscounter_max; i++)
394 sockstats_xmldesc[i] = NULL;
395 #endif
397 #define SET_SOCKSTATDESC(counterid, desc, xmldesc) \
398 do { \
399 set_desc(isc_sockstatscounter_ ## counterid, \
400 isc_sockstatscounter_max, \
401 desc, sockstats_desc, xmldesc, sockstats_xmldesc); \
402 sockstats_index[i++] = isc_sockstatscounter_ ## counterid; \
403 } while (/*CONSTCOND*/0)
405 i = 0;
406 SET_SOCKSTATDESC(udp4open, "UDP/IPv4 sockets opened", "UDP4Open");
407 SET_SOCKSTATDESC(udp6open, "UDP/IPv6 sockets opened", "UDP6Open");
408 SET_SOCKSTATDESC(tcp4open, "TCP/IPv4 sockets opened", "TCP4Open");
409 SET_SOCKSTATDESC(tcp6open, "TCP/IPv6 sockets opened", "TCP6Open");
410 SET_SOCKSTATDESC(unixopen, "Unix domain sockets opened", "UnixOpen");
411 SET_SOCKSTATDESC(rawopen, "Raw sockets opened", "RawOpen");
412 SET_SOCKSTATDESC(udp4openfail, "UDP/IPv4 socket open failures",
413 "UDP4OpenFail");
414 SET_SOCKSTATDESC(udp6openfail, "UDP/IPv6 socket open failures",
415 "UDP6OpenFail");
416 SET_SOCKSTATDESC(tcp4openfail, "TCP/IPv4 socket open failures",
417 "TCP4OpenFail");
418 SET_SOCKSTATDESC(tcp6openfail, "TCP/IPv6 socket open failures",
419 "TCP6OpenFail");
420 SET_SOCKSTATDESC(unixopenfail, "Unix domain socket open failures",
421 "UnixOpenFail");
422 SET_SOCKSTATDESC(rawopenfail, "Raw socket open failures",
423 "RawOpenFail");
424 SET_SOCKSTATDESC(udp4close, "UDP/IPv4 sockets closed", "UDP4Close");
425 SET_SOCKSTATDESC(udp6close, "UDP/IPv6 sockets closed", "UDP6Close");
426 SET_SOCKSTATDESC(tcp4close, "TCP/IPv4 sockets closed", "TCP4Close");
427 SET_SOCKSTATDESC(tcp6close, "TCP/IPv6 sockets closed", "TCP6Close");
428 SET_SOCKSTATDESC(unixclose, "Unix domain sockets closed", "UnixClose");
429 SET_SOCKSTATDESC(fdwatchclose, "FDwatch sockets closed",
430 "FDWatchClose");
431 SET_SOCKSTATDESC(rawclose, "Raw sockets closed", "RawClose");
432 SET_SOCKSTATDESC(udp4bindfail, "UDP/IPv4 socket bind failures",
433 "UDP4BindFail");
434 SET_SOCKSTATDESC(udp6bindfail, "UDP/IPv6 socket bind failures",
435 "UDP6BindFail");
436 SET_SOCKSTATDESC(tcp4bindfail, "TCP/IPv4 socket bind failures",
437 "TCP4BindFail");
438 SET_SOCKSTATDESC(tcp6bindfail, "TCP/IPv6 socket bind failures",
439 "TCP6BindFail");
440 SET_SOCKSTATDESC(unixbindfail, "Unix domain socket bind failures",
441 "UnixBindFail");
442 SET_SOCKSTATDESC(fdwatchbindfail, "FDwatch socket bind failures",
443 "FdwatchBindFail");
444 SET_SOCKSTATDESC(udp4connectfail, "UDP/IPv4 socket connect failures",
445 "UDP4ConnFail");
446 SET_SOCKSTATDESC(udp6connectfail, "UDP/IPv6 socket connect failures",
447 "UDP6ConnFail");
448 SET_SOCKSTATDESC(tcp4connectfail, "TCP/IPv4 socket connect failures",
449 "TCP4ConnFail");
450 SET_SOCKSTATDESC(tcp6connectfail, "TCP/IPv6 socket connect failures",
451 "TCP6ConnFail");
452 SET_SOCKSTATDESC(unixconnectfail, "Unix domain socket connect failures",
453 "UnixConnFail");
454 SET_SOCKSTATDESC(fdwatchconnectfail, "FDwatch socket connect failures",
455 "FDwatchConnFail");
456 SET_SOCKSTATDESC(udp4connect, "UDP/IPv4 connections established",
457 "UDP4Conn");
458 SET_SOCKSTATDESC(udp6connect, "UDP/IPv6 connections established",
459 "UDP6Conn");
460 SET_SOCKSTATDESC(tcp4connect, "TCP/IPv4 connections established",
461 "TCP4Conn");
462 SET_SOCKSTATDESC(tcp6connect, "TCP/IPv6 connections established",
463 "TCP6Conn");
464 SET_SOCKSTATDESC(unixconnect, "Unix domain connections established",
465 "UnixConn");
466 SET_SOCKSTATDESC(fdwatchconnect,
467 "FDwatch domain connections established",
468 "FDwatchConn");
469 SET_SOCKSTATDESC(tcp4acceptfail, "TCP/IPv4 connection accept failures",
470 "TCP4AcceptFail");
471 SET_SOCKSTATDESC(tcp6acceptfail, "TCP/IPv6 connection accept failures",
472 "TCP6AcceptFail");
473 SET_SOCKSTATDESC(unixacceptfail,
474 "Unix domain connection accept failures",
475 "UnixAcceptFail");
476 SET_SOCKSTATDESC(tcp4accept, "TCP/IPv4 connections accepted",
477 "TCP4Accept");
478 SET_SOCKSTATDESC(tcp6accept, "TCP/IPv6 connections accepted",
479 "TCP6Accept");
480 SET_SOCKSTATDESC(unixaccept, "Unix domain connections accepted",
481 "UnixAccept");
482 SET_SOCKSTATDESC(udp4sendfail, "UDP/IPv4 send errors", "UDP4SendErr");
483 SET_SOCKSTATDESC(udp6sendfail, "UDP/IPv6 send errors", "UDP6SendErr");
484 SET_SOCKSTATDESC(tcp4sendfail, "TCP/IPv4 send errors", "TCP4SendErr");
485 SET_SOCKSTATDESC(tcp6sendfail, "TCP/IPv6 send errors", "TCP6SendErr");
486 SET_SOCKSTATDESC(unixsendfail, "Unix domain send errors",
487 "UnixSendErr");
488 SET_SOCKSTATDESC(fdwatchsendfail, "FDwatch send errors",
489 "FDwatchSendErr");
490 SET_SOCKSTATDESC(udp4recvfail, "UDP/IPv4 recv errors", "UDP4RecvErr");
491 SET_SOCKSTATDESC(udp6recvfail, "UDP/IPv6 recv errors", "UDP6RecvErr");
492 SET_SOCKSTATDESC(tcp4recvfail, "TCP/IPv4 recv errors", "TCP4RecvErr");
493 SET_SOCKSTATDESC(tcp6recvfail, "TCP/IPv6 recv errors", "TCP6RecvErr");
494 SET_SOCKSTATDESC(unixrecvfail, "Unix domain recv errors",
495 "UnixRecvErr");
496 SET_SOCKSTATDESC(fdwatchrecvfail, "FDwatch recv errors",
497 "FDwatchRecvErr");
498 SET_SOCKSTATDESC(rawrecvfail, "Raw recv errors", "RawRecvErr");
499 SET_SOCKSTATDESC(udp4active, "UDP/IPv4 sockets active", "UDP4Active");
500 SET_SOCKSTATDESC(udp6active, "UDP/IPv6 sockets active", "UDP6Active");
501 SET_SOCKSTATDESC(tcp4active, "TCP/IPv4 sockets active", "TCP4Active");
502 SET_SOCKSTATDESC(tcp6active, "TCP/IPv6 sockets active", "TCP6Active");
503 SET_SOCKSTATDESC(unixactive, "Unix domain sockets active",
504 "UnixActive");
505 SET_SOCKSTATDESC(rawactive, "Raw sockets active", "RawActive");
506 INSIST(i == isc_sockstatscounter_max);
508 /* Initialize DNSSEC statistics */
509 for (i = 0; i < dns_dnssecstats_max; i++)
510 dnssecstats_desc[i] = NULL;
511 #if defined(EXTENDED_STATS)
512 for (i = 0; i < dns_dnssecstats_max; i++)
513 dnssecstats_xmldesc[i] = NULL;
514 #endif
516 #define SET_DNSSECSTATDESC(counterid, desc, xmldesc) \
517 do { \
518 set_desc(dns_dnssecstats_ ## counterid, \
519 dns_dnssecstats_max, \
520 desc, dnssecstats_desc, \
521 xmldesc, dnssecstats_xmldesc); \
522 dnssecstats_index[i++] = dns_dnssecstats_ ## counterid; \
523 } while (/*CONSTCOND*/0)
525 i = 0;
526 SET_DNSSECSTATDESC(asis, "dnssec validation success with signer "
527 "\"as is\"", "DNSSECasis");
528 SET_DNSSECSTATDESC(downcase, "dnssec validation success with signer "
529 "lower cased", "DNSSECdowncase");
530 SET_DNSSECSTATDESC(wildcard, "dnssec validation of wildcard signature",
531 "DNSSECwild");
532 SET_DNSSECSTATDESC(fail, "dnssec validation failures", "DNSSECfail");
533 INSIST(i == dns_dnssecstats_max);
535 /* Sanity check */
536 for (i = 0; i < dns_nsstatscounter_max; i++)
537 INSIST(nsstats_desc[i] != NULL);
538 for (i = 0; i < dns_resstatscounter_max; i++)
539 INSIST(resstats_desc[i] != NULL);
540 for (i = 0; i < dns_adbstats_max; i++)
541 INSIST(adbstats_desc[i] != NULL);
542 for (i = 0; i < dns_zonestatscounter_max; i++)
543 INSIST(zonestats_desc[i] != NULL);
544 for (i = 0; i < isc_sockstatscounter_max; i++)
545 INSIST(sockstats_desc[i] != NULL);
546 for (i = 0; i < dns_dnssecstats_max; i++)
547 INSIST(dnssecstats_desc[i] != NULL);
548 #if defined(EXTENDED_STATS)
549 for (i = 0; i < dns_nsstatscounter_max; i++)
550 INSIST(nsstats_xmldesc[i] != NULL);
551 for (i = 0; i < dns_resstatscounter_max; i++)
552 INSIST(resstats_xmldesc[i] != NULL);
553 for (i = 0; i < dns_adbstats_max; i++)
554 INSIST(adbstats_xmldesc[i] != NULL);
555 for (i = 0; i < dns_zonestatscounter_max; i++)
556 INSIST(zonestats_xmldesc[i] != NULL);
557 for (i = 0; i < isc_sockstatscounter_max; i++)
558 INSIST(sockstats_xmldesc[i] != NULL);
559 for (i = 0; i < dns_dnssecstats_max; i++)
560 INSIST(dnssecstats_xmldesc[i] != NULL);
561 #endif
565 * Dump callback functions.
567 static void
568 generalstat_dump(isc_statscounter_t counter, isc_uint64_t val, void *arg) {
569 stats_dumparg_t *dumparg = arg;
571 REQUIRE(counter < dumparg->ncounters);
572 dumparg->countervalues[counter] = val;
575 static isc_result_t
576 dump_counters(isc_stats_t *stats, isc_statsformat_t type, void *arg,
577 const char *category, const char **desc, int ncounters,
578 int *indices, isc_uint64_t *values, int options)
580 int i, index;
581 isc_uint64_t value;
582 stats_dumparg_t dumparg;
583 FILE *fp;
584 #ifdef HAVE_LIBXML2
585 xmlTextWriterPtr writer;
586 int xmlrc;
587 #endif
588 #ifdef HAVE_JSON
589 json_object *job, *cat, *counter;
590 #endif
592 #if !defined(EXTENDED_STATS)
593 UNUSED(category);
594 #endif
596 dumparg.type = type;
597 dumparg.ncounters = ncounters;
598 dumparg.counterindices = indices;
599 dumparg.countervalues = values;
601 memset(values, 0, sizeof(values[0]) * ncounters);
602 isc_stats_dump(stats, generalstat_dump, &dumparg, options);
604 #ifdef HAVE_JSON
605 cat = job = (json_object *) arg;
606 if (ncounters > 0 && type == isc_statsformat_json) {
607 if (category != NULL) {
608 cat = json_object_new_object();
609 if (cat == NULL)
610 return (ISC_R_NOMEMORY);
611 json_object_object_add(job, category, cat);
614 #endif
616 for (i = 0; i < ncounters; i++) {
617 index = indices[i];
618 value = values[index];
620 if (value == 0 && (options & ISC_STATSDUMP_VERBOSE) == 0)
621 continue;
623 switch (dumparg.type) {
624 case isc_statsformat_file:
625 fp = arg;
626 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
627 value, desc[index]);
628 break;
629 case isc_statsformat_xml:
630 #ifdef HAVE_LIBXML2
631 writer = (xmlTextWriterPtr) arg;
633 if (category != NULL) {
634 /* <NameOfCategory> */
635 TRY0(xmlTextWriterStartElement(writer,
636 ISC_XMLCHAR
637 category));
639 /* <name> inside category */
640 TRY0(xmlTextWriterStartElement(writer,
641 ISC_XMLCHAR
642 "name"));
643 TRY0(xmlTextWriterWriteString(writer,
644 ISC_XMLCHAR
645 desc[index]));
646 TRY0(xmlTextWriterEndElement(writer));
647 /* </name> */
649 /* <counter> */
650 TRY0(xmlTextWriterStartElement(writer,
651 ISC_XMLCHAR
652 "counter"));
653 TRY0(xmlTextWriterWriteFormatString(writer,
654 "%" ISC_PRINT_QUADFORMAT "u", value));
656 TRY0(xmlTextWriterEndElement(writer));
657 /* </counter> */
658 TRY0(xmlTextWriterEndElement(writer));
659 /* </NameOfCategory> */
661 } else {
662 TRY0(xmlTextWriterStartElement(writer,
663 ISC_XMLCHAR
664 "counter"));
665 TRY0(xmlTextWriterWriteAttribute(writer,
666 ISC_XMLCHAR
667 "name",
668 ISC_XMLCHAR
669 desc[index]));
670 TRY0(xmlTextWriterWriteFormatString(writer,
671 "%" ISC_PRINT_QUADFORMAT "u", value));
672 TRY0(xmlTextWriterEndElement(writer));
673 /* counter */
676 #endif
677 break;
678 case isc_statsformat_json:
679 #ifdef HAVE_JSON
680 counter = json_object_new_int64(value);
681 if (counter == NULL)
682 return (ISC_R_NOMEMORY);
683 json_object_object_add(cat, desc[index], counter);
684 #endif
685 break;
688 return (ISC_R_SUCCESS);
689 #ifdef HAVE_LIBXML2
690 error:
691 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
692 ISC_LOG_ERROR, "failed at dump_counters()");
693 return (ISC_R_FAILURE);
694 #endif
697 static void
698 rdtypestat_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
699 char typebuf[64];
700 const char *typestr;
701 stats_dumparg_t *dumparg = arg;
702 FILE *fp;
703 #ifdef HAVE_LIBXML2
704 xmlTextWriterPtr writer;
705 int xmlrc;
706 #endif
707 #ifdef HAVE_JSON
708 json_object *zoneobj, *obj;
709 #endif
711 if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_OTHERTYPE)
712 == 0) {
713 dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf,
714 sizeof(typebuf));
715 typestr = typebuf;
716 } else
717 typestr = "Others";
719 switch (dumparg->type) {
720 case isc_statsformat_file:
721 fp = dumparg->arg;
722 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, typestr);
723 break;
724 case isc_statsformat_xml:
725 #ifdef HAVE_LIBXML2
726 writer = dumparg->arg;
729 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
730 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
731 ISC_XMLCHAR typestr));
733 TRY0(xmlTextWriterWriteFormatString(writer,
734 "%" ISC_PRINT_QUADFORMAT "u",
735 val));
737 TRY0(xmlTextWriterEndElement(writer)); /* type */
738 #endif
739 break;
740 case isc_statsformat_json:
741 #ifdef HAVE_JSON
742 zoneobj = (json_object *) dumparg->arg;
743 obj = json_object_new_int64(val);
744 if (obj == NULL)
745 return;
746 json_object_object_add(zoneobj, typestr, obj);
747 #endif
748 break;
750 return;
751 #ifdef HAVE_LIBXML2
752 error:
753 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
754 ISC_LOG_ERROR, "failed at rdtypestat_dump()");
755 dumparg->result = ISC_R_FAILURE;
756 return;
757 #endif
760 static void
761 rdatasetstats_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
762 stats_dumparg_t *dumparg = arg;
763 FILE *fp;
764 char typebuf[64];
765 const char *typestr;
766 isc_boolean_t nxrrset = ISC_FALSE;
767 isc_boolean_t stale = ISC_FALSE;
768 #ifdef HAVE_LIBXML2
769 xmlTextWriterPtr writer;
770 int xmlrc;
771 #endif
772 #ifdef HAVE_JSON
773 json_object *zoneobj, *obj;
774 char buf[1024];
775 #endif
777 if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_NXDOMAIN)
778 != 0) {
779 typestr = "NXDOMAIN";
780 } else if ((DNS_RDATASTATSTYPE_ATTR(type) &
781 DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) != 0) {
782 typestr = "Others";
783 } else {
784 dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf,
785 sizeof(typebuf));
786 typestr = typebuf;
789 if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_NXRRSET)
790 != 0)
791 nxrrset = ISC_TRUE;
793 if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_STALE)
794 != 0)
795 stale = ISC_TRUE;
797 switch (dumparg->type) {
798 case isc_statsformat_file:
799 fp = dumparg->arg;
800 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s%s%s\n", val,
801 stale ? "#" : "", nxrrset ? "!" : "", typestr);
802 break;
803 case isc_statsformat_xml:
804 #ifdef HAVE_LIBXML2
805 writer = dumparg->arg;
807 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "rrset"));
808 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
809 TRY0(xmlTextWriterWriteFormatString(writer, "%s%s%s",
810 stale ? "#" : "",
811 nxrrset ? "!" : "", typestr));
812 TRY0(xmlTextWriterEndElement(writer)); /* name */
814 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
815 TRY0(xmlTextWriterWriteFormatString(writer,
816 "%" ISC_PRINT_QUADFORMAT "u",
817 val));
818 TRY0(xmlTextWriterEndElement(writer)); /* counter */
820 TRY0(xmlTextWriterEndElement(writer)); /* rrset */
821 #endif
822 break;
823 case isc_statsformat_json:
824 #ifdef HAVE_JSON
825 zoneobj = (json_object *) dumparg->arg;
826 sprintf(buf, "%s%s%s", stale ? "#" : "",
827 nxrrset ? "!" : "", typestr);
828 obj = json_object_new_int64(val);
829 if (obj == NULL)
830 return;
831 json_object_object_add(zoneobj, buf, obj);
832 #endif
833 break;
835 return;
836 #ifdef HAVE_LIBXML2
837 error:
838 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
839 ISC_LOG_ERROR, "failed at rdatasetstats_dump()");
840 dumparg->result = ISC_R_FAILURE;
841 #endif
845 static void
846 opcodestat_dump(dns_opcode_t code, isc_uint64_t val, void *arg) {
847 FILE *fp;
848 isc_buffer_t b;
849 char codebuf[64];
850 stats_dumparg_t *dumparg = arg;
851 #ifdef HAVE_LIBXML2
852 xmlTextWriterPtr writer;
853 int xmlrc;
854 #endif
855 #ifdef HAVE_JSON
856 json_object *zoneobj, *obj;
857 #endif
859 isc_buffer_init(&b, codebuf, sizeof(codebuf) - 1);
860 dns_opcode_totext(code, &b);
861 codebuf[isc_buffer_usedlength(&b)] = '\0';
863 switch (dumparg->type) {
864 case isc_statsformat_file:
865 fp = dumparg->arg;
866 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, codebuf);
867 break;
868 case isc_statsformat_xml:
869 #ifdef HAVE_LIBXML2
870 writer = dumparg->arg;
871 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
872 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
873 ISC_XMLCHAR codebuf ));
874 TRY0(xmlTextWriterWriteFormatString(writer,
875 "%" ISC_PRINT_QUADFORMAT "u",
876 val));
877 TRY0(xmlTextWriterEndElement(writer)); /* counter */
878 #endif
879 break;
880 case isc_statsformat_json:
881 #ifdef HAVE_JSON
882 zoneobj = (json_object *) dumparg->arg;
883 obj = json_object_new_int64(val);
884 if (obj == NULL)
885 return;
886 json_object_object_add(zoneobj, codebuf, obj);
887 #endif
888 break;
890 return;
892 #ifdef HAVE_LIBXML2
893 error:
894 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
895 ISC_LOG_ERROR, "failed at opcodestat_dump()");
896 dumparg->result = ISC_R_FAILURE;
897 return;
898 #endif
901 #ifdef HAVE_LIBXML2
903 * Which statistics to include when rendering to XML
905 #define STATS_XML_STATUS 0x00 /* display only common statistics */
906 #define STATS_XML_SERVER 0x01
907 #define STATS_XML_ZONES 0x02
908 #define STATS_XML_TASKS 0x04
909 #define STATS_XML_NET 0x08
910 #define STATS_XML_MEM 0x10
911 #define STATS_XML_ALL 0xff
913 static isc_result_t
914 zone_xmlrender(dns_zone_t *zone, void *arg) {
915 isc_result_t result;
916 char buf[1024 + 32]; /* sufficiently large for zone name and class */
917 char *zone_name_only = NULL;
918 dns_rdataclass_t rdclass;
919 isc_uint32_t serial;
920 xmlTextWriterPtr writer = arg;
921 isc_stats_t *zonestats;
922 dns_stats_t *rcvquerystats;
923 dns_zonestat_level_t statlevel;
924 isc_uint64_t nsstat_values[dns_nsstatscounter_max];
925 int xmlrc;
926 stats_dumparg_t dumparg;
928 statlevel = dns_zone_getstatlevel(zone);
929 if (statlevel == dns_zonestat_none)
930 return (ISC_R_SUCCESS);
932 dumparg.type = isc_statsformat_xml;
933 dumparg.arg = writer;
935 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "zone"));
936 dns_zone_name(zone, buf, sizeof(buf));
937 zone_name_only = strtok(buf, "/");
938 if(zone_name_only == NULL)
939 zone_name_only = buf;
941 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
942 ISC_XMLCHAR zone_name_only));
943 rdclass = dns_zone_getclass(zone);
944 dns_rdataclass_format(rdclass, buf, sizeof(buf));
945 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "rdataclass",
946 ISC_XMLCHAR buf));
948 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "serial"));
949 if (dns_zone_getserial2(zone, &serial) == ISC_R_SUCCESS)
950 TRY0(xmlTextWriterWriteFormatString(writer, "%u", serial));
951 else
952 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-"));
953 TRY0(xmlTextWriterEndElement(writer)); /* serial */
955 zonestats = dns_zone_getrequeststats(zone);
956 rcvquerystats = dns_zone_getrcvquerystats(zone);
957 if (statlevel == dns_zonestat_full && zonestats != NULL) {
958 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
959 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
960 ISC_XMLCHAR "rcode"));
962 result = dump_counters(zonestats, isc_statsformat_xml, writer,
963 NULL, nsstats_xmldesc,
964 dns_nsstatscounter_max, nsstats_index,
965 nsstat_values, ISC_STATSDUMP_VERBOSE);
966 if (result != ISC_R_SUCCESS)
967 goto error;
968 /* counters type="rcode"*/
969 TRY0(xmlTextWriterEndElement(writer));
972 if (statlevel == dns_zonestat_full && rcvquerystats != NULL) {
973 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
974 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
975 ISC_XMLCHAR "qtype"));
977 dumparg.result = ISC_R_SUCCESS;
978 dns_rdatatypestats_dump(rcvquerystats, rdtypestat_dump,
979 &dumparg, 0);
980 if(dumparg.result != ISC_R_SUCCESS)
981 goto error;
983 /* counters type="qtype"*/
984 TRY0(xmlTextWriterEndElement(writer));
987 TRY0(xmlTextWriterEndElement(writer)); /* zone */
989 return (ISC_R_SUCCESS);
990 error:
991 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
992 ISC_LOG_ERROR, "Failed at zone_xmlrender()");
993 return (ISC_R_FAILURE);
996 static isc_result_t
997 generatexml(ns_server_t *server, isc_uint32_t flags,
998 int *buflen, xmlChar **buf)
1000 char boottime[sizeof "yyyy-mm-ddThh:mm:ssZ"];
1001 char configtime[sizeof "yyyy-mm-ddThh:mm:ssZ"];
1002 char nowstr[sizeof "yyyy-mm-ddThh:mm:ssZ"];
1003 isc_time_t now;
1004 xmlTextWriterPtr writer = NULL;
1005 xmlDocPtr doc = NULL;
1006 int xmlrc;
1007 dns_view_t *view;
1008 stats_dumparg_t dumparg;
1009 dns_stats_t *cacherrstats;
1010 isc_uint64_t nsstat_values[dns_nsstatscounter_max];
1011 isc_uint64_t resstat_values[dns_resstatscounter_max];
1012 isc_uint64_t adbstat_values[dns_adbstats_max];
1013 isc_uint64_t zonestat_values[dns_zonestatscounter_max];
1014 isc_uint64_t sockstat_values[isc_sockstatscounter_max];
1015 isc_result_t result;
1017 isc_time_now(&now);
1018 isc_time_formatISO8601(&ns_g_boottime, boottime, sizeof boottime);
1019 isc_time_formatISO8601(&ns_g_configtime, configtime, sizeof configtime);
1020 isc_time_formatISO8601(&now, nowstr, sizeof nowstr);
1022 writer = xmlNewTextWriterDoc(&doc, 0);
1023 if (writer == NULL)
1024 goto error;
1025 TRY0(xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL));
1026 TRY0(xmlTextWriterWritePI(writer, ISC_XMLCHAR "xml-stylesheet",
1027 ISC_XMLCHAR "type=\"text/xsl\" href=\"/bind9.xsl\""));
1028 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics"));
1029 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version",
1030 ISC_XMLCHAR "3.5"));
1032 /* Set common fields for statistics dump */
1033 dumparg.type = isc_statsformat_xml;
1034 dumparg.arg = writer;
1036 /* Render server information */
1037 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "server"));
1038 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "boot-time"));
1039 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR boottime));
1040 TRY0(xmlTextWriterEndElement(writer)); /* boot-time */
1041 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "config-time"));
1042 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR configtime));
1043 TRY0(xmlTextWriterEndElement(writer)); /* config-time */
1044 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "current-time"));
1045 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR nowstr));
1046 TRY0(xmlTextWriterEndElement(writer)); /* current-time */
1048 if ((flags & STATS_XML_SERVER) != 0) {
1049 dumparg.result = ISC_R_SUCCESS;
1051 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1052 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1053 ISC_XMLCHAR "opcode"));
1055 dns_opcodestats_dump(server->opcodestats, opcodestat_dump,
1056 &dumparg, ISC_STATSDUMP_VERBOSE);
1057 if (dumparg.result != ISC_R_SUCCESS)
1058 goto error;
1060 TRY0(xmlTextWriterEndElement(writer));
1062 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1063 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1064 ISC_XMLCHAR "qtype"));
1066 dumparg.result = ISC_R_SUCCESS;
1067 dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump,
1068 &dumparg, 0);
1069 if (dumparg.result != ISC_R_SUCCESS)
1070 goto error;
1071 TRY0(xmlTextWriterEndElement(writer)); /* counters */
1073 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1074 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1075 ISC_XMLCHAR "nsstat"));
1077 result = dump_counters(server->nsstats, isc_statsformat_xml,
1078 writer, NULL, nsstats_xmldesc,
1079 dns_nsstatscounter_max,
1080 nsstats_index, nsstat_values,
1081 ISC_STATSDUMP_VERBOSE);
1082 if (result != ISC_R_SUCCESS)
1083 goto error;
1085 TRY0(xmlTextWriterEndElement(writer)); /* /nsstat */
1087 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1088 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1089 ISC_XMLCHAR "zonestat"));
1091 result = dump_counters(server->zonestats, isc_statsformat_xml,
1092 writer, NULL, zonestats_xmldesc,
1093 dns_zonestatscounter_max,
1094 zonestats_index, zonestat_values,
1095 ISC_STATSDUMP_VERBOSE);
1096 if (result != ISC_R_SUCCESS)
1097 goto error;
1099 TRY0(xmlTextWriterEndElement(writer)); /* /zonestat */
1102 * Most of the common resolver statistics entries are 0, so
1103 * we don't use the verbose dump here.
1105 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1106 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1107 ISC_XMLCHAR "resstat"));
1108 result = dump_counters(server->resolverstats,
1109 isc_statsformat_xml, writer,
1110 NULL, resstats_xmldesc,
1111 dns_resstatscounter_max,
1112 resstats_index, resstat_values, 0);
1113 if (result != ISC_R_SUCCESS)
1114 goto error;
1115 TRY0(xmlTextWriterEndElement(writer)); /* resstat */
1118 if ((flags & STATS_XML_NET) != 0) {
1119 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1120 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1121 ISC_XMLCHAR "sockstat"));
1123 result = dump_counters(server->sockstats, isc_statsformat_xml,
1124 writer, NULL, sockstats_xmldesc,
1125 isc_sockstatscounter_max,
1126 sockstats_index, sockstat_values,
1127 ISC_STATSDUMP_VERBOSE);
1128 if (result != ISC_R_SUCCESS)
1129 goto error;
1131 TRY0(xmlTextWriterEndElement(writer)); /* /sockstat */
1133 TRY0(xmlTextWriterEndElement(writer)); /* /server */
1136 * Render views. For each view we know of, call its
1137 * rendering function.
1139 view = ISC_LIST_HEAD(server->viewlist);
1140 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "views"));
1141 while (view != NULL &&
1142 ((flags & (STATS_XML_SERVER | STATS_XML_ZONES)) != 0))
1144 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "view"));
1145 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
1146 ISC_XMLCHAR view->name));
1148 if ((flags & STATS_XML_ZONES) != 0) {
1149 TRY0(xmlTextWriterStartElement(writer,
1150 ISC_XMLCHAR "zones"));
1151 result = dns_zt_apply(view->zonetable, ISC_TRUE,
1152 zone_xmlrender, writer);
1153 if (result != ISC_R_SUCCESS)
1154 goto error;
1155 TRY0(xmlTextWriterEndElement(writer)); /* /zones */
1158 if ((flags & STATS_XML_SERVER) == 0) {
1159 TRY0(xmlTextWriterEndElement(writer)); /* /view */
1160 view = ISC_LIST_NEXT(view, link);
1161 continue;
1164 TRY0(xmlTextWriterStartElement(writer,
1165 ISC_XMLCHAR "counters"));
1166 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1167 ISC_XMLCHAR "resqtype"));
1169 if (view->resquerystats != NULL) {
1170 dumparg.result = ISC_R_SUCCESS;
1171 dns_rdatatypestats_dump(view->resquerystats,
1172 rdtypestat_dump, &dumparg, 0);
1173 if (dumparg.result != ISC_R_SUCCESS)
1174 goto error;
1176 TRY0(xmlTextWriterEndElement(writer));
1178 /* <resstats> */
1179 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1180 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1181 ISC_XMLCHAR "resstats"));
1182 if (view->resstats != NULL) {
1183 result = dump_counters(view->resstats,
1184 isc_statsformat_xml, writer,
1185 NULL, resstats_xmldesc,
1186 dns_resstatscounter_max,
1187 resstats_index, resstat_values,
1188 ISC_STATSDUMP_VERBOSE);
1189 if (result != ISC_R_SUCCESS)
1190 goto error;
1192 TRY0(xmlTextWriterEndElement(writer)); /* </resstats> */
1194 cacherrstats = dns_db_getrrsetstats(view->cachedb);
1195 if (cacherrstats != NULL) {
1196 TRY0(xmlTextWriterStartElement(writer,
1197 ISC_XMLCHAR "cache"));
1198 TRY0(xmlTextWriterWriteAttribute(writer,
1199 ISC_XMLCHAR "name",
1200 ISC_XMLCHAR
1201 dns_cache_getname(view->cache)));
1202 dumparg.result = ISC_R_SUCCESS;
1203 dns_rdatasetstats_dump(cacherrstats, rdatasetstats_dump,
1204 &dumparg, 0);
1205 if (dumparg.result != ISC_R_SUCCESS)
1206 goto error;
1207 TRY0(xmlTextWriterEndElement(writer)); /* cache */
1210 /* <adbstats> */
1211 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1212 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1213 ISC_XMLCHAR "adbstat"));
1214 if (view->adbstats != NULL) {
1215 result = dump_counters(view->adbstats,
1216 isc_statsformat_xml, writer,
1217 NULL, adbstats_xmldesc,
1218 dns_adbstats_max,
1219 adbstats_index, adbstat_values,
1220 ISC_STATSDUMP_VERBOSE);
1221 if (result != ISC_R_SUCCESS)
1222 goto error;
1224 TRY0(xmlTextWriterEndElement(writer)); /* </adbstats> */
1226 /* <cachestats> */
1227 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1228 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1229 ISC_XMLCHAR "cachestats"));
1230 TRY0(dns_cache_renderxml(view->cache, writer));
1231 TRY0(xmlTextWriterEndElement(writer)); /* </cachestats> */
1233 TRY0(xmlTextWriterEndElement(writer)); /* view */
1235 view = ISC_LIST_NEXT(view, link);
1237 TRY0(xmlTextWriterEndElement(writer)); /* /views */
1239 if ((flags & STATS_XML_NET) != 0) {
1240 TRY0(xmlTextWriterStartElement(writer,
1241 ISC_XMLCHAR "socketmgr"));
1242 TRY0(isc_socketmgr_renderxml(ns_g_socketmgr, writer));
1243 TRY0(xmlTextWriterEndElement(writer)); /* /socketmgr */
1246 if ((flags & STATS_XML_TASKS) != 0) {
1247 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "taskmgr"));
1248 TRY0(isc_taskmgr_renderxml(ns_g_taskmgr, writer));
1249 TRY0(xmlTextWriterEndElement(writer)); /* /taskmgr */
1252 if ((flags & STATS_XML_MEM) != 0) {
1253 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "memory"));
1254 TRY0(isc_mem_renderxml(writer));
1255 TRY0(xmlTextWriterEndElement(writer)); /* /memory */
1258 TRY0(xmlTextWriterEndElement(writer)); /* /statistics */
1259 TRY0(xmlTextWriterEndDocument(writer));
1261 xmlFreeTextWriter(writer);
1263 xmlDocDumpFormatMemoryEnc(doc, buf, buflen, "UTF-8", 0);
1264 if (*buf == NULL)
1265 goto error;
1266 xmlFreeDoc(doc);
1267 return (ISC_R_SUCCESS);
1269 error:
1270 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
1271 ISC_LOG_ERROR, "failed generating XML response");
1272 if (writer != NULL)
1273 xmlFreeTextWriter(writer);
1274 if (doc != NULL)
1275 xmlFreeDoc(doc);
1276 return (ISC_R_FAILURE);
1279 static void
1280 wrap_xmlfree(isc_buffer_t *buffer, void *arg) {
1281 UNUSED(arg);
1283 xmlFree(isc_buffer_base(buffer));
1286 static isc_result_t
1287 render_xml(isc_uint32_t flags, const char *url, isc_httpdurl_t *urlinfo,
1288 const char *querystring, const char *headers, void *arg,
1289 unsigned int *retcode, const char **retmsg,
1290 const char **mimetype, isc_buffer_t *b,
1291 isc_httpdfree_t **freecb, void **freecb_args)
1293 unsigned char *msg = NULL;
1294 int msglen;
1295 ns_server_t *server = arg;
1296 isc_result_t result;
1298 UNUSED(url);
1299 UNUSED(urlinfo);
1300 UNUSED(headers);
1301 UNUSED(querystring);
1303 result = generatexml(server, flags, &msglen, &msg);
1305 if (result == ISC_R_SUCCESS) {
1306 *retcode = 200;
1307 *retmsg = "OK";
1308 *mimetype = "text/xml";
1309 isc_buffer_reinit(b, msg, msglen);
1310 isc_buffer_add(b, msglen);
1311 *freecb = wrap_xmlfree;
1312 *freecb_args = NULL;
1313 } else
1314 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1315 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
1316 "failed at rendering XML()");
1318 return (result);
1321 static isc_result_t
1322 render_xml_all(const char *url, isc_httpdurl_t *urlinfo,
1323 const char *querystring, const char *headers, void *arg,
1324 unsigned int *retcode, const char **retmsg,
1325 const char **mimetype, isc_buffer_t *b,
1326 isc_httpdfree_t **freecb, void **freecb_args)
1328 return (render_xml(STATS_XML_ALL, url, urlinfo,
1329 querystring, headers, arg,
1330 retcode, retmsg, mimetype, b,
1331 freecb, freecb_args));
1334 static isc_result_t
1335 render_xml_status(const char *url, isc_httpdurl_t *urlinfo,
1336 const char *querystring, const char *headers, void *arg,
1337 unsigned int *retcode, const char **retmsg,
1338 const char **mimetype, isc_buffer_t *b,
1339 isc_httpdfree_t **freecb, void **freecb_args)
1341 return (render_xml(STATS_XML_STATUS, url, urlinfo,
1342 querystring, headers, arg,
1343 retcode, retmsg, mimetype, b,
1344 freecb, freecb_args));
1347 static isc_result_t
1348 render_xml_server(const char *url, isc_httpdurl_t *urlinfo,
1349 const char *querystring, const char *headers, void *arg,
1350 unsigned int *retcode, const char **retmsg,
1351 const char **mimetype, isc_buffer_t *b,
1352 isc_httpdfree_t **freecb, void **freecb_args)
1354 return (render_xml(STATS_XML_SERVER, url, urlinfo,
1355 querystring, headers, arg,
1356 retcode, retmsg, mimetype, b,
1357 freecb, freecb_args));
1360 static isc_result_t
1361 render_xml_zones(const char *url, isc_httpdurl_t *urlinfo,
1362 const char *querystring, const char *headers, void *arg,
1363 unsigned int *retcode, const char **retmsg,
1364 const char **mimetype, isc_buffer_t *b,
1365 isc_httpdfree_t **freecb, void **freecb_args)
1367 return (render_xml(STATS_XML_ZONES, url, urlinfo,
1368 querystring, headers, arg,
1369 retcode, retmsg, mimetype, b,
1370 freecb, freecb_args));
1373 static isc_result_t
1374 render_xml_net(const char *url, isc_httpdurl_t *urlinfo,
1375 const char *querystring, const char *headers, void *arg,
1376 unsigned int *retcode, const char **retmsg,
1377 const char **mimetype, isc_buffer_t *b,
1378 isc_httpdfree_t **freecb, void **freecb_args)
1380 return (render_xml(STATS_XML_NET, url, urlinfo,
1381 querystring, headers, arg,
1382 retcode, retmsg, mimetype, b,
1383 freecb, freecb_args));
1386 static isc_result_t
1387 render_xml_tasks(const char *url, isc_httpdurl_t *urlinfo,
1388 const char *querystring, const char *headers, void *arg,
1389 unsigned int *retcode, const char **retmsg,
1390 const char **mimetype, isc_buffer_t *b,
1391 isc_httpdfree_t **freecb, void **freecb_args)
1393 return (render_xml(STATS_XML_TASKS, url, urlinfo,
1394 querystring, headers, arg,
1395 retcode, retmsg, mimetype, b,
1396 freecb, freecb_args));
1399 static isc_result_t
1400 render_xml_mem(const char *url, isc_httpdurl_t *urlinfo,
1401 const char *querystring, const char *headers, void *arg,
1402 unsigned int *retcode, const char **retmsg,
1403 const char **mimetype, isc_buffer_t *b,
1404 isc_httpdfree_t **freecb, void **freecb_args)
1406 return (render_xml(STATS_XML_MEM, url, urlinfo,
1407 querystring, headers, arg,
1408 retcode, retmsg, mimetype, b,
1409 freecb, freecb_args));
1412 #endif /* HAVE_LIBXML2 */
1414 #ifdef HAVE_JSON
1416 * Which statistics to include when rendering to JSON
1418 #define STATS_JSON_STATUS 0x00 /* display only common statistics */
1419 #define STATS_JSON_SERVER 0x01
1420 #define STATS_JSON_ZONES 0x02
1421 #define STATS_JSON_TASKS 0x04
1422 #define STATS_JSON_NET 0x08
1423 #define STATS_JSON_MEM 0x10
1424 #define STATS_JSON_ALL 0xff
1426 #define CHECKMEM(m) do { \
1427 if (m == NULL) { \
1428 result = ISC_R_NOMEMORY;\
1429 goto error;\
1431 } while(/*CONSTCOND*/0)
1433 static void
1434 wrap_jsonfree(isc_buffer_t *buffer, void *arg) {
1435 json_object_put(isc_buffer_base(buffer));
1436 if (arg != NULL)
1437 json_object_put((json_object *) arg);
1440 static json_object *
1441 addzone(char *name, char *class, isc_uint32_t serial) {
1442 json_object *node = json_object_new_object();
1444 if (node == NULL)
1445 return (NULL);
1447 json_object_object_add(node, "name", json_object_new_string(name));
1448 json_object_object_add(node, "class", json_object_new_string(class));
1449 json_object_object_add(node, "serial", json_object_new_int64(serial));
1450 return (node);
1453 static isc_result_t
1454 zone_jsonrender(dns_zone_t *zone, void *arg) {
1455 isc_result_t result = ISC_R_SUCCESS;
1456 char buf[1024 + 32]; /* sufficiently large for zone name and class */
1457 char class[1024 + 32]; /* sufficiently large for zone name and class */
1458 char *zone_name_only = NULL;
1459 char *class_only = NULL;
1460 dns_rdataclass_t rdclass;
1461 isc_uint32_t serial;
1462 isc_uint64_t nsstat_values[dns_nsstatscounter_max];
1463 isc_stats_t *zonestats;
1464 dns_stats_t *rcvquerystats;
1465 json_object *zonearray = (json_object *) arg;
1466 json_object *zoneobj = NULL;
1467 dns_zonestat_level_t statlevel;
1469 statlevel = dns_zone_getstatlevel(zone);
1470 if (statlevel == dns_zonestat_none)
1471 return (ISC_R_SUCCESS);
1473 dns_zone_name(zone, buf, sizeof(buf));
1474 zone_name_only = strtok(buf, "/");
1475 if(zone_name_only == NULL)
1476 zone_name_only = buf;
1478 rdclass = dns_zone_getclass(zone);
1479 dns_rdataclass_format(rdclass, class, sizeof(class));
1480 class_only = class;
1482 if (dns_zone_getserial2(zone, &serial) != ISC_R_SUCCESS)
1483 serial = -1;
1485 zoneobj = addzone(zone_name_only, class_only, serial);
1486 if (zoneobj == NULL)
1487 return (ISC_R_NOMEMORY);
1489 zonestats = dns_zone_getrequeststats(zone);
1490 rcvquerystats = dns_zone_getrcvquerystats(zone);
1491 if (statlevel == dns_zonestat_full && zonestats != NULL) {
1492 json_object *counters = json_object_new_object();
1493 if (counters == NULL) {
1494 result = ISC_R_NOMEMORY;
1495 goto error;
1498 result = dump_counters(zonestats, isc_statsformat_json,
1499 counters, NULL, nsstats_xmldesc,
1500 dns_nsstatscounter_max, nsstats_index,
1501 nsstat_values, 0);
1502 if (result != ISC_R_SUCCESS) {
1503 json_object_put(counters);
1504 goto error;
1507 if (json_object_get_object(counters)->count != 0)
1508 json_object_object_add(zoneobj, "rcodes", counters);
1509 else
1510 json_object_put(counters);
1513 if (statlevel == dns_zonestat_full && rcvquerystats != NULL) {
1514 stats_dumparg_t dumparg;
1515 json_object *counters = json_object_new_object();
1516 CHECKMEM(counters);
1518 dumparg.type = isc_statsformat_json;
1519 dumparg.arg = counters;
1520 dumparg.result = ISC_R_SUCCESS;
1521 dns_rdatatypestats_dump(rcvquerystats, rdtypestat_dump,
1522 &dumparg, 0);
1523 if (dumparg.result != ISC_R_SUCCESS) {
1524 json_object_put(counters);
1525 goto error;
1528 if (json_object_get_object(counters)->count != 0)
1529 json_object_object_add(zoneobj, "qtypes", counters);
1530 else
1531 json_object_put(counters);
1534 json_object_array_add(zonearray, zoneobj);
1535 zoneobj = NULL;
1536 result = ISC_R_SUCCESS;
1538 error:
1539 if (zoneobj != NULL)
1540 json_object_put(zoneobj);
1541 return (result);
1544 static isc_result_t
1545 generatejson(ns_server_t *server, size_t *msglen,
1546 const char **msg, json_object **rootp, isc_uint32_t flags)
1548 dns_view_t *view;
1549 isc_result_t result = ISC_R_SUCCESS;
1550 json_object *bindstats, *viewlist, *counters, *obj;
1551 isc_uint64_t nsstat_values[dns_nsstatscounter_max];
1552 isc_uint64_t resstat_values[dns_resstatscounter_max];
1553 isc_uint64_t adbstat_values[dns_adbstats_max];
1554 isc_uint64_t zonestat_values[dns_zonestatscounter_max];
1555 isc_uint64_t sockstat_values[isc_sockstatscounter_max];
1556 stats_dumparg_t dumparg;
1557 char boottime[sizeof "yyyy-mm-ddThh:mm:ssZ"];
1558 char configtime[sizeof "yyyy-mm-ddThh:mm:ssZ"];
1559 char nowstr[sizeof "yyyy-mm-ddThh:mm:ssZ"];
1560 isc_time_t now;
1562 REQUIRE(msglen != NULL);
1563 REQUIRE(msg != NULL && *msg == NULL);
1564 REQUIRE(rootp == NULL || *rootp == NULL);
1566 bindstats = json_object_new_object();
1567 if (bindstats == NULL)
1568 return (ISC_R_NOMEMORY);
1571 * These statistics are included no matter which URL we use.
1573 obj = json_object_new_string("1.0");
1574 CHECKMEM(obj);
1575 json_object_object_add(bindstats, "json-stats-version", obj);
1577 isc_time_now(&now);
1578 isc_time_formatISO8601(&ns_g_boottime,
1579 boottime, sizeof(boottime));
1580 isc_time_formatISO8601(&ns_g_configtime,
1581 configtime, sizeof configtime);
1582 isc_time_formatISO8601(&now, nowstr, sizeof(nowstr));
1584 obj = json_object_new_string(boottime);
1585 CHECKMEM(obj);
1586 json_object_object_add(bindstats, "boot-time", obj);
1588 obj = json_object_new_string(configtime);
1589 CHECKMEM(obj);
1590 json_object_object_add(bindstats, "config-time", obj);
1592 obj = json_object_new_string(nowstr);
1593 CHECKMEM(obj);
1594 json_object_object_add(bindstats, "current-time", obj);
1596 if ((flags & STATS_JSON_SERVER) != 0) {
1597 /* OPCODE counters */
1598 counters = json_object_new_object();
1600 dumparg.result = ISC_R_SUCCESS;
1601 dumparg.type = isc_statsformat_json;
1602 dumparg.arg = counters;
1604 dns_opcodestats_dump(server->opcodestats,
1605 opcodestat_dump, &dumparg,
1606 ISC_STATSDUMP_VERBOSE);
1607 if (dumparg.result != ISC_R_SUCCESS) {
1608 json_object_put(counters);
1609 goto error;
1612 if (json_object_get_object(counters)->count != 0)
1613 json_object_object_add(bindstats, "opcodes", counters);
1614 else
1615 json_object_put(counters);
1617 /* QTYPE counters */
1618 counters = json_object_new_object();
1620 dumparg.result = ISC_R_SUCCESS;
1621 dumparg.arg = counters;
1623 dns_rdatatypestats_dump(server->rcvquerystats,
1624 rdtypestat_dump, &dumparg, 0);
1625 if (dumparg.result != ISC_R_SUCCESS) {
1626 json_object_put(counters);
1627 goto error;
1630 if (json_object_get_object(counters)->count != 0)
1631 json_object_object_add(bindstats, "qtypes", counters);
1632 else
1633 json_object_put(counters);
1635 /* server stat counters */
1636 counters = json_object_new_object();
1638 dumparg.result = ISC_R_SUCCESS;
1639 dumparg.arg = counters;
1641 result = dump_counters(server->nsstats, isc_statsformat_json,
1642 counters, NULL, nsstats_xmldesc,
1643 dns_nsstatscounter_max,
1644 nsstats_index, nsstat_values, 0);
1645 if (result != ISC_R_SUCCESS) {
1646 json_object_put(counters);
1647 goto error;
1650 if (json_object_get_object(counters)->count != 0)
1651 json_object_object_add(bindstats, "nsstats", counters);
1652 else
1653 json_object_put(counters);
1655 /* zone stat counters */
1656 counters = json_object_new_object();
1658 dumparg.result = ISC_R_SUCCESS;
1659 dumparg.arg = counters;
1661 result = dump_counters(server->zonestats, isc_statsformat_json,
1662 counters, NULL, zonestats_xmldesc,
1663 dns_zonestatscounter_max,
1664 zonestats_index, zonestat_values, 0);
1665 if (result != ISC_R_SUCCESS) {
1666 json_object_put(counters);
1667 goto error;
1670 if (json_object_get_object(counters)->count != 0)
1671 json_object_object_add(bindstats, "zonestats",
1672 counters);
1673 else
1674 json_object_put(counters);
1676 /* resolver stat counters */
1677 counters = json_object_new_object();
1679 dumparg.result = ISC_R_SUCCESS;
1680 dumparg.arg = counters;
1682 result = dump_counters(server->resolverstats,
1683 isc_statsformat_json, counters, NULL,
1684 resstats_xmldesc,
1685 dns_resstatscounter_max,
1686 resstats_index, resstat_values, 0);
1687 if (result != ISC_R_SUCCESS) {
1688 json_object_put(counters);
1689 goto error;
1692 if (json_object_get_object(counters)->count != 0)
1693 json_object_object_add(bindstats, "resstats", counters);
1694 else
1695 json_object_put(counters);
1698 if ((flags & (STATS_JSON_ZONES | STATS_JSON_SERVER)) != 0) {
1699 viewlist = json_object_new_object();
1700 CHECKMEM(viewlist);
1702 json_object_object_add(bindstats, "views", viewlist);
1704 view = ISC_LIST_HEAD(server->viewlist);
1705 while (view != NULL) {
1706 json_object *za, *v = json_object_new_object();
1708 CHECKMEM(v);
1709 json_object_object_add(viewlist, view->name, v);
1711 za = json_object_new_array();
1712 CHECKMEM(za);
1714 if ((flags & STATS_JSON_ZONES) != 0) {
1715 result = dns_zt_apply(view->zonetable, ISC_TRUE,
1716 zone_jsonrender, za);
1717 if (result != ISC_R_SUCCESS) {
1718 goto error;
1722 if (json_object_array_length(za) != 0)
1723 json_object_object_add(v, "zones", za);
1724 else
1725 json_object_put(za);
1727 if ((flags & STATS_JSON_SERVER) != 0) {
1728 json_object *res;
1729 dns_stats_t *dstats;
1730 isc_stats_t *istats;
1732 res = json_object_new_object();
1733 CHECKMEM(res);
1734 json_object_object_add(v, "resolver", res);
1736 istats = view->resstats;
1737 if (istats != NULL) {
1738 counters = json_object_new_object();
1739 CHECKMEM(counters);
1741 result = dump_counters(istats,
1742 isc_statsformat_json,
1743 counters, NULL,
1744 resstats_xmldesc,
1745 dns_resstatscounter_max,
1746 resstats_index,
1747 resstat_values, 0);
1748 if (result != ISC_R_SUCCESS) {
1749 json_object_put(counters);
1750 result = dumparg.result;
1751 goto error;
1754 json_object_object_add(res, "stats",
1755 counters);
1758 dstats = view->resquerystats;
1759 if (dstats != NULL) {
1760 counters = json_object_new_object();
1761 CHECKMEM(counters);
1763 dumparg.arg = counters;
1764 dumparg.result = ISC_R_SUCCESS;
1765 dns_rdatatypestats_dump(dstats,
1766 rdtypestat_dump,
1767 &dumparg, 0);
1768 if (dumparg.result != ISC_R_SUCCESS) {
1769 json_object_put(counters);
1770 result = dumparg.result;
1771 goto error;
1774 json_object_object_add(res, "qtypes",
1775 counters);
1778 dstats = dns_db_getrrsetstats(view->cachedb);
1779 if (dstats != NULL) {
1780 counters = json_object_new_object();
1781 CHECKMEM(counters);
1783 dumparg.arg = counters;
1784 dumparg.result = ISC_R_SUCCESS;
1785 dns_rdatasetstats_dump(dstats,
1786 rdatasetstats_dump,
1787 &dumparg, 0);
1788 if (dumparg.result != ISC_R_SUCCESS) {
1789 json_object_put(counters);
1790 result = dumparg.result;
1791 goto error;
1794 json_object_object_add(res,
1795 "cache",
1796 counters);
1799 counters = json_object_new_object();
1800 CHECKMEM(counters);
1802 result = dns_cache_renderjson(view->cache,
1803 counters);
1804 if (result != ISC_R_SUCCESS) {
1805 json_object_put(counters);
1806 goto error;
1809 json_object_object_add(res, "cachestats",
1810 counters);
1812 istats = view->adbstats;
1813 if (istats != NULL) {
1814 counters = json_object_new_object();
1815 CHECKMEM(counters);
1817 result = dump_counters(istats,
1818 isc_statsformat_json,
1819 counters, NULL,
1820 adbstats_xmldesc,
1821 dns_adbstats_max,
1822 adbstats_index,
1823 adbstat_values, 0);
1824 if (result != ISC_R_SUCCESS) {
1825 json_object_put(counters);
1826 result = dumparg.result;
1827 goto error;
1830 json_object_object_add(res, "adb",
1831 counters);
1835 view = ISC_LIST_NEXT(view, link);
1839 if ((flags & STATS_JSON_NET) != 0) {
1840 /* socket stat counters */
1841 json_object *sockets;
1842 counters = json_object_new_object();
1844 dumparg.result = ISC_R_SUCCESS;
1845 dumparg.arg = counters;
1847 result = dump_counters(server->sockstats,
1848 isc_statsformat_json, counters,
1849 NULL, sockstats_xmldesc,
1850 isc_sockstatscounter_max,
1851 sockstats_index, sockstat_values, 0);
1852 if (result != ISC_R_SUCCESS) {
1853 json_object_put(counters);
1854 goto error;
1857 if (json_object_get_object(counters)->count != 0)
1858 json_object_object_add(bindstats, "sockstats",
1859 counters);
1860 else
1861 json_object_put(counters);
1863 sockets = json_object_new_object();
1864 CHECKMEM(sockets);
1866 result = isc_socketmgr_renderjson(ns_g_socketmgr, sockets);
1867 if (result != ISC_R_SUCCESS) {
1868 json_object_put(sockets);
1869 goto error;
1872 json_object_object_add(bindstats, "socketmgr", sockets);
1875 if ((flags & STATS_JSON_TASKS) != 0) {
1876 json_object *tasks = json_object_new_object();
1877 CHECKMEM(tasks);
1879 result = isc_taskmgr_renderjson(ns_g_taskmgr, tasks);
1880 if (result != ISC_R_SUCCESS) {
1881 json_object_put(tasks);
1882 goto error;
1885 json_object_object_add(bindstats, "taskmgr", tasks);
1888 if ((flags & STATS_JSON_MEM) != 0) {
1889 json_object *memory = json_object_new_object();
1890 CHECKMEM(memory);
1892 result = isc_mem_renderjson(memory);
1893 if (result != ISC_R_SUCCESS) {
1894 json_object_put(memory);
1895 goto error;
1898 json_object_object_add(bindstats, "memory", memory);
1901 *msg = json_object_to_json_string_ext(bindstats,
1902 JSON_C_TO_STRING_PRETTY);
1903 *msglen = strlen(*msg);
1905 if (rootp != NULL) {
1906 *rootp = bindstats;
1907 bindstats = NULL;
1910 result = ISC_R_SUCCESS;
1912 error:
1913 if (bindstats != NULL)
1914 json_object_put(bindstats);
1916 return (result);
1919 static isc_result_t
1920 render_json(isc_uint32_t flags,
1921 const char *url, isc_httpdurl_t *urlinfo,
1922 const char *querystring, const char *headers,
1923 void *arg, unsigned int *retcode, const char **retmsg,
1924 const char **mimetype, isc_buffer_t *b,
1925 isc_httpdfree_t **freecb, void **freecb_args)
1927 isc_result_t result;
1928 json_object *bindstats = NULL;
1929 ns_server_t *server = arg;
1930 const char *msg = NULL;
1931 size_t msglen;
1932 char *p;
1934 UNUSED(url);
1935 UNUSED(urlinfo);
1936 UNUSED(headers);
1937 UNUSED(querystring);
1939 result = generatejson(server, &msglen, &msg, &bindstats, flags);
1940 if (result == ISC_R_SUCCESS) {
1941 *retcode = 200;
1942 *retmsg = "OK";
1943 *mimetype = "application/json";
1944 DE_CONST(msg, p);
1945 isc_buffer_reinit(b, p, msglen);
1946 isc_buffer_add(b, msglen);
1947 *freecb = wrap_jsonfree;
1948 *freecb_args = bindstats;
1949 } else
1950 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1951 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
1952 "failed at rendering JSON()");
1954 return (result);
1957 static isc_result_t
1958 render_json_all(const char *url, isc_httpdurl_t *urlinfo,
1959 const char *querystring, const char *headers, void *arg,
1960 unsigned int *retcode, const char **retmsg,
1961 const char **mimetype, isc_buffer_t *b,
1962 isc_httpdfree_t **freecb, void **freecb_args)
1964 return (render_json(STATS_JSON_ALL, url, urlinfo,
1965 querystring, headers, arg,
1966 retcode, retmsg, mimetype, b,
1967 freecb, freecb_args));
1970 static isc_result_t
1971 render_json_status(const char *url, isc_httpdurl_t *urlinfo,
1972 const char *querystring, const char *headers, void *arg,
1973 unsigned int *retcode, const char **retmsg,
1974 const char **mimetype, isc_buffer_t *b,
1975 isc_httpdfree_t **freecb, void **freecb_args)
1977 return (render_json(STATS_JSON_STATUS, url, urlinfo,
1978 querystring, headers, arg,
1979 retcode, retmsg, mimetype, b,
1980 freecb, freecb_args));
1983 static isc_result_t
1984 render_json_server(const char *url, isc_httpdurl_t *urlinfo,
1985 const char *querystring, const char *headers, void *arg,
1986 unsigned int *retcode, const char **retmsg,
1987 const char **mimetype, isc_buffer_t *b,
1988 isc_httpdfree_t **freecb, void **freecb_args)
1990 return (render_json(STATS_JSON_SERVER, url, urlinfo,
1991 querystring, headers, arg,
1992 retcode, retmsg, mimetype, b,
1993 freecb, freecb_args));
1996 static isc_result_t
1997 render_json_zones(const char *url, isc_httpdurl_t *urlinfo,
1998 const char *querystring, const char *headers, void *arg,
1999 unsigned int *retcode, const char **retmsg,
2000 const char **mimetype, isc_buffer_t *b,
2001 isc_httpdfree_t **freecb, void **freecb_args)
2003 return (render_json(STATS_JSON_ZONES, url, urlinfo,
2004 querystring, headers, arg,
2005 retcode, retmsg, mimetype, b,
2006 freecb, freecb_args));
2008 static isc_result_t
2009 render_json_mem(const char *url, isc_httpdurl_t *urlinfo,
2010 const char *querystring, const char *headers, void *arg,
2011 unsigned int *retcode, const char **retmsg,
2012 const char **mimetype, isc_buffer_t *b,
2013 isc_httpdfree_t **freecb, void **freecb_args)
2015 return (render_json(STATS_JSON_MEM, url, urlinfo,
2016 querystring, headers, arg,
2017 retcode, retmsg, mimetype, b,
2018 freecb, freecb_args));
2021 static isc_result_t
2022 render_json_tasks(const char *url, isc_httpdurl_t *urlinfo,
2023 const char *querystring, const char *headers, void *arg,
2024 unsigned int *retcode, const char **retmsg,
2025 const char **mimetype, isc_buffer_t *b,
2026 isc_httpdfree_t **freecb, void **freecb_args)
2028 return (render_json(STATS_JSON_TASKS, url, urlinfo,
2029 querystring, headers, arg,
2030 retcode, retmsg, mimetype, b,
2031 freecb, freecb_args));
2034 static isc_result_t
2035 render_json_net(const char *url, isc_httpdurl_t *urlinfo,
2036 const char *querystring, const char *headers, void *arg,
2037 unsigned int *retcode, const char **retmsg,
2038 const char **mimetype, isc_buffer_t *b,
2039 isc_httpdfree_t **freecb, void **freecb_args)
2041 return (render_json(STATS_JSON_NET, url, urlinfo,
2042 querystring, headers, arg,
2043 retcode, retmsg, mimetype, b,
2044 freecb, freecb_args));
2046 #endif /* HAVE_JSON */
2048 static isc_result_t
2049 render_xsl(const char *url, isc_httpdurl_t *urlinfo,
2050 const char *querystring, const char *headers,
2051 void *args, unsigned int *retcode, const char **retmsg,
2052 const char **mimetype, isc_buffer_t *b,
2053 isc_httpdfree_t **freecb, void **freecb_args)
2055 isc_result_t result;
2057 UNUSED(url);
2058 UNUSED(querystring);
2059 UNUSED(args);
2061 *freecb = NULL;
2062 *freecb_args = NULL;
2063 *mimetype = "text/xslt+xml";
2065 if (urlinfo->isstatic) {
2066 isc_time_t when;
2067 char *p = strcasestr(headers, "If-Modified-Since: ");
2069 if (p != NULL) {
2070 time_t t1, t2;
2071 p += strlen("If-Modified-Since: ");
2072 result = isc_time_parsehttptimestamp(p, &when);
2073 if (result != ISC_R_SUCCESS)
2074 goto send;
2076 result = isc_time_secondsastimet(&when, &t1);
2077 if (result != ISC_R_SUCCESS)
2078 goto send;
2080 result = isc_time_secondsastimet(&urlinfo->loadtime,
2081 &t2);
2082 if (result != ISC_R_SUCCESS)
2083 goto send;
2085 if (t1 < t2)
2086 goto send;
2088 *retcode = 304;
2089 *retmsg = "Not modified";
2090 return (ISC_R_SUCCESS);
2094 send:
2095 *retcode = 200;
2096 *retmsg = "OK";
2097 isc_buffer_reinit(b, xslmsg, strlen(xslmsg));
2098 isc_buffer_add(b, strlen(xslmsg));
2100 return (ISC_R_SUCCESS);
2103 static void
2104 shutdown_listener(ns_statschannel_t *listener) {
2105 char socktext[ISC_SOCKADDR_FORMATSIZE];
2106 isc_sockaddr_format(&listener->address, socktext, sizeof(socktext));
2107 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2108 ISC_LOG_NOTICE, "stopping statistics channel on %s",
2109 socktext);
2111 isc_httpdmgr_shutdown(&listener->httpdmgr);
2114 static isc_boolean_t
2115 client_ok(const isc_sockaddr_t *fromaddr, void *arg) {
2116 ns_statschannel_t *listener = arg;
2117 isc_netaddr_t netaddr;
2118 char socktext[ISC_SOCKADDR_FORMATSIZE];
2119 int match;
2121 REQUIRE(listener != NULL);
2123 isc_netaddr_fromsockaddr(&netaddr, fromaddr);
2125 LOCK(&listener->lock);
2126 if (dns_acl_match(&netaddr, NULL, listener->acl, &ns_g_server->aclenv,
2127 &match, NULL) == ISC_R_SUCCESS && match > 0) {
2128 UNLOCK(&listener->lock);
2129 return (ISC_TRUE);
2131 UNLOCK(&listener->lock);
2133 isc_sockaddr_format(fromaddr, socktext, sizeof(socktext));
2134 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2135 NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
2136 "rejected statistics connection from %s", socktext);
2138 return (ISC_FALSE);
2141 static void
2142 destroy_listener(void *arg) {
2143 ns_statschannel_t *listener = arg;
2145 REQUIRE(listener != NULL);
2146 REQUIRE(!ISC_LINK_LINKED(listener, link));
2148 /* We don't have to acquire the lock here since it's already unlinked */
2149 dns_acl_detach(&listener->acl);
2151 DESTROYLOCK(&listener->lock);
2152 isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener));
2155 static isc_result_t
2156 add_listener(ns_server_t *server, ns_statschannel_t **listenerp,
2157 const cfg_obj_t *listen_params, const cfg_obj_t *config,
2158 isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
2159 const char *socktext)
2161 isc_result_t result;
2162 ns_statschannel_t *listener;
2163 isc_task_t *task = NULL;
2164 isc_socket_t *sock = NULL;
2165 const cfg_obj_t *allow;
2166 dns_acl_t *new_acl = NULL;
2168 listener = isc_mem_get(server->mctx, sizeof(*listener));
2169 if (listener == NULL)
2170 return (ISC_R_NOMEMORY);
2172 listener->httpdmgr = NULL;
2173 listener->address = *addr;
2174 listener->acl = NULL;
2175 listener->mctx = NULL;
2176 ISC_LINK_INIT(listener, link);
2178 result = isc_mutex_init(&listener->lock);
2179 if (result != ISC_R_SUCCESS) {
2180 isc_mem_put(server->mctx, listener, sizeof(*listener));
2181 return (ISC_R_FAILURE);
2184 isc_mem_attach(server->mctx, &listener->mctx);
2186 allow = cfg_tuple_get(listen_params, "allow");
2187 if (allow != NULL && cfg_obj_islist(allow)) {
2188 result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
2189 aclconfctx, listener->mctx, 0,
2190 &new_acl);
2191 } else
2192 result = dns_acl_any(listener->mctx, &new_acl);
2193 if (result != ISC_R_SUCCESS)
2194 goto cleanup;
2195 dns_acl_attach(new_acl, &listener->acl);
2196 dns_acl_detach(&new_acl);
2198 result = isc_task_create(ns_g_taskmgr, 0, &task);
2199 if (result != ISC_R_SUCCESS)
2200 goto cleanup;
2201 isc_task_setname(task, "statchannel", NULL);
2203 result = isc_socket_create(ns_g_socketmgr, isc_sockaddr_pf(addr),
2204 isc_sockettype_tcp, &sock);
2205 if (result != ISC_R_SUCCESS)
2206 goto cleanup;
2207 isc_socket_setname(sock, "statchannel", NULL);
2209 #ifndef ISC_ALLOW_MAPPED
2210 isc_socket_ipv6only(sock, ISC_TRUE);
2211 #endif
2213 result = isc_socket_bind(sock, addr, ISC_SOCKET_REUSEADDRESS);
2214 if (result != ISC_R_SUCCESS)
2215 goto cleanup;
2217 result = isc_httpdmgr_create(server->mctx, sock, task, client_ok,
2218 destroy_listener, listener, ns_g_timermgr,
2219 &listener->httpdmgr);
2220 if (result != ISC_R_SUCCESS)
2221 goto cleanup;
2223 #ifdef HAVE_LIBXML2
2224 isc_httpdmgr_addurl(listener->httpdmgr, "/",
2225 render_xml_all, server);
2226 isc_httpdmgr_addurl(listener->httpdmgr, "/xml",
2227 render_xml_all, server);
2228 isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3",
2229 render_xml_all, server);
2230 isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/status",
2231 render_xml_status, server);
2232 isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/server",
2233 render_xml_server, server);
2234 isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/zones",
2235 render_xml_zones, server);
2236 isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/net",
2237 render_xml_net, server);
2238 isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/tasks",
2239 render_xml_tasks, server);
2240 isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/mem",
2241 render_xml_mem, server);
2242 #endif
2243 #ifdef HAVE_JSON
2244 isc_httpdmgr_addurl(listener->httpdmgr, "/json",
2245 render_json_all, server);
2246 isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1",
2247 render_json_all, server);
2248 isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/status",
2249 render_json_status, server);
2250 isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/server",
2251 render_json_server, server);
2252 isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/zones",
2253 render_json_zones, server);
2254 isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/tasks",
2255 render_json_tasks, server);
2256 isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/net",
2257 render_json_net, server);
2258 isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/mem",
2259 render_json_mem, server);
2260 #endif
2261 isc_httpdmgr_addurl2(listener->httpdmgr, "/bind9.xsl", ISC_TRUE,
2262 render_xsl, server);
2264 *listenerp = listener;
2265 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2266 NS_LOGMODULE_SERVER, ISC_LOG_NOTICE,
2267 "statistics channel listening on %s", socktext);
2269 cleanup:
2270 if (result != ISC_R_SUCCESS) {
2271 if (listener->acl != NULL)
2272 dns_acl_detach(&listener->acl);
2273 DESTROYLOCK(&listener->lock);
2274 isc_mem_putanddetach(&listener->mctx, listener,
2275 sizeof(*listener));
2277 if (task != NULL)
2278 isc_task_detach(&task);
2279 if (sock != NULL)
2280 isc_socket_detach(&sock);
2282 return (result);
2285 static void
2286 update_listener(ns_server_t *server, ns_statschannel_t **listenerp,
2287 const cfg_obj_t *listen_params, const cfg_obj_t *config,
2288 isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
2289 const char *socktext)
2291 ns_statschannel_t *listener;
2292 const cfg_obj_t *allow = NULL;
2293 dns_acl_t *new_acl = NULL;
2294 isc_result_t result = ISC_R_SUCCESS;
2296 for (listener = ISC_LIST_HEAD(server->statschannels);
2297 listener != NULL;
2298 listener = ISC_LIST_NEXT(listener, link))
2299 if (isc_sockaddr_equal(addr, &listener->address))
2300 break;
2302 if (listener == NULL) {
2303 *listenerp = NULL;
2304 return;
2308 * Now, keep the old access list unless a new one can be made.
2310 allow = cfg_tuple_get(listen_params, "allow");
2311 if (allow != NULL && cfg_obj_islist(allow)) {
2312 result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
2313 aclconfctx, listener->mctx, 0,
2314 &new_acl);
2315 } else
2316 result = dns_acl_any(listener->mctx, &new_acl);
2318 if (result == ISC_R_SUCCESS) {
2319 LOCK(&listener->lock);
2321 dns_acl_detach(&listener->acl);
2322 dns_acl_attach(new_acl, &listener->acl);
2323 dns_acl_detach(&new_acl);
2325 UNLOCK(&listener->lock);
2326 } else {
2327 cfg_obj_log(listen_params, ns_g_lctx, ISC_LOG_WARNING,
2328 "couldn't install new acl for "
2329 "statistics channel %s: %s",
2330 socktext, isc_result_totext(result));
2333 *listenerp = listener;
2336 isc_result_t
2337 ns_statschannels_configure(ns_server_t *server, const cfg_obj_t *config,
2338 cfg_aclconfctx_t *aclconfctx)
2340 ns_statschannel_t *listener, *listener_next;
2341 ns_statschannellist_t new_listeners;
2342 const cfg_obj_t *statschannellist = NULL;
2343 const cfg_listelt_t *element, *element2;
2344 char socktext[ISC_SOCKADDR_FORMATSIZE];
2346 RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS);
2348 ISC_LIST_INIT(new_listeners);
2351 * Get the list of named.conf 'statistics-channels' statements.
2353 (void)cfg_map_get(config, "statistics-channels", &statschannellist);
2356 * Run through the new address/port list, noting sockets that are
2357 * already being listened on and moving them to the new list.
2359 * Identifying duplicate addr/port combinations is left to either
2360 * the underlying config code, or to the bind attempt getting an
2361 * address-in-use error.
2363 if (statschannellist != NULL) {
2364 #ifndef EXTENDED_STATS
2365 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2366 NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
2367 "statistics-channels specified but not effective "
2368 "due to missing XML and/or JSON library");
2369 #endif
2371 for (element = cfg_list_first(statschannellist);
2372 element != NULL;
2373 element = cfg_list_next(element)) {
2374 const cfg_obj_t *statschannel;
2375 const cfg_obj_t *listenercfg = NULL;
2377 statschannel = cfg_listelt_value(element);
2378 (void)cfg_map_get(statschannel, "inet",
2379 &listenercfg);
2380 if (listenercfg == NULL)
2381 continue;
2383 for (element2 = cfg_list_first(listenercfg);
2384 element2 != NULL;
2385 element2 = cfg_list_next(element2)) {
2386 const cfg_obj_t *listen_params;
2387 const cfg_obj_t *obj;
2388 isc_sockaddr_t addr;
2390 listen_params = cfg_listelt_value(element2);
2392 obj = cfg_tuple_get(listen_params, "address");
2393 addr = *cfg_obj_assockaddr(obj);
2394 if (isc_sockaddr_getport(&addr) == 0)
2395 isc_sockaddr_setport(&addr,
2396 NS_STATSCHANNEL_HTTPPORT);
2398 isc_sockaddr_format(&addr, socktext,
2399 sizeof(socktext));
2401 isc_log_write(ns_g_lctx,
2402 NS_LOGCATEGORY_GENERAL,
2403 NS_LOGMODULE_SERVER,
2404 ISC_LOG_DEBUG(9),
2405 "processing statistics "
2406 "channel %s",
2407 socktext);
2409 update_listener(server, &listener,
2410 listen_params, config, &addr,
2411 aclconfctx, socktext);
2413 if (listener != NULL) {
2415 * Remove the listener from the old
2416 * list, so it won't be shut down.
2418 ISC_LIST_UNLINK(server->statschannels,
2419 listener, link);
2420 } else {
2422 * This is a new listener.
2424 isc_result_t r;
2426 r = add_listener(server, &listener,
2427 listen_params, config,
2428 &addr, aclconfctx,
2429 socktext);
2430 if (r != ISC_R_SUCCESS) {
2431 cfg_obj_log(listen_params,
2432 ns_g_lctx,
2433 ISC_LOG_WARNING,
2434 "couldn't allocate "
2435 "statistics channel"
2436 " %s: %s",
2437 socktext,
2438 isc_result_totext(r));
2442 if (listener != NULL)
2443 ISC_LIST_APPEND(new_listeners, listener,
2444 link);
2449 for (listener = ISC_LIST_HEAD(server->statschannels);
2450 listener != NULL;
2451 listener = listener_next) {
2452 listener_next = ISC_LIST_NEXT(listener, link);
2453 ISC_LIST_UNLINK(server->statschannels, listener, link);
2454 shutdown_listener(listener);
2457 ISC_LIST_APPENDLIST(server->statschannels, new_listeners, link);
2458 return (ISC_R_SUCCESS);
2461 void
2462 ns_statschannels_shutdown(ns_server_t *server) {
2463 ns_statschannel_t *listener;
2465 while ((listener = ISC_LIST_HEAD(server->statschannels)) != NULL) {
2466 ISC_LIST_UNLINK(server->statschannels, listener, link);
2467 shutdown_listener(listener);
2471 isc_result_t
2472 ns_stats_dump(ns_server_t *server, FILE *fp) {
2473 isc_stdtime_t now;
2474 isc_result_t result;
2475 dns_view_t *view;
2476 dns_zone_t *zone, *next;
2477 stats_dumparg_t dumparg;
2478 isc_uint64_t nsstat_values[dns_nsstatscounter_max];
2479 isc_uint64_t resstat_values[dns_resstatscounter_max];
2480 isc_uint64_t adbstat_values[dns_adbstats_max];
2481 isc_uint64_t zonestat_values[dns_zonestatscounter_max];
2482 isc_uint64_t sockstat_values[isc_sockstatscounter_max];
2484 RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS);
2486 /* Set common fields */
2487 dumparg.type = isc_statsformat_file;
2488 dumparg.arg = fp;
2490 isc_stdtime_get(&now);
2491 fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now);
2493 fprintf(fp, "++ Incoming Requests ++\n");
2494 dns_opcodestats_dump(server->opcodestats, opcodestat_dump, &dumparg, 0);
2496 fprintf(fp, "++ Incoming Queries ++\n");
2497 dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump,
2498 &dumparg, 0);
2500 fprintf(fp, "++ Outgoing Queries ++\n");
2501 for (view = ISC_LIST_HEAD(server->viewlist);
2502 view != NULL;
2503 view = ISC_LIST_NEXT(view, link)) {
2504 if (view->resquerystats == NULL)
2505 continue;
2506 if (strcmp(view->name, "_default") == 0)
2507 fprintf(fp, "[View: default]\n");
2508 else
2509 fprintf(fp, "[View: %s]\n", view->name);
2510 dns_rdatatypestats_dump(view->resquerystats, rdtypestat_dump,
2511 &dumparg, 0);
2514 fprintf(fp, "++ Name Server Statistics ++\n");
2515 (void) dump_counters(server->nsstats, isc_statsformat_file, fp, NULL,
2516 nsstats_desc, dns_nsstatscounter_max,
2517 nsstats_index, nsstat_values, 0);
2519 fprintf(fp, "++ Zone Maintenance Statistics ++\n");
2520 (void) dump_counters(server->zonestats, isc_statsformat_file, fp, NULL,
2521 zonestats_desc, dns_zonestatscounter_max,
2522 zonestats_index, zonestat_values, 0);
2524 fprintf(fp, "++ Resolver Statistics ++\n");
2525 fprintf(fp, "[Common]\n");
2526 (void) dump_counters(server->resolverstats, isc_statsformat_file, fp,
2527 NULL, resstats_desc, dns_resstatscounter_max,
2528 resstats_index, resstat_values, 0);
2529 for (view = ISC_LIST_HEAD(server->viewlist);
2530 view != NULL;
2531 view = ISC_LIST_NEXT(view, link)) {
2532 if (view->resstats == NULL)
2533 continue;
2534 if (strcmp(view->name, "_default") == 0)
2535 fprintf(fp, "[View: default]\n");
2536 else
2537 fprintf(fp, "[View: %s]\n", view->name);
2538 (void) dump_counters(view->resstats, isc_statsformat_file, fp,
2539 NULL, resstats_desc,
2540 dns_resstatscounter_max, resstats_index,
2541 resstat_values, 0);
2544 fprintf(fp, "++ Cache Statistics ++\n");
2545 for (view = ISC_LIST_HEAD(server->viewlist);
2546 view != NULL;
2547 view = ISC_LIST_NEXT(view, link)) {
2548 if (strcmp(view->name, "_default") == 0)
2549 fprintf(fp, "[View: default]\n");
2550 else
2551 fprintf(fp, "[View: %s (Cache: %s)]\n", view->name,
2552 dns_cache_getname(view->cache));
2554 * Avoid dumping redundant statistics when the cache is shared.
2556 if (dns_view_iscacheshared(view))
2557 continue;
2558 dns_cache_dumpstats(view->cache, fp);
2561 fprintf(fp, "++ Cache DB RRsets ++\n");
2562 for (view = ISC_LIST_HEAD(server->viewlist);
2563 view != NULL;
2564 view = ISC_LIST_NEXT(view, link)) {
2565 dns_stats_t *cacherrstats;
2567 cacherrstats = dns_db_getrrsetstats(view->cachedb);
2568 if (cacherrstats == NULL)
2569 continue;
2570 if (strcmp(view->name, "_default") == 0)
2571 fprintf(fp, "[View: default]\n");
2572 else
2573 fprintf(fp, "[View: %s (Cache: %s)]\n", view->name,
2574 dns_cache_getname(view->cache));
2575 if (dns_view_iscacheshared(view)) {
2577 * Avoid dumping redundant statistics when the cache is
2578 * shared.
2580 continue;
2582 dns_rdatasetstats_dump(cacherrstats, rdatasetstats_dump,
2583 &dumparg, 0);
2586 fprintf(fp, "++ ADB stats ++\n");
2587 for (view = ISC_LIST_HEAD(server->viewlist);
2588 view != NULL;
2589 view = ISC_LIST_NEXT(view, link)) {
2590 if (view->adbstats == NULL)
2591 continue;
2592 if (strcmp(view->name, "_default") == 0)
2593 fprintf(fp, "[View: default]\n");
2594 else
2595 fprintf(fp, "[View: %s]\n", view->name);
2596 (void) dump_counters(view->adbstats, isc_statsformat_file, fp,
2597 NULL, adbstats_desc, dns_adbstats_max,
2598 adbstats_index, adbstat_values, 0);
2601 fprintf(fp, "++ Socket I/O Statistics ++\n");
2602 (void) dump_counters(server->sockstats, isc_statsformat_file, fp, NULL,
2603 sockstats_desc, isc_sockstatscounter_max,
2604 sockstats_index, sockstat_values, 0);
2606 fprintf(fp, "++ Per Zone Query Statistics ++\n");
2607 zone = NULL;
2608 for (result = dns_zone_first(server->zonemgr, &zone);
2609 result == ISC_R_SUCCESS;
2610 next = NULL, result = dns_zone_next(zone, &next), zone = next)
2612 isc_stats_t *zonestats = dns_zone_getrequeststats(zone);
2613 if (zonestats != NULL) {
2614 char zonename[DNS_NAME_FORMATSIZE];
2616 dns_name_format(dns_zone_getorigin(zone),
2617 zonename, sizeof(zonename));
2618 view = dns_zone_getview(zone);
2620 fprintf(fp, "[%s", zonename);
2621 if (strcmp(view->name, "_default") != 0)
2622 fprintf(fp, " (view: %s)", view->name);
2623 fprintf(fp, "]\n");
2625 (void) dump_counters(zonestats, isc_statsformat_file,
2626 fp, NULL, nsstats_desc,
2627 dns_nsstatscounter_max,
2628 nsstats_index, nsstat_values, 0);
2632 fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now);
2634 return (ISC_R_SUCCESS); /* this function currently always succeeds */