]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - contrib/bind9/bin/named/statschannel.c
Copy stable/9 to releng/9.3 as part of the 9.3-RELEASE cycle.
[FreeBSD/releng/9.3.git] / contrib / bind9 / bin / named / statschannel.c
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
53 struct 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
70 typedef enum { statsformat_file, statsformat_xml } statsformat_t;
71
72 typedef struct
73 stats_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
82 static 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  */
89 static const char *nsstats_desc[dns_nsstatscounter_max];
90 static const char *resstats_desc[dns_resstatscounter_max];
91 static const char *zonestats_desc[dns_zonestatscounter_max];
92 static const char *sockstats_desc[isc_sockstatscounter_max];
93 static const char *dnssecstats_desc[dns_dnssecstats_max];
94 #ifdef HAVE_LIBXML2
95 static const char *nsstats_xmldesc[dns_nsstatscounter_max];
96 static const char *resstats_xmldesc[dns_resstatscounter_max];
97 static const char *zonestats_xmldesc[dns_zonestatscounter_max];
98 static const char *sockstats_xmldesc[isc_sockstatscounter_max];
99 static 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  */
115 static int nsstats_index[dns_nsstatscounter_max];
116 static int resstats_index[dns_resstatscounter_max];
117 static int zonestats_index[dns_zonestatscounter_max];
118 static int sockstats_index[isc_sockstatscounter_max];
119 static int dnssecstats_index[dns_dnssecstats_max];
120
121 static inline void
122 set_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
140 static void
141 init_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  */
485 static void
486 generalstat_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
493 static isc_result_t
494 dump_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
623 static void
624 rdtypestat_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 */
675 static void
676 rdtypestat_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
728 static void
729 rdatasetstats_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
793 static void
794 opcodestat_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 */
837 static void
838 opcodestat_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
892 static isc_result_t
893 zone_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 */
975 static isc_result_t
976 zone_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
1032 static isc_result_t
1033 generatexml(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                 }
1097 else 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 */
1262 static isc_result_t
1263 generatexml(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
1457 static void
1458 wrap_xmlfree(isc_buffer_t *buffer, void *arg) {
1459         UNUSED(arg);
1460
1461         xmlFree(isc_buffer_base(buffer));
1462 }
1463
1464 static isc_result_t
1465 render_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
1501 static isc_result_t
1502 render_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
1556 static void
1557 shutdown_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
1567 static isc_boolean_t
1568 client_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
1594 static void
1595 destroy_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
1608 static isc_result_t
1609 add_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
1699 cleanup:
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
1715 static void
1716 update_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
1766 isc_result_t
1767 ns_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
1891 void
1892 ns_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
1901 isc_result_t
1902 ns_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 }