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