1/*
2 * Copyright (C) 2008-2014  Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* $Id: statschannel.c,v 1.28 2011/03/12 04:59:46 tbox Exp $ */
18
19/*! \file */
20
21#include <config.h>
22
23#include <isc/buffer.h>
24#include <isc/httpd.h>
25#include <isc/mem.h>
26#include <isc/once.h>
27#include <isc/print.h>
28#include <isc/socket.h>
29#include <isc/stats.h>
30#include <isc/string.h>
31#include <isc/task.h>
32
33#include <dns/cache.h>
34#include <dns/db.h>
35#include <dns/opcode.h>
36#include <dns/resolver.h>
37#include <dns/rdataclass.h>
38#include <dns/rdatatype.h>
39#include <dns/stats.h>
40#include <dns/view.h>
41#include <dns/zt.h>
42
43#include <named/log.h>
44#include <named/server.h>
45#include <named/statschannel.h>
46
47#ifdef NEWSTATS
48	#include "bind9.ver3.xsl.h"
49#else /* OLDSTATS */
50	#include "bind9.xsl.h"
51#endif /* NEWSTATS */
52
53struct ns_statschannel {
54	/* Unlocked */
55	isc_httpdmgr_t				*httpdmgr;
56	isc_sockaddr_t				address;
57	isc_mem_t				*mctx;
58
59	/*
60	 * Locked by channel lock: can be referenced and modified by both
61	 * the server task and the channel task.
62	 */
63	isc_mutex_t				lock;
64	dns_acl_t				*acl;
65
66	/* Locked by server task */
67	ISC_LINK(struct ns_statschannel)	link;
68};
69
70typedef enum { statsformat_file, statsformat_xml } statsformat_t;
71
72typedef struct
73stats_dumparg {
74	statsformat_t	type;
75	void		*arg;		/* type dependent argument */
76	int		ncounters;	/* used for general statistics */
77	int		*counterindices; /* used for general statistics */
78	isc_uint64_t	*countervalues;	 /* used for general statistics */
79	isc_result_t	result;
80} stats_dumparg_t;
81
82static isc_once_t once = ISC_ONCE_INIT;
83
84/*%
85 * Statistics descriptions.  These could be statistically initialized at
86 * compile time, but we configure them run time in the init_desc() function
87 * below so that they'll be less susceptible to counter name changes.
88 */
89static const char *nsstats_desc[dns_nsstatscounter_max];
90static const char *resstats_desc[dns_resstatscounter_max];
91static const char *zonestats_desc[dns_zonestatscounter_max];
92static const char *sockstats_desc[isc_sockstatscounter_max];
93static const char *dnssecstats_desc[dns_dnssecstats_max];
94#ifdef HAVE_LIBXML2
95static const char *nsstats_xmldesc[dns_nsstatscounter_max];
96static const char *resstats_xmldesc[dns_resstatscounter_max];
97static const char *zonestats_xmldesc[dns_zonestatscounter_max];
98static const char *sockstats_xmldesc[isc_sockstatscounter_max];
99static const char *dnssecstats_xmldesc[dns_dnssecstats_max];
100#else
101#define nsstats_xmldesc NULL
102#define resstats_xmldesc NULL
103#define zonestats_xmldesc NULL
104#define sockstats_xmldesc NULL
105#define dnssecstats_xmldesc NULL
106#endif	/* HAVE_LIBXML2 */
107
108#define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0)
109
110/*%
111 * Mapping arrays to represent statistics counters in the order of our
112 * preference, regardless of the order of counter indices.  For example,
113 * nsstats_desc[nsstats_index[0]] will be the description that is shown first.
114 */
115static int nsstats_index[dns_nsstatscounter_max];
116static int resstats_index[dns_resstatscounter_max];
117static int zonestats_index[dns_zonestatscounter_max];
118static int sockstats_index[isc_sockstatscounter_max];
119static int dnssecstats_index[dns_dnssecstats_max];
120
121static inline void
122set_desc(int counter, int maxcounter, const char *fdesc, const char **fdescs,
123	 const char *xdesc, const char **xdescs)
124{
125	REQUIRE(counter < maxcounter);
126	REQUIRE(fdescs[counter] == NULL);
127#ifdef HAVE_LIBXML2
128	REQUIRE(xdescs[counter] == NULL);
129#endif
130
131	fdescs[counter] = fdesc;
132#ifdef HAVE_LIBXML2
133	xdescs[counter] = xdesc;
134#else
135	UNUSED(xdesc);
136	UNUSED(xdescs);
137#endif
138}
139
140static void
141init_desc(void) {
142	int i;
143
144	/* Initialize name server statistics */
145	for (i = 0; i < dns_nsstatscounter_max; i++)
146		nsstats_desc[i] = NULL;
147#ifdef HAVE_LIBXML2
148	for (i = 0; i < dns_nsstatscounter_max; i++)
149		nsstats_xmldesc[i] = NULL;
150#endif
151
152#define SET_NSSTATDESC(counterid, desc, xmldesc) \
153	do { \
154		set_desc(dns_nsstatscounter_ ## counterid, \
155			 dns_nsstatscounter_max, \
156			 desc, nsstats_desc, xmldesc, nsstats_xmldesc); \
157		nsstats_index[i++] = dns_nsstatscounter_ ## counterid; \
158	} while (0)
159
160	i = 0;
161	SET_NSSTATDESC(requestv4, "IPv4 requests received", "Requestv4");
162	SET_NSSTATDESC(requestv6, "IPv6 requests received", "Requestv6");
163	SET_NSSTATDESC(edns0in, "requests with EDNS(0) received", "ReqEdns0");
164	SET_NSSTATDESC(badednsver,
165		       "requests with unsupported EDNS version received",
166		       "ReqBadEDNSVer");
167	SET_NSSTATDESC(tsigin, "requests with TSIG received", "ReqTSIG");
168	SET_NSSTATDESC(sig0in, "requests with SIG(0) received", "ReqSIG0");
169	SET_NSSTATDESC(invalidsig, "requests with invalid signature",
170		       "ReqBadSIG");
171	SET_NSSTATDESC(tcp, "TCP requests received", "ReqTCP");
172	SET_NSSTATDESC(authrej, "auth queries rejected", "AuthQryRej");
173	SET_NSSTATDESC(recurserej, "recursive queries rejected", "RecQryRej");
174	SET_NSSTATDESC(xfrrej, "transfer requests rejected", "XfrRej");
175	SET_NSSTATDESC(updaterej, "update requests rejected", "UpdateRej");
176	SET_NSSTATDESC(response, "responses sent", "Response");
177	SET_NSSTATDESC(truncatedresp, "truncated responses sent",
178		       "TruncatedResp");
179	SET_NSSTATDESC(edns0out, "responses with EDNS(0) sent", "RespEDNS0");
180	SET_NSSTATDESC(tsigout, "responses with TSIG sent", "RespTSIG");
181	SET_NSSTATDESC(sig0out, "responses with SIG(0) sent", "RespSIG0");
182	SET_NSSTATDESC(success, "queries resulted in successful answer",
183		       "QrySuccess");
184	SET_NSSTATDESC(authans, "queries resulted in authoritative answer",
185		       "QryAuthAns");
186	SET_NSSTATDESC(nonauthans,
187		       "queries resulted in non authoritative answer",
188		       "QryNoauthAns");
189	SET_NSSTATDESC(referral, "queries resulted in referral answer",
190		       "QryReferral");
191	SET_NSSTATDESC(nxrrset, "queries resulted in nxrrset", "QryNxrrset");
192	SET_NSSTATDESC(servfail, "queries resulted in SERVFAIL", "QrySERVFAIL");
193	SET_NSSTATDESC(formerr, "queries resulted in FORMERR", "QryFORMERR");
194	SET_NSSTATDESC(nxdomain, "queries resulted in NXDOMAIN", "QryNXDOMAIN");
195	SET_NSSTATDESC(recursion, "queries caused recursion", "QryRecursion");
196	SET_NSSTATDESC(duplicate, "duplicate queries received", "QryDuplicate");
197	SET_NSSTATDESC(dropped, "queries dropped", "QryDropped");
198	SET_NSSTATDESC(failure, "other query failures", "QryFailure");
199	SET_NSSTATDESC(xfrdone, "requested transfers completed", "XfrReqDone");
200	SET_NSSTATDESC(updatereqfwd, "update requests forwarded",
201		       "UpdateReqFwd");
202	SET_NSSTATDESC(updaterespfwd, "update responses forwarded",
203		       "UpdateRespFwd");
204	SET_NSSTATDESC(updatefwdfail, "update forward failed", "UpdateFwdFail");
205	SET_NSSTATDESC(updatedone, "updates completed", "UpdateDone");
206	SET_NSSTATDESC(updatefail, "updates failed", "UpdateFail");
207	SET_NSSTATDESC(updatebadprereq,
208		       "updates rejected due to prerequisite failure",
209		       "UpdateBadPrereq");
210	SET_NSSTATDESC(rpz_rewrites, "response policy zone rewrites",
211		       "RPZRewrites");
212#ifdef USE_RRL
213	SET_NSSTATDESC(ratedropped, "responses dropped for rate limits",
214		       "RateDropped");
215	SET_NSSTATDESC(rateslipped, "responses truncated for rate limits",
216		       "RateSlipped");
217#endif /* USE_RRL */
218	INSIST(i == dns_nsstatscounter_max);
219
220	/* Initialize resolver statistics */
221	for (i = 0; i < dns_resstatscounter_max; i++)
222		resstats_desc[i] = NULL;
223#ifdef  HAVE_LIBXML2
224	for (i = 0; i < dns_resstatscounter_max; i++)
225		resstats_xmldesc[i] = NULL;
226#endif
227
228#define SET_RESSTATDESC(counterid, desc, xmldesc) \
229	do { \
230		set_desc(dns_resstatscounter_ ## counterid, \
231			 dns_resstatscounter_max, \
232			 desc, resstats_desc, xmldesc, resstats_xmldesc); \
233		resstats_index[i++] = dns_resstatscounter_ ## counterid; \
234	} while (0)
235
236	i = 0;
237	SET_RESSTATDESC(queryv4, "IPv4 queries sent", "Queryv4");
238	SET_RESSTATDESC(queryv6, "IPv6 queries sent", "Queryv6");
239	SET_RESSTATDESC(responsev4, "IPv4 responses received", "Responsev4");
240	SET_RESSTATDESC(responsev6, "IPv6 responses received", "Responsev6");
241	SET_RESSTATDESC(nxdomain, "NXDOMAIN received", "NXDOMAIN");
242	SET_RESSTATDESC(servfail, "SERVFAIL received", "SERVFAIL");
243	SET_RESSTATDESC(formerr, "FORMERR received", "FORMERR");
244	SET_RESSTATDESC(othererror, "other errors received", "OtherError");
245	SET_RESSTATDESC(edns0fail, "EDNS(0) query failures", "EDNS0Fail");
246	SET_RESSTATDESC(mismatch, "mismatch responses received", "Mismatch");
247	SET_RESSTATDESC(truncated, "truncated responses received", "Truncated");
248	SET_RESSTATDESC(lame, "lame delegations received", "Lame");
249	SET_RESSTATDESC(retry, "query retries", "Retry");
250	SET_RESSTATDESC(dispabort, "queries aborted due to quota",
251			"QueryAbort");
252	SET_RESSTATDESC(dispsockfail, "failures in opening query sockets",
253			"QuerySockFail");
254	SET_RESSTATDESC(querytimeout, "query timeouts", "QueryTimeout");
255	SET_RESSTATDESC(gluefetchv4, "IPv4 NS address fetches", "GlueFetchv4");
256	SET_RESSTATDESC(gluefetchv6, "IPv6 NS address fetches", "GlueFetchv6");
257	SET_RESSTATDESC(gluefetchv4fail, "IPv4 NS address fetch failed",
258			"GlueFetchv4Fail");
259	SET_RESSTATDESC(gluefetchv6fail, "IPv6 NS address fetch failed",
260			"GlueFetchv6Fail");
261	SET_RESSTATDESC(val, "DNSSEC validation attempted", "ValAttempt");
262	SET_RESSTATDESC(valsuccess, "DNSSEC validation succeeded", "ValOk");
263	SET_RESSTATDESC(valnegsuccess, "DNSSEC NX validation succeeded",
264			"ValNegOk");
265	SET_RESSTATDESC(valfail, "DNSSEC validation failed", "ValFail");
266	SET_RESSTATDESC(queryrtt0, "queries with RTT < "
267			DNS_RESOLVER_QRYRTTCLASS0STR "ms",
268			"QryRTT" DNS_RESOLVER_QRYRTTCLASS0STR);
269	SET_RESSTATDESC(queryrtt1, "queries with RTT "
270			DNS_RESOLVER_QRYRTTCLASS0STR "-"
271			DNS_RESOLVER_QRYRTTCLASS1STR "ms",
272			"QryRTT" DNS_RESOLVER_QRYRTTCLASS1STR);
273	SET_RESSTATDESC(queryrtt2, "queries with RTT "
274			DNS_RESOLVER_QRYRTTCLASS1STR "-"
275			DNS_RESOLVER_QRYRTTCLASS2STR "ms",
276			"QryRTT" DNS_RESOLVER_QRYRTTCLASS2STR);
277	SET_RESSTATDESC(queryrtt3, "queries with RTT "
278			DNS_RESOLVER_QRYRTTCLASS2STR "-"
279			DNS_RESOLVER_QRYRTTCLASS3STR "ms",
280			"QryRTT" DNS_RESOLVER_QRYRTTCLASS3STR);
281	SET_RESSTATDESC(queryrtt4, "queries with RTT "
282			DNS_RESOLVER_QRYRTTCLASS3STR "-"
283			DNS_RESOLVER_QRYRTTCLASS4STR "ms",
284			"QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR);
285	SET_RESSTATDESC(queryrtt5, "queries with RTT > "
286			DNS_RESOLVER_QRYRTTCLASS4STR "ms",
287			"QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR "+");
288	INSIST(i == dns_resstatscounter_max);
289
290	/* Initialize zone statistics */
291	for (i = 0; i < dns_zonestatscounter_max; i++)
292		zonestats_desc[i] = NULL;
293#ifdef  HAVE_LIBXML2
294	for (i = 0; i < dns_zonestatscounter_max; i++)
295		zonestats_xmldesc[i] = NULL;
296#endif
297
298#define SET_ZONESTATDESC(counterid, desc, xmldesc) \
299	do { \
300		set_desc(dns_zonestatscounter_ ## counterid, \
301			 dns_zonestatscounter_max, \
302			 desc, zonestats_desc, xmldesc, zonestats_xmldesc); \
303		zonestats_index[i++] = dns_zonestatscounter_ ## counterid; \
304	} while (0)
305
306	i = 0;
307	SET_ZONESTATDESC(notifyoutv4, "IPv4 notifies sent", "NotifyOutv4");
308	SET_ZONESTATDESC(notifyoutv6, "IPv6 notifies sent", "NotifyOutv6");
309	SET_ZONESTATDESC(notifyinv4, "IPv4 notifies received", "NotifyInv4");
310	SET_ZONESTATDESC(notifyinv6, "IPv6 notifies received", "NotifyInv6");
311	SET_ZONESTATDESC(notifyrej, "notifies rejected", "NotifyRej");
312	SET_ZONESTATDESC(soaoutv4, "IPv4 SOA queries sent", "SOAOutv4");
313	SET_ZONESTATDESC(soaoutv6, "IPv6 SOA queries sent", "SOAOutv6");
314	SET_ZONESTATDESC(axfrreqv4, "IPv4 AXFR requested", "AXFRReqv4");
315	SET_ZONESTATDESC(axfrreqv6, "IPv6 AXFR requested", "AXFRReqv6");
316	SET_ZONESTATDESC(ixfrreqv4, "IPv4 IXFR requested", "IXFRReqv4");
317	SET_ZONESTATDESC(ixfrreqv6, "IPv6 IXFR requested", "IXFRReqv6");
318	SET_ZONESTATDESC(xfrsuccess, "transfer requests succeeded",
319			 "XfrSuccess");
320	SET_ZONESTATDESC(xfrfail, "transfer requests failed", "XfrFail");
321	INSIST(i == dns_zonestatscounter_max);
322
323	/* Initialize socket statistics */
324	for (i = 0; i < isc_sockstatscounter_max; i++)
325		sockstats_desc[i] = NULL;
326#ifdef  HAVE_LIBXML2
327	for (i = 0; i < isc_sockstatscounter_max; i++)
328		sockstats_xmldesc[i] = NULL;
329#endif
330
331#define SET_SOCKSTATDESC(counterid, desc, xmldesc) \
332	do { \
333		set_desc(isc_sockstatscounter_ ## counterid, \
334			 isc_sockstatscounter_max, \
335			 desc, sockstats_desc, xmldesc, sockstats_xmldesc); \
336		sockstats_index[i++] = isc_sockstatscounter_ ## counterid; \
337	} while (0)
338
339	i = 0;
340	SET_SOCKSTATDESC(udp4open, "UDP/IPv4 sockets opened", "UDP4Open");
341	SET_SOCKSTATDESC(udp6open, "UDP/IPv6 sockets opened", "UDP6Open");
342	SET_SOCKSTATDESC(tcp4open, "TCP/IPv4 sockets opened", "TCP4Open");
343	SET_SOCKSTATDESC(tcp6open, "TCP/IPv6 sockets opened", "TCP6Open");
344	SET_SOCKSTATDESC(unixopen, "Unix domain sockets opened", "UnixOpen");
345	SET_SOCKSTATDESC(udp4openfail, "UDP/IPv4 socket open failures",
346			 "UDP4OpenFail");
347	SET_SOCKSTATDESC(udp6openfail, "UDP/IPv6 socket open failures",
348			 "UDP6OpenFail");
349	SET_SOCKSTATDESC(tcp4openfail, "TCP/IPv4 socket open failures",
350			 "TCP4OpenFail");
351	SET_SOCKSTATDESC(tcp6openfail, "TCP/IPv6 socket open failures",
352			 "TCP6OpenFail");
353	SET_SOCKSTATDESC(unixopenfail, "Unix domain socket open failures",
354			 "UnixOpenFail");
355	SET_SOCKSTATDESC(udp4close, "UDP/IPv4 sockets closed", "UDP4Close");
356	SET_SOCKSTATDESC(udp6close, "UDP/IPv6 sockets closed", "UDP6Close");
357	SET_SOCKSTATDESC(tcp4close, "TCP/IPv4 sockets closed", "TCP4Close");
358	SET_SOCKSTATDESC(tcp6close, "TCP/IPv6 sockets closed", "TCP6Close");
359	SET_SOCKSTATDESC(unixclose, "Unix domain sockets closed", "UnixClose");
360	SET_SOCKSTATDESC(fdwatchclose, "FDwatch sockets closed",
361			 "FDWatchClose");
362	SET_SOCKSTATDESC(udp4bindfail, "UDP/IPv4 socket bind failures",
363			 "UDP4BindFail");
364	SET_SOCKSTATDESC(udp6bindfail, "UDP/IPv6 socket bind failures",
365			 "UDP6BindFail");
366	SET_SOCKSTATDESC(tcp4bindfail, "TCP/IPv4 socket bind failures",
367			 "TCP4BindFail");
368	SET_SOCKSTATDESC(tcp6bindfail, "TCP/IPv6 socket bind failures",
369			 "TCP6BindFail");
370	SET_SOCKSTATDESC(unixbindfail, "Unix domain socket bind failures",
371			 "UnixBindFail");
372	SET_SOCKSTATDESC(fdwatchbindfail, "FDwatch socket bind failures",
373			 "FdwatchBindFail");
374	SET_SOCKSTATDESC(udp4connectfail, "UDP/IPv4 socket connect failures",
375			 "UDP4ConnFail");
376	SET_SOCKSTATDESC(udp6connectfail, "UDP/IPv6 socket connect failures",
377			 "UDP6ConnFail");
378	SET_SOCKSTATDESC(tcp4connectfail, "TCP/IPv4 socket connect failures",
379			 "TCP4ConnFail");
380	SET_SOCKSTATDESC(tcp6connectfail, "TCP/IPv6 socket connect failures",
381			 "TCP6ConnFail");
382	SET_SOCKSTATDESC(unixconnectfail, "Unix domain socket connect failures",
383			 "UnixConnFail");
384	SET_SOCKSTATDESC(fdwatchconnectfail, "FDwatch socket connect failures",
385			 "FDwatchConnFail");
386	SET_SOCKSTATDESC(udp4connect, "UDP/IPv4 connections established",
387			 "UDP4Conn");
388	SET_SOCKSTATDESC(udp6connect, "UDP/IPv6 connections established",
389			 "UDP6Conn");
390	SET_SOCKSTATDESC(tcp4connect, "TCP/IPv4 connections established",
391			 "TCP4Conn");
392	SET_SOCKSTATDESC(tcp6connect, "TCP/IPv6 connections established",
393			 "TCP6Conn");
394	SET_SOCKSTATDESC(unixconnect, "Unix domain connections established",
395			 "UnixConn");
396	SET_SOCKSTATDESC(fdwatchconnect,
397			 "FDwatch domain connections established",
398			 "FDwatchConn");
399	SET_SOCKSTATDESC(tcp4acceptfail, "TCP/IPv4 connection accept failures",
400			 "TCP4AcceptFail");
401	SET_SOCKSTATDESC(tcp6acceptfail, "TCP/IPv6 connection accept failures",
402			 "TCP6AcceptFail");
403	SET_SOCKSTATDESC(unixacceptfail,
404			 "Unix domain connection accept failures",
405			 "UnixAcceptFail");
406	SET_SOCKSTATDESC(tcp4accept, "TCP/IPv4 connections accepted",
407			 "TCP4Accept");
408	SET_SOCKSTATDESC(tcp6accept, "TCP/IPv6 connections accepted",
409			 "TCP6Accept");
410	SET_SOCKSTATDESC(unixaccept, "Unix domain connections accepted",
411			 "UnixAccept");
412	SET_SOCKSTATDESC(udp4sendfail, "UDP/IPv4 send errors", "UDP4SendErr");
413	SET_SOCKSTATDESC(udp6sendfail, "UDP/IPv6 send errors", "UDP6SendErr");
414	SET_SOCKSTATDESC(tcp4sendfail, "TCP/IPv4 send errors", "TCP4SendErr");
415	SET_SOCKSTATDESC(tcp6sendfail, "TCP/IPv6 send errors", "TCP6SendErr");
416	SET_SOCKSTATDESC(unixsendfail, "Unix domain send errors",
417			 "UnixSendErr");
418	SET_SOCKSTATDESC(fdwatchsendfail, "FDwatch send errors",
419			 "FDwatchSendErr");
420	SET_SOCKSTATDESC(udp4recvfail, "UDP/IPv4 recv errors", "UDP4RecvErr");
421	SET_SOCKSTATDESC(udp6recvfail, "UDP/IPv6 recv errors", "UDP6RecvErr");
422	SET_SOCKSTATDESC(tcp4recvfail, "TCP/IPv4 recv errors", "TCP4RecvErr");
423	SET_SOCKSTATDESC(tcp6recvfail, "TCP/IPv6 recv errors", "TCP6RecvErr");
424	SET_SOCKSTATDESC(unixrecvfail, "Unix domain recv errors",
425			 "UnixRecvErr");
426	SET_SOCKSTATDESC(fdwatchrecvfail, "FDwatch recv errors",
427			 "FDwatchRecvErr");
428	INSIST(i == isc_sockstatscounter_max);
429
430	/* Initialize DNSSEC statistics */
431	for (i = 0; i < dns_dnssecstats_max; i++)
432		dnssecstats_desc[i] = NULL;
433#ifdef  HAVE_LIBXML2
434	for (i = 0; i < dns_dnssecstats_max; i++)
435		dnssecstats_xmldesc[i] = NULL;
436#endif
437
438#define SET_DNSSECSTATDESC(counterid, desc, xmldesc) \
439	do { \
440		set_desc(dns_dnssecstats_ ## counterid, \
441			 dns_dnssecstats_max, \
442			 desc, dnssecstats_desc, \
443			 xmldesc, dnssecstats_xmldesc); \
444		dnssecstats_index[i++] = dns_dnssecstats_ ## counterid; \
445	} while (0)
446
447	i = 0;
448	SET_DNSSECSTATDESC(asis, "dnssec validation success with signer "
449			   "\"as is\"", "DNSSECasis");
450	SET_DNSSECSTATDESC(downcase, "dnssec validation success with signer "
451			   "lower cased", "DNSSECdowncase");
452	SET_DNSSECSTATDESC(wildcard, "dnssec validation of wildcard signature",
453			   "DNSSECwild");
454	SET_DNSSECSTATDESC(fail, "dnssec validation failures", "DNSSECfail");
455	INSIST(i == dns_dnssecstats_max);
456
457	/* Sanity check */
458	for (i = 0; i < dns_nsstatscounter_max; i++)
459		INSIST(nsstats_desc[i] != NULL);
460	for (i = 0; i < dns_resstatscounter_max; i++)
461		INSIST(resstats_desc[i] != NULL);
462	for (i = 0; i < dns_zonestatscounter_max; i++)
463		INSIST(zonestats_desc[i] != NULL);
464	for (i = 0; i < isc_sockstatscounter_max; i++)
465		INSIST(sockstats_desc[i] != NULL);
466	for (i = 0; i < dns_dnssecstats_max; i++)
467		INSIST(dnssecstats_desc[i] != NULL);
468#ifdef  HAVE_LIBXML2
469	for (i = 0; i < dns_nsstatscounter_max; i++)
470		INSIST(nsstats_xmldesc[i] != NULL);
471	for (i = 0; i < dns_resstatscounter_max; i++)
472		INSIST(resstats_xmldesc[i] != NULL);
473	for (i = 0; i < dns_zonestatscounter_max; i++)
474		INSIST(zonestats_xmldesc[i] != NULL);
475	for (i = 0; i < isc_sockstatscounter_max; i++)
476		INSIST(sockstats_xmldesc[i] != NULL);
477	for (i = 0; i < dns_dnssecstats_max; i++)
478		INSIST(dnssecstats_xmldesc[i] != NULL);
479#endif
480}
481
482/*%
483 * Dump callback functions.
484 */
485static void
486generalstat_dump(isc_statscounter_t counter, isc_uint64_t val, void *arg) {
487	stats_dumparg_t *dumparg = arg;
488
489	REQUIRE(counter < dumparg->ncounters);
490	dumparg->countervalues[counter] = val;
491}
492
493static isc_result_t
494dump_counters(isc_stats_t *stats, statsformat_t type, void *arg,
495	      const char *category, const char **desc, int ncounters,
496	      int *indices, isc_uint64_t *values, int options)
497{
498	int i, index;
499	isc_uint64_t value;
500	stats_dumparg_t dumparg;
501	FILE *fp;
502#ifdef HAVE_LIBXML2
503	xmlTextWriterPtr writer;
504	int xmlrc;
505#endif
506
507#ifndef HAVE_LIBXML2
508	UNUSED(category);
509#endif
510
511	dumparg.type = type;
512	dumparg.ncounters = ncounters;
513	dumparg.counterindices = indices;
514	dumparg.countervalues = values;
515
516	memset(values, 0, sizeof(values[0]) * ncounters);
517	isc_stats_dump(stats, generalstat_dump, &dumparg, options);
518
519	for (i = 0; i < ncounters; i++) {
520		index = indices[i];
521		value = values[index];
522
523		if (value == 0 && (options & ISC_STATSDUMP_VERBOSE) == 0)
524			continue;
525
526		switch (dumparg.type) {
527		case statsformat_file:
528			fp = arg;
529			fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
530				value, desc[index]);
531			break;
532		case statsformat_xml:
533#ifdef HAVE_LIBXML2
534#ifdef NEWSTATS
535		writer = arg;
536
537		if (category != NULL) {
538			/* <NameOfCategory> */
539			TRY0(xmlTextWriterStartElement(writer,
540						       ISC_XMLCHAR
541						       category));
542			/* <name> inside category */
543			TRY0(xmlTextWriterStartElement(writer,
544						       ISC_XMLCHAR
545						       "name"));
546			TRY0(xmlTextWriterWriteString(writer,
547						      ISC_XMLCHAR
548						      desc[index]));
549			TRY0(xmlTextWriterEndElement(writer));
550			/* </name> */
551
552			/* <counter> */
553			TRY0(xmlTextWriterStartElement(writer,
554						       ISC_XMLCHAR
555						       "counter"));
556			TRY0(xmlTextWriterWriteFormatString(writer,
557				"%" ISC_PRINT_QUADFORMAT "u", value));
558
559			TRY0(xmlTextWriterEndElement(writer));
560			/* </counter> */
561			TRY0(xmlTextWriterEndElement(writer));
562			/* </NameOfCategory> */
563
564		} else {
565			TRY0(xmlTextWriterStartElement(writer,
566						       ISC_XMLCHAR
567						       "counter"));
568			TRY0(xmlTextWriterWriteAttribute(writer,
569							 ISC_XMLCHAR
570							 "name",
571							 ISC_XMLCHAR
572							 desc[index]));
573			TRY0(xmlTextWriterWriteFormatString(writer,
574				"%" ISC_PRINT_QUADFORMAT "u", value));
575			TRY0(xmlTextWriterEndElement(writer));
576			/* counter */
577		}
578#else /* !NEWSTATS */
579			writer = arg;
580
581			if (category != NULL) {
582				TRY0(xmlTextWriterStartElement(writer,
583							       ISC_XMLCHAR
584							       category));
585				TRY0(xmlTextWriterStartElement(writer,
586							       ISC_XMLCHAR
587							       "name"));
588				TRY0(xmlTextWriterWriteString(writer,
589							      ISC_XMLCHAR
590							      desc[index]));
591				TRY0(xmlTextWriterEndElement(writer)); /* name */
592
593				TRY0(xmlTextWriterStartElement(writer,
594							       ISC_XMLCHAR
595							       "counter"));
596			} else {
597				TRY0(xmlTextWriterStartElement(writer,
598							       ISC_XMLCHAR
599							       desc[index]));
600			}
601			TRY0(xmlTextWriterWriteFormatString(writer,
602							    "%"
603							    ISC_PRINT_QUADFORMAT
604							    "u", value));
605			TRY0(xmlTextWriterEndElement(writer)); /* counter */
606			if (category != NULL)
607				TRY0(xmlTextWriterEndElement(writer)); /* category */
608#endif /* NEWSTATS */
609#endif /* LIBXML2 */
610			break;
611		}
612	}
613	return (ISC_R_SUCCESS);
614#ifdef HAVE_LIBXML2
615 error:
616	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
617		      ISC_LOG_ERROR, "failed at dump_counters()");
618	return (ISC_R_FAILURE);
619#endif
620}
621
622#ifdef NEWSTATS
623static void
624rdtypestat_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
625	char typebuf[64];
626	const char *typestr;
627	stats_dumparg_t *dumparg = arg;
628	FILE *fp;
629#ifdef HAVE_LIBXML2
630	xmlTextWriterPtr writer;
631	int xmlrc;
632#endif
633
634	if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_OTHERTYPE)
635	    == 0) {
636		dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf,
637				     sizeof(typebuf));
638		typestr = typebuf;
639	} else
640		typestr = "Others";
641
642	switch (dumparg->type) {
643	case statsformat_file:
644		fp = dumparg->arg;
645		fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, typestr);
646		break;
647	case statsformat_xml:
648#ifdef HAVE_LIBXML2
649
650		writer = dumparg->arg;
651
652
653		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
654		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
655						 ISC_XMLCHAR typestr));
656
657		TRY0(xmlTextWriterWriteFormatString(writer,
658					       "%" ISC_PRINT_QUADFORMAT "u",
659					       val));
660
661		TRY0(xmlTextWriterEndElement(writer)); /* type */
662#endif
663		break;
664	}
665	return;
666#ifdef HAVE_LIBXML2
667 error:
668	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
669		      ISC_LOG_ERROR, "failed at rdtypestat_dump()");
670	dumparg->result = ISC_R_FAILURE;
671	return;
672#endif
673}
674#else  /* NEWSTATS */
675static void
676rdtypestat_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
677	char typebuf[64];
678	const char *typestr;
679	stats_dumparg_t *dumparg = arg;
680	FILE *fp;
681#ifdef HAVE_LIBXML2
682	xmlTextWriterPtr writer;
683	int xmlrc;
684#endif
685
686	if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_OTHERTYPE)
687	    == 0) {
688		dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf,
689				     sizeof(typebuf));
690		typestr = typebuf;
691	} else
692		typestr = "Others";
693
694	switch (dumparg->type) {
695	case statsformat_file:
696		fp = dumparg->arg;
697		fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, typestr);
698		break;
699	case statsformat_xml:
700#ifdef HAVE_LIBXML2
701		writer = dumparg->arg;
702
703		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "rdtype"));
704
705		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
706		TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR typestr));
707		TRY0(xmlTextWriterEndElement(writer)); /* name */
708
709		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
710		TRY0(xmlTextWriterWriteFormatString(writer,
711					       "%" ISC_PRINT_QUADFORMAT "u",
712					       val));
713		TRY0(xmlTextWriterEndElement(writer)); /* counter */
714
715		TRY0(xmlTextWriterEndElement(writer)); /* rdtype */
716#endif
717		break;
718	}
719	return;
720#ifdef HAVE_LIBXML2
721 error:
722	dumparg->result = ISC_R_FAILURE;
723	return;
724#endif
725}
726#endif  /* NEWSTATS */
727
728static void
729rdatasetstats_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
730	stats_dumparg_t *dumparg = arg;
731	FILE *fp;
732	char typebuf[64];
733	const char *typestr;
734	isc_boolean_t nxrrset = ISC_FALSE;
735#ifdef HAVE_LIBXML2
736	xmlTextWriterPtr writer;
737	int xmlrc;
738#endif
739
740	if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_NXDOMAIN)
741	    != 0) {
742		typestr = "NXDOMAIN";
743	} else if ((DNS_RDATASTATSTYPE_ATTR(type) &
744		    DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) != 0) {
745		typestr = "Others";
746	} else {
747		dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf,
748				     sizeof(typebuf));
749		typestr = typebuf;
750	}
751
752	if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_NXRRSET)
753	    != 0)
754		nxrrset = ISC_TRUE;
755
756	switch (dumparg->type) {
757	case statsformat_file:
758		fp = dumparg->arg;
759		fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s%s\n", val,
760			nxrrset ? "!" : "", typestr);
761		break;
762	case statsformat_xml:
763#ifdef HAVE_LIBXML2
764		writer = dumparg->arg;
765
766		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "rrset"));
767		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
768		TRY0(xmlTextWriterWriteFormatString(writer, "%s%s",
769					       nxrrset ? "!" : "", typestr));
770		TRY0(xmlTextWriterEndElement(writer)); /* name */
771
772		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
773		TRY0(xmlTextWriterWriteFormatString(writer,
774					       "%" ISC_PRINT_QUADFORMAT "u",
775					       val));
776		TRY0(xmlTextWriterEndElement(writer)); /* counter */
777
778		TRY0(xmlTextWriterEndElement(writer)); /* rrset */
779#endif
780		break;
781	}
782	return;
783#ifdef HAVE_LIBXML2
784 error:
785	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
786		      ISC_LOG_ERROR, "failed at rdatasetstats_dump()");
787	dumparg->result = ISC_R_FAILURE;
788#endif
789
790}
791
792#ifdef NEWSTATS
793static void
794opcodestat_dump(dns_opcode_t code, isc_uint64_t val, void *arg) {
795	FILE *fp;
796	isc_buffer_t b;
797	char codebuf[64];
798	stats_dumparg_t *dumparg = arg;
799#ifdef HAVE_LIBXML2
800	xmlTextWriterPtr writer;
801	int xmlrc;
802#endif
803
804	isc_buffer_init(&b, codebuf, sizeof(codebuf) - 1);
805	dns_opcode_totext(code, &b);
806	codebuf[isc_buffer_usedlength(&b)] = '\0';
807
808	switch (dumparg->type) {
809	case statsformat_file:
810		fp = dumparg->arg;
811		fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, codebuf);
812		break;
813	case statsformat_xml:
814#ifdef HAVE_LIBXML2
815		writer = dumparg->arg;
816		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
817		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
818						 ISC_XMLCHAR codebuf ));
819		TRY0(xmlTextWriterWriteFormatString(writer,
820						       "%" ISC_PRINT_QUADFORMAT "u",
821						       val));
822		TRY0(xmlTextWriterEndElement(writer)); /* counter */
823#endif
824		break;
825	}
826	return;
827
828#ifdef HAVE_LIBXML2
829 error:
830	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
831		      ISC_LOG_ERROR, "failed at opcodestat_dump()");
832	dumparg->result = ISC_R_FAILURE;
833	return;
834#endif
835}
836#else  /* NEWSTATS */
837static void
838opcodestat_dump(dns_opcode_t code, isc_uint64_t val, void *arg) {
839	FILE *fp;
840	isc_buffer_t b;
841	char codebuf[64];
842	stats_dumparg_t *dumparg = arg;
843#ifdef HAVE_LIBXML2
844	xmlTextWriterPtr writer;
845	int xmlrc;
846#endif
847
848	isc_buffer_init(&b, codebuf, sizeof(codebuf) - 1);
849	dns_opcode_totext(code, &b);
850	codebuf[isc_buffer_usedlength(&b)] = '\0';
851
852	switch (dumparg->type) {
853	case statsformat_file:
854		fp = dumparg->arg;
855		fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, codebuf);
856		break;
857	case statsformat_xml:
858#ifdef HAVE_LIBXML2
859		writer = dumparg->arg;
860
861		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "opcode"));
862
863		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
864		TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR codebuf));
865		TRY0(xmlTextWriterEndElement(writer)); /* name */
866
867		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
868		TRY0(xmlTextWriterWriteFormatString(writer,
869					       "%" ISC_PRINT_QUADFORMAT "u",
870					       val));
871		TRY0(xmlTextWriterEndElement(writer)); /* counter */
872
873		TRY0(xmlTextWriterEndElement(writer)); /* opcode */
874#endif
875		break;
876	}
877	return;
878
879#ifdef HAVE_LIBXML2
880 error:
881	dumparg->result = ISC_R_FAILURE;
882	return;
883#endif
884}
885#endif  /* NEWSTATS */
886
887#ifdef HAVE_LIBXML2
888
889/* XXXMLG below here sucks. (not so much) */
890
891#ifdef NEWSTATS
892static isc_result_t
893zone_xmlrender(dns_zone_t *zone, void *arg) {
894	isc_result_t result;
895	char buf[1024 + 32];	/* sufficiently large for zone name and class */
896	char *zone_name_only = NULL;
897	dns_rdataclass_t rdclass;
898	isc_uint32_t serial;
899	xmlTextWriterPtr writer = arg;
900	isc_stats_t *zonestats;
901	dns_stats_t *rcvquerystats;
902	dns_zonestat_level_t statlevel;
903	isc_uint64_t nsstat_values[dns_nsstatscounter_max];
904	int xmlrc;
905	stats_dumparg_t dumparg;
906
907	statlevel = dns_zone_getstatlevel(zone);
908	if (statlevel == dns_zonestat_none)
909		return (ISC_R_SUCCESS);
910
911	dumparg.type = statsformat_xml;
912	dumparg.arg = writer;
913
914	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "zone"));
915	dns_zone_name(zone, buf, sizeof(buf));
916	zone_name_only = strtok(buf, "/");
917	if(zone_name_only == NULL)
918		zone_name_only = buf;
919
920	TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
921					 ISC_XMLCHAR zone_name_only));
922	rdclass = dns_zone_getclass(zone);
923	dns_rdataclass_format(rdclass, buf, sizeof(buf));
924	TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "rdataclass",
925					 ISC_XMLCHAR buf));
926
927	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "serial"));
928	if (dns_zone_getserial2(zone, &serial) == ISC_R_SUCCESS)
929		TRY0(xmlTextWriterWriteFormatString(writer, "%u", serial));
930	else
931		TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-"));
932	TRY0(xmlTextWriterEndElement(writer)); /* serial */
933
934	zonestats = dns_zone_getrequeststats(zone);
935	rcvquerystats = dns_zone_getrcvquerystats(zone);
936	if (statlevel == dns_zonestat_full && zonestats != NULL) {
937		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
938		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
939						 ISC_XMLCHAR "rcode"));
940
941		result = dump_counters(zonestats, statsformat_xml, writer,
942				       NULL, nsstats_xmldesc,
943				       dns_nsstatscounter_max, nsstats_index,
944				       nsstat_values, ISC_STATSDUMP_VERBOSE);
945		if (result != ISC_R_SUCCESS)
946			goto error;
947		/* counters type="rcode"*/
948		TRY0(xmlTextWriterEndElement(writer));
949	}
950
951	if (statlevel == dns_zonestat_full && rcvquerystats != NULL) {
952		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
953		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
954						 ISC_XMLCHAR "qtype"));
955
956		dumparg.result = ISC_R_SUCCESS;
957		dns_rdatatypestats_dump(rcvquerystats, rdtypestat_dump,
958					&dumparg, 0);
959		if(dumparg.result != ISC_R_SUCCESS)
960			goto error;
961
962		/* counters type="qtype"*/
963		TRY0(xmlTextWriterEndElement(writer));
964	}
965
966	TRY0(xmlTextWriterEndElement(writer)); /* zone */
967
968	return (ISC_R_SUCCESS);
969 error:
970	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
971		      ISC_LOG_ERROR, "Failed at zone_xmlrender()");
972	return (ISC_R_FAILURE);
973}
974#else  /* NEWSTATS */
975static isc_result_t
976zone_xmlrender(dns_zone_t *zone, void *arg) {
977	char buf[1024 + 32];	/* sufficiently large for zone name and class */
978	dns_rdataclass_t rdclass;
979	isc_uint32_t serial;
980	xmlTextWriterPtr writer = arg;
981	isc_stats_t *zonestats;
982	dns_zonestat_level_t statlevel;
983	isc_uint64_t nsstat_values[dns_nsstatscounter_max];
984	int xmlrc;
985	isc_result_t result;
986
987	statlevel = dns_zone_getstatlevel(zone);
988	if (statlevel == dns_zonestat_none)
989		return (ISC_R_SUCCESS);
990
991	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "zone"));
992
993	dns_zone_name(zone, buf, sizeof(buf));
994	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
995	TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR buf));
996	TRY0(xmlTextWriterEndElement(writer));
997
998	rdclass = dns_zone_getclass(zone);
999	dns_rdataclass_format(rdclass, buf, sizeof(buf));
1000	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "rdataclass"));
1001	TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR buf));
1002	TRY0(xmlTextWriterEndElement(writer));
1003
1004	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "serial"));
1005	if (dns_zone_getserial2(zone, &serial) == ISC_R_SUCCESS)
1006		TRY0(xmlTextWriterWriteFormatString(writer, "%u", serial));
1007	else
1008		TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-"));
1009	TRY0(xmlTextWriterEndElement(writer));
1010
1011	zonestats = dns_zone_getrequeststats(zone);
1012	if (zonestats != NULL) {
1013		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1014		result = dump_counters(zonestats, statsformat_xml, writer, NULL,
1015				      nsstats_xmldesc, dns_nsstatscounter_max,
1016				      nsstats_index, nsstat_values,
1017				      ISC_STATSDUMP_VERBOSE);
1018		if (result != ISC_R_SUCCESS)
1019			goto error;
1020		TRY0(xmlTextWriterEndElement(writer)); /* counters */
1021	}
1022
1023	TRY0(xmlTextWriterEndElement(writer)); /* zone */
1024
1025	return (ISC_R_SUCCESS);
1026 error:
1027	return (ISC_R_FAILURE);
1028}
1029#endif  /* NEWSTATS */
1030
1031#ifdef NEWSTATS
1032static isc_result_t
1033generatexml(ns_server_t *server, int *buflen, xmlChar **buf) {
1034	char boottime[sizeof "yyyy-mm-ddThh:mm:ssZ"];
1035	char nowstr[sizeof "yyyy-mm-ddThh:mm:ssZ"];
1036	isc_time_t now;
1037	xmlTextWriterPtr writer = NULL;
1038	xmlDocPtr doc = NULL;
1039	int xmlrc;
1040	dns_view_t *view;
1041	stats_dumparg_t dumparg;
1042	dns_stats_t *cacherrstats;
1043	isc_uint64_t nsstat_values[dns_nsstatscounter_max];
1044	isc_uint64_t resstat_values[dns_resstatscounter_max];
1045	isc_uint64_t zonestat_values[dns_zonestatscounter_max];
1046	isc_uint64_t sockstat_values[isc_sockstatscounter_max];
1047	isc_result_t result;
1048
1049	isc_time_now(&now);
1050	isc_time_formatISO8601(&ns_g_boottime, boottime, sizeof boottime);
1051	isc_time_formatISO8601(&now, nowstr, sizeof nowstr);
1052
1053	writer = xmlNewTextWriterDoc(&doc, 0);
1054	if (writer == NULL)
1055		goto error;
1056	TRY0(xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL));
1057	TRY0(xmlTextWriterWritePI(writer, ISC_XMLCHAR "xml-stylesheet",
1058			ISC_XMLCHAR "type=\"text/xsl\" href=\"/bind9.ver3.xsl\""));
1059	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics"));
1060	TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version",
1061					 ISC_XMLCHAR "3.3"));
1062
1063	/* Set common fields for statistics dump */
1064	dumparg.type = statsformat_xml;
1065	dumparg.arg = writer;
1066
1067	/*
1068	 * Start by rendering the views we know of here.  For each view we
1069	 * know of, call its rendering function.
1070	 */
1071	view = ISC_LIST_HEAD(server->viewlist);
1072	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "views"));
1073	while (view != NULL) {
1074		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "view"));
1075		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
1076						 ISC_XMLCHAR view->name));
1077
1078		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "zones"));
1079		result = dns_zt_apply(view->zonetable, ISC_TRUE, zone_xmlrender,
1080				      writer);
1081		if (result != ISC_R_SUCCESS)
1082			goto error;
1083		TRY0(xmlTextWriterEndElement(writer)); /* zones */
1084
1085		TRY0(xmlTextWriterStartElement(writer,
1086					       ISC_XMLCHAR "counters"));
1087		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1088						 ISC_XMLCHAR "resqtype"));
1089
1090		if (view->resquerystats != NULL) {
1091			dumparg.result = ISC_R_SUCCESS;
1092			dns_rdatatypestats_dump(view->resquerystats,
1093						rdtypestat_dump, &dumparg, 0);
1094			if (dumparg.result != ISC_R_SUCCESS)
1095				goto error;
1096		}
1097else fprintf(stderr, "WTF WHERE'S RESQUERYRSTATS\n");
1098		TRY0(xmlTextWriterEndElement(writer));
1099
1100		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1101		TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1102						 ISC_XMLCHAR "resstats"));
1103		if (view->resstats != NULL) {
1104			result = dump_counters(view->resstats,
1105					       statsformat_xml, writer,
1106					       NULL, resstats_xmldesc,
1107					       dns_resstatscounter_max,
1108					       resstats_index, resstat_values,
1109					       ISC_STATSDUMP_VERBOSE);
1110			if (result != ISC_R_SUCCESS)
1111				goto error;
1112		}
1113		TRY0(xmlTextWriterEndElement(writer));
1114
1115		cacherrstats = dns_db_getrrsetstats(view->cachedb);
1116		if (cacherrstats != NULL) {
1117			TRY0(xmlTextWriterStartElement(writer,
1118						       ISC_XMLCHAR "cache"));
1119			TRY0(xmlTextWriterWriteAttribute(writer,
1120					 ISC_XMLCHAR "name",
1121					 ISC_XMLCHAR
1122					 dns_cache_getname(view->cache)));
1123			dumparg.result = ISC_R_SUCCESS;
1124			dns_rdatasetstats_dump(cacherrstats, rdatasetstats_dump,
1125					       &dumparg, 0);
1126			if (dumparg.result != ISC_R_SUCCESS)
1127				goto error;
1128			TRY0(xmlTextWriterEndElement(writer)); /* cache */
1129		}
1130
1131		TRY0(xmlTextWriterEndElement(writer)); /* view */
1132
1133		view = ISC_LIST_NEXT(view, link);
1134	}
1135	TRY0(xmlTextWriterEndElement(writer)); /* views */
1136
1137	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "socketmgr"));
1138	isc_socketmgr_renderxml(ns_g_socketmgr, writer);
1139	TRY0(xmlTextWriterEndElement(writer)); /* socketmgr */
1140
1141	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "taskmgr"));
1142	isc_taskmgr_renderxml(ns_g_taskmgr, writer);
1143	TRY0(xmlTextWriterEndElement(writer)); /* taskmgr */
1144
1145	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "server"));
1146	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "boot-time"));
1147	TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR boottime));
1148	TRY0(xmlTextWriterEndElement(writer)); /* boot-time */
1149	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "current-time"));
1150	TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR nowstr));
1151	TRY0(xmlTextWriterEndElement(writer));  /* current-time */
1152
1153	dumparg.result = ISC_R_SUCCESS;
1154
1155	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1156	TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1157					 ISC_XMLCHAR "opcode"));
1158
1159	dns_opcodestats_dump(server->opcodestats, opcodestat_dump, &dumparg,
1160			     ISC_STATSDUMP_VERBOSE);
1161	if (dumparg.result != ISC_R_SUCCESS)
1162		goto error;
1163
1164	TRY0(xmlTextWriterEndElement(writer)); /* counters type=opcode */
1165
1166	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1167	TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1168					 ISC_XMLCHAR "qtype"));
1169
1170	dumparg.result = ISC_R_SUCCESS;
1171	dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump,
1172				&dumparg, 0);
1173	if (dumparg.result != ISC_R_SUCCESS)
1174		goto error;
1175	TRY0(xmlTextWriterEndElement(writer)); /* counters */
1176
1177	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1178	TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1179					 ISC_XMLCHAR "nsstat"));
1180
1181	result = dump_counters(server->nsstats, statsformat_xml,
1182			       writer, NULL, nsstats_xmldesc,
1183			       dns_nsstatscounter_max,
1184			       nsstats_index, nsstat_values,
1185			       ISC_STATSDUMP_VERBOSE);
1186	if (result != ISC_R_SUCCESS)
1187		goto error;
1188
1189	TRY0(xmlTextWriterEndElement(writer)); /* counters type=nsstat */
1190
1191	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1192	TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1193					 ISC_XMLCHAR "zonestat"));
1194
1195	result = dump_counters(server->zonestats, statsformat_xml, writer,
1196			       NULL, zonestats_xmldesc,
1197			       dns_zonestatscounter_max, zonestats_index,
1198			       zonestat_values, ISC_STATSDUMP_VERBOSE);
1199	if (result != ISC_R_SUCCESS)
1200		goto error;
1201
1202	TRY0(xmlTextWriterEndElement(writer)); /* counters type=zonestat */
1203
1204	/*
1205	 * Most of the common resolver statistics entries are 0, so we don't
1206	 * use the verbose dump here.
1207	 */
1208
1209	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1210	TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1211					 ISC_XMLCHAR "resstat"));
1212	result = dump_counters(server->resolverstats, statsformat_xml,
1213			       writer, NULL, resstats_xmldesc,
1214			       dns_resstatscounter_max, resstats_index,
1215			       resstat_values, 0);
1216	if (result != ISC_R_SUCCESS)
1217		goto error;
1218
1219	TRY0(xmlTextWriterEndElement(writer)); /* counters type=resstat */
1220
1221	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
1222	TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
1223					 ISC_XMLCHAR "sockstat"));
1224
1225	result = dump_counters(server->sockstats, statsformat_xml,
1226			       writer, NULL, sockstats_xmldesc,
1227			       isc_sockstatscounter_max, sockstats_index,
1228			       sockstat_values, ISC_STATSDUMP_VERBOSE);
1229	if (result != ISC_R_SUCCESS)
1230		goto error;
1231
1232	TRY0(xmlTextWriterEndElement(writer)); /* counters type=sockstat */
1233
1234	TRY0(xmlTextWriterEndElement(writer)); /* server */
1235
1236	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "memory"));
1237	isc_mem_renderxml(writer);
1238	TRY0(xmlTextWriterEndElement(writer)); /* memory */
1239
1240	TRY0(xmlTextWriterEndElement(writer)); /* statistics */
1241
1242	TRY0(xmlTextWriterEndDocument(writer));
1243
1244	xmlFreeTextWriter(writer);
1245
1246	xmlDocDumpFormatMemoryEnc(doc, buf, buflen, "UTF-8", 0);
1247	if (*buf == NULL)
1248		goto error;
1249	xmlFreeDoc(doc);
1250	return (ISC_R_SUCCESS);
1251
1252 error:
1253	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
1254		      ISC_LOG_ERROR, "failed generating XML response");
1255	if (writer != NULL)
1256		xmlFreeTextWriter(writer);
1257	if (doc != NULL)
1258		xmlFreeDoc(doc);
1259	return (ISC_R_FAILURE);
1260}
1261#else /* OLDSTATS */
1262static isc_result_t
1263generatexml(ns_server_t *server, int *buflen, xmlChar **buf) {
1264	char boottime[sizeof "yyyy-mm-ddThh:mm:ssZ"];
1265	char nowstr[sizeof "yyyy-mm-ddThh:mm:ssZ"];
1266	isc_time_t now;
1267	xmlTextWriterPtr writer = NULL;
1268	xmlDocPtr doc = NULL;
1269	int xmlrc;
1270	dns_view_t *view;
1271	stats_dumparg_t dumparg;
1272	dns_stats_t *cachestats;
1273	isc_uint64_t nsstat_values[dns_nsstatscounter_max];
1274	isc_uint64_t resstat_values[dns_resstatscounter_max];
1275	isc_uint64_t zonestat_values[dns_zonestatscounter_max];
1276	isc_uint64_t sockstat_values[isc_sockstatscounter_max];
1277	isc_result_t result;
1278
1279	isc_time_now(&now);
1280	isc_time_formatISO8601(&ns_g_boottime, boottime, sizeof boottime);
1281	isc_time_formatISO8601(&now, nowstr, sizeof nowstr);
1282
1283	writer = xmlNewTextWriterDoc(&doc, 0);
1284	if (writer == NULL)
1285		goto error;
1286	TRY0(xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL));
1287	TRY0(xmlTextWriterWritePI(writer, ISC_XMLCHAR "xml-stylesheet",
1288			ISC_XMLCHAR "type=\"text/xsl\" href=\"/bind9.xsl\""));
1289	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "isc"));
1290	TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version",
1291					 ISC_XMLCHAR "1.0"));
1292
1293	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "bind"));
1294	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics"));
1295	TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version",
1296					 ISC_XMLCHAR "2.2"));
1297
1298	/* Set common fields for statistics dump */
1299	dumparg.type = statsformat_xml;
1300	dumparg.arg = writer;
1301
1302	/*
1303	 * Start by rendering the views we know of here.  For each view we
1304	 * know of, call its rendering function.
1305	 */
1306	view = ISC_LIST_HEAD(server->viewlist);
1307	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "views"));
1308	while (view != NULL) {
1309		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "view"));
1310
1311		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
1312		TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR view->name));
1313		TRY0(xmlTextWriterEndElement(writer));
1314
1315		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "zones"));
1316		result = dns_zt_apply(view->zonetable, ISC_TRUE, zone_xmlrender,
1317				      writer);
1318		if (result != ISC_R_SUCCESS)
1319			goto error;
1320		TRY0(xmlTextWriterEndElement(writer));
1321
1322		if (view->resquerystats != NULL) {
1323			dumparg.result = ISC_R_SUCCESS;
1324			dns_rdatatypestats_dump(view->resquerystats,
1325						rdtypestat_dump, &dumparg, 0);
1326			if (dumparg.result != ISC_R_SUCCESS)
1327				goto error;
1328		}
1329
1330		if (view->resstats != NULL) {
1331			result = dump_counters(view->resstats, statsformat_xml,
1332					       writer, "resstat",
1333					       resstats_xmldesc,
1334					       dns_resstatscounter_max,
1335					       resstats_index, resstat_values,
1336					       ISC_STATSDUMP_VERBOSE);
1337			if (result != ISC_R_SUCCESS)
1338				goto error;
1339		}
1340
1341		cachestats = dns_db_getrrsetstats(view->cachedb);
1342		if (cachestats != NULL) {
1343			TRY0(xmlTextWriterStartElement(writer,
1344						       ISC_XMLCHAR "cache"));
1345			TRY0(xmlTextWriterWriteAttribute(writer,
1346					 ISC_XMLCHAR "name",
1347					 ISC_XMLCHAR
1348					 dns_cache_getname(view->cache)));
1349			dumparg.result = ISC_R_SUCCESS;
1350			dns_rdatasetstats_dump(cachestats, rdatasetstats_dump,
1351					       &dumparg, 0);
1352			if (dumparg.result != ISC_R_SUCCESS)
1353				goto error;
1354			TRY0(xmlTextWriterEndElement(writer)); /* cache */
1355		}
1356
1357		TRY0(xmlTextWriterEndElement(writer)); /* view */
1358
1359		view = ISC_LIST_NEXT(view, link);
1360	}
1361	TRY0(xmlTextWriterEndElement(writer)); /* views */
1362
1363	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "socketmgr"));
1364	TRY0(isc_socketmgr_renderxml(ns_g_socketmgr, writer));
1365	TRY0(xmlTextWriterEndElement(writer)); /* socketmgr */
1366
1367	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "taskmgr"));
1368	TRY0(isc_taskmgr_renderxml(ns_g_taskmgr, writer));
1369	TRY0(xmlTextWriterEndElement(writer)); /* taskmgr */
1370
1371	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "server"));
1372	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "boot-time"));
1373	TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR boottime));
1374	TRY0(xmlTextWriterEndElement(writer)); /* boot-time */
1375	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "current-time"));
1376	TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR nowstr));
1377	TRY0(xmlTextWriterEndElement(writer)); /* current-time */
1378
1379	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "requests"));
1380	dumparg.result = ISC_R_SUCCESS;
1381	dns_opcodestats_dump(server->opcodestats, opcodestat_dump, &dumparg,
1382			     0);
1383	if (dumparg.result != ISC_R_SUCCESS)
1384		goto error;
1385	TRY0(xmlTextWriterEndElement(writer)); /* requests */
1386
1387	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "queries-in"));
1388	dumparg.result = ISC_R_SUCCESS;
1389	dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump,
1390				&dumparg, 0);
1391	if (dumparg.result != ISC_R_SUCCESS)
1392		goto error;
1393	TRY0(xmlTextWriterEndElement(writer)); /* queries-in */
1394
1395	result = dump_counters(server->nsstats, statsformat_xml, writer,
1396			       "nsstat", nsstats_xmldesc,
1397				dns_nsstatscounter_max,
1398				nsstats_index, nsstat_values,
1399				ISC_STATSDUMP_VERBOSE);
1400	if (result != ISC_R_SUCCESS)
1401		goto error;
1402
1403	result = dump_counters(server->zonestats, statsformat_xml, writer,
1404			       "zonestat", zonestats_xmldesc,
1405			       dns_zonestatscounter_max, zonestats_index,
1406			       zonestat_values, ISC_STATSDUMP_VERBOSE);
1407	if (result != ISC_R_SUCCESS)
1408		goto error;
1409
1410	/*
1411	 * Most of the common resolver statistics entries are 0, so we don't
1412	 * use the verbose dump here.
1413	 */
1414	result = dump_counters(server->resolverstats, statsformat_xml, writer,
1415			       "resstat", resstats_xmldesc,
1416			       dns_resstatscounter_max, resstats_index,
1417			       resstat_values, 0);
1418	if (result != ISC_R_SUCCESS)
1419		goto error;
1420
1421	result = dump_counters(server->sockstats, statsformat_xml, writer,
1422			       "sockstat", sockstats_xmldesc,
1423			       isc_sockstatscounter_max, sockstats_index,
1424			       sockstat_values, ISC_STATSDUMP_VERBOSE);
1425	if (result != ISC_R_SUCCESS)
1426		goto error;
1427
1428	TRY0(xmlTextWriterEndElement(writer)); /* server */
1429
1430	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "memory"));
1431	TRY0(isc_mem_renderxml(writer));
1432	TRY0(xmlTextWriterEndElement(writer)); /* memory */
1433
1434	TRY0(xmlTextWriterEndElement(writer)); /* statistics */
1435	TRY0(xmlTextWriterEndElement(writer)); /* bind */
1436	TRY0(xmlTextWriterEndElement(writer)); /* isc */
1437
1438	TRY0(xmlTextWriterEndDocument(writer));
1439
1440	xmlFreeTextWriter(writer);
1441
1442	xmlDocDumpFormatMemoryEnc(doc, buf, buflen, "UTF-8", 1);
1443	if (*buf == NULL)
1444		goto error;
1445	xmlFreeDoc(doc);
1446	return (ISC_R_SUCCESS);
1447
1448 error:
1449	if (writer != NULL)
1450		xmlFreeTextWriter(writer);
1451	if (doc != NULL)
1452		xmlFreeDoc(doc);
1453	return (ISC_R_FAILURE);
1454}
1455#endif /* NEWSTATS */
1456
1457static void
1458wrap_xmlfree(isc_buffer_t *buffer, void *arg) {
1459	UNUSED(arg);
1460
1461	xmlFree(isc_buffer_base(buffer));
1462}
1463
1464static isc_result_t
1465render_index(const char *url, isc_httpdurl_t *urlinfo,
1466	     const char *querystring, const char *headers, void *arg,
1467	     unsigned int *retcode, const char **retmsg, const char **mimetype,
1468	     isc_buffer_t *b, isc_httpdfree_t **freecb,
1469	     void **freecb_args)
1470{
1471	unsigned char *msg = NULL;
1472	int msglen;
1473	ns_server_t *server = arg;
1474	isc_result_t result;
1475
1476	UNUSED(url);
1477	UNUSED(urlinfo);
1478	UNUSED(querystring);
1479	UNUSED(headers);
1480
1481	result = generatexml(server, &msglen, &msg);
1482
1483	if (result == ISC_R_SUCCESS) {
1484		*retcode = 200;
1485		*retmsg = "OK";
1486		*mimetype = "text/xml";
1487		isc_buffer_reinit(b, msg, msglen);
1488		isc_buffer_add(b, msglen);
1489		*freecb = wrap_xmlfree;
1490		*freecb_args = NULL;
1491	} else
1492		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1493			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
1494			      "failed at rendering XML()");
1495
1496	return (result);
1497}
1498
1499#endif	/* HAVE_LIBXML2 */
1500
1501static isc_result_t
1502render_xsl(const char *url, isc_httpdurl_t *urlinfo,
1503	   const char *querystring, const char *headers,
1504	   void *args, unsigned int *retcode, const char **retmsg,
1505	   const char **mimetype, isc_buffer_t *b,
1506	   isc_httpdfree_t **freecb, void **freecb_args)
1507{
1508	isc_result_t result;
1509
1510	UNUSED(url);
1511	UNUSED(querystring);
1512	UNUSED(args);
1513
1514	*freecb = NULL;
1515	*freecb_args = NULL;
1516	*mimetype = "text/xslt+xml";
1517
1518	if (urlinfo->isstatic) {
1519		isc_time_t when;
1520		char *p = strcasestr(headers, "If-Modified-Since: ");
1521
1522		if (p != NULL) {
1523			time_t t1, t2;
1524			p += strlen("If-Modified-Since: ");
1525			result = isc_time_parsehttptimestamp(p, &when);
1526			if (result != ISC_R_SUCCESS)
1527				goto send;
1528
1529			result = isc_time_secondsastimet(&when, &t1);
1530			if (result != ISC_R_SUCCESS)
1531				goto send;
1532
1533			result = isc_time_secondsastimet(&urlinfo->loadtime,
1534							 &t2);
1535			if (result != ISC_R_SUCCESS)
1536				goto send;
1537
1538			if (t1 < t2)
1539				goto send;
1540
1541			*retcode = 304;
1542			*retmsg = "Not modified";
1543			return (ISC_R_SUCCESS);
1544		}
1545	}
1546
1547 send:
1548	*retcode = 200;
1549	*retmsg = "OK";
1550	isc_buffer_reinit(b, xslmsg, strlen(xslmsg));
1551	isc_buffer_add(b, strlen(xslmsg));
1552
1553	return (ISC_R_SUCCESS);
1554}
1555
1556static void
1557shutdown_listener(ns_statschannel_t *listener) {
1558	char socktext[ISC_SOCKADDR_FORMATSIZE];
1559	isc_sockaddr_format(&listener->address, socktext, sizeof(socktext));
1560	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
1561		      ISC_LOG_NOTICE, "stopping statistics channel on %s",
1562		      socktext);
1563
1564	isc_httpdmgr_shutdown(&listener->httpdmgr);
1565}
1566
1567static isc_boolean_t
1568client_ok(const isc_sockaddr_t *fromaddr, void *arg) {
1569	ns_statschannel_t *listener = arg;
1570	isc_netaddr_t netaddr;
1571	char socktext[ISC_SOCKADDR_FORMATSIZE];
1572	int match;
1573
1574	REQUIRE(listener != NULL);
1575
1576	isc_netaddr_fromsockaddr(&netaddr, fromaddr);
1577
1578	LOCK(&listener->lock);
1579	if (dns_acl_match(&netaddr, NULL, listener->acl, &ns_g_server->aclenv,
1580			  &match, NULL) == ISC_R_SUCCESS && match > 0) {
1581		UNLOCK(&listener->lock);
1582		return (ISC_TRUE);
1583	}
1584	UNLOCK(&listener->lock);
1585
1586	isc_sockaddr_format(fromaddr, socktext, sizeof(socktext));
1587	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1588		      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
1589		      "rejected statistics connection from %s", socktext);
1590
1591	return (ISC_FALSE);
1592}
1593
1594static void
1595destroy_listener(void *arg) {
1596	ns_statschannel_t *listener = arg;
1597
1598	REQUIRE(listener != NULL);
1599	REQUIRE(!ISC_LINK_LINKED(listener, link));
1600
1601	/* We don't have to acquire the lock here since it's already unlinked */
1602	dns_acl_detach(&listener->acl);
1603
1604	DESTROYLOCK(&listener->lock);
1605	isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener));
1606}
1607
1608static isc_result_t
1609add_listener(ns_server_t *server, ns_statschannel_t **listenerp,
1610	     const cfg_obj_t *listen_params, const cfg_obj_t *config,
1611	     isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
1612	     const char *socktext)
1613{
1614	isc_result_t result;
1615	ns_statschannel_t *listener;
1616	isc_task_t *task = NULL;
1617	isc_socket_t *sock = NULL;
1618	const cfg_obj_t *allow;
1619	dns_acl_t *new_acl = NULL;
1620
1621	listener = isc_mem_get(server->mctx, sizeof(*listener));
1622	if (listener == NULL)
1623		return (ISC_R_NOMEMORY);
1624
1625	listener->httpdmgr = NULL;
1626	listener->address = *addr;
1627	listener->acl = NULL;
1628	listener->mctx = NULL;
1629	ISC_LINK_INIT(listener, link);
1630
1631	result = isc_mutex_init(&listener->lock);
1632	if (result != ISC_R_SUCCESS) {
1633		isc_mem_put(server->mctx, listener, sizeof(*listener));
1634		return (ISC_R_FAILURE);
1635	}
1636
1637	isc_mem_attach(server->mctx, &listener->mctx);
1638
1639	allow = cfg_tuple_get(listen_params, "allow");
1640	if (allow != NULL && cfg_obj_islist(allow)) {
1641		result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
1642					    aclconfctx, listener->mctx, 0,
1643					    &new_acl);
1644	} else
1645		result = dns_acl_any(listener->mctx, &new_acl);
1646	if (result != ISC_R_SUCCESS)
1647		goto cleanup;
1648	dns_acl_attach(new_acl, &listener->acl);
1649	dns_acl_detach(&new_acl);
1650
1651	result = isc_task_create(ns_g_taskmgr, 0, &task);
1652	if (result != ISC_R_SUCCESS)
1653		goto cleanup;
1654	isc_task_setname(task, "statchannel", NULL);
1655
1656	result = isc_socket_create(ns_g_socketmgr, isc_sockaddr_pf(addr),
1657				   isc_sockettype_tcp, &sock);
1658	if (result != ISC_R_SUCCESS)
1659		goto cleanup;
1660	isc_socket_setname(sock, "statchannel", NULL);
1661
1662#ifndef ISC_ALLOW_MAPPED
1663	isc_socket_ipv6only(sock, ISC_TRUE);
1664#endif
1665
1666	result = isc_socket_bind(sock, addr, ISC_SOCKET_REUSEADDRESS);
1667	if (result != ISC_R_SUCCESS)
1668		goto cleanup;
1669
1670	result = isc_httpdmgr_create(server->mctx, sock, task, client_ok,
1671				     destroy_listener, listener, ns_g_timermgr,
1672				     &listener->httpdmgr);
1673	if (result != ISC_R_SUCCESS)
1674		goto cleanup;
1675
1676#ifdef HAVE_LIBXML2
1677	isc_httpdmgr_addurl(listener->httpdmgr, "/", render_index, server);
1678	isc_httpdmgr_addurl(listener->httpdmgr, "/xml", render_index, server);
1679#ifdef NEWSTATS
1680	isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3", render_index,
1681			    server);
1682#else /* OLDSTATS */
1683	isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v2", render_index,
1684			    server);
1685#endif /* NEWSTATS */
1686#endif
1687#ifdef NEWSTATS
1688	isc_httpdmgr_addurl2(listener->httpdmgr, "/bind9.ver3.xsl", ISC_TRUE,
1689			     render_xsl, server);
1690#else /* OLDSTATS */
1691	isc_httpdmgr_addurl2(listener->httpdmgr, "/bind9.xsl", ISC_TRUE,
1692			     render_xsl, server);
1693#endif /* NEWSTATS */
1694	*listenerp = listener;
1695	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1696		      NS_LOGMODULE_SERVER, ISC_LOG_NOTICE,
1697		      "statistics channel listening on %s", socktext);
1698
1699cleanup:
1700	if (result != ISC_R_SUCCESS) {
1701		if (listener->acl != NULL)
1702			dns_acl_detach(&listener->acl);
1703		DESTROYLOCK(&listener->lock);
1704		isc_mem_putanddetach(&listener->mctx, listener,
1705				     sizeof(*listener));
1706	}
1707	if (task != NULL)
1708		isc_task_detach(&task);
1709	if (sock != NULL)
1710		isc_socket_detach(&sock);
1711
1712	return (result);
1713}
1714
1715static void
1716update_listener(ns_server_t *server, ns_statschannel_t **listenerp,
1717		const cfg_obj_t *listen_params, const cfg_obj_t *config,
1718		isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
1719		const char *socktext)
1720{
1721	ns_statschannel_t *listener;
1722	const cfg_obj_t *allow = NULL;
1723	dns_acl_t *new_acl = NULL;
1724	isc_result_t result = ISC_R_SUCCESS;
1725
1726	for (listener = ISC_LIST_HEAD(server->statschannels);
1727	     listener != NULL;
1728	     listener = ISC_LIST_NEXT(listener, link))
1729		if (isc_sockaddr_equal(addr, &listener->address))
1730			break;
1731
1732	if (listener == NULL) {
1733		*listenerp = NULL;
1734		return;
1735	}
1736
1737	/*
1738	 * Now, keep the old access list unless a new one can be made.
1739	 */
1740	allow = cfg_tuple_get(listen_params, "allow");
1741	if (allow != NULL && cfg_obj_islist(allow)) {
1742		result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
1743					    aclconfctx, listener->mctx, 0,
1744					    &new_acl);
1745	} else
1746		result = dns_acl_any(listener->mctx, &new_acl);
1747
1748	if (result == ISC_R_SUCCESS) {
1749		LOCK(&listener->lock);
1750
1751		dns_acl_detach(&listener->acl);
1752		dns_acl_attach(new_acl, &listener->acl);
1753		dns_acl_detach(&new_acl);
1754
1755		UNLOCK(&listener->lock);
1756	} else {
1757		cfg_obj_log(listen_params, ns_g_lctx, ISC_LOG_WARNING,
1758			    "couldn't install new acl for "
1759			    "statistics channel %s: %s",
1760			    socktext, isc_result_totext(result));
1761	}
1762
1763	*listenerp = listener;
1764}
1765
1766isc_result_t
1767ns_statschannels_configure(ns_server_t *server, const cfg_obj_t *config,
1768			 cfg_aclconfctx_t *aclconfctx)
1769{
1770	ns_statschannel_t *listener, *listener_next;
1771	ns_statschannellist_t new_listeners;
1772	const cfg_obj_t *statschannellist = NULL;
1773	const cfg_listelt_t *element, *element2;
1774	char socktext[ISC_SOCKADDR_FORMATSIZE];
1775
1776	RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS);
1777
1778	ISC_LIST_INIT(new_listeners);
1779
1780	/*
1781	 * Get the list of named.conf 'statistics-channels' statements.
1782	 */
1783	(void)cfg_map_get(config, "statistics-channels", &statschannellist);
1784
1785	/*
1786	 * Run through the new address/port list, noting sockets that are
1787	 * already being listened on and moving them to the new list.
1788	 *
1789	 * Identifying duplicate addr/port combinations is left to either
1790	 * the underlying config code, or to the bind attempt getting an
1791	 * address-in-use error.
1792	 */
1793	if (statschannellist != NULL) {
1794#ifndef HAVE_LIBXML2
1795		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1796			      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
1797			      "statistics-channels specified but not effective "
1798			      "due to missing XML library");
1799#endif
1800
1801		for (element = cfg_list_first(statschannellist);
1802		     element != NULL;
1803		     element = cfg_list_next(element)) {
1804			const cfg_obj_t *statschannel;
1805			const cfg_obj_t *listenercfg = NULL;
1806
1807			statschannel = cfg_listelt_value(element);
1808			(void)cfg_map_get(statschannel, "inet",
1809					  &listenercfg);
1810			if (listenercfg == NULL)
1811				continue;
1812
1813			for (element2 = cfg_list_first(listenercfg);
1814			     element2 != NULL;
1815			     element2 = cfg_list_next(element2)) {
1816				const cfg_obj_t *listen_params;
1817				const cfg_obj_t *obj;
1818				isc_sockaddr_t addr;
1819
1820				listen_params = cfg_listelt_value(element2);
1821
1822				obj = cfg_tuple_get(listen_params, "address");
1823				addr = *cfg_obj_assockaddr(obj);
1824				if (isc_sockaddr_getport(&addr) == 0)
1825					isc_sockaddr_setport(&addr,
1826						     NS_STATSCHANNEL_HTTPPORT);
1827
1828				isc_sockaddr_format(&addr, socktext,
1829						    sizeof(socktext));
1830
1831				isc_log_write(ns_g_lctx,
1832					      NS_LOGCATEGORY_GENERAL,
1833					      NS_LOGMODULE_SERVER,
1834					      ISC_LOG_DEBUG(9),
1835					      "processing statistics "
1836					      "channel %s",
1837					      socktext);
1838
1839				update_listener(server, &listener,
1840						listen_params, config, &addr,
1841						aclconfctx, socktext);
1842
1843				if (listener != NULL) {
1844					/*
1845					 * Remove the listener from the old
1846					 * list, so it won't be shut down.
1847					 */
1848					ISC_LIST_UNLINK(server->statschannels,
1849							listener, link);
1850				} else {
1851					/*
1852					 * This is a new listener.
1853					 */
1854					isc_result_t r;
1855
1856					r = add_listener(server, &listener,
1857							 listen_params, config,
1858							 &addr, aclconfctx,
1859							 socktext);
1860					if (r != ISC_R_SUCCESS) {
1861						cfg_obj_log(listen_params,
1862							    ns_g_lctx,
1863							    ISC_LOG_WARNING,
1864							    "couldn't allocate "
1865							    "statistics channel"
1866							    " %s: %s",
1867							    socktext,
1868							    isc_result_totext(r));
1869					}
1870				}
1871
1872				if (listener != NULL)
1873					ISC_LIST_APPEND(new_listeners, listener,
1874							link);
1875			}
1876		}
1877	}
1878
1879	for (listener = ISC_LIST_HEAD(server->statschannels);
1880	     listener != NULL;
1881	     listener = listener_next) {
1882		listener_next = ISC_LIST_NEXT(listener, link);
1883		ISC_LIST_UNLINK(server->statschannels, listener, link);
1884		shutdown_listener(listener);
1885	}
1886
1887	ISC_LIST_APPENDLIST(server->statschannels, new_listeners, link);
1888	return (ISC_R_SUCCESS);
1889}
1890
1891void
1892ns_statschannels_shutdown(ns_server_t *server) {
1893	ns_statschannel_t *listener;
1894
1895	while ((listener = ISC_LIST_HEAD(server->statschannels)) != NULL) {
1896		ISC_LIST_UNLINK(server->statschannels, listener, link);
1897		shutdown_listener(listener);
1898	}
1899}
1900
1901isc_result_t
1902ns_stats_dump(ns_server_t *server, FILE *fp) {
1903	isc_stdtime_t now;
1904	isc_result_t result;
1905	dns_view_t *view;
1906	dns_zone_t *zone, *next;
1907	stats_dumparg_t dumparg;
1908	isc_uint64_t nsstat_values[dns_nsstatscounter_max];
1909	isc_uint64_t resstat_values[dns_resstatscounter_max];
1910	isc_uint64_t zonestat_values[dns_zonestatscounter_max];
1911	isc_uint64_t sockstat_values[isc_sockstatscounter_max];
1912
1913	RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS);
1914
1915	/* Set common fields */
1916	dumparg.type = statsformat_file;
1917	dumparg.arg = fp;
1918
1919	isc_stdtime_get(&now);
1920	fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now);
1921
1922	fprintf(fp, "++ Incoming Requests ++\n");
1923	dns_opcodestats_dump(server->opcodestats, opcodestat_dump, &dumparg, 0);
1924
1925	fprintf(fp, "++ Incoming Queries ++\n");
1926	dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump,
1927				&dumparg, 0);
1928
1929	fprintf(fp, "++ Outgoing Queries ++\n");
1930	for (view = ISC_LIST_HEAD(server->viewlist);
1931	     view != NULL;
1932	     view = ISC_LIST_NEXT(view, link)) {
1933		if (view->resquerystats == NULL)
1934			continue;
1935		if (strcmp(view->name, "_default") == 0)
1936			fprintf(fp, "[View: default]\n");
1937		else
1938			fprintf(fp, "[View: %s]\n", view->name);
1939		dns_rdatatypestats_dump(view->resquerystats, rdtypestat_dump,
1940					&dumparg, 0);
1941	}
1942
1943	fprintf(fp, "++ Name Server Statistics ++\n");
1944	(void) dump_counters(server->nsstats, statsformat_file, fp, NULL,
1945			     nsstats_desc, dns_nsstatscounter_max,
1946			     nsstats_index, nsstat_values, 0);
1947
1948	fprintf(fp, "++ Zone Maintenance Statistics ++\n");
1949	(void) dump_counters(server->zonestats, statsformat_file, fp, NULL,
1950			     zonestats_desc, dns_zonestatscounter_max,
1951			     zonestats_index, zonestat_values, 0);
1952
1953	fprintf(fp, "++ Resolver Statistics ++\n");
1954	fprintf(fp, "[Common]\n");
1955	(void) dump_counters(server->resolverstats, statsformat_file, fp, NULL,
1956			     resstats_desc, dns_resstatscounter_max,
1957			     resstats_index, resstat_values, 0);
1958	for (view = ISC_LIST_HEAD(server->viewlist);
1959	     view != NULL;
1960	     view = ISC_LIST_NEXT(view, link)) {
1961		if (view->resstats == NULL)
1962			continue;
1963		if (strcmp(view->name, "_default") == 0)
1964			fprintf(fp, "[View: default]\n");
1965		else
1966			fprintf(fp, "[View: %s]\n", view->name);
1967		(void) dump_counters(view->resstats, statsformat_file, fp, NULL,
1968				     resstats_desc, dns_resstatscounter_max,
1969				     resstats_index, resstat_values, 0);
1970	}
1971
1972	fprintf(fp, "++ Cache DB RRsets ++\n");
1973	for (view = ISC_LIST_HEAD(server->viewlist);
1974	     view != NULL;
1975	     view = ISC_LIST_NEXT(view, link)) {
1976		dns_stats_t *cachestats;
1977
1978		cachestats = dns_db_getrrsetstats(view->cachedb);
1979		if (cachestats == NULL)
1980			continue;
1981		if (strcmp(view->name, "_default") == 0)
1982			fprintf(fp, "[View: default]\n");
1983		else
1984			fprintf(fp, "[View: %s (Cache: %s)]\n", view->name,
1985				dns_cache_getname(view->cache));
1986		if (dns_view_iscacheshared(view)) {
1987			/*
1988			 * Avoid dumping redundant statistics when the cache is
1989			 * shared.
1990			 */
1991			continue;
1992		}
1993		dns_rdatasetstats_dump(cachestats, rdatasetstats_dump, &dumparg,
1994				       0);
1995	}
1996
1997	fprintf(fp, "++ Socket I/O Statistics ++\n");
1998	(void) dump_counters(server->sockstats, statsformat_file, fp, NULL,
1999			     sockstats_desc, isc_sockstatscounter_max,
2000			     sockstats_index, sockstat_values, 0);
2001
2002	fprintf(fp, "++ Per Zone Query Statistics ++\n");
2003	zone = NULL;
2004	for (result = dns_zone_first(server->zonemgr, &zone);
2005	     result == ISC_R_SUCCESS;
2006	     next = NULL, result = dns_zone_next(zone, &next), zone = next)
2007	{
2008		isc_stats_t *zonestats = dns_zone_getrequeststats(zone);
2009		if (zonestats != NULL) {
2010			char zonename[DNS_NAME_FORMATSIZE];
2011
2012			dns_name_format(dns_zone_getorigin(zone),
2013					zonename, sizeof(zonename));
2014			view = dns_zone_getview(zone);
2015
2016			fprintf(fp, "[%s", zonename);
2017			if (strcmp(view->name, "_default") != 0)
2018				fprintf(fp, " (view: %s)", view->name);
2019			fprintf(fp, "]\n");
2020
2021			(void) dump_counters(zonestats, statsformat_file, fp,
2022					     NULL, nsstats_desc,
2023					     dns_nsstatscounter_max,
2024					     nsstats_index, nsstat_values, 0);
2025		}
2026	}
2027
2028	fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now);
2029
2030	return (ISC_R_SUCCESS);	/* this function currently always succeeds */
2031}
2032