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