xref: /netbsd-src/external/mpl/bind/dist/bin/named/statschannel.c (revision 2718af68c3efc72c9769069b5c7f9ed36f6b9def)
1 /*	$NetBSD: statschannel.c,v 1.11 2021/04/05 11:29:49 rillig Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 /*! \file */
15 
16 #include <inttypes.h>
17 #include <stdbool.h>
18 
19 #include <isc/buffer.h>
20 #include <isc/httpd.h>
21 #include <isc/mem.h>
22 #include <isc/once.h>
23 #include <isc/print.h>
24 #include <isc/socket.h>
25 #include <isc/stats.h>
26 #include <isc/string.h>
27 #include <isc/task.h>
28 #include <isc/util.h>
29 
30 #include <dns/cache.h>
31 #include <dns/db.h>
32 #include <dns/opcode.h>
33 #include <dns/rcode.h>
34 #include <dns/rdataclass.h>
35 #include <dns/rdatatype.h>
36 #include <dns/resolver.h>
37 #include <dns/stats.h>
38 #include <dns/view.h>
39 #include <dns/zt.h>
40 
41 #include <ns/stats.h>
42 
43 #include <named/log.h>
44 #include <named/server.h>
45 #include <named/statschannel.h>
46 
47 #if HAVE_JSON_C
48 #include <json_object.h>
49 #include <linkhash.h>
50 #endif /* HAVE_JSON_C */
51 
52 #if HAVE_LIBXML2
53 #include <libxml/xmlwriter.h>
54 #define ISC_XMLCHAR (const xmlChar *)
55 #endif /* HAVE_LIBXML2 */
56 
57 #include "bind9.xsl.h"
58 
59 struct named_statschannel {
60 	/* Unlocked */
61 	isc_httpdmgr_t *httpdmgr;
62 	isc_sockaddr_t address;
63 	isc_mem_t *mctx;
64 
65 	/*
66 	 * Locked by channel lock: can be referenced and modified by both
67 	 * the server task and the channel task.
68 	 */
69 	isc_mutex_t lock;
70 	dns_acl_t *acl;
71 
72 	/* Locked by server task */
73 	ISC_LINK(struct named_statschannel) link;
74 };
75 
76 typedef struct stats_dumparg {
77 	isc_statsformat_t type;
78 	void *arg;		 /* type dependent argument */
79 	int ncounters;		 /* for general statistics */
80 	int *counterindices;	 /* for general statistics */
81 	uint64_t *countervalues; /* for general statistics */
82 	isc_result_t result;
83 } stats_dumparg_t;
84 
85 static isc_once_t once = ISC_ONCE_INIT;
86 
87 #if defined(HAVE_LIBXML2) || defined(HAVE_JSON_C)
88 #define EXTENDED_STATS
89 #else /* if defined(HAVE_LIBXML2) || defined(HAVE_JSON_C) */
90 #undef EXTENDED_STATS
91 #endif /* if defined(HAVE_LIBXML2) || defined(HAVE_JSON_C) */
92 
93 #ifdef EXTENDED_STATS
94 static const char *
95 user_zonetype(dns_zone_t *zone) {
96 	dns_zonetype_t ztype;
97 	dns_view_t *view;
98 	static const struct zt {
99 		const dns_zonetype_t type;
100 		const char *const string;
101 	} typemap[] = { { dns_zone_none, "none" },
102 			{ dns_zone_master, "master" },
103 			{ dns_zone_slave, "slave" },
104 			{ dns_zone_mirror, "mirror" },
105 			{ dns_zone_stub, "stub" },
106 			{ dns_zone_staticstub, "static-stub" },
107 			{ dns_zone_key, "key" },
108 			{ dns_zone_dlz, "dlz" },
109 			{ dns_zone_redirect, "redirect" },
110 			{ 0, NULL } };
111 	const struct zt *tp;
112 
113 	if ((dns_zone_getoptions(zone) & DNS_ZONEOPT_AUTOEMPTY) != 0) {
114 		return ("builtin");
115 	}
116 
117 	view = dns_zone_getview(zone);
118 	if (view != NULL && strcmp(view->name, "_bind") == 0) {
119 		return ("builtin");
120 	}
121 
122 	ztype = dns_zone_gettype(zone);
123 	for (tp = typemap; tp->string != NULL && tp->type != ztype; tp++) {
124 		/* empty */
125 	}
126 	return (tp->string);
127 }
128 #endif /* ifdef EXTENDED_STATS */
129 
130 /*%
131  * Statistics descriptions.  These could be statistically initialized at
132  * compile time, but we configure them run time in the init_desc() function
133  * below so that they'll be less susceptible to counter name changes.
134  */
135 static const char *nsstats_desc[ns_statscounter_max];
136 static const char *resstats_desc[dns_resstatscounter_max];
137 static const char *adbstats_desc[dns_adbstats_max];
138 static const char *zonestats_desc[dns_zonestatscounter_max];
139 static const char *sockstats_desc[isc_sockstatscounter_max];
140 static const char *dnssecstats_desc[dns_dnssecstats_max];
141 static const char *udpinsizestats_desc[dns_sizecounter_in_max];
142 static const char *udpoutsizestats_desc[dns_sizecounter_out_max];
143 static const char *tcpinsizestats_desc[dns_sizecounter_in_max];
144 static const char *tcpoutsizestats_desc[dns_sizecounter_out_max];
145 static const char *dnstapstats_desc[dns_dnstapcounter_max];
146 static const char *gluecachestats_desc[dns_gluecachestatscounter_max];
147 #if defined(EXTENDED_STATS)
148 static const char *nsstats_xmldesc[ns_statscounter_max];
149 static const char *resstats_xmldesc[dns_resstatscounter_max];
150 static const char *adbstats_xmldesc[dns_adbstats_max];
151 static const char *zonestats_xmldesc[dns_zonestatscounter_max];
152 static const char *sockstats_xmldesc[isc_sockstatscounter_max];
153 static const char *dnssecstats_xmldesc[dns_dnssecstats_max];
154 static const char *udpinsizestats_xmldesc[dns_sizecounter_in_max];
155 static const char *udpoutsizestats_xmldesc[dns_sizecounter_out_max];
156 static const char *tcpinsizestats_xmldesc[dns_sizecounter_in_max];
157 static const char *tcpoutsizestats_xmldesc[dns_sizecounter_out_max];
158 static const char *dnstapstats_xmldesc[dns_dnstapcounter_max];
159 static const char *gluecachestats_xmldesc[dns_gluecachestatscounter_max];
160 #else /* if defined(EXTENDED_STATS) */
161 #define nsstats_xmldesc		NULL
162 #define resstats_xmldesc	NULL
163 #define adbstats_xmldesc	NULL
164 #define zonestats_xmldesc	NULL
165 #define sockstats_xmldesc	NULL
166 #define dnssecstats_xmldesc	NULL
167 #define udpinsizestats_xmldesc	NULL
168 #define udpoutsizestats_xmldesc NULL
169 #define tcpinsizestats_xmldesc	NULL
170 #define tcpoutsizestats_xmldesc NULL
171 #define dnstapstats_xmldesc	NULL
172 #define gluecachestats_xmldesc	NULL
173 #endif /* EXTENDED_STATS */
174 
175 #define TRY0(a)                     \
176 	do {                        \
177 		xmlrc = (a);        \
178 		if (xmlrc < 0)      \
179 			goto error; \
180 	} while (0)
181 
182 /*%
183  * Mapping arrays to represent statistics counters in the order of our
184  * preference, regardless of the order of counter indices.  For example,
185  * nsstats_desc[nsstats_index[0]] will be the description that is shown first.
186  */
187 static int nsstats_index[ns_statscounter_max];
188 static int resstats_index[dns_resstatscounter_max];
189 static int adbstats_index[dns_adbstats_max];
190 static int zonestats_index[dns_zonestatscounter_max];
191 static int sockstats_index[isc_sockstatscounter_max];
192 static int dnssecstats_index[dns_dnssecstats_max];
193 static int udpinsizestats_index[dns_sizecounter_in_max];
194 static int udpoutsizestats_index[dns_sizecounter_out_max];
195 static int tcpinsizestats_index[dns_sizecounter_in_max];
196 static int tcpoutsizestats_index[dns_sizecounter_out_max];
197 static int dnstapstats_index[dns_dnstapcounter_max];
198 static int gluecachestats_index[dns_gluecachestatscounter_max];
199 
200 static inline void
201 set_desc(int counter, int maxcounter, const char *fdesc, const char **fdescs,
202 	 const char *xdesc, const char **xdescs) {
203 	REQUIRE(counter < maxcounter);
204 	REQUIRE(fdescs != NULL && fdescs[counter] == NULL);
205 #if defined(EXTENDED_STATS)
206 	REQUIRE(xdescs != NULL && xdescs[counter] == NULL);
207 #endif /* if defined(EXTENDED_STATS) */
208 
209 	fdescs[counter] = fdesc;
210 #if defined(EXTENDED_STATS)
211 	xdescs[counter] = xdesc;
212 #else  /* if defined(EXTENDED_STATS) */
213 	UNUSED(xdesc);
214 	UNUSED(xdescs);
215 #endif /* if defined(EXTENDED_STATS) */
216 }
217 
218 static void
219 init_desc(void) {
220 	int i;
221 
222 	/* Initialize name server statistics */
223 	for (i = 0; i < ns_statscounter_max; i++) {
224 		nsstats_desc[i] = NULL;
225 	}
226 #if defined(EXTENDED_STATS)
227 	for (i = 0; i < ns_statscounter_max; i++) {
228 		nsstats_xmldesc[i] = NULL;
229 	}
230 #endif /* if defined(EXTENDED_STATS) */
231 
232 #define SET_NSSTATDESC(counterid, desc, xmldesc)                           \
233 	do {                                                               \
234 		set_desc(ns_statscounter_##counterid, ns_statscounter_max, \
235 			 desc, nsstats_desc, xmldesc, nsstats_xmldesc);    \
236 		nsstats_index[i++] = ns_statscounter_##counterid;          \
237 	} while (0)
238 
239 	i = 0;
240 	SET_NSSTATDESC(requestv4, "IPv4 requests received", "Requestv4");
241 	SET_NSSTATDESC(requestv6, "IPv6 requests received", "Requestv6");
242 	SET_NSSTATDESC(edns0in, "requests with EDNS(0) received", "ReqEdns0");
243 	SET_NSSTATDESC(badednsver,
244 		       "requests with unsupported EDNS version received",
245 		       "ReqBadEDNSVer");
246 	SET_NSSTATDESC(tsigin, "requests with TSIG received", "ReqTSIG");
247 	SET_NSSTATDESC(sig0in, "requests with SIG(0) received", "ReqSIG0");
248 	SET_NSSTATDESC(invalidsig, "requests with invalid signature",
249 		       "ReqBadSIG");
250 	SET_NSSTATDESC(requesttcp, "TCP requests received", "ReqTCP");
251 	SET_NSSTATDESC(tcphighwater, "TCP connection high-water",
252 		       "TCPConnHighWater");
253 	SET_NSSTATDESC(authrej, "auth queries rejected", "AuthQryRej");
254 	SET_NSSTATDESC(recurserej, "recursive queries rejected", "RecQryRej");
255 	SET_NSSTATDESC(xfrrej, "transfer requests rejected", "XfrRej");
256 	SET_NSSTATDESC(updaterej, "update requests rejected", "UpdateRej");
257 	SET_NSSTATDESC(response, "responses sent", "Response");
258 	SET_NSSTATDESC(truncatedresp, "truncated responses sent",
259 		       "TruncatedResp");
260 	SET_NSSTATDESC(edns0out, "responses with EDNS(0) sent", "RespEDNS0");
261 	SET_NSSTATDESC(tsigout, "responses with TSIG sent", "RespTSIG");
262 	SET_NSSTATDESC(sig0out, "responses with SIG(0) sent", "RespSIG0");
263 	SET_NSSTATDESC(success, "queries resulted in successful answer",
264 		       "QrySuccess");
265 	SET_NSSTATDESC(authans, "queries resulted in authoritative answer",
266 		       "QryAuthAns");
267 	SET_NSSTATDESC(nonauthans,
268 		       "queries resulted in non authoritative answer",
269 		       "QryNoauthAns");
270 	SET_NSSTATDESC(referral, "queries resulted in referral answer",
271 		       "QryReferral");
272 	SET_NSSTATDESC(nxrrset, "queries resulted in nxrrset", "QryNxrrset");
273 	SET_NSSTATDESC(servfail, "queries resulted in SERVFAIL", "QrySERVFAIL");
274 	SET_NSSTATDESC(formerr, "queries resulted in FORMERR", "QryFORMERR");
275 	SET_NSSTATDESC(nxdomain, "queries resulted in NXDOMAIN", "QryNXDOMAIN");
276 	SET_NSSTATDESC(recursion, "queries caused recursion", "QryRecursion");
277 	SET_NSSTATDESC(duplicate, "duplicate queries received", "QryDuplicate");
278 	SET_NSSTATDESC(dropped, "queries dropped", "QryDropped");
279 	SET_NSSTATDESC(failure, "other query failures", "QryFailure");
280 	SET_NSSTATDESC(xfrdone, "requested transfers completed", "XfrReqDone");
281 	SET_NSSTATDESC(updatereqfwd, "update requests forwarded",
282 		       "UpdateReqFwd");
283 	SET_NSSTATDESC(updaterespfwd, "update responses forwarded",
284 		       "UpdateRespFwd");
285 	SET_NSSTATDESC(updatefwdfail, "update forward failed", "UpdateFwdFail");
286 	SET_NSSTATDESC(updatedone, "updates completed", "UpdateDone");
287 	SET_NSSTATDESC(updatefail, "updates failed", "UpdateFail");
288 	SET_NSSTATDESC(updatebadprereq,
289 		       "updates rejected due to prerequisite failure",
290 		       "UpdateBadPrereq");
291 	SET_NSSTATDESC(recursclients, "recursing clients", "RecursClients");
292 	SET_NSSTATDESC(dns64, "queries answered by DNS64", "DNS64");
293 	SET_NSSTATDESC(ratedropped, "responses dropped for rate limits",
294 		       "RateDropped");
295 	SET_NSSTATDESC(rateslipped, "responses truncated for rate limits",
296 		       "RateSlipped");
297 	SET_NSSTATDESC(rpz_rewrites, "response policy zone rewrites",
298 		       "RPZRewrites");
299 	SET_NSSTATDESC(udp, "UDP queries received", "QryUDP");
300 	SET_NSSTATDESC(tcp, "TCP queries received", "QryTCP");
301 	SET_NSSTATDESC(nsidopt, "NSID option received", "NSIDOpt");
302 	SET_NSSTATDESC(expireopt, "Expire option received", "ExpireOpt");
303 	SET_NSSTATDESC(keepaliveopt, "EDNS TCP keepalive option received",
304 		       "KeepAliveOpt");
305 	SET_NSSTATDESC(padopt, "EDNS padding option received", "PadOpt");
306 	SET_NSSTATDESC(otheropt, "Other EDNS option received", "OtherOpt");
307 	SET_NSSTATDESC(cookiein, "COOKIE option received", "CookieIn");
308 	SET_NSSTATDESC(cookienew, "COOKIE - client only", "CookieNew");
309 	SET_NSSTATDESC(cookiebadsize, "COOKIE - bad size", "CookieBadSize");
310 	SET_NSSTATDESC(cookiebadtime, "COOKIE - bad time", "CookieBadTime");
311 	SET_NSSTATDESC(cookienomatch, "COOKIE - no match", "CookieNoMatch");
312 	SET_NSSTATDESC(cookiematch, "COOKIE - match", "CookieMatch");
313 	SET_NSSTATDESC(ecsopt, "EDNS client subnet option received", "ECSOpt");
314 	SET_NSSTATDESC(nxdomainredirect,
315 		       "queries resulted in NXDOMAIN that were redirected",
316 		       "QryNXRedir");
317 	SET_NSSTATDESC(nxdomainredirect_rlookup,
318 		       "queries resulted in NXDOMAIN that were redirected and "
319 		       "resulted in a successful remote lookup",
320 		       "QryNXRedirRLookup");
321 	SET_NSSTATDESC(badcookie, "sent badcookie response", "QryBADCOOKIE");
322 	SET_NSSTATDESC(nxdomainsynth, "synthesized a NXDOMAIN response",
323 		       "SynthNXDOMAIN");
324 	SET_NSSTATDESC(nodatasynth, "syththesized a no-data response",
325 		       "SynthNODATA");
326 	SET_NSSTATDESC(wildcardsynth, "synthesized a wildcard response",
327 		       "SynthWILDCARD");
328 	SET_NSSTATDESC(trystale,
329 		       "attempts to use stale cache data after lookup failure",
330 		       "QryTryStale");
331 	SET_NSSTATDESC(usedstale,
332 		       "successful uses of stale cache data after lookup "
333 		       "failure",
334 		       "QryUsedStale");
335 	SET_NSSTATDESC(prefetch, "queries triggered prefetch", "Prefetch");
336 	SET_NSSTATDESC(keytagopt, "Keytag option received", "KeyTagOpt");
337 	SET_NSSTATDESC(reclimitdropped,
338 		       "queries dropped due to recursive client limit",
339 		       "RecLimitDropped");
340 
341 	INSIST(i == ns_statscounter_max);
342 
343 	/* Initialize resolver statistics */
344 	for (i = 0; i < dns_resstatscounter_max; i++) {
345 		resstats_desc[i] = NULL;
346 	}
347 #if defined(EXTENDED_STATS)
348 	for (i = 0; i < dns_resstatscounter_max; i++) {
349 		resstats_xmldesc[i] = NULL;
350 	}
351 #endif /* if defined(EXTENDED_STATS) */
352 
353 #define SET_RESSTATDESC(counterid, desc, xmldesc)                      \
354 	do {                                                           \
355 		set_desc(dns_resstatscounter_##counterid,              \
356 			 dns_resstatscounter_max, desc, resstats_desc, \
357 			 xmldesc, resstats_xmldesc);                   \
358 		resstats_index[i++] = dns_resstatscounter_##counterid; \
359 	} while (0)
360 
361 	i = 0;
362 	SET_RESSTATDESC(queryv4, "IPv4 queries sent", "Queryv4");
363 	SET_RESSTATDESC(queryv6, "IPv6 queries sent", "Queryv6");
364 	SET_RESSTATDESC(responsev4, "IPv4 responses received", "Responsev4");
365 	SET_RESSTATDESC(responsev6, "IPv6 responses received", "Responsev6");
366 	SET_RESSTATDESC(nxdomain, "NXDOMAIN received", "NXDOMAIN");
367 	SET_RESSTATDESC(servfail, "SERVFAIL received", "SERVFAIL");
368 	SET_RESSTATDESC(formerr, "FORMERR received", "FORMERR");
369 	SET_RESSTATDESC(othererror, "other errors received", "OtherError");
370 	SET_RESSTATDESC(edns0fail, "EDNS(0) query failures", "EDNS0Fail");
371 	SET_RESSTATDESC(mismatch, "mismatch responses received", "Mismatch");
372 	SET_RESSTATDESC(truncated, "truncated responses received", "Truncated");
373 	SET_RESSTATDESC(lame, "lame delegations received", "Lame");
374 	SET_RESSTATDESC(retry, "query retries", "Retry");
375 	SET_RESSTATDESC(dispabort, "queries aborted due to quota",
376 			"QueryAbort");
377 	SET_RESSTATDESC(dispsockfail, "failures in opening query sockets",
378 			"QuerySockFail");
379 	SET_RESSTATDESC(disprequdp, "UDP queries in progress", "QueryCurUDP");
380 	SET_RESSTATDESC(dispreqtcp, "TCP queries in progress", "QueryCurTCP");
381 	SET_RESSTATDESC(querytimeout, "query timeouts", "QueryTimeout");
382 	SET_RESSTATDESC(gluefetchv4, "IPv4 NS address fetches", "GlueFetchv4");
383 	SET_RESSTATDESC(gluefetchv6, "IPv6 NS address fetches", "GlueFetchv6");
384 	SET_RESSTATDESC(gluefetchv4fail, "IPv4 NS address fetch failed",
385 			"GlueFetchv4Fail");
386 	SET_RESSTATDESC(gluefetchv6fail, "IPv6 NS address fetch failed",
387 			"GlueFetchv6Fail");
388 	SET_RESSTATDESC(val, "DNSSEC validation attempted", "ValAttempt");
389 	SET_RESSTATDESC(valsuccess, "DNSSEC validation succeeded", "ValOk");
390 	SET_RESSTATDESC(valnegsuccess, "DNSSEC NX validation succeeded",
391 			"ValNegOk");
392 	SET_RESSTATDESC(valfail, "DNSSEC validation failed", "ValFail");
393 	SET_RESSTATDESC(queryrtt0,
394 			"queries with RTT < " DNS_RESOLVER_QRYRTTCLASS0STR "ms",
395 			"QryRTT" DNS_RESOLVER_QRYRTTCLASS0STR);
396 	SET_RESSTATDESC(queryrtt1,
397 			"queries with RTT " DNS_RESOLVER_QRYRTTCLASS0STR
398 			"-" DNS_RESOLVER_QRYRTTCLASS1STR "ms",
399 			"QryRTT" DNS_RESOLVER_QRYRTTCLASS1STR);
400 	SET_RESSTATDESC(queryrtt2,
401 			"queries with RTT " DNS_RESOLVER_QRYRTTCLASS1STR
402 			"-" DNS_RESOLVER_QRYRTTCLASS2STR "ms",
403 			"QryRTT" DNS_RESOLVER_QRYRTTCLASS2STR);
404 	SET_RESSTATDESC(queryrtt3,
405 			"queries with RTT " DNS_RESOLVER_QRYRTTCLASS2STR
406 			"-" DNS_RESOLVER_QRYRTTCLASS3STR "ms",
407 			"QryRTT" DNS_RESOLVER_QRYRTTCLASS3STR);
408 	SET_RESSTATDESC(queryrtt4,
409 			"queries with RTT " DNS_RESOLVER_QRYRTTCLASS3STR
410 			"-" DNS_RESOLVER_QRYRTTCLASS4STR "ms",
411 			"QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR);
412 	SET_RESSTATDESC(queryrtt5,
413 			"queries with RTT > " DNS_RESOLVER_QRYRTTCLASS4STR "ms",
414 			"QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR "+");
415 	SET_RESSTATDESC(nfetch, "active fetches", "NumFetch");
416 	SET_RESSTATDESC(buckets, "bucket size", "BucketSize");
417 	SET_RESSTATDESC(refused, "REFUSED received", "REFUSED");
418 	SET_RESSTATDESC(cookienew, "COOKIE send with client cookie only",
419 			"ClientCookieOut");
420 	SET_RESSTATDESC(cookieout, "COOKIE sent with client and server cookie",
421 			"ServerCookieOut");
422 	SET_RESSTATDESC(cookiein, "COOKIE replies received", "CookieIn");
423 	SET_RESSTATDESC(cookieok, "COOKIE client ok", "CookieClientOk");
424 	SET_RESSTATDESC(badvers, "bad EDNS version", "BadEDNSVersion");
425 	SET_RESSTATDESC(badcookie, "bad cookie rcode", "BadCookieRcode");
426 	SET_RESSTATDESC(zonequota, "spilled due to zone quota", "ZoneQuota");
427 	SET_RESSTATDESC(serverquota, "spilled due to server quota",
428 			"ServerQuota");
429 	SET_RESSTATDESC(nextitem, "waited for next item", "NextItem");
430 	SET_RESSTATDESC(priming, "priming queries", "Priming");
431 
432 	INSIST(i == dns_resstatscounter_max);
433 
434 	/* Initialize adb statistics */
435 	for (i = 0; i < dns_adbstats_max; i++) {
436 		adbstats_desc[i] = NULL;
437 	}
438 #if defined(EXTENDED_STATS)
439 	for (i = 0; i < dns_adbstats_max; i++) {
440 		adbstats_xmldesc[i] = NULL;
441 	}
442 #endif /* if defined(EXTENDED_STATS) */
443 
444 #define SET_ADBSTATDESC(id, desc, xmldesc)                          \
445 	do {                                                        \
446 		set_desc(dns_adbstats_##id, dns_adbstats_max, desc, \
447 			 adbstats_desc, xmldesc, adbstats_xmldesc); \
448 		adbstats_index[i++] = dns_adbstats_##id;            \
449 	} while (0)
450 	i = 0;
451 	SET_ADBSTATDESC(nentries, "Address hash table size", "nentries");
452 	SET_ADBSTATDESC(entriescnt, "Addresses in hash table", "entriescnt");
453 	SET_ADBSTATDESC(nnames, "Name hash table size", "nnames");
454 	SET_ADBSTATDESC(namescnt, "Names in hash table", "namescnt");
455 
456 	INSIST(i == dns_adbstats_max);
457 
458 	/* Initialize zone statistics */
459 	for (i = 0; i < dns_zonestatscounter_max; i++) {
460 		zonestats_desc[i] = NULL;
461 	}
462 #if defined(EXTENDED_STATS)
463 	for (i = 0; i < dns_zonestatscounter_max; i++) {
464 		zonestats_xmldesc[i] = NULL;
465 	}
466 #endif /* if defined(EXTENDED_STATS) */
467 
468 #define SET_ZONESTATDESC(counterid, desc, xmldesc)                       \
469 	do {                                                             \
470 		set_desc(dns_zonestatscounter_##counterid,               \
471 			 dns_zonestatscounter_max, desc, zonestats_desc, \
472 			 xmldesc, zonestats_xmldesc);                    \
473 		zonestats_index[i++] = dns_zonestatscounter_##counterid; \
474 	} while (0)
475 
476 	i = 0;
477 	SET_ZONESTATDESC(notifyoutv4, "IPv4 notifies sent", "NotifyOutv4");
478 	SET_ZONESTATDESC(notifyoutv6, "IPv6 notifies sent", "NotifyOutv6");
479 	SET_ZONESTATDESC(notifyinv4, "IPv4 notifies received", "NotifyInv4");
480 	SET_ZONESTATDESC(notifyinv6, "IPv6 notifies received", "NotifyInv6");
481 	SET_ZONESTATDESC(notifyrej, "notifies rejected", "NotifyRej");
482 	SET_ZONESTATDESC(soaoutv4, "IPv4 SOA queries sent", "SOAOutv4");
483 	SET_ZONESTATDESC(soaoutv6, "IPv6 SOA queries sent", "SOAOutv6");
484 	SET_ZONESTATDESC(axfrreqv4, "IPv4 AXFR requested", "AXFRReqv4");
485 	SET_ZONESTATDESC(axfrreqv6, "IPv6 AXFR requested", "AXFRReqv6");
486 	SET_ZONESTATDESC(ixfrreqv4, "IPv4 IXFR requested", "IXFRReqv4");
487 	SET_ZONESTATDESC(ixfrreqv6, "IPv6 IXFR requested", "IXFRReqv6");
488 	SET_ZONESTATDESC(xfrsuccess, "transfer requests succeeded",
489 			 "XfrSuccess");
490 	SET_ZONESTATDESC(xfrfail, "transfer requests failed", "XfrFail");
491 	INSIST(i == dns_zonestatscounter_max);
492 
493 	/* Initialize socket statistics */
494 	for (i = 0; i < isc_sockstatscounter_max; i++) {
495 		sockstats_desc[i] = NULL;
496 	}
497 #if defined(EXTENDED_STATS)
498 	for (i = 0; i < isc_sockstatscounter_max; i++) {
499 		sockstats_xmldesc[i] = NULL;
500 	}
501 #endif /* if defined(EXTENDED_STATS) */
502 
503 #define SET_SOCKSTATDESC(counterid, desc, xmldesc)                       \
504 	do {                                                             \
505 		set_desc(isc_sockstatscounter_##counterid,               \
506 			 isc_sockstatscounter_max, desc, sockstats_desc, \
507 			 xmldesc, sockstats_xmldesc);                    \
508 		sockstats_index[i++] = isc_sockstatscounter_##counterid; \
509 	} while (0)
510 
511 	i = 0;
512 	SET_SOCKSTATDESC(udp4open, "UDP/IPv4 sockets opened", "UDP4Open");
513 	SET_SOCKSTATDESC(udp6open, "UDP/IPv6 sockets opened", "UDP6Open");
514 	SET_SOCKSTATDESC(tcp4open, "TCP/IPv4 sockets opened", "TCP4Open");
515 	SET_SOCKSTATDESC(tcp6open, "TCP/IPv6 sockets opened", "TCP6Open");
516 	SET_SOCKSTATDESC(unixopen, "Unix domain sockets opened", "UnixOpen");
517 	SET_SOCKSTATDESC(rawopen, "Raw sockets opened", "RawOpen");
518 	SET_SOCKSTATDESC(udp4openfail, "UDP/IPv4 socket open failures",
519 			 "UDP4OpenFail");
520 	SET_SOCKSTATDESC(udp6openfail, "UDP/IPv6 socket open failures",
521 			 "UDP6OpenFail");
522 	SET_SOCKSTATDESC(tcp4openfail, "TCP/IPv4 socket open failures",
523 			 "TCP4OpenFail");
524 	SET_SOCKSTATDESC(tcp6openfail, "TCP/IPv6 socket open failures",
525 			 "TCP6OpenFail");
526 	SET_SOCKSTATDESC(unixopenfail, "Unix domain socket open failures",
527 			 "UnixOpenFail");
528 	SET_SOCKSTATDESC(rawopenfail, "Raw socket open failures",
529 			 "RawOpenFail");
530 	SET_SOCKSTATDESC(udp4close, "UDP/IPv4 sockets closed", "UDP4Close");
531 	SET_SOCKSTATDESC(udp6close, "UDP/IPv6 sockets closed", "UDP6Close");
532 	SET_SOCKSTATDESC(tcp4close, "TCP/IPv4 sockets closed", "TCP4Close");
533 	SET_SOCKSTATDESC(tcp6close, "TCP/IPv6 sockets closed", "TCP6Close");
534 	SET_SOCKSTATDESC(unixclose, "Unix domain sockets closed", "UnixClose");
535 	SET_SOCKSTATDESC(fdwatchclose, "FDwatch sockets closed",
536 			 "FDWatchClose");
537 	SET_SOCKSTATDESC(rawclose, "Raw sockets closed", "RawClose");
538 	SET_SOCKSTATDESC(udp4bindfail, "UDP/IPv4 socket bind failures",
539 			 "UDP4BindFail");
540 	SET_SOCKSTATDESC(udp6bindfail, "UDP/IPv6 socket bind failures",
541 			 "UDP6BindFail");
542 	SET_SOCKSTATDESC(tcp4bindfail, "TCP/IPv4 socket bind failures",
543 			 "TCP4BindFail");
544 	SET_SOCKSTATDESC(tcp6bindfail, "TCP/IPv6 socket bind failures",
545 			 "TCP6BindFail");
546 	SET_SOCKSTATDESC(unixbindfail, "Unix domain socket bind failures",
547 			 "UnixBindFail");
548 	SET_SOCKSTATDESC(fdwatchbindfail, "FDwatch socket bind failures",
549 			 "FdwatchBindFail");
550 	SET_SOCKSTATDESC(udp4connectfail, "UDP/IPv4 socket connect failures",
551 			 "UDP4ConnFail");
552 	SET_SOCKSTATDESC(udp6connectfail, "UDP/IPv6 socket connect failures",
553 			 "UDP6ConnFail");
554 	SET_SOCKSTATDESC(tcp4connectfail, "TCP/IPv4 socket connect failures",
555 			 "TCP4ConnFail");
556 	SET_SOCKSTATDESC(tcp6connectfail, "TCP/IPv6 socket connect failures",
557 			 "TCP6ConnFail");
558 	SET_SOCKSTATDESC(unixconnectfail, "Unix domain socket connect failures",
559 			 "UnixConnFail");
560 	SET_SOCKSTATDESC(fdwatchconnectfail, "FDwatch socket connect failures",
561 			 "FDwatchConnFail");
562 	SET_SOCKSTATDESC(udp4connect, "UDP/IPv4 connections established",
563 			 "UDP4Conn");
564 	SET_SOCKSTATDESC(udp6connect, "UDP/IPv6 connections established",
565 			 "UDP6Conn");
566 	SET_SOCKSTATDESC(tcp4connect, "TCP/IPv4 connections established",
567 			 "TCP4Conn");
568 	SET_SOCKSTATDESC(tcp6connect, "TCP/IPv6 connections established",
569 			 "TCP6Conn");
570 	SET_SOCKSTATDESC(unixconnect, "Unix domain connections established",
571 			 "UnixConn");
572 	SET_SOCKSTATDESC(fdwatchconnect,
573 			 "FDwatch domain connections established",
574 			 "FDwatchConn");
575 	SET_SOCKSTATDESC(tcp4acceptfail, "TCP/IPv4 connection accept failures",
576 			 "TCP4AcceptFail");
577 	SET_SOCKSTATDESC(tcp6acceptfail, "TCP/IPv6 connection accept failures",
578 			 "TCP6AcceptFail");
579 	SET_SOCKSTATDESC(unixacceptfail,
580 			 "Unix domain connection accept failures",
581 			 "UnixAcceptFail");
582 	SET_SOCKSTATDESC(tcp4accept, "TCP/IPv4 connections accepted",
583 			 "TCP4Accept");
584 	SET_SOCKSTATDESC(tcp6accept, "TCP/IPv6 connections accepted",
585 			 "TCP6Accept");
586 	SET_SOCKSTATDESC(unixaccept, "Unix domain connections accepted",
587 			 "UnixAccept");
588 	SET_SOCKSTATDESC(udp4sendfail, "UDP/IPv4 send errors", "UDP4SendErr");
589 	SET_SOCKSTATDESC(udp6sendfail, "UDP/IPv6 send errors", "UDP6SendErr");
590 	SET_SOCKSTATDESC(tcp4sendfail, "TCP/IPv4 send errors", "TCP4SendErr");
591 	SET_SOCKSTATDESC(tcp6sendfail, "TCP/IPv6 send errors", "TCP6SendErr");
592 	SET_SOCKSTATDESC(unixsendfail, "Unix domain send errors",
593 			 "UnixSendErr");
594 	SET_SOCKSTATDESC(fdwatchsendfail, "FDwatch send errors",
595 			 "FDwatchSendErr");
596 	SET_SOCKSTATDESC(udp4recvfail, "UDP/IPv4 recv errors", "UDP4RecvErr");
597 	SET_SOCKSTATDESC(udp6recvfail, "UDP/IPv6 recv errors", "UDP6RecvErr");
598 	SET_SOCKSTATDESC(tcp4recvfail, "TCP/IPv4 recv errors", "TCP4RecvErr");
599 	SET_SOCKSTATDESC(tcp6recvfail, "TCP/IPv6 recv errors", "TCP6RecvErr");
600 	SET_SOCKSTATDESC(unixrecvfail, "Unix domain recv errors",
601 			 "UnixRecvErr");
602 	SET_SOCKSTATDESC(fdwatchrecvfail, "FDwatch recv errors",
603 			 "FDwatchRecvErr");
604 	SET_SOCKSTATDESC(rawrecvfail, "Raw recv errors", "RawRecvErr");
605 	SET_SOCKSTATDESC(udp4active, "UDP/IPv4 sockets active", "UDP4Active");
606 	SET_SOCKSTATDESC(udp6active, "UDP/IPv6 sockets active", "UDP6Active");
607 	SET_SOCKSTATDESC(tcp4active, "TCP/IPv4 sockets active", "TCP4Active");
608 	SET_SOCKSTATDESC(tcp6active, "TCP/IPv6 sockets active", "TCP6Active");
609 	SET_SOCKSTATDESC(unixactive, "Unix domain sockets active",
610 			 "UnixActive");
611 	SET_SOCKSTATDESC(rawactive, "Raw sockets active", "RawActive");
612 	INSIST(i == isc_sockstatscounter_max);
613 
614 	/* Initialize DNSSEC statistics */
615 	for (i = 0; i < dns_dnssecstats_max; i++) {
616 		dnssecstats_desc[i] = NULL;
617 	}
618 #if defined(EXTENDED_STATS)
619 	for (i = 0; i < dns_dnssecstats_max; i++) {
620 		dnssecstats_xmldesc[i] = NULL;
621 	}
622 #endif /* if defined(EXTENDED_STATS) */
623 
624 #define SET_DNSSECSTATDESC(counterid, desc, xmldesc)                       \
625 	do {                                                               \
626 		set_desc(dns_dnssecstats_##counterid, dns_dnssecstats_max, \
627 			 desc, dnssecstats_desc, xmldesc,                  \
628 			 dnssecstats_xmldesc);                             \
629 		dnssecstats_index[i++] = dns_dnssecstats_##counterid;      \
630 	} while (0)
631 
632 	i = 0;
633 	SET_DNSSECSTATDESC(asis,
634 			   "dnssec validation success with signer "
635 			   "\"as is\"",
636 			   "DNSSECasis");
637 	SET_DNSSECSTATDESC(downcase,
638 			   "dnssec validation success with signer "
639 			   "lower cased",
640 			   "DNSSECdowncase");
641 	SET_DNSSECSTATDESC(wildcard, "dnssec validation of wildcard signature",
642 			   "DNSSECwild");
643 	SET_DNSSECSTATDESC(fail, "dnssec validation failures", "DNSSECfail");
644 	INSIST(i == dns_dnssecstats_max);
645 
646 	/* Initialize dnstap statistics */
647 	for (i = 0; i < dns_dnstapcounter_max; i++) {
648 		dnstapstats_desc[i] = NULL;
649 	}
650 #if defined(EXTENDED_STATS)
651 	for (i = 0; i < dns_dnstapcounter_max; i++) {
652 		dnstapstats_xmldesc[i] = NULL;
653 	}
654 #endif /* if defined(EXTENDED_STATS) */
655 
656 #define SET_DNSTAPSTATDESC(counterid, desc, xmldesc)                           \
657 	do {                                                                   \
658 		set_desc(dns_dnstapcounter_##counterid, dns_dnstapcounter_max, \
659 			 desc, dnstapstats_desc, xmldesc,                      \
660 			 dnstapstats_xmldesc);                                 \
661 		dnstapstats_index[i++] = dns_dnstapcounter_##counterid;        \
662 	} while (0)
663 	i = 0;
664 	SET_DNSTAPSTATDESC(success, "dnstap messages written", "DNSTAPsuccess");
665 	SET_DNSTAPSTATDESC(drop, "dnstap messages dropped", "DNSTAPdropped");
666 	INSIST(i == dns_dnstapcounter_max);
667 
668 #define SET_GLUECACHESTATDESC(counterid, desc, xmldesc)         \
669 	do {                                                    \
670 		set_desc(dns_gluecachestatscounter_##counterid, \
671 			 dns_gluecachestatscounter_max, desc,   \
672 			 gluecachestats_desc, xmldesc,          \
673 			 gluecachestats_xmldesc);               \
674 		gluecachestats_index[i++] =                     \
675 			dns_gluecachestatscounter_##counterid;  \
676 	} while (0)
677 	i = 0;
678 	SET_GLUECACHESTATDESC(hits_present, "Hits for present glue (cached)",
679 			      "GLUECACHEhitspresent");
680 	SET_GLUECACHESTATDESC(hits_absent,
681 			      "Hits for non-existent glue (cached)",
682 			      "GLUECACHEhitsabsent");
683 	SET_GLUECACHESTATDESC(inserts_present,
684 			      "Miss-plus-cache-inserts for present glue",
685 			      "GLUECACHEinsertspresent");
686 	SET_GLUECACHESTATDESC(inserts_absent,
687 			      "Miss-plus-cache-inserts for non-existent glue",
688 			      "GLUECACHEinsertsabsent");
689 	INSIST(i == dns_gluecachestatscounter_max);
690 
691 	/* Sanity check */
692 	for (i = 0; i < ns_statscounter_max; i++) {
693 		INSIST(nsstats_desc[i] != NULL);
694 	}
695 	for (i = 0; i < dns_resstatscounter_max; i++) {
696 		INSIST(resstats_desc[i] != NULL);
697 	}
698 	for (i = 0; i < dns_adbstats_max; i++) {
699 		INSIST(adbstats_desc[i] != NULL);
700 	}
701 	for (i = 0; i < dns_zonestatscounter_max; i++) {
702 		INSIST(zonestats_desc[i] != NULL);
703 	}
704 	for (i = 0; i < isc_sockstatscounter_max; i++) {
705 		INSIST(sockstats_desc[i] != NULL);
706 	}
707 	for (i = 0; i < dns_dnssecstats_max; i++) {
708 		INSIST(dnssecstats_desc[i] != NULL);
709 	}
710 	for (i = 0; i < dns_dnstapcounter_max; i++) {
711 		INSIST(dnstapstats_desc[i] != NULL);
712 	}
713 	for (i = 0; i < dns_gluecachestatscounter_max; i++) {
714 		INSIST(gluecachestats_desc[i] != NULL);
715 	}
716 #if defined(EXTENDED_STATS)
717 	for (i = 0; i < ns_statscounter_max; i++) {
718 		INSIST(nsstats_xmldesc[i] != NULL);
719 	}
720 	for (i = 0; i < dns_resstatscounter_max; i++) {
721 		INSIST(resstats_xmldesc[i] != NULL);
722 	}
723 	for (i = 0; i < dns_adbstats_max; i++) {
724 		INSIST(adbstats_xmldesc[i] != NULL);
725 	}
726 	for (i = 0; i < dns_zonestatscounter_max; i++) {
727 		INSIST(zonestats_xmldesc[i] != NULL);
728 	}
729 	for (i = 0; i < isc_sockstatscounter_max; i++) {
730 		INSIST(sockstats_xmldesc[i] != NULL);
731 	}
732 	for (i = 0; i < dns_dnssecstats_max; i++) {
733 		INSIST(dnssecstats_xmldesc[i] != NULL);
734 	}
735 	for (i = 0; i < dns_dnstapcounter_max; i++) {
736 		INSIST(dnstapstats_xmldesc[i] != NULL);
737 	}
738 	for (i = 0; i < dns_gluecachestatscounter_max; i++) {
739 		INSIST(gluecachestats_xmldesc[i] != NULL);
740 	}
741 #endif /* if defined(EXTENDED_STATS) */
742 
743 	/* Initialize traffic size statistics */
744 	for (i = 0; i < dns_sizecounter_in_max; i++) {
745 		udpinsizestats_desc[i] = NULL;
746 		tcpinsizestats_desc[i] = NULL;
747 #if defined(EXTENDED_STATS)
748 		udpinsizestats_xmldesc[i] = NULL;
749 		tcpinsizestats_xmldesc[i] = NULL;
750 #endif /* if defined(EXTENDED_STATS) */
751 	}
752 	for (i = 0; i < dns_sizecounter_out_max; i++) {
753 		udpoutsizestats_desc[i] = NULL;
754 		tcpoutsizestats_desc[i] = NULL;
755 #if defined(EXTENDED_STATS)
756 		udpoutsizestats_xmldesc[i] = NULL;
757 		tcpoutsizestats_xmldesc[i] = NULL;
758 #endif /* if defined(EXTENDED_STATS) */
759 	}
760 
761 #define SET_SIZESTATDESC(counterid, desc, xmldesc, inout)       \
762 	do {                                                    \
763 		set_desc(dns_sizecounter_##inout##_##counterid, \
764 			 dns_sizecounter_##inout##_max, desc,   \
765 			 udp##inout##sizestats_desc, xmldesc,   \
766 			 udp##inout##sizestats_xmldesc);        \
767 		set_desc(dns_sizecounter_##inout##_##counterid, \
768 			 dns_sizecounter_##inout##_max, desc,   \
769 			 tcp##inout##sizestats_desc, xmldesc,   \
770 			 tcp##inout##sizestats_xmldesc);        \
771 		udp##inout##sizestats_index[i] =                \
772 			dns_sizecounter_##inout##_##counterid;  \
773 		tcp##inout##sizestats_index[i] =                \
774 			dns_sizecounter_##inout##_##counterid;  \
775 		i++;                                            \
776 	} while (0)
777 
778 	i = 0;
779 	SET_SIZESTATDESC(0, "requests received 0-15 bytes", "0-15", in);
780 	SET_SIZESTATDESC(16, "requests received 16-31 bytes", "16-31", in);
781 	SET_SIZESTATDESC(32, "requests received 32-47 bytes", "32-47", in);
782 	SET_SIZESTATDESC(48, "requests received 48-63 bytes", "48-63", in);
783 	SET_SIZESTATDESC(64, "requests received 64-79 bytes", "64-79", in);
784 	SET_SIZESTATDESC(80, "requests received 80-95 bytes", "80-95", in);
785 	SET_SIZESTATDESC(96, "requests received 96-111 bytes", "96-111", in);
786 	SET_SIZESTATDESC(112, "requests received 112-127 bytes", "112-127", in);
787 	SET_SIZESTATDESC(128, "requests received 128-143 bytes", "128-143", in);
788 	SET_SIZESTATDESC(144, "requests received 144-159 bytes", "144-159", in);
789 	SET_SIZESTATDESC(160, "requests received 160-175 bytes", "160-175", in);
790 	SET_SIZESTATDESC(176, "requests received 176-191 bytes", "176-191", in);
791 	SET_SIZESTATDESC(192, "requests received 192-207 bytes", "192-207", in);
792 	SET_SIZESTATDESC(208, "requests received 208-223 bytes", "208-223", in);
793 	SET_SIZESTATDESC(224, "requests received 224-239 bytes", "224-239", in);
794 	SET_SIZESTATDESC(240, "requests received 240-255 bytes", "240-255", in);
795 	SET_SIZESTATDESC(256, "requests received 256-271 bytes", "256-271", in);
796 	SET_SIZESTATDESC(272, "requests received 272-287 bytes", "272-287", in);
797 	SET_SIZESTATDESC(288, "requests received 288+ bytes", "288+", in);
798 	INSIST(i == dns_sizecounter_in_max);
799 
800 	i = 0;
801 	SET_SIZESTATDESC(0, "responses sent 0-15 bytes", "0-15", out);
802 	SET_SIZESTATDESC(16, "responses sent 16-31 bytes", "16-31", out);
803 	SET_SIZESTATDESC(32, "responses sent 32-47 bytes", "32-47", out);
804 	SET_SIZESTATDESC(48, "responses sent 48-63 bytes", "48-63", out);
805 	SET_SIZESTATDESC(64, "responses sent 64-79 bytes", "64-79", out);
806 	SET_SIZESTATDESC(80, "responses sent 80-95 bytes", "80-95", out);
807 	SET_SIZESTATDESC(96, "responses sent 96-111 bytes", "96-111", out);
808 	SET_SIZESTATDESC(112, "responses sent 112-127 bytes", "112-127", out);
809 	SET_SIZESTATDESC(128, "responses sent 128-143 bytes", "128-143", out);
810 	SET_SIZESTATDESC(144, "responses sent 144-159 bytes", "144-159", out);
811 	SET_SIZESTATDESC(160, "responses sent 160-175 bytes", "160-175", out);
812 	SET_SIZESTATDESC(176, "responses sent 176-191 bytes", "176-191", out);
813 	SET_SIZESTATDESC(192, "responses sent 192-207 bytes", "192-207", out);
814 	SET_SIZESTATDESC(208, "responses sent 208-223 bytes", "208-223", out);
815 	SET_SIZESTATDESC(224, "responses sent 224-239 bytes", "224-239", out);
816 	SET_SIZESTATDESC(240, "responses sent 240-255 bytes", "240-255", out);
817 	SET_SIZESTATDESC(256, "responses sent 256-271 bytes", "256-271", out);
818 	SET_SIZESTATDESC(272, "responses sent 272-287 bytes", "272-287", out);
819 	SET_SIZESTATDESC(288, "responses sent 288-303 bytes", "288-303", out);
820 	SET_SIZESTATDESC(304, "responses sent 304-319 bytes", "304-319", out);
821 	SET_SIZESTATDESC(320, "responses sent 320-335 bytes", "320-335", out);
822 	SET_SIZESTATDESC(336, "responses sent 336-351 bytes", "336-351", out);
823 	SET_SIZESTATDESC(352, "responses sent 352-367 bytes", "352-367", out);
824 	SET_SIZESTATDESC(368, "responses sent 368-383 bytes", "368-383", out);
825 	SET_SIZESTATDESC(384, "responses sent 384-399 bytes", "384-399", out);
826 	SET_SIZESTATDESC(400, "responses sent 400-415 bytes", "400-415", out);
827 	SET_SIZESTATDESC(416, "responses sent 416-431 bytes", "416-431", out);
828 	SET_SIZESTATDESC(432, "responses sent 432-447 bytes", "432-447", out);
829 	SET_SIZESTATDESC(448, "responses sent 448-463 bytes", "448-463", out);
830 	SET_SIZESTATDESC(464, "responses sent 464-479 bytes", "464-479", out);
831 	SET_SIZESTATDESC(480, "responses sent 480-495 bytes", "480-495", out);
832 	SET_SIZESTATDESC(496, "responses sent 496-511 bytes", "496-511", out);
833 	SET_SIZESTATDESC(512, "responses sent 512-527 bytes", "512-527", out);
834 	SET_SIZESTATDESC(528, "responses sent 528-543 bytes", "528-543", out);
835 	SET_SIZESTATDESC(544, "responses sent 544-559 bytes", "544-559", out);
836 	SET_SIZESTATDESC(560, "responses sent 560-575 bytes", "560-575", out);
837 	SET_SIZESTATDESC(576, "responses sent 576-591 bytes", "576-591", out);
838 	SET_SIZESTATDESC(592, "responses sent 592-607 bytes", "592-607", out);
839 	SET_SIZESTATDESC(608, "responses sent 608-623 bytes", "608-623", out);
840 	SET_SIZESTATDESC(624, "responses sent 624-639 bytes", "624-639", out);
841 	SET_SIZESTATDESC(640, "responses sent 640-655 bytes", "640-655", out);
842 	SET_SIZESTATDESC(656, "responses sent 656-671 bytes", "656-671", out);
843 	SET_SIZESTATDESC(672, "responses sent 672-687 bytes", "672-687", out);
844 	SET_SIZESTATDESC(688, "responses sent 688-703 bytes", "688-703", out);
845 	SET_SIZESTATDESC(704, "responses sent 704-719 bytes", "704-719", out);
846 	SET_SIZESTATDESC(720, "responses sent 720-735 bytes", "720-735", out);
847 	SET_SIZESTATDESC(736, "responses sent 736-751 bytes", "736-751", out);
848 	SET_SIZESTATDESC(752, "responses sent 752-767 bytes", "752-767", out);
849 	SET_SIZESTATDESC(768, "responses sent 768-783 bytes", "768-783", out);
850 	SET_SIZESTATDESC(784, "responses sent 784-799 bytes", "784-799", out);
851 	SET_SIZESTATDESC(800, "responses sent 800-815 bytes", "800-815", out);
852 	SET_SIZESTATDESC(816, "responses sent 816-831 bytes", "816-831", out);
853 	SET_SIZESTATDESC(832, "responses sent 832-847 bytes", "832-847", out);
854 	SET_SIZESTATDESC(848, "responses sent 848-863 bytes", "848-863", out);
855 	SET_SIZESTATDESC(864, "responses sent 864-879 bytes", "864-879", out);
856 	SET_SIZESTATDESC(880, "responses sent 880-895 bytes", "880-895", out);
857 	SET_SIZESTATDESC(896, "responses sent 896-911 bytes", "896-911", out);
858 	SET_SIZESTATDESC(912, "responses sent 912-927 bytes", "912-927", out);
859 	SET_SIZESTATDESC(928, "responses sent 928-943 bytes", "928-943", out);
860 	SET_SIZESTATDESC(944, "responses sent 944-959 bytes", "944-959", out);
861 	SET_SIZESTATDESC(960, "responses sent 960-975 bytes", "960-975", out);
862 	SET_SIZESTATDESC(976, "responses sent 976-991 bytes", "976-991", out);
863 	SET_SIZESTATDESC(992, "responses sent 992-1007 bytes", "992-1007", out);
864 	SET_SIZESTATDESC(1008, "responses sent 1008-1023 bytes", "1008-1023",
865 			 out);
866 	SET_SIZESTATDESC(1024, "responses sent 1024-1039 bytes", "1024-1039",
867 			 out);
868 	SET_SIZESTATDESC(1040, "responses sent 1040-1055 bytes", "1040-1055",
869 			 out);
870 	SET_SIZESTATDESC(1056, "responses sent 1056-1071 bytes", "1056-1071",
871 			 out);
872 	SET_SIZESTATDESC(1072, "responses sent 1072-1087 bytes", "1072-1087",
873 			 out);
874 	SET_SIZESTATDESC(1088, "responses sent 1088-1103 bytes", "1088-1103",
875 			 out);
876 	SET_SIZESTATDESC(1104, "responses sent 1104-1119 bytes", "1104-1119",
877 			 out);
878 	SET_SIZESTATDESC(1120, "responses sent 1120-1135 bytes", "1120-1135",
879 			 out);
880 	SET_SIZESTATDESC(1136, "responses sent 1136-1151 bytes", "1136-1151",
881 			 out);
882 	SET_SIZESTATDESC(1152, "responses sent 1152-1167 bytes", "1152-1167",
883 			 out);
884 	SET_SIZESTATDESC(1168, "responses sent 1168-1183 bytes", "1168-1183",
885 			 out);
886 	SET_SIZESTATDESC(1184, "responses sent 1184-1199 bytes", "1184-1199",
887 			 out);
888 	SET_SIZESTATDESC(1200, "responses sent 1200-1215 bytes", "1200-1215",
889 			 out);
890 	SET_SIZESTATDESC(1216, "responses sent 1216-1231 bytes", "1216-1231",
891 			 out);
892 	SET_SIZESTATDESC(1232, "responses sent 1232-1247 bytes", "1232-1247",
893 			 out);
894 	SET_SIZESTATDESC(1248, "responses sent 1248-1263 bytes", "1248-1263",
895 			 out);
896 	SET_SIZESTATDESC(1264, "responses sent 1264-1279 bytes", "1264-1279",
897 			 out);
898 	SET_SIZESTATDESC(1280, "responses sent 1280-1295 bytes", "1280-1295",
899 			 out);
900 	SET_SIZESTATDESC(1296, "responses sent 1296-1311 bytes", "1296-1311",
901 			 out);
902 	SET_SIZESTATDESC(1312, "responses sent 1312-1327 bytes", "1312-1327",
903 			 out);
904 	SET_SIZESTATDESC(1328, "responses sent 1328-1343 bytes", "1328-1343",
905 			 out);
906 	SET_SIZESTATDESC(1344, "responses sent 1344-1359 bytes", "1344-1359",
907 			 out);
908 	SET_SIZESTATDESC(1360, "responses sent 1360-1375 bytes", "1360-1375",
909 			 out);
910 	SET_SIZESTATDESC(1376, "responses sent 1376-1391 bytes", "1376-1391",
911 			 out);
912 	SET_SIZESTATDESC(1392, "responses sent 1392-1407 bytes", "1392-1407",
913 			 out);
914 	SET_SIZESTATDESC(1408, "responses sent 1408-1423 bytes", "1408-1423",
915 			 out);
916 	SET_SIZESTATDESC(1424, "responses sent 1424-1439 bytes", "1424-1439",
917 			 out);
918 	SET_SIZESTATDESC(1440, "responses sent 1440-1455 bytes", "1440-1455",
919 			 out);
920 	SET_SIZESTATDESC(1456, "responses sent 1456-1471 bytes", "1456-1471",
921 			 out);
922 	SET_SIZESTATDESC(1472, "responses sent 1472-1487 bytes", "1472-1487",
923 			 out);
924 	SET_SIZESTATDESC(1488, "responses sent 1488-1503 bytes", "1488-1503",
925 			 out);
926 	SET_SIZESTATDESC(1504, "responses sent 1504-1519 bytes", "1504-1519",
927 			 out);
928 	SET_SIZESTATDESC(1520, "responses sent 1520-1535 bytes", "1520-1535",
929 			 out);
930 	SET_SIZESTATDESC(1536, "responses sent 1536-1551 bytes", "1536-1551",
931 			 out);
932 	SET_SIZESTATDESC(1552, "responses sent 1552-1567 bytes", "1552-1567",
933 			 out);
934 	SET_SIZESTATDESC(1568, "responses sent 1568-1583 bytes", "1568-1583",
935 			 out);
936 	SET_SIZESTATDESC(1584, "responses sent 1584-1599 bytes", "1584-1599",
937 			 out);
938 	SET_SIZESTATDESC(1600, "responses sent 1600-1615 bytes", "1600-1615",
939 			 out);
940 	SET_SIZESTATDESC(1616, "responses sent 1616-1631 bytes", "1616-1631",
941 			 out);
942 	SET_SIZESTATDESC(1632, "responses sent 1632-1647 bytes", "1632-1647",
943 			 out);
944 	SET_SIZESTATDESC(1648, "responses sent 1648-1663 bytes", "1648-1663",
945 			 out);
946 	SET_SIZESTATDESC(1664, "responses sent 1664-1679 bytes", "1664-1679",
947 			 out);
948 	SET_SIZESTATDESC(1680, "responses sent 1680-1695 bytes", "1680-1695",
949 			 out);
950 	SET_SIZESTATDESC(1696, "responses sent 1696-1711 bytes", "1696-1711",
951 			 out);
952 	SET_SIZESTATDESC(1712, "responses sent 1712-1727 bytes", "1712-1727",
953 			 out);
954 	SET_SIZESTATDESC(1728, "responses sent 1728-1743 bytes", "1728-1743",
955 			 out);
956 	SET_SIZESTATDESC(1744, "responses sent 1744-1759 bytes", "1744-1759",
957 			 out);
958 	SET_SIZESTATDESC(1760, "responses sent 1760-1775 bytes", "1760-1775",
959 			 out);
960 	SET_SIZESTATDESC(1776, "responses sent 1776-1791 bytes", "1776-1791",
961 			 out);
962 	SET_SIZESTATDESC(1792, "responses sent 1792-1807 bytes", "1792-1807",
963 			 out);
964 	SET_SIZESTATDESC(1808, "responses sent 1808-1823 bytes", "1808-1823",
965 			 out);
966 	SET_SIZESTATDESC(1824, "responses sent 1824-1839 bytes", "1824-1839",
967 			 out);
968 	SET_SIZESTATDESC(1840, "responses sent 1840-1855 bytes", "1840-1855",
969 			 out);
970 	SET_SIZESTATDESC(1856, "responses sent 1856-1871 bytes", "1856-1871",
971 			 out);
972 	SET_SIZESTATDESC(1872, "responses sent 1872-1887 bytes", "1872-1887",
973 			 out);
974 	SET_SIZESTATDESC(1888, "responses sent 1888-1903 bytes", "1888-1903",
975 			 out);
976 	SET_SIZESTATDESC(1904, "responses sent 1904-1919 bytes", "1904-1919",
977 			 out);
978 	SET_SIZESTATDESC(1920, "responses sent 1920-1935 bytes", "1920-1935",
979 			 out);
980 	SET_SIZESTATDESC(1936, "responses sent 1936-1951 bytes", "1936-1951",
981 			 out);
982 	SET_SIZESTATDESC(1952, "responses sent 1952-1967 bytes", "1952-1967",
983 			 out);
984 	SET_SIZESTATDESC(1968, "responses sent 1968-1983 bytes", "1968-1983",
985 			 out);
986 	SET_SIZESTATDESC(1984, "responses sent 1984-1999 bytes", "1984-1999",
987 			 out);
988 	SET_SIZESTATDESC(2000, "responses sent 2000-2015 bytes", "2000-2015",
989 			 out);
990 	SET_SIZESTATDESC(2016, "responses sent 2016-2031 bytes", "2016-2031",
991 			 out);
992 	SET_SIZESTATDESC(2032, "responses sent 2032-2047 bytes", "2032-2047",
993 			 out);
994 	SET_SIZESTATDESC(2048, "responses sent 2048-2063 bytes", "2048-2063",
995 			 out);
996 	SET_SIZESTATDESC(2064, "responses sent 2064-2079 bytes", "2064-2079",
997 			 out);
998 	SET_SIZESTATDESC(2080, "responses sent 2080-2095 bytes", "2080-2095",
999 			 out);
1000 	SET_SIZESTATDESC(2096, "responses sent 2096-2111 bytes", "2096-2111",
1001 			 out);
1002 	SET_SIZESTATDESC(2112, "responses sent 2112-2127 bytes", "2112-2127",
1003 			 out);
1004 	SET_SIZESTATDESC(2128, "responses sent 2128-2143 bytes", "2128-2143",
1005 			 out);
1006 	SET_SIZESTATDESC(2144, "responses sent 2144-2159 bytes", "2144-2159",
1007 			 out);
1008 	SET_SIZESTATDESC(2160, "responses sent 2160-2175 bytes", "2160-2175",
1009 			 out);
1010 	SET_SIZESTATDESC(2176, "responses sent 2176-2191 bytes", "2176-2191",
1011 			 out);
1012 	SET_SIZESTATDESC(2192, "responses sent 2192-2207 bytes", "2192-2207",
1013 			 out);
1014 	SET_SIZESTATDESC(2208, "responses sent 2208-2223 bytes", "2208-2223",
1015 			 out);
1016 	SET_SIZESTATDESC(2224, "responses sent 2224-2239 bytes", "2224-2239",
1017 			 out);
1018 	SET_SIZESTATDESC(2240, "responses sent 2240-2255 bytes", "2240-2255",
1019 			 out);
1020 	SET_SIZESTATDESC(2256, "responses sent 2256-2271 bytes", "2256-2271",
1021 			 out);
1022 	SET_SIZESTATDESC(2272, "responses sent 2272-2287 bytes", "2272-2287",
1023 			 out);
1024 	SET_SIZESTATDESC(2288, "responses sent 2288-2303 bytes", "2288-2303",
1025 			 out);
1026 	SET_SIZESTATDESC(2304, "responses sent 2304-2319 bytes", "2304-2319",
1027 			 out);
1028 	SET_SIZESTATDESC(2320, "responses sent 2320-2335 bytes", "2320-2335",
1029 			 out);
1030 	SET_SIZESTATDESC(2336, "responses sent 2336-2351 bytes", "2336-2351",
1031 			 out);
1032 	SET_SIZESTATDESC(2352, "responses sent 2352-2367 bytes", "2352-2367",
1033 			 out);
1034 	SET_SIZESTATDESC(2368, "responses sent 2368-2383 bytes", "2368-2383",
1035 			 out);
1036 	SET_SIZESTATDESC(2384, "responses sent 2384-2399 bytes", "2384-2399",
1037 			 out);
1038 	SET_SIZESTATDESC(2400, "responses sent 2400-2415 bytes", "2400-2415",
1039 			 out);
1040 	SET_SIZESTATDESC(2416, "responses sent 2416-2431 bytes", "2416-2431",
1041 			 out);
1042 	SET_SIZESTATDESC(2432, "responses sent 2432-2447 bytes", "2432-2447",
1043 			 out);
1044 	SET_SIZESTATDESC(2448, "responses sent 2448-2463 bytes", "2448-2463",
1045 			 out);
1046 	SET_SIZESTATDESC(2464, "responses sent 2464-2479 bytes", "2464-2479",
1047 			 out);
1048 	SET_SIZESTATDESC(2480, "responses sent 2480-2495 bytes", "2480-2495",
1049 			 out);
1050 	SET_SIZESTATDESC(2496, "responses sent 2496-2511 bytes", "2496-2511",
1051 			 out);
1052 	SET_SIZESTATDESC(2512, "responses sent 2512-2527 bytes", "2512-2527",
1053 			 out);
1054 	SET_SIZESTATDESC(2528, "responses sent 2528-2543 bytes", "2528-2543",
1055 			 out);
1056 	SET_SIZESTATDESC(2544, "responses sent 2544-2559 bytes", "2544-2559",
1057 			 out);
1058 	SET_SIZESTATDESC(2560, "responses sent 2560-2575 bytes", "2560-2575",
1059 			 out);
1060 	SET_SIZESTATDESC(2576, "responses sent 2576-2591 bytes", "2576-2591",
1061 			 out);
1062 	SET_SIZESTATDESC(2592, "responses sent 2592-2607 bytes", "2592-2607",
1063 			 out);
1064 	SET_SIZESTATDESC(2608, "responses sent 2608-2623 bytes", "2608-2623",
1065 			 out);
1066 	SET_SIZESTATDESC(2624, "responses sent 2624-2639 bytes", "2624-2639",
1067 			 out);
1068 	SET_SIZESTATDESC(2640, "responses sent 2640-2655 bytes", "2640-2655",
1069 			 out);
1070 	SET_SIZESTATDESC(2656, "responses sent 2656-2671 bytes", "2656-2671",
1071 			 out);
1072 	SET_SIZESTATDESC(2672, "responses sent 2672-2687 bytes", "2672-2687",
1073 			 out);
1074 	SET_SIZESTATDESC(2688, "responses sent 2688-2703 bytes", "2688-2703",
1075 			 out);
1076 	SET_SIZESTATDESC(2704, "responses sent 2704-2719 bytes", "2704-2719",
1077 			 out);
1078 	SET_SIZESTATDESC(2720, "responses sent 2720-2735 bytes", "2720-2735",
1079 			 out);
1080 	SET_SIZESTATDESC(2736, "responses sent 2736-2751 bytes", "2736-2751",
1081 			 out);
1082 	SET_SIZESTATDESC(2752, "responses sent 2752-2767 bytes", "2752-2767",
1083 			 out);
1084 	SET_SIZESTATDESC(2768, "responses sent 2768-2783 bytes", "2768-2783",
1085 			 out);
1086 	SET_SIZESTATDESC(2784, "responses sent 2784-2799 bytes", "2784-2799",
1087 			 out);
1088 	SET_SIZESTATDESC(2800, "responses sent 2800-2815 bytes", "2800-2815",
1089 			 out);
1090 	SET_SIZESTATDESC(2816, "responses sent 2816-2831 bytes", "2816-2831",
1091 			 out);
1092 	SET_SIZESTATDESC(2832, "responses sent 2832-2847 bytes", "2832-2847",
1093 			 out);
1094 	SET_SIZESTATDESC(2848, "responses sent 2848-2863 bytes", "2848-2863",
1095 			 out);
1096 	SET_SIZESTATDESC(2864, "responses sent 2864-2879 bytes", "2864-2879",
1097 			 out);
1098 	SET_SIZESTATDESC(2880, "responses sent 2880-2895 bytes", "2880-2895",
1099 			 out);
1100 	SET_SIZESTATDESC(2896, "responses sent 2896-2911 bytes", "2896-2911",
1101 			 out);
1102 	SET_SIZESTATDESC(2912, "responses sent 2912-2927 bytes", "2912-2927",
1103 			 out);
1104 	SET_SIZESTATDESC(2928, "responses sent 2928-2943 bytes", "2928-2943",
1105 			 out);
1106 	SET_SIZESTATDESC(2944, "responses sent 2944-2959 bytes", "2944-2959",
1107 			 out);
1108 	SET_SIZESTATDESC(2960, "responses sent 2960-2975 bytes", "2960-2975",
1109 			 out);
1110 	SET_SIZESTATDESC(2976, "responses sent 2976-2991 bytes", "2976-2991",
1111 			 out);
1112 	SET_SIZESTATDESC(2992, "responses sent 2992-3007 bytes", "2992-3007",
1113 			 out);
1114 	SET_SIZESTATDESC(3008, "responses sent 3008-3023 bytes", "3008-3023",
1115 			 out);
1116 	SET_SIZESTATDESC(3024, "responses sent 3024-3039 bytes", "3024-3039",
1117 			 out);
1118 	SET_SIZESTATDESC(3040, "responses sent 3040-3055 bytes", "3040-3055",
1119 			 out);
1120 	SET_SIZESTATDESC(3056, "responses sent 3056-3071 bytes", "3056-3071",
1121 			 out);
1122 	SET_SIZESTATDESC(3072, "responses sent 3072-3087 bytes", "3072-3087",
1123 			 out);
1124 	SET_SIZESTATDESC(3088, "responses sent 3088-3103 bytes", "3088-3103",
1125 			 out);
1126 	SET_SIZESTATDESC(3104, "responses sent 3104-3119 bytes", "3104-3119",
1127 			 out);
1128 	SET_SIZESTATDESC(3120, "responses sent 3120-3135 bytes", "3120-3135",
1129 			 out);
1130 	SET_SIZESTATDESC(3136, "responses sent 3136-3151 bytes", "3136-3151",
1131 			 out);
1132 	SET_SIZESTATDESC(3152, "responses sent 3152-3167 bytes", "3152-3167",
1133 			 out);
1134 	SET_SIZESTATDESC(3168, "responses sent 3168-3183 bytes", "3168-3183",
1135 			 out);
1136 	SET_SIZESTATDESC(3184, "responses sent 3184-3199 bytes", "3184-3199",
1137 			 out);
1138 	SET_SIZESTATDESC(3200, "responses sent 3200-3215 bytes", "3200-3215",
1139 			 out);
1140 	SET_SIZESTATDESC(3216, "responses sent 3216-3231 bytes", "3216-3231",
1141 			 out);
1142 	SET_SIZESTATDESC(3232, "responses sent 3232-3247 bytes", "3232-3247",
1143 			 out);
1144 	SET_SIZESTATDESC(3248, "responses sent 3248-3263 bytes", "3248-3263",
1145 			 out);
1146 	SET_SIZESTATDESC(3264, "responses sent 3264-3279 bytes", "3264-3279",
1147 			 out);
1148 	SET_SIZESTATDESC(3280, "responses sent 3280-3295 bytes", "3280-3295",
1149 			 out);
1150 	SET_SIZESTATDESC(3296, "responses sent 3296-3311 bytes", "3296-3311",
1151 			 out);
1152 	SET_SIZESTATDESC(3312, "responses sent 3312-3327 bytes", "3312-3327",
1153 			 out);
1154 	SET_SIZESTATDESC(3328, "responses sent 3328-3343 bytes", "3328-3343",
1155 			 out);
1156 	SET_SIZESTATDESC(3344, "responses sent 3344-3359 bytes", "3344-3359",
1157 			 out);
1158 	SET_SIZESTATDESC(3360, "responses sent 3360-3375 bytes", "3360-3375",
1159 			 out);
1160 	SET_SIZESTATDESC(3376, "responses sent 3376-3391 bytes", "3376-3391",
1161 			 out);
1162 	SET_SIZESTATDESC(3392, "responses sent 3392-3407 bytes", "3392-3407",
1163 			 out);
1164 	SET_SIZESTATDESC(3408, "responses sent 3408-3423 bytes", "3408-3423",
1165 			 out);
1166 	SET_SIZESTATDESC(3424, "responses sent 3424-3439 bytes", "3424-3439",
1167 			 out);
1168 	SET_SIZESTATDESC(3440, "responses sent 3440-3455 bytes", "3440-3455",
1169 			 out);
1170 	SET_SIZESTATDESC(3456, "responses sent 3456-3471 bytes", "3456-3471",
1171 			 out);
1172 	SET_SIZESTATDESC(3472, "responses sent 3472-3487 bytes", "3472-3487",
1173 			 out);
1174 	SET_SIZESTATDESC(3488, "responses sent 3488-3503 bytes", "3488-3503",
1175 			 out);
1176 	SET_SIZESTATDESC(3504, "responses sent 3504-3519 bytes", "3504-3519",
1177 			 out);
1178 	SET_SIZESTATDESC(3520, "responses sent 3520-3535 bytes", "3520-3535",
1179 			 out);
1180 	SET_SIZESTATDESC(3536, "responses sent 3536-3551 bytes", "3536-3551",
1181 			 out);
1182 	SET_SIZESTATDESC(3552, "responses sent 3552-3567 bytes", "3552-3567",
1183 			 out);
1184 	SET_SIZESTATDESC(3568, "responses sent 3568-3583 bytes", "3568-3583",
1185 			 out);
1186 	SET_SIZESTATDESC(3584, "responses sent 3584-3599 bytes", "3584-3599",
1187 			 out);
1188 	SET_SIZESTATDESC(3600, "responses sent 3600-3615 bytes", "3600-3615",
1189 			 out);
1190 	SET_SIZESTATDESC(3616, "responses sent 3616-3631 bytes", "3616-3631",
1191 			 out);
1192 	SET_SIZESTATDESC(3632, "responses sent 3632-3647 bytes", "3632-3647",
1193 			 out);
1194 	SET_SIZESTATDESC(3648, "responses sent 3648-3663 bytes", "3648-3663",
1195 			 out);
1196 	SET_SIZESTATDESC(3664, "responses sent 3664-3679 bytes", "3664-3679",
1197 			 out);
1198 	SET_SIZESTATDESC(3680, "responses sent 3680-3695 bytes", "3680-3695",
1199 			 out);
1200 	SET_SIZESTATDESC(3696, "responses sent 3696-3711 bytes", "3696-3711",
1201 			 out);
1202 	SET_SIZESTATDESC(3712, "responses sent 3712-3727 bytes", "3712-3727",
1203 			 out);
1204 	SET_SIZESTATDESC(3728, "responses sent 3728-3743 bytes", "3728-3743",
1205 			 out);
1206 	SET_SIZESTATDESC(3744, "responses sent 3744-3759 bytes", "3744-3759",
1207 			 out);
1208 	SET_SIZESTATDESC(3760, "responses sent 3760-3775 bytes", "3760-3775",
1209 			 out);
1210 	SET_SIZESTATDESC(3776, "responses sent 3776-3791 bytes", "3776-3791",
1211 			 out);
1212 	SET_SIZESTATDESC(3792, "responses sent 3792-3807 bytes", "3792-3807",
1213 			 out);
1214 	SET_SIZESTATDESC(3808, "responses sent 3808-3823 bytes", "3808-3823",
1215 			 out);
1216 	SET_SIZESTATDESC(3824, "responses sent 3824-3839 bytes", "3824-3839",
1217 			 out);
1218 	SET_SIZESTATDESC(3840, "responses sent 3840-3855 bytes", "3840-3855",
1219 			 out);
1220 	SET_SIZESTATDESC(3856, "responses sent 3856-3871 bytes", "3856-3871",
1221 			 out);
1222 	SET_SIZESTATDESC(3872, "responses sent 3872-3887 bytes", "3872-3887",
1223 			 out);
1224 	SET_SIZESTATDESC(3888, "responses sent 3888-3903 bytes", "3888-3903",
1225 			 out);
1226 	SET_SIZESTATDESC(3904, "responses sent 3904-3919 bytes", "3904-3919",
1227 			 out);
1228 	SET_SIZESTATDESC(3920, "responses sent 3920-3935 bytes", "3920-3935",
1229 			 out);
1230 	SET_SIZESTATDESC(3936, "responses sent 3936-3951 bytes", "3936-3951",
1231 			 out);
1232 	SET_SIZESTATDESC(3952, "responses sent 3952-3967 bytes", "3952-3967",
1233 			 out);
1234 	SET_SIZESTATDESC(3968, "responses sent 3968-3983 bytes", "3968-3983",
1235 			 out);
1236 	SET_SIZESTATDESC(3984, "responses sent 3984-3999 bytes", "3984-3999",
1237 			 out);
1238 	SET_SIZESTATDESC(4000, "responses sent 4000-4015 bytes", "4000-4015",
1239 			 out);
1240 	SET_SIZESTATDESC(4016, "responses sent 4016-4031 bytes", "4016-4031",
1241 			 out);
1242 	SET_SIZESTATDESC(4032, "responses sent 4032-4047 bytes", "4032-4047",
1243 			 out);
1244 	SET_SIZESTATDESC(4048, "responses sent 4048-4063 bytes", "4048-4063",
1245 			 out);
1246 	SET_SIZESTATDESC(4064, "responses sent 4064-4079 bytes", "4064-4079",
1247 			 out);
1248 	SET_SIZESTATDESC(4080, "responses sent 4080-4095 bytes", "4080-4095",
1249 			 out);
1250 	SET_SIZESTATDESC(4096, "responses sent 4096+ bytes", "4096+", out);
1251 	INSIST(i == dns_sizecounter_out_max);
1252 
1253 	/* Sanity check */
1254 	for (i = 0; i < ns_statscounter_max; i++) {
1255 		INSIST(nsstats_desc[i] != NULL);
1256 	}
1257 	for (i = 0; i < dns_resstatscounter_max; i++) {
1258 		INSIST(resstats_desc[i] != NULL);
1259 	}
1260 	for (i = 0; i < dns_adbstats_max; i++) {
1261 		INSIST(adbstats_desc[i] != NULL);
1262 	}
1263 	for (i = 0; i < dns_zonestatscounter_max; i++) {
1264 		INSIST(zonestats_desc[i] != NULL);
1265 	}
1266 	for (i = 0; i < isc_sockstatscounter_max; i++) {
1267 		INSIST(sockstats_desc[i] != NULL);
1268 	}
1269 	for (i = 0; i < dns_dnssecstats_max; i++) {
1270 		INSIST(dnssecstats_desc[i] != NULL);
1271 	}
1272 	for (i = 0; i < dns_sizecounter_in_max; i++) {
1273 		INSIST(udpinsizestats_desc[i] != NULL);
1274 		INSIST(tcpinsizestats_desc[i] != NULL);
1275 	}
1276 	for (i = 0; i < dns_sizecounter_out_max; i++) {
1277 		INSIST(udpoutsizestats_desc[i] != NULL);
1278 		INSIST(tcpoutsizestats_desc[i] != NULL);
1279 	}
1280 #if defined(EXTENDED_STATS)
1281 	for (i = 0; i < ns_statscounter_max; i++) {
1282 		INSIST(nsstats_xmldesc[i] != NULL);
1283 	}
1284 	for (i = 0; i < dns_resstatscounter_max; i++) {
1285 		INSIST(resstats_xmldesc[i] != NULL);
1286 	}
1287 	for (i = 0; i < dns_adbstats_max; i++) {
1288 		INSIST(adbstats_xmldesc[i] != NULL);
1289 	}
1290 	for (i = 0; i < dns_zonestatscounter_max; i++) {
1291 		INSIST(zonestats_xmldesc[i] != NULL);
1292 	}
1293 	for (i = 0; i < isc_sockstatscounter_max; i++) {
1294 		INSIST(sockstats_xmldesc[i] != NULL);
1295 	}
1296 	for (i = 0; i < dns_dnssecstats_max; i++) {
1297 		INSIST(dnssecstats_xmldesc[i] != NULL);
1298 	}
1299 	for (i = 0; i < dns_sizecounter_in_max; i++) {
1300 		INSIST(udpinsizestats_xmldesc[i] != NULL);
1301 		INSIST(tcpinsizestats_xmldesc[i] != NULL);
1302 	}
1303 	for (i = 0; i < dns_sizecounter_out_max; i++) {
1304 		INSIST(udpoutsizestats_xmldesc[i] != NULL);
1305 		INSIST(tcpoutsizestats_xmldesc[i] != NULL);
1306 	}
1307 #endif /* if defined(EXTENDED_STATS) */
1308 }
1309 
1310 /*%
1311  * Dump callback functions.
1312  */
1313 static void
1314 generalstat_dump(isc_statscounter_t counter, uint64_t val, void *arg) {
1315 	stats_dumparg_t *dumparg = arg;
1316 
1317 	REQUIRE(counter < dumparg->ncounters);
1318 	dumparg->countervalues[counter] = val;
1319 }
1320 
1321 static isc_result_t
1322 dump_counters(isc_stats_t *stats, isc_statsformat_t type, void *arg,
1323 	      const char *category, const char **desc, int ncounters,
1324 	      int *indices, uint64_t *values, int options) {
1325 	int i, idx;
1326 	uint64_t value;
1327 	stats_dumparg_t dumparg;
1328 	FILE *fp;
1329 #ifdef HAVE_LIBXML2
1330 	void *writer;
1331 	int xmlrc;
1332 #endif /* ifdef HAVE_LIBXML2 */
1333 #ifdef HAVE_JSON_C
1334 	json_object *job, *cat, *counter;
1335 #endif /* ifdef HAVE_JSON_C */
1336 
1337 #if !defined(EXTENDED_STATS)
1338 	UNUSED(category);
1339 #endif /* if !defined(EXTENDED_STATS) */
1340 
1341 	dumparg.type = type;
1342 	dumparg.ncounters = ncounters;
1343 	dumparg.counterindices = indices;
1344 	dumparg.countervalues = values;
1345 
1346 	memset(values, 0, sizeof(values[0]) * ncounters);
1347 	isc_stats_dump(stats, generalstat_dump, &dumparg, options);
1348 
1349 #ifdef HAVE_JSON_C
1350 	cat = job = (json_object *)arg;
1351 	if (ncounters > 0 && type == isc_statsformat_json) {
1352 		if (category != NULL) {
1353 			cat = json_object_new_object();
1354 			if (cat == NULL) {
1355 				return (ISC_R_NOMEMORY);
1356 			}
1357 			json_object_object_add(job, category, cat);
1358 		}
1359 	}
1360 #endif /* ifdef HAVE_JSON_C */
1361 
1362 	for (i = 0; i < ncounters; i++) {
1363 		idx = indices[i];
1364 		value = values[idx];
1365 
1366 		if (value == 0 && (options & ISC_STATSDUMP_VERBOSE) == 0) {
1367 			continue;
1368 		}
1369 
1370 		switch (dumparg.type) {
1371 		case isc_statsformat_file:
1372 			fp = arg;
1373 			fprintf(fp, "%20" PRIu64 " %s\n", value, desc[idx]);
1374 			break;
1375 		case isc_statsformat_xml:
1376 #ifdef HAVE_LIBXML2
1377 			writer = arg;
1378 
1379 			if (category != NULL) {
1380 				/* <NameOfCategory> */
1381 				TRY0(xmlTextWriterStartElement(
1382 					writer, ISC_XMLCHAR category));
1383 
1384 				/* <name> inside category */
1385 				TRY0(xmlTextWriterStartElement(
1386 					writer, ISC_XMLCHAR "name"));
1387 				TRY0(xmlTextWriterWriteString(
1388 					writer, ISC_XMLCHAR desc[idx]));
1389 				TRY0(xmlTextWriterEndElement(writer));
1390 				/* </name> */
1391 
1392 				/* <counter> */
1393 				TRY0(xmlTextWriterStartElement(
1394 					writer, ISC_XMLCHAR "counter"));
1395 				TRY0(xmlTextWriterWriteFormatString(
1396 					writer, "%" PRIu64, value));
1397 
1398 				TRY0(xmlTextWriterEndElement(writer));
1399 				/* </counter> */
1400 				TRY0(xmlTextWriterEndElement(writer));
1401 				/* </NameOfCategory> */
1402 			} else {
1403 				TRY0(xmlTextWriterStartElement(
1404 					writer, ISC_XMLCHAR "counter"));
1405 				TRY0(xmlTextWriterWriteAttribute(
1406 					writer, ISC_XMLCHAR "name",
1407 					ISC_XMLCHAR desc[idx]));
1408 				TRY0(xmlTextWriterWriteFormatString(
1409 					writer, "%" PRIu64, value));
1410 				TRY0(xmlTextWriterEndElement(writer));
1411 				/* counter */
1412 			}
1413 
1414 #endif /* ifdef HAVE_LIBXML2 */
1415 			break;
1416 		case isc_statsformat_json:
1417 #ifdef HAVE_JSON_C
1418 			counter = json_object_new_int64(value);
1419 			if (counter == NULL) {
1420 				return (ISC_R_NOMEMORY);
1421 			}
1422 			json_object_object_add(cat, desc[idx], counter);
1423 #endif /* ifdef HAVE_JSON_C */
1424 			break;
1425 		}
1426 	}
1427 	return (ISC_R_SUCCESS);
1428 #ifdef HAVE_LIBXML2
1429 error:
1430 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1431 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1432 		      "failed at dump_counters()");
1433 	return (ISC_R_FAILURE);
1434 #endif /* ifdef HAVE_LIBXML2 */
1435 }
1436 
1437 static void
1438 rdtypestat_dump(dns_rdatastatstype_t type, uint64_t val, void *arg) {
1439 	char typebuf[64];
1440 	const char *typestr;
1441 	stats_dumparg_t *dumparg = arg;
1442 	FILE *fp;
1443 #ifdef HAVE_LIBXML2
1444 	void *writer;
1445 	int xmlrc;
1446 #endif /* ifdef HAVE_LIBXML2 */
1447 #ifdef HAVE_JSON_C
1448 	json_object *zoneobj, *obj;
1449 #endif /* ifdef HAVE_JSON_C */
1450 
1451 	if ((DNS_RDATASTATSTYPE_ATTR(type) &
1452 	     DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) == 0) {
1453 		dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf,
1454 				     sizeof(typebuf));
1455 		typestr = typebuf;
1456 	} else {
1457 		typestr = "Others";
1458 	}
1459 
1460 	switch (dumparg->type) {
1461 	case isc_statsformat_file:
1462 		fp = dumparg->arg;
1463 		fprintf(fp, "%20" PRIu64 " %s\n", val, typestr);
1464 		break;
1465 	case isc_statsformat_xml:
1466 #ifdef HAVE_LIBXML2
1467 		writer = dumparg->arg;
1468 
1469 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
1470 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
1471 						 ISC_XMLCHAR typestr));
1472 
1473 		TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, val));
1474 
1475 		TRY0(xmlTextWriterEndElement(writer)); /* type */
1476 #endif						       /* ifdef HAVE_LIBXML2 */
1477 		break;
1478 	case isc_statsformat_json:
1479 #ifdef HAVE_JSON_C
1480 		zoneobj = (json_object *)dumparg->arg;
1481 		obj = json_object_new_int64(val);
1482 		if (obj == NULL) {
1483 			return;
1484 		}
1485 		json_object_object_add(zoneobj, typestr, obj);
1486 #endif /* ifdef HAVE_JSON_C */
1487 		break;
1488 	}
1489 	return;
1490 #ifdef HAVE_LIBXML2
1491 error:
1492 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1493 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1494 		      "failed at rdtypestat_dump()");
1495 	dumparg->result = ISC_R_FAILURE;
1496 	return;
1497 #endif /* ifdef HAVE_LIBXML2 */
1498 }
1499 
1500 static bool
1501 rdatastatstype_attr(dns_rdatastatstype_t type, unsigned int attr) {
1502 	return ((DNS_RDATASTATSTYPE_ATTR(type) & attr) != 0);
1503 }
1504 
1505 static void
1506 rdatasetstats_dump(dns_rdatastatstype_t type, uint64_t val, void *arg) {
1507 	stats_dumparg_t *dumparg = arg;
1508 	FILE *fp;
1509 	char typebuf[64];
1510 	const char *typestr;
1511 	bool nxrrset = false;
1512 	bool stale = false;
1513 	bool ancient = false;
1514 #ifdef HAVE_LIBXML2
1515 	void *writer;
1516 	int xmlrc;
1517 #endif /* ifdef HAVE_LIBXML2 */
1518 #ifdef HAVE_JSON_C
1519 	json_object *zoneobj, *obj;
1520 	char buf[1024];
1521 #endif /* ifdef HAVE_JSON_C */
1522 
1523 	if ((DNS_RDATASTATSTYPE_ATTR(type) &
1524 	     DNS_RDATASTATSTYPE_ATTR_NXDOMAIN) != 0) {
1525 		typestr = "NXDOMAIN";
1526 	} else if ((DNS_RDATASTATSTYPE_ATTR(type) &
1527 		    DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) != 0)
1528 	{
1529 		typestr = "Others";
1530 	} else {
1531 		dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf,
1532 				     sizeof(typebuf));
1533 		typestr = typebuf;
1534 	}
1535 
1536 	nxrrset = rdatastatstype_attr(type, DNS_RDATASTATSTYPE_ATTR_NXRRSET);
1537 	stale = rdatastatstype_attr(type, DNS_RDATASTATSTYPE_ATTR_STALE);
1538 	ancient = rdatastatstype_attr(type, DNS_RDATASTATSTYPE_ATTR_ANCIENT);
1539 
1540 	switch (dumparg->type) {
1541 	case isc_statsformat_file:
1542 		fp = dumparg->arg;
1543 		fprintf(fp, "%20" PRIu64 " %s%s%s%s\n", val, ancient ? "~" : "",
1544 			stale ? "#" : "", nxrrset ? "!" : "", typestr);
1545 		break;
1546 	case isc_statsformat_xml:
1547 #ifdef HAVE_LIBXML2
1548 		writer = dumparg->arg;
1549 
1550 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "rrset"));
1551 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
1552 		TRY0(xmlTextWriterWriteFormatString(
1553 			writer, "%s%s%s%s", ancient ? "~" : "",
1554 			stale ? "#" : "", nxrrset ? "!" : "", typestr));
1555 		TRY0(xmlTextWriterEndElement(writer)); /* name */
1556 
1557 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
1558 		TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, val));
1559 		TRY0(xmlTextWriterEndElement(writer)); /* counter */
1560 
1561 		TRY0(xmlTextWriterEndElement(writer)); /* rrset */
1562 #endif						       /* ifdef HAVE_LIBXML2 */
1563 		break;
1564 	case isc_statsformat_json:
1565 #ifdef HAVE_JSON_C
1566 		zoneobj = (json_object *)dumparg->arg;
1567 		snprintf(buf, sizeof(buf), "%s%s%s%s", ancient ? "~" : "",
1568 			 stale ? "#" : "", nxrrset ? "!" : "", typestr);
1569 		obj = json_object_new_int64(val);
1570 		if (obj == NULL) {
1571 			return;
1572 		}
1573 		json_object_object_add(zoneobj, buf, obj);
1574 #endif /* ifdef HAVE_JSON_C */
1575 		break;
1576 	}
1577 	return;
1578 #ifdef HAVE_LIBXML2
1579 error:
1580 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1581 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1582 		      "failed at rdatasetstats_dump()");
1583 	dumparg->result = ISC_R_FAILURE;
1584 #endif /* ifdef HAVE_LIBXML2 */
1585 }
1586 
1587 static void
1588 opcodestat_dump(dns_opcode_t code, uint64_t val, void *arg) {
1589 	FILE *fp;
1590 	isc_buffer_t b;
1591 	char codebuf[64];
1592 	stats_dumparg_t *dumparg = arg;
1593 #ifdef HAVE_LIBXML2
1594 	void *writer;
1595 	int xmlrc;
1596 #endif /* ifdef HAVE_LIBXML2 */
1597 #ifdef HAVE_JSON_C
1598 	json_object *zoneobj, *obj;
1599 #endif /* ifdef HAVE_JSON_C */
1600 
1601 	isc_buffer_init(&b, codebuf, sizeof(codebuf) - 1);
1602 	dns_opcode_totext(code, &b);
1603 	codebuf[isc_buffer_usedlength(&b)] = '\0';
1604 
1605 	switch (dumparg->type) {
1606 	case isc_statsformat_file:
1607 		fp = dumparg->arg;
1608 		fprintf(fp, "%20" PRIu64 " %s\n", val, codebuf);
1609 		break;
1610 	case isc_statsformat_xml:
1611 #ifdef HAVE_LIBXML2
1612 		writer = dumparg->arg;
1613 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
1614 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
1615 						 ISC_XMLCHAR codebuf));
1616 		TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, val));
1617 		TRY0(xmlTextWriterEndElement(writer)); /* counter */
1618 #endif						       /* ifdef HAVE_LIBXML2 */
1619 		break;
1620 	case isc_statsformat_json:
1621 #ifdef HAVE_JSON_C
1622 		zoneobj = (json_object *)dumparg->arg;
1623 		obj = json_object_new_int64(val);
1624 		if (obj == NULL) {
1625 			return;
1626 		}
1627 		json_object_object_add(zoneobj, codebuf, obj);
1628 #endif /* ifdef HAVE_JSON_C */
1629 		break;
1630 	}
1631 	return;
1632 
1633 #ifdef HAVE_LIBXML2
1634 error:
1635 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1636 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1637 		      "failed at opcodestat_dump()");
1638 	dumparg->result = ISC_R_FAILURE;
1639 	return;
1640 #endif /* ifdef HAVE_LIBXML2 */
1641 }
1642 
1643 static void
1644 rcodestat_dump(dns_rcode_t code, uint64_t val, void *arg) {
1645 	FILE *fp;
1646 	isc_buffer_t b;
1647 	char codebuf[64];
1648 	stats_dumparg_t *dumparg = arg;
1649 #ifdef HAVE_LIBXML2
1650 	void *writer;
1651 	int xmlrc;
1652 #endif /* ifdef HAVE_LIBXML2 */
1653 #ifdef HAVE_JSON_C
1654 	json_object *zoneobj, *obj;
1655 #endif /* ifdef HAVE_JSON_C */
1656 
1657 	isc_buffer_init(&b, codebuf, sizeof(codebuf) - 1);
1658 	dns_rcode_totext(code, &b);
1659 	codebuf[isc_buffer_usedlength(&b)] = '\0';
1660 
1661 	switch (dumparg->type) {
1662 	case isc_statsformat_file:
1663 		fp = dumparg->arg;
1664 		fprintf(fp, "%20" PRIu64 " %s\n", val, codebuf);
1665 		break;
1666 	case isc_statsformat_xml:
1667 #ifdef HAVE_LIBXML2
1668 		writer = dumparg->arg;
1669 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
1670 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
1671 						 ISC_XMLCHAR codebuf));
1672 		TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, val));
1673 		TRY0(xmlTextWriterEndElement(writer)); /* counter */
1674 #endif						       /* ifdef HAVE_LIBXML2 */
1675 		break;
1676 	case isc_statsformat_json:
1677 #ifdef HAVE_JSON_C
1678 		zoneobj = (json_object *)dumparg->arg;
1679 		obj = json_object_new_int64(val);
1680 		if (obj == NULL) {
1681 			return;
1682 		}
1683 		json_object_object_add(zoneobj, codebuf, obj);
1684 #endif /* ifdef HAVE_JSON_C */
1685 		break;
1686 	}
1687 	return;
1688 
1689 #ifdef HAVE_LIBXML2
1690 error:
1691 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1692 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1693 		      "failed at rcodestat_dump()");
1694 	dumparg->result = ISC_R_FAILURE;
1695 	return;
1696 #endif /* ifdef HAVE_LIBXML2 */
1697 }
1698 
1699 #if defined(EXTENDED_STATS)
1700 static void
1701 dnssecsignstat_dump(dns_keytag_t tag, uint64_t val, void *arg) {
1702 	FILE *fp;
1703 	char tagbuf[64];
1704 	stats_dumparg_t *dumparg = arg;
1705 #ifdef HAVE_LIBXML2
1706 	xmlTextWriterPtr writer;
1707 	int xmlrc;
1708 #endif /* ifdef HAVE_LIBXML2 */
1709 #ifdef HAVE_JSON_C
1710 	json_object *zoneobj, *obj;
1711 #endif /* ifdef HAVE_JSON_C */
1712 
1713 	snprintf(tagbuf, sizeof(tagbuf), "%u", tag);
1714 
1715 	switch (dumparg->type) {
1716 	case isc_statsformat_file:
1717 		fp = dumparg->arg;
1718 		fprintf(fp, "%20" PRIu64 " %s\n", val, tagbuf);
1719 		break;
1720 	case isc_statsformat_xml:
1721 #ifdef HAVE_LIBXML2
1722 		writer = dumparg->arg;
1723 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
1724 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
1725 						 ISC_XMLCHAR tagbuf));
1726 		TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, val));
1727 		TRY0(xmlTextWriterEndElement(writer)); /* counter */
1728 #endif						       /* ifdef HAVE_LIBXML2 */
1729 		break;
1730 	case isc_statsformat_json:
1731 #ifdef HAVE_JSON_C
1732 		zoneobj = (json_object *)dumparg->arg;
1733 		obj = json_object_new_int64(val);
1734 		if (obj == NULL) {
1735 			return;
1736 		}
1737 		json_object_object_add(zoneobj, tagbuf, obj);
1738 #endif /* ifdef HAVE_JSON_C */
1739 		break;
1740 	}
1741 	return;
1742 #ifdef HAVE_LIBXML2
1743 error:
1744 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1745 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1746 		      "failed at dnssecsignstat_dump()");
1747 	dumparg->result = ISC_R_FAILURE;
1748 	return;
1749 #endif /* ifdef HAVE_LIBXML2 */
1750 }
1751 #endif /* defined(EXTENDED_STATS) */
1752 
1753 #ifdef HAVE_LIBXML2
1754 /*
1755  * Which statistics to include when rendering to XML
1756  */
1757 #define STATS_XML_STATUS  0x00 /* display only common statistics */
1758 #define STATS_XML_SERVER  0x01
1759 #define STATS_XML_ZONES	  0x02
1760 #define STATS_XML_TASKS	  0x04
1761 #define STATS_XML_NET	  0x08
1762 #define STATS_XML_MEM	  0x10
1763 #define STATS_XML_TRAFFIC 0x20
1764 #define STATS_XML_ALL	  0xff
1765 
1766 static isc_result_t
1767 zone_xmlrender(dns_zone_t *zone, void *arg) {
1768 	isc_result_t result;
1769 	char buf[1024 + 32]; /* sufficiently large for zone name and class */
1770 	dns_rdataclass_t rdclass;
1771 	uint32_t serial;
1772 	xmlTextWriterPtr writer = arg;
1773 	dns_zonestat_level_t statlevel;
1774 	int xmlrc;
1775 	stats_dumparg_t dumparg;
1776 	const char *ztype;
1777 
1778 	statlevel = dns_zone_getstatlevel(zone);
1779 	if (statlevel == dns_zonestat_none) {
1780 		return (ISC_R_SUCCESS);
1781 	}
1782 
1783 	dumparg.type = isc_statsformat_xml;
1784 	dumparg.arg = writer;
1785 
1786 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "zone"));
1787 
1788 	dns_zone_nameonly(zone, buf, sizeof(buf));
1789 	TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
1790 					 ISC_XMLCHAR buf));
1791 
1792 	rdclass = dns_zone_getclass(zone);
1793 	dns_rdataclass_format(rdclass, buf, sizeof(buf));
1794 	TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "rdataclass",
1795 					 ISC_XMLCHAR buf));
1796 
1797 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "type"));
1798 	ztype = user_zonetype(zone);
1799 	if (ztype != NULL) {
1800 		TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR ztype));
1801 	} else {
1802 		TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "unknown"));
1803 	}
1804 	TRY0(xmlTextWriterEndElement(writer)); /* type */
1805 
1806 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "serial"));
1807 	if (dns_zone_getserial(zone, &serial) == ISC_R_SUCCESS) {
1808 		TRY0(xmlTextWriterWriteFormatString(writer, "%u", serial));
1809 	} else {
1810 		TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-"));
1811 	}
1812 	TRY0(xmlTextWriterEndElement(writer)); /* serial */
1813 
1814 	/*
1815 	 * Export zone timers to the statistics channel in XML format.  For
1816 	 * master zones, only include the loaded time.  For slave zones, also
1817 	 * include the expires and refresh times.
1818 	 */
1819 	isc_time_t timestamp;
1820 
1821 	result = dns_zone_getloadtime(zone, &timestamp);
1822 	if (result != ISC_R_SUCCESS) {
1823 		goto error;
1824 	}
1825 
1826 	isc_time_formatISO8601(&timestamp, buf, 64);
1827 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "loaded"));
1828 	TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR buf));
1829 	TRY0(xmlTextWriterEndElement(writer));
1830 
1831 	if (dns_zone_gettype(zone) == dns_zone_slave) {
1832 		result = dns_zone_getexpiretime(zone, &timestamp);
1833 		if (result != ISC_R_SUCCESS) {
1834 			goto error;
1835 		}
1836 		isc_time_formatISO8601(&timestamp, buf, 64);
1837 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "expires"));
1838 		TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR buf));
1839 		TRY0(xmlTextWriterEndElement(writer));
1840 
1841 		result = dns_zone_getrefreshtime(zone, &timestamp);
1842 		if (result != ISC_R_SUCCESS) {
1843 			goto error;
1844 		}
1845 		isc_time_formatISO8601(&timestamp, buf, 64);
1846 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "refresh"));
1847 		TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR buf));
1848 		TRY0(xmlTextWriterEndElement(writer));
1849 	}
1850 
1851 	if (statlevel == dns_zonestat_full) {
1852 		isc_stats_t *zonestats;
1853 		isc_stats_t *gluecachestats;
1854 		dns_stats_t *rcvquerystats;
1855 		dns_stats_t *dnssecsignstats;
1856 		uint64_t nsstat_values[ns_statscounter_max];
1857 		uint64_t gluecachestats_values[dns_gluecachestatscounter_max];
1858 
1859 		zonestats = dns_zone_getrequeststats(zone);
1860 		if (zonestats != NULL) {
1861 			TRY0(xmlTextWriterStartElement(writer,
1862 						       ISC_XMLCHAR "counters"));
1863 			TRY0(xmlTextWriterWriteAttribute(writer,
1864 							 ISC_XMLCHAR "type",
1865 							 ISC_XMLCHAR "rcode"));
1866 
1867 			result = dump_counters(zonestats, isc_statsformat_xml,
1868 					       writer, NULL, nsstats_xmldesc,
1869 					       ns_statscounter_max,
1870 					       nsstats_index, nsstat_values,
1871 					       ISC_STATSDUMP_VERBOSE);
1872 			if (result != ISC_R_SUCCESS) {
1873 				goto error;
1874 			}
1875 			/* counters type="rcode"*/
1876 			TRY0(xmlTextWriterEndElement(writer));
1877 		}
1878 
1879 		gluecachestats = dns_zone_getgluecachestats(zone);
1880 		if (gluecachestats != NULL) {
1881 			TRY0(xmlTextWriterStartElement(writer,
1882 						       ISC_XMLCHAR "counters"));
1883 			TRY0(xmlTextWriterWriteAttribute(
1884 				writer, ISC_XMLCHAR "type",
1885 				ISC_XMLCHAR "gluecache"));
1886 
1887 			result = dump_counters(
1888 				gluecachestats, isc_statsformat_xml, writer,
1889 				NULL, gluecachestats_xmldesc,
1890 				dns_gluecachestatscounter_max,
1891 				gluecachestats_index, gluecachestats_values,
1892 				ISC_STATSDUMP_VERBOSE);
1893 			if (result != ISC_R_SUCCESS) {
1894 				goto error;
1895 			}
1896 			/* counters type="rcode"*/
1897 			TRY0(xmlTextWriterEndElement(writer));
1898 		}
1899 
1900 		rcvquerystats = dns_zone_getrcvquerystats(zone);
1901 		if (rcvquerystats != NULL) {
1902 			TRY0(xmlTextWriterStartElement(writer,
1903 						       ISC_XMLCHAR "counters"));
1904 			TRY0(xmlTextWriterWriteAttribute(writer,
1905 							 ISC_XMLCHAR "type",
1906 							 ISC_XMLCHAR "qtype"));
1907 
1908 			dumparg.result = ISC_R_SUCCESS;
1909 			dns_rdatatypestats_dump(rcvquerystats, rdtypestat_dump,
1910 						&dumparg, 0);
1911 			if (dumparg.result != ISC_R_SUCCESS) {
1912 				goto error;
1913 			}
1914 
1915 			/* counters type="qtype"*/
1916 			TRY0(xmlTextWriterEndElement(writer));
1917 		}
1918 
1919 		dnssecsignstats = dns_zone_getdnssecsignstats(zone);
1920 		if (dnssecsignstats != NULL) {
1921 			/* counters type="dnssec-sign"*/
1922 			TRY0(xmlTextWriterStartElement(writer,
1923 						       ISC_XMLCHAR "counters"));
1924 			TRY0(xmlTextWriterWriteAttribute(
1925 				writer, ISC_XMLCHAR "type",
1926 				ISC_XMLCHAR "dnssec-sign"));
1927 
1928 			dumparg.result = ISC_R_SUCCESS;
1929 			dns_dnssecsignstats_dump(
1930 				dnssecsignstats, dns_dnssecsignstats_sign,
1931 				dnssecsignstat_dump, &dumparg, 0);
1932 			if (dumparg.result != ISC_R_SUCCESS) {
1933 				goto error;
1934 			}
1935 
1936 			/* counters type="dnssec-sign"*/
1937 			TRY0(xmlTextWriterEndElement(writer));
1938 
1939 			/* counters type="dnssec-refresh"*/
1940 			TRY0(xmlTextWriterStartElement(writer,
1941 						       ISC_XMLCHAR "counters"));
1942 			TRY0(xmlTextWriterWriteAttribute(
1943 				writer, ISC_XMLCHAR "type",
1944 				ISC_XMLCHAR "dnssec-refresh"));
1945 
1946 			dumparg.result = ISC_R_SUCCESS;
1947 			dns_dnssecsignstats_dump(
1948 				dnssecsignstats, dns_dnssecsignstats_refresh,
1949 				dnssecsignstat_dump, &dumparg, 0);
1950 			if (dumparg.result != ISC_R_SUCCESS) {
1951 				goto error;
1952 			}
1953 
1954 			/* counters type="dnssec-refresh"*/
1955 			TRY0(xmlTextWriterEndElement(writer));
1956 		}
1957 	}
1958 
1959 	TRY0(xmlTextWriterEndElement(writer)); /* zone */
1960 
1961 	return (ISC_R_SUCCESS);
1962 error:
1963 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1964 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1965 		      "Failed at zone_xmlrender()");
1966 	return (ISC_R_FAILURE);
1967 }
1968 
1969 static isc_result_t
1970 generatexml(named_server_t *server, uint32_t flags, int *buflen,
1971 	    xmlChar **buf) {
1972 	char boottime[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"];
1973 	char configtime[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"];
1974 	char nowstr[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"];
1975 	isc_time_t now;
1976 	xmlTextWriterPtr writer = NULL;
1977 	xmlDocPtr doc = NULL;
1978 	int xmlrc;
1979 	dns_view_t *view;
1980 	stats_dumparg_t dumparg;
1981 	dns_stats_t *cacherrstats;
1982 	uint64_t nsstat_values[ns_statscounter_max];
1983 	uint64_t resstat_values[dns_resstatscounter_max];
1984 	uint64_t adbstat_values[dns_adbstats_max];
1985 	uint64_t zonestat_values[dns_zonestatscounter_max];
1986 	uint64_t sockstat_values[isc_sockstatscounter_max];
1987 	uint64_t udpinsizestat_values[dns_sizecounter_in_max];
1988 	uint64_t udpoutsizestat_values[dns_sizecounter_out_max];
1989 	uint64_t tcpinsizestat_values[dns_sizecounter_in_max];
1990 	uint64_t tcpoutsizestat_values[dns_sizecounter_out_max];
1991 #ifdef HAVE_DNSTAP
1992 	uint64_t dnstapstat_values[dns_dnstapcounter_max];
1993 #endif /* ifdef HAVE_DNSTAP */
1994 	isc_result_t result;
1995 
1996 	isc_time_now(&now);
1997 	isc_time_formatISO8601ms(&named_g_boottime, boottime, sizeof boottime);
1998 	isc_time_formatISO8601ms(&named_g_configtime, configtime,
1999 				 sizeof configtime);
2000 	isc_time_formatISO8601ms(&now, nowstr, sizeof nowstr);
2001 
2002 	writer = xmlNewTextWriterDoc(&doc, 0);
2003 	if (writer == NULL) {
2004 		goto error;
2005 	}
2006 	TRY0(xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL));
2007 	TRY0(xmlTextWriterWritePI(writer, ISC_XMLCHAR "xml-stylesheet",
2008 				  ISC_XMLCHAR "type=\"text/xsl\" "
2009 					      "href=\"/bind9.xsl\""));
2010 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics"));
2011 	TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version",
2012 					 ISC_XMLCHAR "3.11"));
2013 
2014 	/* Set common fields for statistics dump */
2015 	dumparg.type = isc_statsformat_xml;
2016 	dumparg.arg = writer;
2017 
2018 	/* Render server information */
2019 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "server"));
2020 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "boot-time"));
2021 	TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR boottime));
2022 	TRY0(xmlTextWriterEndElement(writer)); /* boot-time */
2023 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "config-time"));
2024 	TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR configtime));
2025 	TRY0(xmlTextWriterEndElement(writer)); /* config-time */
2026 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "current-time"));
2027 	TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR nowstr));
2028 	TRY0(xmlTextWriterEndElement(writer)); /* current-time */
2029 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "version"));
2030 	TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR named_g_version));
2031 	TRY0(xmlTextWriterEndElement(writer)); /* version */
2032 
2033 	if ((flags & STATS_XML_SERVER) != 0) {
2034 		dumparg.result = ISC_R_SUCCESS;
2035 
2036 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2037 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2038 						 ISC_XMLCHAR "opcode"));
2039 
2040 		dns_opcodestats_dump(server->sctx->opcodestats, opcodestat_dump,
2041 				     &dumparg, ISC_STATSDUMP_VERBOSE);
2042 		if (dumparg.result != ISC_R_SUCCESS) {
2043 			goto error;
2044 		}
2045 
2046 		TRY0(xmlTextWriterEndElement(writer));
2047 
2048 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2049 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2050 						 ISC_XMLCHAR "rcode"));
2051 
2052 		dns_rcodestats_dump(server->sctx->rcodestats, rcodestat_dump,
2053 				    &dumparg, ISC_STATSDUMP_VERBOSE);
2054 		if (dumparg.result != ISC_R_SUCCESS) {
2055 			goto error;
2056 		}
2057 
2058 		TRY0(xmlTextWriterEndElement(writer));
2059 
2060 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2061 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2062 						 ISC_XMLCHAR "qtype"));
2063 
2064 		dumparg.result = ISC_R_SUCCESS;
2065 		dns_rdatatypestats_dump(server->sctx->rcvquerystats,
2066 					rdtypestat_dump, &dumparg, 0);
2067 		if (dumparg.result != ISC_R_SUCCESS) {
2068 			goto error;
2069 		}
2070 		TRY0(xmlTextWriterEndElement(writer)); /* counters */
2071 
2072 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2073 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2074 						 ISC_XMLCHAR "nsstat"));
2075 
2076 		result = dump_counters(ns_stats_get(server->sctx->nsstats),
2077 				       isc_statsformat_xml, writer, NULL,
2078 				       nsstats_xmldesc, ns_statscounter_max,
2079 				       nsstats_index, nsstat_values,
2080 				       ISC_STATSDUMP_VERBOSE);
2081 		if (result != ISC_R_SUCCESS) {
2082 			goto error;
2083 		}
2084 
2085 		TRY0(xmlTextWriterEndElement(writer)); /* /nsstat */
2086 
2087 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2088 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2089 						 ISC_XMLCHAR "zonestat"));
2090 
2091 		result = dump_counters(server->zonestats, isc_statsformat_xml,
2092 				       writer, NULL, zonestats_xmldesc,
2093 				       dns_zonestatscounter_max,
2094 				       zonestats_index, zonestat_values,
2095 				       ISC_STATSDUMP_VERBOSE);
2096 		if (result != ISC_R_SUCCESS) {
2097 			goto error;
2098 		}
2099 
2100 		TRY0(xmlTextWriterEndElement(writer)); /* /zonestat */
2101 
2102 		/*
2103 		 * Most of the common resolver statistics entries are 0, so
2104 		 * we don't use the verbose dump here.
2105 		 */
2106 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2107 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2108 						 ISC_XMLCHAR "resstat"));
2109 		result = dump_counters(
2110 			server->resolverstats, isc_statsformat_xml, writer,
2111 			NULL, resstats_xmldesc, dns_resstatscounter_max,
2112 			resstats_index, resstat_values, 0);
2113 		if (result != ISC_R_SUCCESS) {
2114 			goto error;
2115 		}
2116 		TRY0(xmlTextWriterEndElement(writer)); /* resstat */
2117 
2118 #ifdef HAVE_DNSTAP
2119 		if (server->dtenv != NULL) {
2120 			isc_stats_t *dnstapstats = NULL;
2121 			TRY0(xmlTextWriterStartElement(writer,
2122 						       ISC_XMLCHAR "counters"));
2123 			TRY0(xmlTextWriterWriteAttribute(writer,
2124 							 ISC_XMLCHAR "type",
2125 							 ISC_XMLCHAR "dnstap"));
2126 			dns_dt_getstats(named_g_server->dtenv, &dnstapstats);
2127 			result = dump_counters(
2128 				dnstapstats, isc_statsformat_xml, writer, NULL,
2129 				dnstapstats_xmldesc, dns_dnstapcounter_max,
2130 				dnstapstats_index, dnstapstat_values, 0);
2131 			isc_stats_detach(&dnstapstats);
2132 			if (result != ISC_R_SUCCESS) {
2133 				goto error;
2134 			}
2135 			TRY0(xmlTextWriterEndElement(writer)); /* dnstap */
2136 		}
2137 #endif /* ifdef HAVE_DNSTAP */
2138 	}
2139 
2140 	if ((flags & STATS_XML_NET) != 0) {
2141 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2142 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2143 						 ISC_XMLCHAR "sockstat"));
2144 
2145 		result = dump_counters(server->sockstats, isc_statsformat_xml,
2146 				       writer, NULL, sockstats_xmldesc,
2147 				       isc_sockstatscounter_max,
2148 				       sockstats_index, sockstat_values,
2149 				       ISC_STATSDUMP_VERBOSE);
2150 		if (result != ISC_R_SUCCESS) {
2151 			goto error;
2152 		}
2153 
2154 		TRY0(xmlTextWriterEndElement(writer)); /* /sockstat */
2155 	}
2156 	TRY0(xmlTextWriterEndElement(writer)); /* /server */
2157 
2158 	if ((flags & STATS_XML_TRAFFIC) != 0) {
2159 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "traffic"));
2160 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "ipv4"));
2161 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "udp"));
2162 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2163 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2164 						 ISC_XMLCHAR "request-size"));
2165 
2166 		result = dump_counters(
2167 			server->sctx->udpinstats4, isc_statsformat_xml, writer,
2168 			NULL, udpinsizestats_xmldesc, dns_sizecounter_in_max,
2169 			udpinsizestats_index, udpinsizestat_values, 0);
2170 		if (result != ISC_R_SUCCESS) {
2171 			goto error;
2172 		}
2173 
2174 		TRY0(xmlTextWriterEndElement(writer)); /* </counters> */
2175 
2176 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2177 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2178 						 ISC_XMLCHAR "response-size"));
2179 
2180 		result = dump_counters(
2181 			server->sctx->udpoutstats4, isc_statsformat_xml, writer,
2182 			NULL, udpoutsizestats_xmldesc, dns_sizecounter_out_max,
2183 			udpoutsizestats_index, udpoutsizestat_values, 0);
2184 		if (result != ISC_R_SUCCESS) {
2185 			goto error;
2186 		}
2187 
2188 		TRY0(xmlTextWriterEndElement(writer)); /* </counters> */
2189 		TRY0(xmlTextWriterEndElement(writer)); /* </udp> */
2190 
2191 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tcp"));
2192 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2193 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2194 						 ISC_XMLCHAR "request-size"));
2195 
2196 		result = dump_counters(
2197 			server->sctx->tcpinstats4, isc_statsformat_xml, writer,
2198 			NULL, tcpinsizestats_xmldesc, dns_sizecounter_in_max,
2199 			tcpinsizestats_index, tcpinsizestat_values, 0);
2200 		if (result != ISC_R_SUCCESS) {
2201 			goto error;
2202 		}
2203 
2204 		TRY0(xmlTextWriterEndElement(writer)); /* </counters> */
2205 
2206 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2207 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2208 						 ISC_XMLCHAR "response-size"));
2209 
2210 		result = dump_counters(
2211 			server->sctx->tcpoutstats4, isc_statsformat_xml, writer,
2212 			NULL, tcpoutsizestats_xmldesc, dns_sizecounter_out_max,
2213 			tcpoutsizestats_index, tcpoutsizestat_values, 0);
2214 		if (result != ISC_R_SUCCESS) {
2215 			goto error;
2216 		}
2217 
2218 		TRY0(xmlTextWriterEndElement(writer)); /* </counters> */
2219 		TRY0(xmlTextWriterEndElement(writer)); /* </tcp> */
2220 		TRY0(xmlTextWriterEndElement(writer)); /* </ipv4> */
2221 
2222 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "ipv6"));
2223 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "udp"));
2224 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2225 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2226 						 ISC_XMLCHAR "request-size"));
2227 
2228 		result = dump_counters(
2229 			server->sctx->udpinstats6, isc_statsformat_xml, writer,
2230 			NULL, udpinsizestats_xmldesc, dns_sizecounter_in_max,
2231 			udpinsizestats_index, udpinsizestat_values, 0);
2232 		if (result != ISC_R_SUCCESS) {
2233 			goto error;
2234 		}
2235 
2236 		TRY0(xmlTextWriterEndElement(writer)); /* </counters> */
2237 
2238 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2239 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2240 						 ISC_XMLCHAR "response-size"));
2241 
2242 		result = dump_counters(
2243 			server->sctx->udpoutstats6, isc_statsformat_xml, writer,
2244 			NULL, udpoutsizestats_xmldesc, dns_sizecounter_out_max,
2245 			udpoutsizestats_index, udpoutsizestat_values, 0);
2246 		if (result != ISC_R_SUCCESS) {
2247 			goto error;
2248 		}
2249 
2250 		TRY0(xmlTextWriterEndElement(writer)); /* </counters> */
2251 		TRY0(xmlTextWriterEndElement(writer)); /* </udp> */
2252 
2253 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tcp"));
2254 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2255 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2256 						 ISC_XMLCHAR "request-size"));
2257 
2258 		result = dump_counters(
2259 			server->sctx->tcpinstats6, isc_statsformat_xml, writer,
2260 			NULL, tcpinsizestats_xmldesc, dns_sizecounter_in_max,
2261 			tcpinsizestats_index, tcpinsizestat_values, 0);
2262 		if (result != ISC_R_SUCCESS) {
2263 			goto error;
2264 		}
2265 
2266 		TRY0(xmlTextWriterEndElement(writer)); /* </counters> */
2267 
2268 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2269 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2270 						 ISC_XMLCHAR "response-size"));
2271 
2272 		result = dump_counters(
2273 			server->sctx->tcpoutstats6, isc_statsformat_xml, writer,
2274 			NULL, tcpoutsizestats_xmldesc, dns_sizecounter_out_max,
2275 			tcpoutsizestats_index, tcpoutsizestat_values, 0);
2276 		if (result != ISC_R_SUCCESS) {
2277 			goto error;
2278 		}
2279 
2280 		TRY0(xmlTextWriterEndElement(writer)); /* </counters> */
2281 		TRY0(xmlTextWriterEndElement(writer)); /* </tcp> */
2282 		TRY0(xmlTextWriterEndElement(writer)); /* </ipv6> */
2283 		TRY0(xmlTextWriterEndElement(writer)); /* </traffic> */
2284 	}
2285 
2286 	/*
2287 	 * Render views.  For each view we know of, call its
2288 	 * rendering function.
2289 	 */
2290 	view = ISC_LIST_HEAD(server->viewlist);
2291 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "views"));
2292 	while (view != NULL &&
2293 	       ((flags & (STATS_XML_SERVER | STATS_XML_ZONES)) != 0)) {
2294 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "view"));
2295 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
2296 						 ISC_XMLCHAR view->name));
2297 
2298 		if ((flags & STATS_XML_ZONES) != 0) {
2299 			TRY0(xmlTextWriterStartElement(writer,
2300 						       ISC_XMLCHAR "zones"));
2301 			result = dns_zt_apply(view->zonetable, true, NULL,
2302 					      zone_xmlrender, writer);
2303 			if (result != ISC_R_SUCCESS) {
2304 				goto error;
2305 			}
2306 			TRY0(xmlTextWriterEndElement(writer)); /* /zones */
2307 		}
2308 
2309 		if ((flags & STATS_XML_SERVER) == 0) {
2310 			TRY0(xmlTextWriterEndElement(writer)); /* /view */
2311 			view = ISC_LIST_NEXT(view, link);
2312 			continue;
2313 		}
2314 
2315 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2316 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2317 						 ISC_XMLCHAR "resqtype"));
2318 
2319 		if (view->resquerystats != NULL) {
2320 			dumparg.result = ISC_R_SUCCESS;
2321 			dns_rdatatypestats_dump(view->resquerystats,
2322 						rdtypestat_dump, &dumparg, 0);
2323 			if (dumparg.result != ISC_R_SUCCESS) {
2324 				goto error;
2325 			}
2326 		}
2327 		TRY0(xmlTextWriterEndElement(writer));
2328 
2329 		/* <resstats> */
2330 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2331 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2332 						 ISC_XMLCHAR "resstats"));
2333 		if (view->resstats != NULL) {
2334 			result = dump_counters(
2335 				view->resstats, isc_statsformat_xml, writer,
2336 				NULL, resstats_xmldesc, dns_resstatscounter_max,
2337 				resstats_index, resstat_values,
2338 				ISC_STATSDUMP_VERBOSE);
2339 			if (result != ISC_R_SUCCESS) {
2340 				goto error;
2341 			}
2342 		}
2343 		TRY0(xmlTextWriterEndElement(writer)); /* </resstats> */
2344 
2345 		cacherrstats = dns_db_getrrsetstats(view->cachedb);
2346 		if (cacherrstats != NULL) {
2347 			TRY0(xmlTextWriterStartElement(writer,
2348 						       ISC_XMLCHAR "cache"));
2349 			TRY0(xmlTextWriterWriteAttribute(
2350 				writer, ISC_XMLCHAR "name",
2351 				ISC_XMLCHAR dns_cache_getname(view->cache)));
2352 			dumparg.result = ISC_R_SUCCESS;
2353 			dns_rdatasetstats_dump(cacherrstats, rdatasetstats_dump,
2354 					       &dumparg, 0);
2355 			if (dumparg.result != ISC_R_SUCCESS) {
2356 				goto error;
2357 			}
2358 			TRY0(xmlTextWriterEndElement(writer)); /* cache */
2359 		}
2360 
2361 		/* <adbstats> */
2362 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2363 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2364 						 ISC_XMLCHAR "adbstat"));
2365 		if (view->adbstats != NULL) {
2366 			result = dump_counters(
2367 				view->adbstats, isc_statsformat_xml, writer,
2368 				NULL, adbstats_xmldesc, dns_adbstats_max,
2369 				adbstats_index, adbstat_values,
2370 				ISC_STATSDUMP_VERBOSE);
2371 			if (result != ISC_R_SUCCESS) {
2372 				goto error;
2373 			}
2374 		}
2375 		TRY0(xmlTextWriterEndElement(writer)); /* </adbstats> */
2376 
2377 		/* <cachestats> */
2378 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
2379 		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
2380 						 ISC_XMLCHAR "cachestats"));
2381 		TRY0(dns_cache_renderxml(view->cache, writer));
2382 		TRY0(xmlTextWriterEndElement(writer)); /* </cachestats> */
2383 
2384 		TRY0(xmlTextWriterEndElement(writer)); /* view */
2385 
2386 		view = ISC_LIST_NEXT(view, link);
2387 	}
2388 	TRY0(xmlTextWriterEndElement(writer)); /* /views */
2389 
2390 	if ((flags & STATS_XML_NET) != 0) {
2391 		TRY0(xmlTextWriterStartElement(writer,
2392 					       ISC_XMLCHAR "socketmgr"));
2393 		TRY0(isc_socketmgr_renderxml(named_g_socketmgr, writer));
2394 		TRY0(xmlTextWriterEndElement(writer)); /* /socketmgr */
2395 	}
2396 
2397 	if ((flags & STATS_XML_TASKS) != 0) {
2398 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "taskmgr"));
2399 		TRY0(isc_taskmgr_renderxml(named_g_taskmgr, writer));
2400 		TRY0(xmlTextWriterEndElement(writer)); /* /taskmgr */
2401 	}
2402 
2403 	if ((flags & STATS_XML_MEM) != 0) {
2404 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "memory"));
2405 		TRY0(isc_mem_renderxml(writer));
2406 		TRY0(xmlTextWriterEndElement(writer)); /* /memory */
2407 	}
2408 
2409 	TRY0(xmlTextWriterEndElement(writer)); /* /statistics */
2410 	TRY0(xmlTextWriterEndDocument(writer));
2411 
2412 	xmlDocDumpFormatMemoryEnc(doc, buf, buflen, "UTF-8", 0);
2413 	if (*buf == NULL) {
2414 		goto error;
2415 	}
2416 
2417 	xmlFreeTextWriter(writer);
2418 	xmlFreeDoc(doc);
2419 	return (ISC_R_SUCCESS);
2420 
2421 error:
2422 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2423 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2424 		      "failed generating XML response");
2425 	if (writer != NULL) {
2426 		xmlFreeTextWriter(writer);
2427 	}
2428 	if (doc != NULL) {
2429 		xmlFreeDoc(doc);
2430 	}
2431 	return (ISC_R_FAILURE);
2432 }
2433 
2434 static void
2435 wrap_xmlfree(isc_buffer_t *buffer, void *arg) {
2436 	UNUSED(arg);
2437 
2438 	xmlFree(isc_buffer_base(buffer));
2439 }
2440 
2441 static isc_result_t
2442 render_xml(uint32_t flags, const char *url, isc_httpdurl_t *urlinfo,
2443 	   const char *querystring, const char *headers, void *arg,
2444 	   unsigned int *retcode, const char **retmsg, const char **mimetype,
2445 	   isc_buffer_t *b, isc_httpdfree_t **freecb, void **freecb_args) {
2446 	unsigned char *msg = NULL;
2447 	int msglen;
2448 	named_server_t *server = arg;
2449 	isc_result_t result;
2450 
2451 	UNUSED(url);
2452 	UNUSED(urlinfo);
2453 	UNUSED(headers);
2454 	UNUSED(querystring);
2455 
2456 	result = generatexml(server, flags, &msglen, &msg);
2457 
2458 	if (result == ISC_R_SUCCESS) {
2459 		*retcode = 200;
2460 		*retmsg = "OK";
2461 		*mimetype = "text/xml";
2462 		isc_buffer_reinit(b, msg, msglen);
2463 		isc_buffer_add(b, msglen);
2464 		*freecb = wrap_xmlfree;
2465 		*freecb_args = NULL;
2466 	} else {
2467 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2468 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2469 			      "failed at rendering XML()");
2470 	}
2471 
2472 	return (result);
2473 }
2474 
2475 static isc_result_t
2476 render_xml_all(const char *url, isc_httpdurl_t *urlinfo,
2477 	       const char *querystring, const char *headers, void *arg,
2478 	       unsigned int *retcode, const char **retmsg,
2479 	       const char **mimetype, isc_buffer_t *b, isc_httpdfree_t **freecb,
2480 	       void **freecb_args) {
2481 	return (render_xml(STATS_XML_ALL, url, urlinfo, querystring, headers,
2482 			   arg, retcode, retmsg, mimetype, b, freecb,
2483 			   freecb_args));
2484 }
2485 
2486 static isc_result_t
2487 render_xml_status(const char *url, isc_httpdurl_t *urlinfo,
2488 		  const char *querystring, const char *headers, void *arg,
2489 		  unsigned int *retcode, const char **retmsg,
2490 		  const char **mimetype, isc_buffer_t *b,
2491 		  isc_httpdfree_t **freecb, void **freecb_args) {
2492 	return (render_xml(STATS_XML_STATUS, url, urlinfo, querystring, headers,
2493 			   arg, retcode, retmsg, mimetype, b, freecb,
2494 			   freecb_args));
2495 }
2496 
2497 static isc_result_t
2498 render_xml_server(const char *url, isc_httpdurl_t *urlinfo,
2499 		  const char *querystring, const char *headers, void *arg,
2500 		  unsigned int *retcode, const char **retmsg,
2501 		  const char **mimetype, isc_buffer_t *b,
2502 		  isc_httpdfree_t **freecb, void **freecb_args) {
2503 	return (render_xml(STATS_XML_SERVER, url, urlinfo, querystring, headers,
2504 			   arg, retcode, retmsg, mimetype, b, freecb,
2505 			   freecb_args));
2506 }
2507 
2508 static isc_result_t
2509 render_xml_zones(const char *url, isc_httpdurl_t *urlinfo,
2510 		 const char *querystring, const char *headers, void *arg,
2511 		 unsigned int *retcode, const char **retmsg,
2512 		 const char **mimetype, isc_buffer_t *b,
2513 		 isc_httpdfree_t **freecb, void **freecb_args) {
2514 	return (render_xml(STATS_XML_ZONES, url, urlinfo, querystring, headers,
2515 			   arg, retcode, retmsg, mimetype, b, freecb,
2516 			   freecb_args));
2517 }
2518 
2519 static isc_result_t
2520 render_xml_net(const char *url, isc_httpdurl_t *urlinfo,
2521 	       const char *querystring, const char *headers, void *arg,
2522 	       unsigned int *retcode, const char **retmsg,
2523 	       const char **mimetype, isc_buffer_t *b, isc_httpdfree_t **freecb,
2524 	       void **freecb_args) {
2525 	return (render_xml(STATS_XML_NET, url, urlinfo, querystring, headers,
2526 			   arg, retcode, retmsg, mimetype, b, freecb,
2527 			   freecb_args));
2528 }
2529 
2530 static isc_result_t
2531 render_xml_tasks(const char *url, isc_httpdurl_t *urlinfo,
2532 		 const char *querystring, const char *headers, void *arg,
2533 		 unsigned int *retcode, const char **retmsg,
2534 		 const char **mimetype, isc_buffer_t *b,
2535 		 isc_httpdfree_t **freecb, void **freecb_args) {
2536 	return (render_xml(STATS_XML_TASKS, url, urlinfo, querystring, headers,
2537 			   arg, retcode, retmsg, mimetype, b, freecb,
2538 			   freecb_args));
2539 }
2540 
2541 static isc_result_t
2542 render_xml_mem(const char *url, isc_httpdurl_t *urlinfo,
2543 	       const char *querystring, const char *headers, void *arg,
2544 	       unsigned int *retcode, const char **retmsg,
2545 	       const char **mimetype, isc_buffer_t *b, isc_httpdfree_t **freecb,
2546 	       void **freecb_args) {
2547 	return (render_xml(STATS_XML_MEM, url, urlinfo, querystring, headers,
2548 			   arg, retcode, retmsg, mimetype, b, freecb,
2549 			   freecb_args));
2550 }
2551 
2552 static isc_result_t
2553 render_xml_traffic(const char *url, isc_httpdurl_t *urlinfo,
2554 		   const char *querystring, const char *headers, void *arg,
2555 		   unsigned int *retcode, const char **retmsg,
2556 		   const char **mimetype, isc_buffer_t *b,
2557 		   isc_httpdfree_t **freecb, void **freecb_args) {
2558 	return (render_xml(STATS_XML_TRAFFIC, url, urlinfo, querystring,
2559 			   headers, arg, retcode, retmsg, mimetype, b, freecb,
2560 			   freecb_args));
2561 }
2562 
2563 #endif /* HAVE_LIBXML2 */
2564 
2565 #ifdef HAVE_JSON_C
2566 /*
2567  * Which statistics to include when rendering to JSON
2568  */
2569 #define STATS_JSON_STATUS  0x00 /* display only common statistics */
2570 #define STATS_JSON_SERVER  0x01
2571 #define STATS_JSON_ZONES   0x02
2572 #define STATS_JSON_TASKS   0x04
2573 #define STATS_JSON_NET	   0x08
2574 #define STATS_JSON_MEM	   0x10
2575 #define STATS_JSON_TRAFFIC 0x20
2576 #define STATS_JSON_ALL	   0xff
2577 
2578 #define CHECK(m)                             \
2579 	do {                                 \
2580 		result = (m);                \
2581 		if (result != ISC_R_SUCCESS) \
2582 			goto error;          \
2583 	} while (0)
2584 
2585 #define CHECKMEM(m)                              \
2586 	do {                                     \
2587 		if (m == NULL) {                 \
2588 			result = ISC_R_NOMEMORY; \
2589 			goto error;              \
2590 		}                                \
2591 	} while (0)
2592 
2593 static void
2594 wrap_jsonfree(isc_buffer_t *buffer, void *arg) {
2595 	json_object_put(isc_buffer_base(buffer));
2596 	if (arg != NULL) {
2597 		json_object_put((json_object *)arg);
2598 	}
2599 }
2600 
2601 static json_object *
2602 addzone(char *name, char *classname, const char *ztype, uint32_t serial,
2603 	bool add_serial) {
2604 	json_object *node = json_object_new_object();
2605 
2606 	if (node == NULL) {
2607 		return (NULL);
2608 	}
2609 
2610 	json_object_object_add(node, "name", json_object_new_string(name));
2611 	json_object_object_add(node, "class",
2612 			       json_object_new_string(classname));
2613 	if (add_serial) {
2614 		json_object_object_add(node, "serial",
2615 				       json_object_new_int64(serial));
2616 	}
2617 	if (ztype != NULL) {
2618 		json_object_object_add(node, "type",
2619 				       json_object_new_string(ztype));
2620 	}
2621 	return (node);
2622 }
2623 
2624 static isc_result_t
2625 zone_jsonrender(dns_zone_t *zone, void *arg) {
2626 	isc_result_t result = ISC_R_SUCCESS;
2627 	char buf[1024 + 32]; /* sufficiently large for zone name and class */
2628 	char classbuf[64];   /* sufficiently large for class */
2629 	char *zone_name_only = NULL;
2630 	char *class_only = NULL;
2631 	dns_rdataclass_t rdclass;
2632 	uint32_t serial;
2633 	json_object *zonearray = (json_object *)arg;
2634 	json_object *zoneobj = NULL;
2635 	dns_zonestat_level_t statlevel;
2636 
2637 	statlevel = dns_zone_getstatlevel(zone);
2638 	if (statlevel == dns_zonestat_none) {
2639 		return (ISC_R_SUCCESS);
2640 	}
2641 
2642 	dns_zone_nameonly(zone, buf, sizeof(buf));
2643 	zone_name_only = buf;
2644 
2645 	rdclass = dns_zone_getclass(zone);
2646 	dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf));
2647 	class_only = classbuf;
2648 
2649 	if (dns_zone_getserial(zone, &serial) != ISC_R_SUCCESS) {
2650 		zoneobj = addzone(zone_name_only, class_only,
2651 				  user_zonetype(zone), 0, false);
2652 	} else {
2653 		zoneobj = addzone(zone_name_only, class_only,
2654 				  user_zonetype(zone), serial, true);
2655 	}
2656 
2657 	if (zoneobj == NULL) {
2658 		return (ISC_R_NOMEMORY);
2659 	}
2660 
2661 	/*
2662 	 * Export zone timers to the statistics channel in JSON format.  For
2663 	 * master zones, only include the loaded time.  For slave zones, also
2664 	 * include the expires and refresh times.
2665 	 */
2666 
2667 	isc_time_t timestamp;
2668 
2669 	result = dns_zone_getloadtime(zone, &timestamp);
2670 	if (result != ISC_R_SUCCESS) {
2671 		goto error;
2672 	}
2673 
2674 	isc_time_formatISO8601(&timestamp, buf, 64);
2675 	json_object_object_add(zoneobj, "loaded", json_object_new_string(buf));
2676 
2677 	if (dns_zone_gettype(zone) == dns_zone_slave) {
2678 		result = dns_zone_getexpiretime(zone, &timestamp);
2679 		if (result != ISC_R_SUCCESS) {
2680 			goto error;
2681 		}
2682 		isc_time_formatISO8601(&timestamp, buf, 64);
2683 		json_object_object_add(zoneobj, "expires",
2684 				       json_object_new_string(buf));
2685 
2686 		result = dns_zone_getrefreshtime(zone, &timestamp);
2687 		if (result != ISC_R_SUCCESS) {
2688 			goto error;
2689 		}
2690 		isc_time_formatISO8601(&timestamp, buf, 64);
2691 		json_object_object_add(zoneobj, "refresh",
2692 				       json_object_new_string(buf));
2693 	}
2694 
2695 	if (statlevel == dns_zonestat_full) {
2696 		isc_stats_t *zonestats;
2697 		isc_stats_t *gluecachestats;
2698 		dns_stats_t *rcvquerystats;
2699 		dns_stats_t *dnssecsignstats;
2700 		uint64_t nsstat_values[ns_statscounter_max];
2701 		uint64_t gluecachestats_values[dns_gluecachestatscounter_max];
2702 
2703 		zonestats = dns_zone_getrequeststats(zone);
2704 		if (zonestats != NULL) {
2705 			json_object *counters = json_object_new_object();
2706 			if (counters == NULL) {
2707 				result = ISC_R_NOMEMORY;
2708 				goto error;
2709 			}
2710 
2711 			result = dump_counters(zonestats, isc_statsformat_json,
2712 					       counters, NULL, nsstats_xmldesc,
2713 					       ns_statscounter_max,
2714 					       nsstats_index, nsstat_values, 0);
2715 			if (result != ISC_R_SUCCESS) {
2716 				json_object_put(counters);
2717 				goto error;
2718 			}
2719 
2720 			if (json_object_get_object(counters)->count != 0) {
2721 				json_object_object_add(zoneobj, "rcodes",
2722 						       counters);
2723 			} else {
2724 				json_object_put(counters);
2725 			}
2726 		}
2727 
2728 		gluecachestats = dns_zone_getgluecachestats(zone);
2729 		if (gluecachestats != NULL) {
2730 			json_object *counters = json_object_new_object();
2731 			if (counters == NULL) {
2732 				result = ISC_R_NOMEMORY;
2733 				goto error;
2734 			}
2735 
2736 			result = dump_counters(
2737 				gluecachestats, isc_statsformat_json, counters,
2738 				NULL, gluecachestats_xmldesc,
2739 				dns_gluecachestatscounter_max,
2740 				gluecachestats_index, gluecachestats_values, 0);
2741 			if (result != ISC_R_SUCCESS) {
2742 				json_object_put(counters);
2743 				goto error;
2744 			}
2745 
2746 			if (json_object_get_object(counters)->count != 0) {
2747 				json_object_object_add(zoneobj, "gluecache",
2748 						       counters);
2749 			} else {
2750 				json_object_put(counters);
2751 			}
2752 		}
2753 
2754 		rcvquerystats = dns_zone_getrcvquerystats(zone);
2755 		if (rcvquerystats != NULL) {
2756 			stats_dumparg_t dumparg;
2757 			json_object *counters = json_object_new_object();
2758 			CHECKMEM(counters);
2759 
2760 			dumparg.type = isc_statsformat_json;
2761 			dumparg.arg = counters;
2762 			dumparg.result = ISC_R_SUCCESS;
2763 			dns_rdatatypestats_dump(rcvquerystats, rdtypestat_dump,
2764 						&dumparg, 0);
2765 			if (dumparg.result != ISC_R_SUCCESS) {
2766 				json_object_put(counters);
2767 				goto error;
2768 			}
2769 
2770 			if (json_object_get_object(counters)->count != 0) {
2771 				json_object_object_add(zoneobj, "qtypes",
2772 						       counters);
2773 			} else {
2774 				json_object_put(counters);
2775 			}
2776 		}
2777 
2778 		dnssecsignstats = dns_zone_getdnssecsignstats(zone);
2779 		if (dnssecsignstats != NULL) {
2780 			stats_dumparg_t dumparg;
2781 			json_object *sign_counters = json_object_new_object();
2782 			CHECKMEM(sign_counters);
2783 
2784 			dumparg.type = isc_statsformat_json;
2785 			dumparg.arg = sign_counters;
2786 			dumparg.result = ISC_R_SUCCESS;
2787 			dns_dnssecsignstats_dump(
2788 				dnssecsignstats, dns_dnssecsignstats_sign,
2789 				dnssecsignstat_dump, &dumparg, 0);
2790 			if (dumparg.result != ISC_R_SUCCESS) {
2791 				json_object_put(sign_counters);
2792 				goto error;
2793 			}
2794 
2795 			if (json_object_get_object(sign_counters)->count != 0) {
2796 				json_object_object_add(zoneobj, "dnssec-sign",
2797 						       sign_counters);
2798 			} else {
2799 				json_object_put(sign_counters);
2800 			}
2801 
2802 			json_object *refresh_counters =
2803 				json_object_new_object();
2804 			CHECKMEM(refresh_counters);
2805 
2806 			dumparg.type = isc_statsformat_json;
2807 			dumparg.arg = refresh_counters;
2808 			dumparg.result = ISC_R_SUCCESS;
2809 			dns_dnssecsignstats_dump(
2810 				dnssecsignstats, dns_dnssecsignstats_refresh,
2811 				dnssecsignstat_dump, &dumparg, 0);
2812 			if (dumparg.result != ISC_R_SUCCESS) {
2813 				json_object_put(refresh_counters);
2814 				goto error;
2815 			}
2816 
2817 			if (json_object_get_object(refresh_counters)->count !=
2818 			    0) {
2819 				json_object_object_add(zoneobj,
2820 						       "dnssec-refresh",
2821 						       refresh_counters);
2822 			} else {
2823 				json_object_put(refresh_counters);
2824 			}
2825 		}
2826 	}
2827 
2828 	json_object_array_add(zonearray, zoneobj);
2829 	zoneobj = NULL;
2830 	result = ISC_R_SUCCESS;
2831 
2832 error:
2833 	if (zoneobj != NULL) {
2834 		json_object_put(zoneobj);
2835 	}
2836 	return (result);
2837 }
2838 
2839 static isc_result_t
2840 generatejson(named_server_t *server, size_t *msglen, const char **msg,
2841 	     json_object **rootp, uint32_t flags) {
2842 	dns_view_t *view;
2843 	isc_result_t result = ISC_R_SUCCESS;
2844 	json_object *bindstats, *viewlist, *counters, *obj;
2845 	json_object *traffic = NULL;
2846 	json_object *udpreq4 = NULL, *udpresp4 = NULL;
2847 	json_object *tcpreq4 = NULL, *tcpresp4 = NULL;
2848 	json_object *udpreq6 = NULL, *udpresp6 = NULL;
2849 	json_object *tcpreq6 = NULL, *tcpresp6 = NULL;
2850 	uint64_t nsstat_values[ns_statscounter_max];
2851 	uint64_t resstat_values[dns_resstatscounter_max];
2852 	uint64_t adbstat_values[dns_adbstats_max];
2853 	uint64_t zonestat_values[dns_zonestatscounter_max];
2854 	uint64_t sockstat_values[isc_sockstatscounter_max];
2855 	uint64_t udpinsizestat_values[dns_sizecounter_in_max];
2856 	uint64_t udpoutsizestat_values[dns_sizecounter_out_max];
2857 	uint64_t tcpinsizestat_values[dns_sizecounter_in_max];
2858 	uint64_t tcpoutsizestat_values[dns_sizecounter_out_max];
2859 #ifdef HAVE_DNSTAP
2860 	uint64_t dnstapstat_values[dns_dnstapcounter_max];
2861 #endif /* ifdef HAVE_DNSTAP */
2862 	stats_dumparg_t dumparg;
2863 	char boottime[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"];
2864 	char configtime[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"];
2865 	char nowstr[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"];
2866 	isc_time_t now;
2867 
2868 	REQUIRE(msglen != NULL);
2869 	REQUIRE(msg != NULL && *msg == NULL);
2870 	REQUIRE(rootp == NULL || *rootp == NULL);
2871 
2872 	bindstats = json_object_new_object();
2873 	if (bindstats == NULL) {
2874 		return (ISC_R_NOMEMORY);
2875 	}
2876 
2877 	/*
2878 	 * These statistics are included no matter which URL we use.
2879 	 */
2880 	obj = json_object_new_string("1.5");
2881 	CHECKMEM(obj);
2882 	json_object_object_add(bindstats, "json-stats-version", obj);
2883 
2884 	isc_time_now(&now);
2885 	isc_time_formatISO8601ms(&named_g_boottime, boottime, sizeof(boottime));
2886 	isc_time_formatISO8601ms(&named_g_configtime, configtime,
2887 				 sizeof configtime);
2888 	isc_time_formatISO8601ms(&now, nowstr, sizeof(nowstr));
2889 
2890 	obj = json_object_new_string(boottime);
2891 	CHECKMEM(obj);
2892 	json_object_object_add(bindstats, "boot-time", obj);
2893 
2894 	obj = json_object_new_string(configtime);
2895 	CHECKMEM(obj);
2896 	json_object_object_add(bindstats, "config-time", obj);
2897 
2898 	obj = json_object_new_string(nowstr);
2899 	CHECKMEM(obj);
2900 	json_object_object_add(bindstats, "current-time", obj);
2901 	obj = json_object_new_string(named_g_version);
2902 	CHECKMEM(obj);
2903 	json_object_object_add(bindstats, "version", obj);
2904 
2905 	if ((flags & STATS_JSON_SERVER) != 0) {
2906 		/* OPCODE counters */
2907 		counters = json_object_new_object();
2908 
2909 		dumparg.result = ISC_R_SUCCESS;
2910 		dumparg.type = isc_statsformat_json;
2911 		dumparg.arg = counters;
2912 
2913 		dns_opcodestats_dump(server->sctx->opcodestats, opcodestat_dump,
2914 				     &dumparg, ISC_STATSDUMP_VERBOSE);
2915 		if (dumparg.result != ISC_R_SUCCESS) {
2916 			json_object_put(counters);
2917 			goto error;
2918 		}
2919 
2920 		if (json_object_get_object(counters)->count != 0) {
2921 			json_object_object_add(bindstats, "opcodes", counters);
2922 		} else {
2923 			json_object_put(counters);
2924 		}
2925 
2926 		/* OPCODE counters */
2927 		counters = json_object_new_object();
2928 
2929 		dumparg.type = isc_statsformat_json;
2930 		dumparg.arg = counters;
2931 
2932 		dns_rcodestats_dump(server->sctx->rcodestats, rcodestat_dump,
2933 				    &dumparg, ISC_STATSDUMP_VERBOSE);
2934 		if (dumparg.result != ISC_R_SUCCESS) {
2935 			json_object_put(counters);
2936 			goto error;
2937 		}
2938 
2939 		if (json_object_get_object(counters)->count != 0) {
2940 			json_object_object_add(bindstats, "rcodes", counters);
2941 		} else {
2942 			json_object_put(counters);
2943 		}
2944 
2945 		/* QTYPE counters */
2946 		counters = json_object_new_object();
2947 
2948 		dumparg.result = ISC_R_SUCCESS;
2949 		dumparg.arg = counters;
2950 
2951 		dns_rdatatypestats_dump(server->sctx->rcvquerystats,
2952 					rdtypestat_dump, &dumparg, 0);
2953 		if (dumparg.result != ISC_R_SUCCESS) {
2954 			json_object_put(counters);
2955 			goto error;
2956 		}
2957 
2958 		if (json_object_get_object(counters)->count != 0) {
2959 			json_object_object_add(bindstats, "qtypes", counters);
2960 		} else {
2961 			json_object_put(counters);
2962 		}
2963 
2964 		/* server stat counters */
2965 		counters = json_object_new_object();
2966 
2967 		dumparg.result = ISC_R_SUCCESS;
2968 		dumparg.arg = counters;
2969 
2970 		result = dump_counters(ns_stats_get(server->sctx->nsstats),
2971 				       isc_statsformat_json, counters, NULL,
2972 				       nsstats_xmldesc, ns_statscounter_max,
2973 				       nsstats_index, nsstat_values, 0);
2974 		if (result != ISC_R_SUCCESS) {
2975 			json_object_put(counters);
2976 			goto error;
2977 		}
2978 
2979 		if (json_object_get_object(counters)->count != 0) {
2980 			json_object_object_add(bindstats, "nsstats", counters);
2981 		} else {
2982 			json_object_put(counters);
2983 		}
2984 
2985 		/* zone stat counters */
2986 		counters = json_object_new_object();
2987 
2988 		dumparg.result = ISC_R_SUCCESS;
2989 		dumparg.arg = counters;
2990 
2991 		result = dump_counters(server->zonestats, isc_statsformat_json,
2992 				       counters, NULL, zonestats_xmldesc,
2993 				       dns_zonestatscounter_max,
2994 				       zonestats_index, zonestat_values, 0);
2995 		if (result != ISC_R_SUCCESS) {
2996 			json_object_put(counters);
2997 			goto error;
2998 		}
2999 
3000 		if (json_object_get_object(counters)->count != 0) {
3001 			json_object_object_add(bindstats, "zonestats",
3002 					       counters);
3003 		} else {
3004 			json_object_put(counters);
3005 		}
3006 
3007 		/* resolver stat counters */
3008 		counters = json_object_new_object();
3009 
3010 		dumparg.result = ISC_R_SUCCESS;
3011 		dumparg.arg = counters;
3012 
3013 		result = dump_counters(
3014 			server->resolverstats, isc_statsformat_json, counters,
3015 			NULL, resstats_xmldesc, dns_resstatscounter_max,
3016 			resstats_index, resstat_values, 0);
3017 		if (result != ISC_R_SUCCESS) {
3018 			json_object_put(counters);
3019 			goto error;
3020 		}
3021 
3022 		if (json_object_get_object(counters)->count != 0) {
3023 			json_object_object_add(bindstats, "resstats", counters);
3024 		} else {
3025 			json_object_put(counters);
3026 		}
3027 
3028 #ifdef HAVE_DNSTAP
3029 		/* dnstap stat counters */
3030 		if (named_g_server->dtenv != NULL) {
3031 			isc_stats_t *dnstapstats = NULL;
3032 			dns_dt_getstats(named_g_server->dtenv, &dnstapstats);
3033 			counters = json_object_new_object();
3034 			dumparg.result = ISC_R_SUCCESS;
3035 			dumparg.arg = counters;
3036 			result = dump_counters(
3037 				dnstapstats, isc_statsformat_json, counters,
3038 				NULL, dnstapstats_xmldesc,
3039 				dns_dnstapcounter_max, dnstapstats_index,
3040 				dnstapstat_values, 0);
3041 			isc_stats_detach(&dnstapstats);
3042 			if (result != ISC_R_SUCCESS) {
3043 				json_object_put(counters);
3044 				goto error;
3045 			}
3046 
3047 			if (json_object_get_object(counters)->count != 0) {
3048 				json_object_object_add(bindstats, "dnstapstats",
3049 						       counters);
3050 			} else {
3051 				json_object_put(counters);
3052 			}
3053 		}
3054 #endif /* ifdef HAVE_DNSTAP */
3055 	}
3056 
3057 	if ((flags & (STATS_JSON_ZONES | STATS_JSON_SERVER)) != 0) {
3058 		viewlist = json_object_new_object();
3059 		CHECKMEM(viewlist);
3060 
3061 		json_object_object_add(bindstats, "views", viewlist);
3062 
3063 		view = ISC_LIST_HEAD(server->viewlist);
3064 		while (view != NULL) {
3065 			json_object *za, *v = json_object_new_object();
3066 
3067 			CHECKMEM(v);
3068 			json_object_object_add(viewlist, view->name, v);
3069 
3070 			za = json_object_new_array();
3071 			CHECKMEM(za);
3072 
3073 			if ((flags & STATS_JSON_ZONES) != 0) {
3074 				result = dns_zt_apply(view->zonetable, true,
3075 						      NULL, zone_jsonrender,
3076 						      za);
3077 				if (result != ISC_R_SUCCESS) {
3078 					goto error;
3079 				}
3080 			}
3081 
3082 			if (json_object_array_length(za) != 0) {
3083 				json_object_object_add(v, "zones", za);
3084 			} else {
3085 				json_object_put(za);
3086 			}
3087 
3088 			if ((flags & STATS_JSON_SERVER) != 0) {
3089 				json_object *res;
3090 				dns_stats_t *dstats;
3091 				isc_stats_t *istats;
3092 
3093 				res = json_object_new_object();
3094 				CHECKMEM(res);
3095 				json_object_object_add(v, "resolver", res);
3096 
3097 				istats = view->resstats;
3098 				if (istats != NULL) {
3099 					counters = json_object_new_object();
3100 					CHECKMEM(counters);
3101 
3102 					result = dump_counters(
3103 						istats, isc_statsformat_json,
3104 						counters, NULL,
3105 						resstats_xmldesc,
3106 						dns_resstatscounter_max,
3107 						resstats_index, resstat_values,
3108 						0);
3109 					if (result != ISC_R_SUCCESS) {
3110 						json_object_put(counters);
3111 						result = dumparg.result;
3112 						goto error;
3113 					}
3114 
3115 					json_object_object_add(res, "stats",
3116 							       counters);
3117 				}
3118 
3119 				dstats = view->resquerystats;
3120 				if (dstats != NULL) {
3121 					counters = json_object_new_object();
3122 					CHECKMEM(counters);
3123 
3124 					dumparg.arg = counters;
3125 					dumparg.result = ISC_R_SUCCESS;
3126 					dns_rdatatypestats_dump(dstats,
3127 								rdtypestat_dump,
3128 								&dumparg, 0);
3129 					if (dumparg.result != ISC_R_SUCCESS) {
3130 						json_object_put(counters);
3131 						result = dumparg.result;
3132 						goto error;
3133 					}
3134 
3135 					json_object_object_add(res, "qtypes",
3136 							       counters);
3137 				}
3138 
3139 				dstats = dns_db_getrrsetstats(view->cachedb);
3140 				if (dstats != NULL) {
3141 					counters = json_object_new_object();
3142 					CHECKMEM(counters);
3143 
3144 					dumparg.arg = counters;
3145 					dumparg.result = ISC_R_SUCCESS;
3146 					dns_rdatasetstats_dump(
3147 						dstats, rdatasetstats_dump,
3148 						&dumparg, 0);
3149 					if (dumparg.result != ISC_R_SUCCESS) {
3150 						json_object_put(counters);
3151 						result = dumparg.result;
3152 						goto error;
3153 					}
3154 
3155 					json_object_object_add(res, "cache",
3156 							       counters);
3157 				}
3158 
3159 				counters = json_object_new_object();
3160 				CHECKMEM(counters);
3161 
3162 				result = dns_cache_renderjson(view->cache,
3163 							      counters);
3164 				if (result != ISC_R_SUCCESS) {
3165 					json_object_put(counters);
3166 					goto error;
3167 				}
3168 
3169 				json_object_object_add(res, "cachestats",
3170 						       counters);
3171 
3172 				istats = view->adbstats;
3173 				if (istats != NULL) {
3174 					counters = json_object_new_object();
3175 					CHECKMEM(counters);
3176 
3177 					result = dump_counters(
3178 						istats, isc_statsformat_json,
3179 						counters, NULL,
3180 						adbstats_xmldesc,
3181 						dns_adbstats_max,
3182 						adbstats_index, adbstat_values,
3183 						0);
3184 					if (result != ISC_R_SUCCESS) {
3185 						json_object_put(counters);
3186 						result = dumparg.result;
3187 						goto error;
3188 					}
3189 
3190 					json_object_object_add(res, "adb",
3191 							       counters);
3192 				}
3193 			}
3194 
3195 			view = ISC_LIST_NEXT(view, link);
3196 		}
3197 	}
3198 
3199 	if ((flags & STATS_JSON_NET) != 0) {
3200 		/* socket stat counters */
3201 		json_object *sockets;
3202 		counters = json_object_new_object();
3203 
3204 		dumparg.result = ISC_R_SUCCESS;
3205 		dumparg.arg = counters;
3206 
3207 		result = dump_counters(server->sockstats, isc_statsformat_json,
3208 				       counters, NULL, sockstats_xmldesc,
3209 				       isc_sockstatscounter_max,
3210 				       sockstats_index, sockstat_values, 0);
3211 		if (result != ISC_R_SUCCESS) {
3212 			json_object_put(counters);
3213 			goto error;
3214 		}
3215 
3216 		if (json_object_get_object(counters)->count != 0) {
3217 			json_object_object_add(bindstats, "sockstats",
3218 					       counters);
3219 		} else {
3220 			json_object_put(counters);
3221 		}
3222 
3223 		sockets = json_object_new_object();
3224 		CHECKMEM(sockets);
3225 
3226 		result = isc_socketmgr_renderjson(named_g_socketmgr, sockets);
3227 		if (result != ISC_R_SUCCESS) {
3228 			json_object_put(sockets);
3229 			goto error;
3230 		}
3231 
3232 		json_object_object_add(bindstats, "socketmgr", sockets);
3233 	}
3234 
3235 	if ((flags & STATS_JSON_TASKS) != 0) {
3236 		json_object *tasks = json_object_new_object();
3237 		CHECKMEM(tasks);
3238 
3239 		result = isc_taskmgr_renderjson(named_g_taskmgr, tasks);
3240 		if (result != ISC_R_SUCCESS) {
3241 			json_object_put(tasks);
3242 			goto error;
3243 		}
3244 
3245 		json_object_object_add(bindstats, "taskmgr", tasks);
3246 	}
3247 
3248 	if ((flags & STATS_JSON_MEM) != 0) {
3249 		json_object *memory = json_object_new_object();
3250 		CHECKMEM(memory);
3251 
3252 		result = isc_mem_renderjson(memory);
3253 		if (result != ISC_R_SUCCESS) {
3254 			json_object_put(memory);
3255 			goto error;
3256 		}
3257 
3258 		json_object_object_add(bindstats, "memory", memory);
3259 	}
3260 
3261 	if ((flags & STATS_JSON_TRAFFIC) != 0) {
3262 		traffic = json_object_new_object();
3263 		CHECKMEM(traffic);
3264 
3265 		udpreq4 = json_object_new_object();
3266 		CHECKMEM(udpreq4);
3267 
3268 		udpresp4 = json_object_new_object();
3269 		CHECKMEM(udpresp4);
3270 
3271 		tcpreq4 = json_object_new_object();
3272 		CHECKMEM(tcpreq4);
3273 
3274 		tcpresp4 = json_object_new_object();
3275 		CHECKMEM(tcpresp4);
3276 
3277 		udpreq6 = json_object_new_object();
3278 		CHECKMEM(udpreq6);
3279 
3280 		udpresp6 = json_object_new_object();
3281 		CHECKMEM(udpresp6);
3282 
3283 		tcpreq6 = json_object_new_object();
3284 		CHECKMEM(tcpreq6);
3285 
3286 		tcpresp6 = json_object_new_object();
3287 		CHECKMEM(tcpresp6);
3288 
3289 		CHECK(dump_counters(
3290 			server->sctx->udpinstats4, isc_statsformat_json,
3291 			udpreq4, NULL, udpinsizestats_xmldesc,
3292 			dns_sizecounter_in_max, udpinsizestats_index,
3293 			udpinsizestat_values, 0));
3294 
3295 		CHECK(dump_counters(
3296 			server->sctx->udpoutstats4, isc_statsformat_json,
3297 			udpresp4, NULL, udpoutsizestats_xmldesc,
3298 			dns_sizecounter_out_max, udpoutsizestats_index,
3299 			udpoutsizestat_values, 0));
3300 
3301 		CHECK(dump_counters(
3302 			server->sctx->tcpinstats4, isc_statsformat_json,
3303 			tcpreq4, NULL, tcpinsizestats_xmldesc,
3304 			dns_sizecounter_in_max, tcpinsizestats_index,
3305 			tcpinsizestat_values, 0));
3306 
3307 		CHECK(dump_counters(
3308 			server->sctx->tcpoutstats4, isc_statsformat_json,
3309 			tcpresp4, NULL, tcpoutsizestats_xmldesc,
3310 			dns_sizecounter_out_max, tcpoutsizestats_index,
3311 			tcpoutsizestat_values, 0));
3312 
3313 		CHECK(dump_counters(
3314 			server->sctx->udpinstats6, isc_statsformat_json,
3315 			udpreq6, NULL, udpinsizestats_xmldesc,
3316 			dns_sizecounter_in_max, udpinsizestats_index,
3317 			udpinsizestat_values, 0));
3318 
3319 		CHECK(dump_counters(
3320 			server->sctx->udpoutstats6, isc_statsformat_json,
3321 			udpresp6, NULL, udpoutsizestats_xmldesc,
3322 			dns_sizecounter_out_max, udpoutsizestats_index,
3323 			udpoutsizestat_values, 0));
3324 
3325 		CHECK(dump_counters(
3326 			server->sctx->tcpinstats6, isc_statsformat_json,
3327 			tcpreq6, NULL, tcpinsizestats_xmldesc,
3328 			dns_sizecounter_in_max, tcpinsizestats_index,
3329 			tcpinsizestat_values, 0));
3330 
3331 		CHECK(dump_counters(
3332 			server->sctx->tcpoutstats6, isc_statsformat_json,
3333 			tcpresp6, NULL, tcpoutsizestats_xmldesc,
3334 			dns_sizecounter_out_max, tcpoutsizestats_index,
3335 			tcpoutsizestat_values, 0));
3336 
3337 		json_object_object_add(traffic,
3338 				       "dns-udp-requests-sizes-received-ipv4",
3339 				       udpreq4);
3340 		json_object_object_add(
3341 			traffic, "dns-udp-responses-sizes-sent-ipv4", udpresp4);
3342 		json_object_object_add(traffic,
3343 				       "dns-tcp-requests-sizes-received-ipv4",
3344 				       tcpreq4);
3345 		json_object_object_add(
3346 			traffic, "dns-tcp-responses-sizes-sent-ipv4", tcpresp4);
3347 		json_object_object_add(traffic,
3348 				       "dns-udp-requests-sizes-received-ipv6",
3349 				       udpreq6);
3350 		json_object_object_add(
3351 			traffic, "dns-udp-responses-sizes-sent-ipv6", udpresp6);
3352 		json_object_object_add(traffic,
3353 				       "dns-tcp-requests-sizes-received-ipv6",
3354 				       tcpreq6);
3355 		json_object_object_add(
3356 			traffic, "dns-tcp-responses-sizes-sent-ipv6", tcpresp6);
3357 		json_object_object_add(bindstats, "traffic", traffic);
3358 		udpreq4 = NULL;
3359 		udpresp4 = NULL;
3360 		tcpreq4 = NULL;
3361 		tcpresp4 = NULL;
3362 		udpreq6 = NULL;
3363 		udpresp6 = NULL;
3364 		tcpreq6 = NULL;
3365 		tcpresp6 = NULL;
3366 		traffic = NULL;
3367 	}
3368 
3369 	*msg = json_object_to_json_string_ext(bindstats,
3370 					      JSON_C_TO_STRING_PRETTY);
3371 	*msglen = strlen(*msg);
3372 
3373 	if (rootp != NULL) {
3374 		*rootp = bindstats;
3375 		bindstats = NULL;
3376 	}
3377 
3378 	result = ISC_R_SUCCESS;
3379 
3380 error:
3381 	if (udpreq4 != NULL) {
3382 		json_object_put(udpreq4);
3383 	}
3384 	if (udpresp4 != NULL) {
3385 		json_object_put(udpresp4);
3386 	}
3387 	if (tcpreq4 != NULL) {
3388 		json_object_put(tcpreq4);
3389 	}
3390 	if (tcpresp4 != NULL) {
3391 		json_object_put(tcpresp4);
3392 	}
3393 	if (udpreq6 != NULL) {
3394 		json_object_put(udpreq6);
3395 	}
3396 	if (udpresp6 != NULL) {
3397 		json_object_put(udpresp6);
3398 	}
3399 	if (tcpreq6 != NULL) {
3400 		json_object_put(tcpreq6);
3401 	}
3402 	if (tcpresp6 != NULL) {
3403 		json_object_put(tcpresp6);
3404 	}
3405 	if (traffic != NULL) {
3406 		json_object_put(traffic);
3407 	}
3408 	if (bindstats != NULL) {
3409 		json_object_put(bindstats);
3410 	}
3411 
3412 	return (result);
3413 }
3414 
3415 static isc_result_t
3416 render_json(uint32_t flags, const char *url, isc_httpdurl_t *urlinfo,
3417 	    const char *querystring, const char *headers, void *arg,
3418 	    unsigned int *retcode, const char **retmsg, const char **mimetype,
3419 	    isc_buffer_t *b, isc_httpdfree_t **freecb, void **freecb_args) {
3420 	isc_result_t result;
3421 	json_object *bindstats = NULL;
3422 	named_server_t *server = arg;
3423 	const char *msg = NULL;
3424 	size_t msglen = 0;
3425 	char *p;
3426 
3427 	UNUSED(url);
3428 	UNUSED(urlinfo);
3429 	UNUSED(headers);
3430 	UNUSED(querystring);
3431 
3432 	result = generatejson(server, &msglen, &msg, &bindstats, flags);
3433 	if (result == ISC_R_SUCCESS) {
3434 		*retcode = 200;
3435 		*retmsg = "OK";
3436 		*mimetype = "application/json";
3437 		DE_CONST(msg, p);
3438 		isc_buffer_reinit(b, p, msglen);
3439 		isc_buffer_add(b, msglen);
3440 		*freecb = wrap_jsonfree;
3441 		*freecb_args = bindstats;
3442 	} else {
3443 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3444 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
3445 			      "failed at rendering JSON()");
3446 	}
3447 
3448 	return (result);
3449 }
3450 
3451 static isc_result_t
3452 render_json_all(const char *url, isc_httpdurl_t *urlinfo,
3453 		const char *querystring, const char *headers, void *arg,
3454 		unsigned int *retcode, const char **retmsg,
3455 		const char **mimetype, isc_buffer_t *b,
3456 		isc_httpdfree_t **freecb, void **freecb_args) {
3457 	return (render_json(STATS_JSON_ALL, url, urlinfo, querystring, headers,
3458 			    arg, retcode, retmsg, mimetype, b, freecb,
3459 			    freecb_args));
3460 }
3461 
3462 static isc_result_t
3463 render_json_status(const char *url, isc_httpdurl_t *urlinfo,
3464 		   const char *querystring, const char *headers, void *arg,
3465 		   unsigned int *retcode, const char **retmsg,
3466 		   const char **mimetype, isc_buffer_t *b,
3467 		   isc_httpdfree_t **freecb, void **freecb_args) {
3468 	return (render_json(STATS_JSON_STATUS, url, urlinfo, querystring,
3469 			    headers, arg, retcode, retmsg, mimetype, b, freecb,
3470 			    freecb_args));
3471 }
3472 
3473 static isc_result_t
3474 render_json_server(const char *url, isc_httpdurl_t *urlinfo,
3475 		   const char *querystring, const char *headers, void *arg,
3476 		   unsigned int *retcode, const char **retmsg,
3477 		   const char **mimetype, isc_buffer_t *b,
3478 		   isc_httpdfree_t **freecb, void **freecb_args) {
3479 	return (render_json(STATS_JSON_SERVER, url, urlinfo, querystring,
3480 			    headers, arg, retcode, retmsg, mimetype, b, freecb,
3481 			    freecb_args));
3482 }
3483 
3484 static isc_result_t
3485 render_json_zones(const char *url, isc_httpdurl_t *urlinfo,
3486 		  const char *querystring, const char *headers, void *arg,
3487 		  unsigned int *retcode, const char **retmsg,
3488 		  const char **mimetype, isc_buffer_t *b,
3489 		  isc_httpdfree_t **freecb, void **freecb_args) {
3490 	return (render_json(STATS_JSON_ZONES, url, urlinfo, querystring,
3491 			    headers, arg, retcode, retmsg, mimetype, b, freecb,
3492 			    freecb_args));
3493 }
3494 
3495 static isc_result_t
3496 render_json_mem(const char *url, isc_httpdurl_t *urlinfo,
3497 		const char *querystring, const char *headers, void *arg,
3498 		unsigned int *retcode, const char **retmsg,
3499 		const char **mimetype, isc_buffer_t *b,
3500 		isc_httpdfree_t **freecb, void **freecb_args) {
3501 	return (render_json(STATS_JSON_MEM, url, urlinfo, querystring, headers,
3502 			    arg, retcode, retmsg, mimetype, b, freecb,
3503 			    freecb_args));
3504 }
3505 
3506 static isc_result_t
3507 render_json_tasks(const char *url, isc_httpdurl_t *urlinfo,
3508 		  const char *querystring, const char *headers, void *arg,
3509 		  unsigned int *retcode, const char **retmsg,
3510 		  const char **mimetype, isc_buffer_t *b,
3511 		  isc_httpdfree_t **freecb, void **freecb_args) {
3512 	return (render_json(STATS_JSON_TASKS, url, urlinfo, querystring,
3513 			    headers, arg, retcode, retmsg, mimetype, b, freecb,
3514 			    freecb_args));
3515 }
3516 
3517 static isc_result_t
3518 render_json_net(const char *url, isc_httpdurl_t *urlinfo,
3519 		const char *querystring, const char *headers, void *arg,
3520 		unsigned int *retcode, const char **retmsg,
3521 		const char **mimetype, isc_buffer_t *b,
3522 		isc_httpdfree_t **freecb, void **freecb_args) {
3523 	return (render_json(STATS_JSON_NET, url, urlinfo, querystring, headers,
3524 			    arg, retcode, retmsg, mimetype, b, freecb,
3525 			    freecb_args));
3526 }
3527 
3528 static isc_result_t
3529 render_json_traffic(const char *url, isc_httpdurl_t *urlinfo,
3530 		    const char *querystring, const char *headers, void *arg,
3531 		    unsigned int *retcode, const char **retmsg,
3532 		    const char **mimetype, isc_buffer_t *b,
3533 		    isc_httpdfree_t **freecb, void **freecb_args) {
3534 	return (render_json(STATS_JSON_TRAFFIC, url, urlinfo, querystring,
3535 			    headers, arg, retcode, retmsg, mimetype, b, freecb,
3536 			    freecb_args));
3537 }
3538 
3539 #endif /* HAVE_JSON_C */
3540 
3541 static isc_result_t
3542 render_xsl(const char *url, isc_httpdurl_t *urlinfo, const char *querystring,
3543 	   const char *headers, void *args, unsigned int *retcode,
3544 	   const char **retmsg, const char **mimetype, isc_buffer_t *b,
3545 	   isc_httpdfree_t **freecb, void **freecb_args) {
3546 	isc_result_t result;
3547 	char *_headers = NULL;
3548 
3549 	UNUSED(url);
3550 	UNUSED(querystring);
3551 	UNUSED(args);
3552 
3553 	*freecb = NULL;
3554 	*freecb_args = NULL;
3555 	*mimetype = "text/xslt+xml";
3556 
3557 	if (urlinfo->isstatic) {
3558 		isc_time_t when;
3559 		char *line, *saveptr;
3560 		const char *if_modified_since = "If-Modified-Since: ";
3561 		_headers = strdup(headers);
3562 
3563 		if (_headers == NULL) {
3564 			goto send;
3565 		}
3566 
3567 		saveptr = NULL;
3568 		for (line = strtok_r(_headers, "\n", &saveptr); line;
3569 		     line = strtok_r(NULL, "\n", &saveptr))
3570 		{
3571 			if (strncasecmp(line, if_modified_since,
3572 					strlen(if_modified_since)) == 0) {
3573 				time_t t1, t2;
3574 				line += strlen(if_modified_since);
3575 				result = isc_time_parsehttptimestamp(line,
3576 								     &when);
3577 				if (result != ISC_R_SUCCESS) {
3578 					goto send;
3579 				}
3580 
3581 				result = isc_time_secondsastimet(&when, &t1);
3582 				if (result != ISC_R_SUCCESS) {
3583 					goto send;
3584 				}
3585 
3586 				result = isc_time_secondsastimet(
3587 					&urlinfo->loadtime, &t2);
3588 				if (result != ISC_R_SUCCESS) {
3589 					goto send;
3590 				}
3591 
3592 				if (t1 < t2) {
3593 					goto send;
3594 				}
3595 
3596 				*retcode = 304;
3597 				*retmsg = "Not modified";
3598 				goto end;
3599 			}
3600 		}
3601 	}
3602 
3603 send:
3604 	*retcode = 200;
3605 	*retmsg = "OK";
3606 	isc_buffer_reinit(b, xslmsg, strlen(xslmsg));
3607 	isc_buffer_add(b, strlen(xslmsg));
3608 end:
3609 	free(_headers);
3610 	return (ISC_R_SUCCESS);
3611 }
3612 
3613 static void
3614 shutdown_listener(named_statschannel_t *listener) {
3615 	char socktext[ISC_SOCKADDR_FORMATSIZE];
3616 	isc_sockaddr_format(&listener->address, socktext, sizeof(socktext));
3617 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3618 		      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
3619 		      "stopping statistics channel on %s", socktext);
3620 
3621 	isc_httpdmgr_shutdown(&listener->httpdmgr);
3622 }
3623 
3624 static bool
3625 client_ok(const isc_sockaddr_t *fromaddr, void *arg) {
3626 	named_statschannel_t *listener = arg;
3627 	dns_aclenv_t *env =
3628 		ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
3629 	isc_netaddr_t netaddr;
3630 	char socktext[ISC_SOCKADDR_FORMATSIZE];
3631 	int match;
3632 
3633 	REQUIRE(listener != NULL);
3634 
3635 	isc_netaddr_fromsockaddr(&netaddr, fromaddr);
3636 
3637 	LOCK(&listener->lock);
3638 	if ((dns_acl_match(&netaddr, NULL, listener->acl, env, &match, NULL) ==
3639 	     ISC_R_SUCCESS) &&
3640 	    match > 0)
3641 	{
3642 		UNLOCK(&listener->lock);
3643 		return (true);
3644 	}
3645 	UNLOCK(&listener->lock);
3646 
3647 	isc_sockaddr_format(fromaddr, socktext, sizeof(socktext));
3648 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3649 		      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
3650 		      "rejected statistics connection from %s", socktext);
3651 
3652 	return (false);
3653 }
3654 
3655 static void
3656 destroy_listener(void *arg) {
3657 	named_statschannel_t *listener = arg;
3658 
3659 	REQUIRE(listener != NULL);
3660 	REQUIRE(!ISC_LINK_LINKED(listener, link));
3661 
3662 	/* We don't have to acquire the lock here since it's already unlinked */
3663 	dns_acl_detach(&listener->acl);
3664 
3665 	isc_mutex_destroy(&listener->lock);
3666 	isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener));
3667 }
3668 
3669 static isc_result_t
3670 add_listener(named_server_t *server, named_statschannel_t **listenerp,
3671 	     const cfg_obj_t *listen_params, const cfg_obj_t *config,
3672 	     isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
3673 	     const char *socktext) {
3674 	isc_result_t result;
3675 	named_statschannel_t *listener;
3676 	isc_task_t *task = NULL;
3677 	isc_socket_t *sock = NULL;
3678 	const cfg_obj_t *allow;
3679 	dns_acl_t *new_acl = NULL;
3680 
3681 	listener = isc_mem_get(server->mctx, sizeof(*listener));
3682 
3683 	listener->httpdmgr = NULL;
3684 	listener->address = *addr;
3685 	listener->acl = NULL;
3686 	listener->mctx = NULL;
3687 	ISC_LINK_INIT(listener, link);
3688 
3689 	isc_mutex_init(&listener->lock);
3690 
3691 	isc_mem_attach(server->mctx, &listener->mctx);
3692 
3693 	allow = cfg_tuple_get(listen_params, "allow");
3694 	if (allow != NULL && cfg_obj_islist(allow)) {
3695 		result = cfg_acl_fromconfig(allow, config, named_g_lctx,
3696 					    aclconfctx, listener->mctx, 0,
3697 					    &new_acl);
3698 	} else {
3699 		result = dns_acl_any(listener->mctx, &new_acl);
3700 	}
3701 	if (result != ISC_R_SUCCESS) {
3702 		goto cleanup;
3703 	}
3704 	dns_acl_attach(new_acl, &listener->acl);
3705 	dns_acl_detach(&new_acl);
3706 
3707 	result = isc_task_create(named_g_taskmgr, 0, &task);
3708 	if (result != ISC_R_SUCCESS) {
3709 		goto cleanup;
3710 	}
3711 	isc_task_setname(task, "statchannel", NULL);
3712 
3713 	result = isc_socket_create(named_g_socketmgr, isc_sockaddr_pf(addr),
3714 				   isc_sockettype_tcp, &sock);
3715 	if (result != ISC_R_SUCCESS) {
3716 		goto cleanup;
3717 	}
3718 	isc_socket_setname(sock, "statchannel", NULL);
3719 
3720 #ifndef ISC_ALLOW_MAPPED
3721 	isc_socket_ipv6only(sock, true);
3722 #endif /* ifndef ISC_ALLOW_MAPPED */
3723 
3724 	result = isc_socket_bind(sock, addr, ISC_SOCKET_REUSEADDRESS);
3725 	if (result != ISC_R_SUCCESS) {
3726 		goto cleanup;
3727 	}
3728 
3729 	result = isc_httpdmgr_create(server->mctx, sock, task, client_ok,
3730 				     destroy_listener, listener,
3731 				     named_g_timermgr, &listener->httpdmgr);
3732 	if (result != ISC_R_SUCCESS) {
3733 		goto cleanup;
3734 	}
3735 
3736 #ifdef HAVE_LIBXML2
3737 	isc_httpdmgr_addurl(listener->httpdmgr, "/", render_xml_all, server);
3738 	isc_httpdmgr_addurl(listener->httpdmgr, "/xml", render_xml_all, server);
3739 	isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3", render_xml_all,
3740 			    server);
3741 	isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/status",
3742 			    render_xml_status, server);
3743 	isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/server",
3744 			    render_xml_server, server);
3745 	isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/zones",
3746 			    render_xml_zones, server);
3747 	isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/net", render_xml_net,
3748 			    server);
3749 	isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/tasks",
3750 			    render_xml_tasks, server);
3751 	isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/mem", render_xml_mem,
3752 			    server);
3753 	isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/traffic",
3754 			    render_xml_traffic, server);
3755 #endif /* ifdef HAVE_LIBXML2 */
3756 #ifdef HAVE_JSON_C
3757 	isc_httpdmgr_addurl(listener->httpdmgr, "/json", render_json_all,
3758 			    server);
3759 	isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1", render_json_all,
3760 			    server);
3761 	isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/status",
3762 			    render_json_status, server);
3763 	isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/server",
3764 			    render_json_server, server);
3765 	isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/zones",
3766 			    render_json_zones, server);
3767 	isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/tasks",
3768 			    render_json_tasks, server);
3769 	isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/net", render_json_net,
3770 			    server);
3771 	isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/mem", render_json_mem,
3772 			    server);
3773 	isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/traffic",
3774 			    render_json_traffic, server);
3775 #endif /* ifdef HAVE_JSON_C */
3776 	isc_httpdmgr_addurl2(listener->httpdmgr, "/bind9.xsl", true, render_xsl,
3777 			     server);
3778 
3779 	*listenerp = listener;
3780 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3781 		      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
3782 		      "statistics channel listening on %s", socktext);
3783 
3784 cleanup:
3785 	if (result != ISC_R_SUCCESS) {
3786 		if (listener->acl != NULL) {
3787 			dns_acl_detach(&listener->acl);
3788 		}
3789 		isc_mutex_destroy(&listener->lock);
3790 		isc_mem_putanddetach(&listener->mctx, listener,
3791 				     sizeof(*listener));
3792 	}
3793 	if (task != NULL) {
3794 		isc_task_detach(&task);
3795 	}
3796 	if (sock != NULL) {
3797 		isc_socket_detach(&sock);
3798 	}
3799 
3800 	return (result);
3801 }
3802 
3803 static void
3804 update_listener(named_server_t *server, named_statschannel_t **listenerp,
3805 		const cfg_obj_t *listen_params, const cfg_obj_t *config,
3806 		isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
3807 		const char *socktext) {
3808 	named_statschannel_t *listener;
3809 	const cfg_obj_t *allow = NULL;
3810 	dns_acl_t *new_acl = NULL;
3811 	isc_result_t result = ISC_R_SUCCESS;
3812 
3813 	for (listener = ISC_LIST_HEAD(server->statschannels); listener != NULL;
3814 	     listener = ISC_LIST_NEXT(listener, link))
3815 	{
3816 		if (isc_sockaddr_equal(addr, &listener->address)) {
3817 			break;
3818 		}
3819 	}
3820 
3821 	if (listener == NULL) {
3822 		*listenerp = NULL;
3823 		return;
3824 	}
3825 
3826 	/*
3827 	 * Now, keep the old access list unless a new one can be made.
3828 	 */
3829 	allow = cfg_tuple_get(listen_params, "allow");
3830 	if (allow != NULL && cfg_obj_islist(allow)) {
3831 		result = cfg_acl_fromconfig(allow, config, named_g_lctx,
3832 					    aclconfctx, listener->mctx, 0,
3833 					    &new_acl);
3834 	} else {
3835 		result = dns_acl_any(listener->mctx, &new_acl);
3836 	}
3837 
3838 	if (result == ISC_R_SUCCESS) {
3839 		LOCK(&listener->lock);
3840 
3841 		dns_acl_detach(&listener->acl);
3842 		dns_acl_attach(new_acl, &listener->acl);
3843 		dns_acl_detach(&new_acl);
3844 
3845 		UNLOCK(&listener->lock);
3846 	} else {
3847 		cfg_obj_log(listen_params, named_g_lctx, ISC_LOG_WARNING,
3848 			    "couldn't install new acl for "
3849 			    "statistics channel %s: %s",
3850 			    socktext, isc_result_totext(result));
3851 	}
3852 
3853 	*listenerp = listener;
3854 }
3855 
3856 isc_result_t
3857 named_statschannels_configure(named_server_t *server, const cfg_obj_t *config,
3858 			      cfg_aclconfctx_t *aclconfctx) {
3859 	named_statschannel_t *listener, *listener_next;
3860 	named_statschannellist_t new_listeners;
3861 	const cfg_obj_t *statschannellist = NULL;
3862 	const cfg_listelt_t *element, *element2;
3863 	char socktext[ISC_SOCKADDR_FORMATSIZE];
3864 
3865 	RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS);
3866 
3867 	ISC_LIST_INIT(new_listeners);
3868 
3869 	/*
3870 	 * Get the list of named.conf 'statistics-channels' statements.
3871 	 */
3872 	(void)cfg_map_get(config, "statistics-channels", &statschannellist);
3873 
3874 	/*
3875 	 * Run through the new address/port list, noting sockets that are
3876 	 * already being listened on and moving them to the new list.
3877 	 *
3878 	 * Identifying duplicate addr/port combinations is left to either
3879 	 * the underlying config code, or to the bind attempt getting an
3880 	 * address-in-use error.
3881 	 */
3882 	if (statschannellist != NULL) {
3883 #ifndef EXTENDED_STATS
3884 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3885 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
3886 			      "statistics-channels specified but not effective "
3887 			      "due to missing XML and/or JSON library");
3888 #else /* EXTENDED_STATS */
3889 #ifndef HAVE_LIBXML2
3890 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3891 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
3892 			      "statistics-channels: XML library missing, "
3893 			      "only JSON stats will be available");
3894 #endif /* !HAVE_LIBXML2 */
3895 #ifndef HAVE_JSON_C
3896 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3897 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
3898 			      "statistics-channels: JSON library missing, "
3899 			      "only XML stats will be available");
3900 #endif /* !HAVE_JSON_C */
3901 #endif /* EXTENDED_STATS */
3902 
3903 		for (element = cfg_list_first(statschannellist);
3904 		     element != NULL; element = cfg_list_next(element))
3905 		{
3906 			const cfg_obj_t *statschannel;
3907 			const cfg_obj_t *listenercfg = NULL;
3908 
3909 			statschannel = cfg_listelt_value(element);
3910 			(void)cfg_map_get(statschannel, "inet", &listenercfg);
3911 			if (listenercfg == NULL) {
3912 				continue;
3913 			}
3914 
3915 			for (element2 = cfg_list_first(listenercfg);
3916 			     element2 != NULL;
3917 			     element2 = cfg_list_next(element2))
3918 			{
3919 				const cfg_obj_t *listen_params;
3920 				const cfg_obj_t *obj;
3921 				isc_sockaddr_t addr;
3922 
3923 				listen_params = cfg_listelt_value(element2);
3924 
3925 				obj = cfg_tuple_get(listen_params, "address");
3926 				addr = *cfg_obj_assockaddr(obj);
3927 				if (isc_sockaddr_getport(&addr) == 0) {
3928 					isc_sockaddr_setport(
3929 						&addr,
3930 						NAMED_STATSCHANNEL_HTTPPORT);
3931 				}
3932 
3933 				isc_sockaddr_format(&addr, socktext,
3934 						    sizeof(socktext));
3935 
3936 				isc_log_write(named_g_lctx,
3937 					      NAMED_LOGCATEGORY_GENERAL,
3938 					      NAMED_LOGMODULE_SERVER,
3939 					      ISC_LOG_DEBUG(9),
3940 					      "processing statistics "
3941 					      "channel %s",
3942 					      socktext);
3943 
3944 				update_listener(server, &listener,
3945 						listen_params, config, &addr,
3946 						aclconfctx, socktext);
3947 
3948 				if (listener != NULL) {
3949 					/*
3950 					 * Remove the listener from the old
3951 					 * list, so it won't be shut down.
3952 					 */
3953 					ISC_LIST_UNLINK(server->statschannels,
3954 							listener, link);
3955 				} else {
3956 					/*
3957 					 * This is a new listener.
3958 					 */
3959 					isc_result_t r;
3960 
3961 					r = add_listener(server, &listener,
3962 							 listen_params, config,
3963 							 &addr, aclconfctx,
3964 							 socktext);
3965 					if (r != ISC_R_SUCCESS) {
3966 						cfg_obj_log(
3967 							listen_params,
3968 							named_g_lctx,
3969 							ISC_LOG_WARNING,
3970 							"couldn't allocate "
3971 							"statistics channel"
3972 							" %s: %s",
3973 							socktext,
3974 							isc_result_totext(r));
3975 					}
3976 				}
3977 
3978 				if (listener != NULL) {
3979 					ISC_LIST_APPEND(new_listeners, listener,
3980 							link);
3981 				}
3982 			}
3983 		}
3984 	}
3985 
3986 	for (listener = ISC_LIST_HEAD(server->statschannels); listener != NULL;
3987 	     listener = listener_next)
3988 	{
3989 		listener_next = ISC_LIST_NEXT(listener, link);
3990 		ISC_LIST_UNLINK(server->statschannels, listener, link);
3991 		shutdown_listener(listener);
3992 	}
3993 
3994 	ISC_LIST_APPENDLIST(server->statschannels, new_listeners, link);
3995 	return (ISC_R_SUCCESS);
3996 }
3997 
3998 void
3999 named_statschannels_shutdown(named_server_t *server) {
4000 	named_statschannel_t *listener;
4001 
4002 	while ((listener = ISC_LIST_HEAD(server->statschannels)) != NULL) {
4003 		ISC_LIST_UNLINK(server->statschannels, listener, link);
4004 		shutdown_listener(listener);
4005 	}
4006 }
4007 
4008 isc_result_t
4009 named_stats_dump(named_server_t *server, FILE *fp) {
4010 	isc_stdtime_t now;
4011 	isc_result_t result;
4012 	dns_view_t *view;
4013 	dns_zone_t *zone, *next;
4014 	stats_dumparg_t dumparg;
4015 	uint64_t nsstat_values[ns_statscounter_max];
4016 	uint64_t resstat_values[dns_resstatscounter_max];
4017 	uint64_t adbstat_values[dns_adbstats_max];
4018 	uint64_t zonestat_values[dns_zonestatscounter_max];
4019 	uint64_t sockstat_values[isc_sockstatscounter_max];
4020 	uint64_t gluecachestats_values[dns_gluecachestatscounter_max];
4021 
4022 	RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS);
4023 
4024 	/* Set common fields */
4025 	dumparg.type = isc_statsformat_file;
4026 	dumparg.arg = fp;
4027 
4028 	isc_stdtime_get(&now);
4029 	fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now);
4030 
4031 	fprintf(fp, "++ Incoming Requests ++\n");
4032 	dns_opcodestats_dump(server->sctx->opcodestats, opcodestat_dump,
4033 			     &dumparg, 0);
4034 
4035 	fprintf(fp, "++ Incoming Queries ++\n");
4036 	dns_rdatatypestats_dump(server->sctx->rcvquerystats, rdtypestat_dump,
4037 				&dumparg, 0);
4038 
4039 	fprintf(fp, "++ Outgoing Rcodes ++\n");
4040 	dns_rcodestats_dump(server->sctx->rcodestats, rcodestat_dump, &dumparg,
4041 			    0);
4042 
4043 	fprintf(fp, "++ Outgoing Queries ++\n");
4044 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
4045 	     view = ISC_LIST_NEXT(view, link))
4046 	{
4047 		if (view->resquerystats == NULL) {
4048 			continue;
4049 		}
4050 		if (strcmp(view->name, "_default") == 0) {
4051 			fprintf(fp, "[View: default]\n");
4052 		} else {
4053 			fprintf(fp, "[View: %s]\n", view->name);
4054 		}
4055 		dns_rdatatypestats_dump(view->resquerystats, rdtypestat_dump,
4056 					&dumparg, 0);
4057 	}
4058 
4059 	fprintf(fp, "++ Name Server Statistics ++\n");
4060 	(void)dump_counters(ns_stats_get(server->sctx->nsstats),
4061 			    isc_statsformat_file, fp, NULL, nsstats_desc,
4062 			    ns_statscounter_max, nsstats_index, nsstat_values,
4063 			    0);
4064 
4065 	fprintf(fp, "++ Zone Maintenance Statistics ++\n");
4066 	(void)dump_counters(server->zonestats, isc_statsformat_file, fp, NULL,
4067 			    zonestats_desc, dns_zonestatscounter_max,
4068 			    zonestats_index, zonestat_values, 0);
4069 
4070 	fprintf(fp, "++ Resolver Statistics ++\n");
4071 	fprintf(fp, "[Common]\n");
4072 	(void)dump_counters(server->resolverstats, isc_statsformat_file, fp,
4073 			    NULL, resstats_desc, dns_resstatscounter_max,
4074 			    resstats_index, resstat_values, 0);
4075 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
4076 	     view = ISC_LIST_NEXT(view, link))
4077 	{
4078 		if (view->resstats == NULL) {
4079 			continue;
4080 		}
4081 		if (strcmp(view->name, "_default") == 0) {
4082 			fprintf(fp, "[View: default]\n");
4083 		} else {
4084 			fprintf(fp, "[View: %s]\n", view->name);
4085 		}
4086 		(void)dump_counters(view->resstats, isc_statsformat_file, fp,
4087 				    NULL, resstats_desc,
4088 				    dns_resstatscounter_max, resstats_index,
4089 				    resstat_values, 0);
4090 	}
4091 
4092 	fprintf(fp, "++ Cache Statistics ++\n");
4093 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
4094 	     view = ISC_LIST_NEXT(view, link))
4095 	{
4096 		if (strcmp(view->name, "_default") == 0) {
4097 			fprintf(fp, "[View: default]\n");
4098 		} else {
4099 			fprintf(fp, "[View: %s (Cache: %s)]\n", view->name,
4100 				dns_cache_getname(view->cache));
4101 		}
4102 		/*
4103 		 * Avoid dumping redundant statistics when the cache is shared.
4104 		 */
4105 		if (dns_view_iscacheshared(view)) {
4106 			continue;
4107 		}
4108 		dns_cache_dumpstats(view->cache, fp);
4109 	}
4110 
4111 	fprintf(fp, "++ Cache DB RRsets ++\n");
4112 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
4113 	     view = ISC_LIST_NEXT(view, link))
4114 	{
4115 		dns_stats_t *cacherrstats;
4116 
4117 		cacherrstats = dns_db_getrrsetstats(view->cachedb);
4118 		if (cacherrstats == NULL) {
4119 			continue;
4120 		}
4121 		if (strcmp(view->name, "_default") == 0) {
4122 			fprintf(fp, "[View: default]\n");
4123 		} else {
4124 			fprintf(fp, "[View: %s (Cache: %s)]\n", view->name,
4125 				dns_cache_getname(view->cache));
4126 		}
4127 		if (dns_view_iscacheshared(view)) {
4128 			/*
4129 			 * Avoid dumping redundant statistics when the cache is
4130 			 * shared.
4131 			 */
4132 			continue;
4133 		}
4134 		dns_rdatasetstats_dump(cacherrstats, rdatasetstats_dump,
4135 				       &dumparg, 0);
4136 	}
4137 
4138 	fprintf(fp, "++ ADB stats ++\n");
4139 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
4140 	     view = ISC_LIST_NEXT(view, link))
4141 	{
4142 		if (view->adbstats == NULL) {
4143 			continue;
4144 		}
4145 		if (strcmp(view->name, "_default") == 0) {
4146 			fprintf(fp, "[View: default]\n");
4147 		} else {
4148 			fprintf(fp, "[View: %s]\n", view->name);
4149 		}
4150 		(void)dump_counters(view->adbstats, isc_statsformat_file, fp,
4151 				    NULL, adbstats_desc, dns_adbstats_max,
4152 				    adbstats_index, adbstat_values, 0);
4153 	}
4154 
4155 	fprintf(fp, "++ Socket I/O Statistics ++\n");
4156 	(void)dump_counters(server->sockstats, isc_statsformat_file, fp, NULL,
4157 			    sockstats_desc, isc_sockstatscounter_max,
4158 			    sockstats_index, sockstat_values, 0);
4159 
4160 	fprintf(fp, "++ Per Zone Query Statistics ++\n");
4161 	zone = NULL;
4162 	for (result = dns_zone_first(server->zonemgr, &zone);
4163 	     result == ISC_R_SUCCESS;
4164 	     next = NULL, result = dns_zone_next(zone, &next), zone = next)
4165 	{
4166 		isc_stats_t *zonestats = dns_zone_getrequeststats(zone);
4167 		if (zonestats != NULL) {
4168 			char zonename[DNS_NAME_FORMATSIZE];
4169 
4170 			view = dns_zone_getview(zone);
4171 			if (view == NULL) {
4172 				continue;
4173 			}
4174 
4175 			dns_name_format(dns_zone_getorigin(zone), zonename,
4176 					sizeof(zonename));
4177 			fprintf(fp, "[%s", zonename);
4178 			if (strcmp(view->name, "_default") != 0) {
4179 				fprintf(fp, " (view: %s)", view->name);
4180 			}
4181 			fprintf(fp, "]\n");
4182 
4183 			(void)dump_counters(zonestats, isc_statsformat_file, fp,
4184 					    NULL, nsstats_desc,
4185 					    ns_statscounter_max, nsstats_index,
4186 					    nsstat_values, 0);
4187 		}
4188 	}
4189 
4190 	fprintf(fp, "++ Per Zone Glue Cache Statistics ++\n");
4191 	zone = NULL;
4192 	for (result = dns_zone_first(server->zonemgr, &zone);
4193 	     result == ISC_R_SUCCESS;
4194 	     next = NULL, result = dns_zone_next(zone, &next), zone = next)
4195 	{
4196 		isc_stats_t *gluecachestats = dns_zone_getgluecachestats(zone);
4197 		if (gluecachestats != NULL) {
4198 			char zonename[DNS_NAME_FORMATSIZE];
4199 
4200 			view = dns_zone_getview(zone);
4201 			if (view == NULL) {
4202 				continue;
4203 			}
4204 
4205 			dns_name_format(dns_zone_getorigin(zone), zonename,
4206 					sizeof(zonename));
4207 			fprintf(fp, "[%s", zonename);
4208 			if (strcmp(view->name, "_default") != 0) {
4209 				fprintf(fp, " (view: %s)", view->name);
4210 			}
4211 			fprintf(fp, "]\n");
4212 
4213 			(void)dump_counters(
4214 				gluecachestats, isc_statsformat_file, fp, NULL,
4215 				gluecachestats_desc,
4216 				dns_gluecachestatscounter_max,
4217 				gluecachestats_index, gluecachestats_values, 0);
4218 		}
4219 	}
4220 
4221 	fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now);
4222 
4223 	return (ISC_R_SUCCESS); /* this function currently always succeeds */
4224 }
4225