]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - contrib/bind9/bin/named/statschannel.c
MFC r362623:
[FreeBSD/stable/8.git] / contrib / bind9 / bin / named / statschannel.c
1 /*
2  * Copyright (C) 2008-2013  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.26.150.2 2011/03/12 04:59:14 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/task.h>
31
32 #include <dns/cache.h>
33 #include <dns/db.h>
34 #include <dns/opcode.h>
35 #include <dns/resolver.h>
36 #include <dns/rdataclass.h>
37 #include <dns/rdatatype.h>
38 #include <dns/stats.h>
39 #include <dns/view.h>
40 #include <dns/zt.h>
41
42 #include <named/log.h>
43 #include <named/server.h>
44 #include <named/statschannel.h>
45
46 #include "bind9.xsl.h"
47
48 struct ns_statschannel {
49         /* Unlocked */
50         isc_httpdmgr_t                          *httpdmgr;
51         isc_sockaddr_t                          address;
52         isc_mem_t                               *mctx;
53
54         /*
55          * Locked by channel lock: can be referenced and modified by both
56          * the server task and the channel task.
57          */
58         isc_mutex_t                             lock;
59         dns_acl_t                               *acl;
60
61         /* Locked by server task */
62         ISC_LINK(struct ns_statschannel)        link;
63 };
64
65 typedef enum { statsformat_file, statsformat_xml } statsformat_t;
66
67 typedef struct
68 stats_dumparg {
69         statsformat_t   type;
70         void            *arg;           /* type dependent argument */
71         int             ncounters;      /* used for general statistics */
72         int             *counterindices; /* used for general statistics */
73         isc_uint64_t    *countervalues;  /* used for general statistics */
74         isc_result_t    result;
75 } stats_dumparg_t;
76
77 static isc_once_t once = ISC_ONCE_INIT;
78
79 /*%
80  * Statistics descriptions.  These could be statistically initialized at
81  * compile time, but we configure them run time in the init_desc() function
82  * below so that they'll be less susceptible to counter name changes.
83  */
84 static const char *nsstats_desc[dns_nsstatscounter_max];
85 static const char *resstats_desc[dns_resstatscounter_max];
86 static const char *zonestats_desc[dns_zonestatscounter_max];
87 static const char *sockstats_desc[isc_sockstatscounter_max];
88 static const char *dnssecstats_desc[dns_dnssecstats_max];
89 #ifdef HAVE_LIBXML2
90 static const char *nsstats_xmldesc[dns_nsstatscounter_max];
91 static const char *resstats_xmldesc[dns_resstatscounter_max];
92 static const char *zonestats_xmldesc[dns_zonestatscounter_max];
93 static const char *sockstats_xmldesc[isc_sockstatscounter_max];
94 static const char *dnssecstats_xmldesc[dns_dnssecstats_max];
95 #else
96 #define nsstats_xmldesc NULL
97 #define resstats_xmldesc NULL
98 #define zonestats_xmldesc NULL
99 #define sockstats_xmldesc NULL
100 #define dnssecstats_xmldesc NULL
101 #endif  /* HAVE_LIBXML2 */
102
103 #define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0)
104
105 /*%
106  * Mapping arrays to represent statistics counters in the order of our
107  * preference, regardless of the order of counter indices.  For example,
108  * nsstats_desc[nsstats_index[0]] will be the description that is shown first.
109  */
110 static int nsstats_index[dns_nsstatscounter_max];
111 static int resstats_index[dns_resstatscounter_max];
112 static int zonestats_index[dns_zonestatscounter_max];
113 static int sockstats_index[isc_sockstatscounter_max];
114 static int dnssecstats_index[dns_dnssecstats_max];
115
116 static inline void
117 set_desc(int counter, int maxcounter, const char *fdesc, const char **fdescs,
118          const char *xdesc, const char **xdescs)
119 {
120         REQUIRE(counter < maxcounter);
121         REQUIRE(fdescs[counter] == NULL);
122 #ifdef HAVE_LIBXML2
123         REQUIRE(xdescs[counter] == NULL);
124 #endif
125
126         fdescs[counter] = fdesc;
127 #ifdef HAVE_LIBXML2
128         xdescs[counter] = xdesc;
129 #else
130         UNUSED(xdesc);
131         UNUSED(xdescs);
132 #endif
133 }
134
135 static void
136 init_desc(void) {
137         int i;
138
139         /* Initialize name server statistics */
140         for (i = 0; i < dns_nsstatscounter_max; i++)
141                 nsstats_desc[i] = NULL;
142 #ifdef HAVE_LIBXML2
143         for (i = 0; i < dns_nsstatscounter_max; i++)
144                 nsstats_xmldesc[i] = NULL;
145 #endif
146
147 #define SET_NSSTATDESC(counterid, desc, xmldesc) \
148         do { \
149                 set_desc(dns_nsstatscounter_ ## counterid, \
150                          dns_nsstatscounter_max, \
151                          desc, nsstats_desc, xmldesc, nsstats_xmldesc); \
152                 nsstats_index[i++] = dns_nsstatscounter_ ## counterid; \
153         } while (0)
154
155         i = 0;
156         SET_NSSTATDESC(requestv4, "IPv4 requests received", "Requestv4");
157         SET_NSSTATDESC(requestv6, "IPv6 requests received", "Requestv6");
158         SET_NSSTATDESC(edns0in, "requests with EDNS(0) received", "ReqEdns0");
159         SET_NSSTATDESC(badednsver,
160                        "requests with unsupported EDNS version received",
161                        "ReqBadEDNSVer");
162         SET_NSSTATDESC(tsigin, "requests with TSIG received", "ReqTSIG");
163         SET_NSSTATDESC(sig0in, "requests with SIG(0) received", "ReqSIG0");
164         SET_NSSTATDESC(invalidsig, "requests with invalid signature",
165                        "ReqBadSIG");
166         SET_NSSTATDESC(tcp, "TCP requests received", "ReqTCP");
167         SET_NSSTATDESC(authrej, "auth queries rejected", "AuthQryRej");
168         SET_NSSTATDESC(recurserej, "recursive queries rejected", "RecQryRej");
169         SET_NSSTATDESC(xfrrej, "transfer requests rejected", "XfrRej");
170         SET_NSSTATDESC(updaterej, "update requests rejected", "UpdateRej");
171         SET_NSSTATDESC(response, "responses sent", "Response");
172         SET_NSSTATDESC(truncatedresp, "truncated responses sent",
173                        "TruncatedResp");
174         SET_NSSTATDESC(edns0out, "responses with EDNS(0) sent", "RespEDNS0");
175         SET_NSSTATDESC(tsigout, "responses with TSIG sent", "RespTSIG");
176         SET_NSSTATDESC(sig0out, "responses with SIG(0) sent", "RespSIG0");
177         SET_NSSTATDESC(success, "queries resulted in successful answer",
178                        "QrySuccess");
179         SET_NSSTATDESC(authans, "queries resulted in authoritative answer",
180                        "QryAuthAns");
181         SET_NSSTATDESC(nonauthans,
182                        "queries resulted in non authoritative answer",
183                        "QryNoauthAns");
184         SET_NSSTATDESC(referral, "queries resulted in referral answer",
185                        "QryReferral");
186         SET_NSSTATDESC(nxrrset, "queries resulted in nxrrset", "QryNxrrset");
187         SET_NSSTATDESC(servfail, "queries resulted in SERVFAIL", "QrySERVFAIL");
188         SET_NSSTATDESC(formerr, "queries resulted in FORMERR", "QryFORMERR");
189         SET_NSSTATDESC(nxdomain, "queries resulted in NXDOMAIN", "QryNXDOMAIN");
190         SET_NSSTATDESC(recursion, "queries caused recursion","QryRecursion");
191         SET_NSSTATDESC(duplicate, "duplicate queries received", "QryDuplicate");
192         SET_NSSTATDESC(dropped, "queries dropped", "QryDropped");
193         SET_NSSTATDESC(failure, "other query failures", "QryFailure");
194         SET_NSSTATDESC(xfrdone, "requested transfers completed", "XfrReqDone");
195         SET_NSSTATDESC(updatereqfwd, "update requests forwarded",
196                        "UpdateReqFwd");
197         SET_NSSTATDESC(updaterespfwd, "update responses forwarded",
198                        "UpdateRespFwd");
199         SET_NSSTATDESC(updatefwdfail, "update forward failed", "UpdateFwdFail");
200         SET_NSSTATDESC(updatedone, "updates completed", "UpdateDone");
201         SET_NSSTATDESC(updatefail, "updates failed", "UpdateFail");
202         SET_NSSTATDESC(updatebadprereq,
203                        "updates rejected due to prerequisite failure",
204                        "UpdateBadPrereq");
205         SET_NSSTATDESC(rpz_rewrites, "response policy zone rewrites",
206                        "RPZRewrites");
207         INSIST(i == dns_nsstatscounter_max);
208
209         /* Initialize resolver statistics */
210         for (i = 0; i < dns_resstatscounter_max; i++)
211                 resstats_desc[i] = NULL;
212 #ifdef  HAVE_LIBXML2
213         for (i = 0; i < dns_resstatscounter_max; i++)
214                 resstats_xmldesc[i] = NULL;
215 #endif
216
217 #define SET_RESSTATDESC(counterid, desc, xmldesc) \
218         do { \
219                 set_desc(dns_resstatscounter_ ## counterid, \
220                          dns_resstatscounter_max, \
221                          desc, resstats_desc, xmldesc, resstats_xmldesc); \
222                 resstats_index[i++] = dns_resstatscounter_ ## counterid; \
223         } while (0)
224
225         i = 0;
226         SET_RESSTATDESC(queryv4, "IPv4 queries sent", "Queryv4");
227         SET_RESSTATDESC(queryv6, "IPv6 queries sent", "Queryv6");
228         SET_RESSTATDESC(responsev4, "IPv4 responses received", "Responsev4");
229         SET_RESSTATDESC(responsev6, "IPv6 responses received", "Responsev6");
230         SET_RESSTATDESC(nxdomain, "NXDOMAIN received", "NXDOMAIN");
231         SET_RESSTATDESC(servfail, "SERVFAIL received", "SERVFAIL");
232         SET_RESSTATDESC(formerr, "FORMERR received", "FORMERR");
233         SET_RESSTATDESC(othererror, "other errors received", "OtherError");
234         SET_RESSTATDESC(edns0fail, "EDNS(0) query failures", "EDNS0Fail");
235         SET_RESSTATDESC(mismatch, "mismatch responses received", "Mismatch");
236         SET_RESSTATDESC(truncated, "truncated responses received", "Truncated");
237         SET_RESSTATDESC(lame, "lame delegations received", "Lame");
238         SET_RESSTATDESC(retry, "query retries", "Retry");
239         SET_RESSTATDESC(dispabort, "queries aborted due to quota",
240                         "QueryAbort");
241         SET_RESSTATDESC(dispsockfail, "failures in opening query sockets",
242                         "QuerySockFail");
243         SET_RESSTATDESC(querytimeout, "query timeouts", "QueryTimeout");
244         SET_RESSTATDESC(gluefetchv4, "IPv4 NS address fetches", "GlueFetchv4");
245         SET_RESSTATDESC(gluefetchv6, "IPv6 NS address fetches", "GlueFetchv6");
246         SET_RESSTATDESC(gluefetchv4fail, "IPv4 NS address fetch failed",
247                         "GlueFetchv4Fail");
248         SET_RESSTATDESC(gluefetchv6fail, "IPv6 NS address fetch failed",
249                         "GlueFetchv6Fail");
250         SET_RESSTATDESC(val, "DNSSEC validation attempted", "ValAttempt");
251         SET_RESSTATDESC(valsuccess, "DNSSEC validation succeeded", "ValOk");
252         SET_RESSTATDESC(valnegsuccess, "DNSSEC NX validation succeeded",
253                         "ValNegOk");
254         SET_RESSTATDESC(valfail, "DNSSEC validation failed", "ValFail");
255         SET_RESSTATDESC(queryrtt0, "queries with RTT < "
256                         DNS_RESOLVER_QRYRTTCLASS0STR "ms",
257                         "QryRTT" DNS_RESOLVER_QRYRTTCLASS0STR);
258         SET_RESSTATDESC(queryrtt1, "queries with RTT "
259                         DNS_RESOLVER_QRYRTTCLASS0STR "-"
260                         DNS_RESOLVER_QRYRTTCLASS1STR "ms",
261                         "QryRTT" DNS_RESOLVER_QRYRTTCLASS1STR);
262         SET_RESSTATDESC(queryrtt2, "queries with RTT "
263                         DNS_RESOLVER_QRYRTTCLASS1STR "-"
264                         DNS_RESOLVER_QRYRTTCLASS2STR "ms",
265                         "QryRTT" DNS_RESOLVER_QRYRTTCLASS2STR);
266         SET_RESSTATDESC(queryrtt3, "queries with RTT "
267                         DNS_RESOLVER_QRYRTTCLASS2STR "-"
268                         DNS_RESOLVER_QRYRTTCLASS3STR "ms",
269                         "QryRTT" DNS_RESOLVER_QRYRTTCLASS3STR);
270         SET_RESSTATDESC(queryrtt4, "queries with RTT "
271                         DNS_RESOLVER_QRYRTTCLASS3STR "-"
272                         DNS_RESOLVER_QRYRTTCLASS4STR "ms",
273                         "QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR);
274         SET_RESSTATDESC(queryrtt5, "queries with RTT > "
275                         DNS_RESOLVER_QRYRTTCLASS4STR "ms",
276                         "QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR "+");
277         INSIST(i == dns_resstatscounter_max);
278
279         /* Initialize zone statistics */
280         for (i = 0; i < dns_zonestatscounter_max; i++)
281                 zonestats_desc[i] = NULL;
282 #ifdef  HAVE_LIBXML2
283         for (i = 0; i < dns_zonestatscounter_max; i++)
284                 zonestats_xmldesc[i] = NULL;
285 #endif
286
287 #define SET_ZONESTATDESC(counterid, desc, xmldesc) \
288         do { \
289                 set_desc(dns_zonestatscounter_ ## counterid, \
290                          dns_zonestatscounter_max, \
291                          desc, zonestats_desc, xmldesc, zonestats_xmldesc); \
292                 zonestats_index[i++] = dns_zonestatscounter_ ## counterid; \
293         } while (0)
294
295         i = 0;
296         SET_ZONESTATDESC(notifyoutv4, "IPv4 notifies sent", "NotifyOutv4");
297         SET_ZONESTATDESC(notifyoutv6, "IPv6 notifies sent", "NotifyOutv6");
298         SET_ZONESTATDESC(notifyinv4, "IPv4 notifies received", "NotifyInv4");
299         SET_ZONESTATDESC(notifyinv6, "IPv6 notifies received", "NotifyInv6");
300         SET_ZONESTATDESC(notifyrej, "notifies rejected", "NotifyRej");
301         SET_ZONESTATDESC(soaoutv4, "IPv4 SOA queries sent", "SOAOutv4");
302         SET_ZONESTATDESC(soaoutv6, "IPv6 SOA queries sent", "SOAOutv6");
303         SET_ZONESTATDESC(axfrreqv4, "IPv4 AXFR requested", "AXFRReqv4");
304         SET_ZONESTATDESC(axfrreqv6, "IPv6 AXFR requested", "AXFRReqv6");
305         SET_ZONESTATDESC(ixfrreqv4, "IPv4 IXFR requested", "IXFRReqv4");
306         SET_ZONESTATDESC(ixfrreqv6, "IPv6 IXFR requested", "IXFRReqv6");
307         SET_ZONESTATDESC(xfrsuccess, "transfer requests succeeded","XfrSuccess");
308         SET_ZONESTATDESC(xfrfail, "transfer requests failed", "XfrFail");
309         INSIST(i == dns_zonestatscounter_max);
310
311         /* Initialize socket statistics */
312         for (i = 0; i < isc_sockstatscounter_max; i++)
313                 sockstats_desc[i] = NULL;
314 #ifdef  HAVE_LIBXML2
315         for (i = 0; i < isc_sockstatscounter_max; i++)
316                 sockstats_xmldesc[i] = NULL;
317 #endif
318
319 #define SET_SOCKSTATDESC(counterid, desc, xmldesc) \
320         do { \
321                 set_desc(isc_sockstatscounter_ ## counterid, \
322                          isc_sockstatscounter_max, \
323                          desc, sockstats_desc, xmldesc, sockstats_xmldesc); \
324                 sockstats_index[i++] = isc_sockstatscounter_ ## counterid; \
325         } while (0)
326
327         i = 0;
328         SET_SOCKSTATDESC(udp4open, "UDP/IPv4 sockets opened", "UDP4Open");
329         SET_SOCKSTATDESC(udp6open, "UDP/IPv6 sockets opened", "UDP6Open");
330         SET_SOCKSTATDESC(tcp4open, "TCP/IPv4 sockets opened", "TCP4Open");
331         SET_SOCKSTATDESC(tcp6open, "TCP/IPv6 sockets opened", "TCP6Open");
332         SET_SOCKSTATDESC(unixopen, "Unix domain sockets opened", "UnixOpen");
333         SET_SOCKSTATDESC(udp4openfail, "UDP/IPv4 socket open failures",
334                          "UDP4OpenFail");
335         SET_SOCKSTATDESC(udp6openfail, "UDP/IPv6 socket open failures",
336                          "UDP6OpenFail");
337         SET_SOCKSTATDESC(tcp4openfail, "TCP/IPv4 socket open failures",
338                          "TCP4OpenFail");
339         SET_SOCKSTATDESC(tcp6openfail, "TCP/IPv6 socket open failures",
340                          "TCP6OpenFail");
341         SET_SOCKSTATDESC(unixopenfail, "Unix domain socket open failures",
342                          "UnixOpenFail");
343         SET_SOCKSTATDESC(udp4close, "UDP/IPv4 sockets closed", "UDP4Close");
344         SET_SOCKSTATDESC(udp6close, "UDP/IPv6 sockets closed", "UDP6Close");
345         SET_SOCKSTATDESC(tcp4close, "TCP/IPv4 sockets closed", "TCP4Close");
346         SET_SOCKSTATDESC(tcp6close, "TCP/IPv6 sockets closed", "TCP6Close");
347         SET_SOCKSTATDESC(unixclose, "Unix domain sockets closed", "UnixClose");
348         SET_SOCKSTATDESC(fdwatchclose, "FDwatch sockets closed",
349                          "FDWatchClose");
350         SET_SOCKSTATDESC(udp4bindfail, "UDP/IPv4 socket bind failures",
351                          "UDP4BindFail");
352         SET_SOCKSTATDESC(udp6bindfail, "UDP/IPv6 socket bind failures",
353                          "UDP6BindFail");
354         SET_SOCKSTATDESC(tcp4bindfail, "TCP/IPv4 socket bind failures",
355                          "TCP4BindFail");
356         SET_SOCKSTATDESC(tcp6bindfail, "TCP/IPv6 socket bind failures",
357                          "TCP6BindFail");
358         SET_SOCKSTATDESC(unixbindfail, "Unix domain socket bind failures",
359                          "UnixBindFail");
360         SET_SOCKSTATDESC(fdwatchbindfail, "FDwatch socket bind failures",
361                          "FdwatchBindFail");
362         SET_SOCKSTATDESC(udp4connectfail, "UDP/IPv4 socket connect failures",
363                          "UDP4ConnFail");
364         SET_SOCKSTATDESC(udp6connectfail, "UDP/IPv6 socket connect failures",
365                          "UDP6ConnFail");
366         SET_SOCKSTATDESC(tcp4connectfail, "TCP/IPv4 socket connect failures",
367                          "TCP4ConnFail");
368         SET_SOCKSTATDESC(tcp6connectfail, "TCP/IPv6 socket connect failures",
369                          "TCP6ConnFail");
370         SET_SOCKSTATDESC(unixconnectfail, "Unix domain socket connect failures",
371                          "UnixConnFail");
372         SET_SOCKSTATDESC(fdwatchconnectfail, "FDwatch socket connect failures",
373                          "FDwatchConnFail");
374         SET_SOCKSTATDESC(udp4connect, "UDP/IPv4 connections established",
375                          "UDP4Conn");
376         SET_SOCKSTATDESC(udp6connect, "UDP/IPv6 connections established",
377                          "UDP6Conn");
378         SET_SOCKSTATDESC(tcp4connect, "TCP/IPv4 connections established",
379                          "TCP4Conn");
380         SET_SOCKSTATDESC(tcp6connect, "TCP/IPv6 connections established",
381                          "TCP6Conn");
382         SET_SOCKSTATDESC(unixconnect, "Unix domain connections established",
383                          "UnixConn");
384         SET_SOCKSTATDESC(fdwatchconnect,
385                          "FDwatch domain connections established",
386                          "FDwatchConn");
387         SET_SOCKSTATDESC(tcp4acceptfail, "TCP/IPv4 connection accept failures",
388                          "TCP4AcceptFail");
389         SET_SOCKSTATDESC(tcp6acceptfail, "TCP/IPv6 connection accept failures",
390                          "TCP6AcceptFail");
391         SET_SOCKSTATDESC(unixacceptfail,
392                          "Unix domain connection accept failures",
393                          "UnixAcceptFail");
394         SET_SOCKSTATDESC(tcp4accept, "TCP/IPv4 connections accepted",
395                          "TCP4Accept");
396         SET_SOCKSTATDESC(tcp6accept, "TCP/IPv6 connections accepted",
397                          "TCP6Accept");
398         SET_SOCKSTATDESC(unixaccept, "Unix domain connections accepted",
399                          "UnixAccept");
400         SET_SOCKSTATDESC(udp4sendfail, "UDP/IPv4 send errors", "UDP4SendErr");
401         SET_SOCKSTATDESC(udp6sendfail, "UDP/IPv6 send errors", "UDP6SendErr");
402         SET_SOCKSTATDESC(tcp4sendfail, "TCP/IPv4 send errors", "TCP4SendErr");
403         SET_SOCKSTATDESC(tcp6sendfail, "TCP/IPv6 send errors", "TCP6SendErr");
404         SET_SOCKSTATDESC(unixsendfail, "Unix domain send errors",
405                          "UnixSendErr");
406         SET_SOCKSTATDESC(fdwatchsendfail, "FDwatch send errors",
407                          "FDwatchSendErr");
408         SET_SOCKSTATDESC(udp4recvfail, "UDP/IPv4 recv errors", "UDP4RecvErr");
409         SET_SOCKSTATDESC(udp6recvfail, "UDP/IPv6 recv errors", "UDP6RecvErr");
410         SET_SOCKSTATDESC(tcp4recvfail, "TCP/IPv4 recv errors", "TCP4RecvErr");
411         SET_SOCKSTATDESC(tcp6recvfail, "TCP/IPv6 recv errors", "TCP6RecvErr");
412         SET_SOCKSTATDESC(unixrecvfail, "Unix domain recv errors",
413                          "UnixRecvErr");
414         SET_SOCKSTATDESC(fdwatchrecvfail, "FDwatch recv errors",
415                          "FDwatchRecvErr");
416         INSIST(i == isc_sockstatscounter_max);
417
418         /* Initialize DNSSEC statistics */
419         for (i = 0; i < dns_dnssecstats_max; i++)
420                 dnssecstats_desc[i] = NULL;
421 #ifdef  HAVE_LIBXML2
422         for (i = 0; i < dns_dnssecstats_max; i++)
423                 dnssecstats_xmldesc[i] = NULL;
424 #endif
425
426 #define SET_DNSSECSTATDESC(counterid, desc, xmldesc) \
427         do { \
428                 set_desc(dns_dnssecstats_ ## counterid, \
429                          dns_dnssecstats_max, \
430                          desc, dnssecstats_desc,\
431                          xmldesc, dnssecstats_xmldesc); \
432                 dnssecstats_index[i++] = dns_dnssecstats_ ## counterid; \
433         } while (0)
434
435         i = 0;
436         SET_DNSSECSTATDESC(asis, "dnssec validation success with signer "
437                            "\"as is\"", "DNSSECasis");
438         SET_DNSSECSTATDESC(downcase, "dnssec validation success with signer "
439                            "lower cased", "DNSSECdowncase");
440         SET_DNSSECSTATDESC(wildcard, "dnssec validation of wildcard signature",
441                            "DNSSECwild");
442         SET_DNSSECSTATDESC(fail, "dnssec validation failures", "DNSSECfail");
443         INSIST(i == dns_dnssecstats_max);
444
445         /* Sanity check */
446         for (i = 0; i < dns_nsstatscounter_max; i++)
447                 INSIST(nsstats_desc[i] != NULL);
448         for (i = 0; i < dns_resstatscounter_max; i++)
449                 INSIST(resstats_desc[i] != NULL);
450         for (i = 0; i < dns_zonestatscounter_max; i++)
451                 INSIST(zonestats_desc[i] != NULL);
452         for (i = 0; i < isc_sockstatscounter_max; i++)
453                 INSIST(sockstats_desc[i] != NULL);
454         for (i = 0; i < dns_dnssecstats_max; i++)
455                 INSIST(dnssecstats_desc[i] != NULL);
456 #ifdef  HAVE_LIBXML2
457         for (i = 0; i < dns_nsstatscounter_max; i++)
458                 INSIST(nsstats_xmldesc[i] != NULL);
459         for (i = 0; i < dns_resstatscounter_max; i++)
460                 INSIST(resstats_xmldesc[i] != NULL);
461         for (i = 0; i < dns_zonestatscounter_max; i++)
462                 INSIST(zonestats_xmldesc[i] != NULL);
463         for (i = 0; i < isc_sockstatscounter_max; i++)
464                 INSIST(sockstats_xmldesc[i] != NULL);
465         for (i = 0; i < dns_dnssecstats_max; i++)
466                 INSIST(dnssecstats_xmldesc[i] != NULL);
467 #endif
468 }
469
470 /*%
471  * Dump callback functions.
472  */
473 static void
474 generalstat_dump(isc_statscounter_t counter, isc_uint64_t val, void *arg) {
475         stats_dumparg_t *dumparg = arg;
476
477         REQUIRE(counter < dumparg->ncounters);
478         dumparg->countervalues[counter] = val;
479 }
480
481 static isc_result_t
482 dump_counters(isc_stats_t *stats, statsformat_t type, void *arg,
483               const char *category, const char **desc, int ncounters,
484               int *indices, isc_uint64_t *values, int options)
485 {
486         int i, index;
487         isc_uint64_t value;
488         stats_dumparg_t dumparg;
489         FILE *fp;
490 #ifdef HAVE_LIBXML2
491         xmlTextWriterPtr writer;
492         int xmlrc;
493 #endif
494
495 #ifndef HAVE_LIBXML2
496         UNUSED(category);
497 #endif
498
499         dumparg.type = type;
500         dumparg.ncounters = ncounters;
501         dumparg.counterindices = indices;
502         dumparg.countervalues = values;
503
504         memset(values, 0, sizeof(values[0]) * ncounters);
505         isc_stats_dump(stats, generalstat_dump, &dumparg, options);
506
507         for (i = 0; i < ncounters; i++) {
508                 index = indices[i];
509                 value = values[index];
510
511                 if (value == 0 && (options & ISC_STATSDUMP_VERBOSE) == 0)
512                         continue;
513
514                 switch (dumparg.type) {
515                 case statsformat_file:
516                         fp = arg;
517                         fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
518                                 value, desc[index]);
519                         break;
520                 case statsformat_xml:
521 #ifdef HAVE_LIBXML2
522                         writer = arg;
523
524                         if (category != NULL) {
525                                 TRY0(xmlTextWriterStartElement(writer,
526                                                                ISC_XMLCHAR
527                                                                category));
528                                 TRY0(xmlTextWriterStartElement(writer,
529                                                                ISC_XMLCHAR
530                                                                "name"));
531                                 TRY0(xmlTextWriterWriteString(writer,
532                                                               ISC_XMLCHAR
533                                                               desc[index]));
534                                 TRY0(xmlTextWriterEndElement(writer)); /* name */
535
536                                 TRY0(xmlTextWriterStartElement(writer,
537                                                                ISC_XMLCHAR
538                                                                "counter"));
539                         } else {
540                                 TRY0(xmlTextWriterStartElement(writer,
541                                                                ISC_XMLCHAR
542                                                                desc[index]));
543                         }
544                         TRY0(xmlTextWriterWriteFormatString(writer,
545                                                             "%"
546                                                             ISC_PRINT_QUADFORMAT
547                                                             "u", value));
548                         TRY0(xmlTextWriterEndElement(writer)); /* counter */
549                         if (category != NULL)
550                                 TRY0(xmlTextWriterEndElement(writer)); /* category */
551 #endif
552                         break;
553                 }
554         }
555         return (ISC_R_SUCCESS);
556 #ifdef HAVE_LIBXML2
557  error:
558         return (ISC_R_FAILURE);
559 #endif
560 }
561
562 static void
563 rdtypestat_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
564         char typebuf[64];
565         const char *typestr;
566         stats_dumparg_t *dumparg = arg;
567         FILE *fp;
568 #ifdef HAVE_LIBXML2
569         xmlTextWriterPtr writer;
570         int xmlrc;
571 #endif
572
573         if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_OTHERTYPE)
574             == 0) {
575                 dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf,
576                                      sizeof(typebuf));
577                 typestr = typebuf;
578         } else
579                 typestr = "Others";
580
581         switch (dumparg->type) {
582         case statsformat_file:
583                 fp = dumparg->arg;
584                 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, typestr);
585                 break;
586         case statsformat_xml:
587 #ifdef HAVE_LIBXML2
588                 writer = dumparg->arg;
589
590                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "rdtype"));
591
592                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
593                 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR typestr));
594                 TRY0(xmlTextWriterEndElement(writer)); /* name */
595
596                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
597                 TRY0(xmlTextWriterWriteFormatString(writer,
598                                                "%" ISC_PRINT_QUADFORMAT "u",
599                                                val));
600                 TRY0(xmlTextWriterEndElement(writer)); /* counter */
601
602                 TRY0(xmlTextWriterEndElement(writer)); /* rdtype */
603 #endif
604                 break;
605         }
606         return;
607 #ifdef HAVE_LIBXML2
608  error:
609         dumparg->result = ISC_R_FAILURE;
610         return;
611 #endif
612 }
613
614 static void
615 rdatasetstats_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
616         stats_dumparg_t *dumparg = arg;
617         FILE *fp;
618         char typebuf[64];
619         const char *typestr;
620         isc_boolean_t nxrrset = ISC_FALSE;
621 #ifdef HAVE_LIBXML2
622         xmlTextWriterPtr writer;
623         int xmlrc;
624 #endif
625
626         if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_NXDOMAIN)
627             != 0) {
628                 typestr = "NXDOMAIN";
629         } else if ((DNS_RDATASTATSTYPE_ATTR(type) &
630                     DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) != 0) {
631                 typestr = "Others";
632         } else {
633                 dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf,
634                                      sizeof(typebuf));
635                 typestr = typebuf;
636         }
637
638         if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_NXRRSET)
639             != 0)
640                 nxrrset = ISC_TRUE;
641
642         switch (dumparg->type) {
643         case statsformat_file:
644                 fp = dumparg->arg;
645                 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s%s\n", val,
646                         nxrrset ? "!" : "", typestr);
647                 break;
648         case statsformat_xml:
649 #ifdef HAVE_LIBXML2
650                 writer = dumparg->arg;
651
652                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "rrset"));
653                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
654                 TRY0(xmlTextWriterWriteFormatString(writer, "%s%s",
655                                                nxrrset ? "!" : "", typestr));
656                 TRY0(xmlTextWriterEndElement(writer)); /* name */
657
658                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
659                 TRY0(xmlTextWriterWriteFormatString(writer,
660                                                "%" ISC_PRINT_QUADFORMAT "u",
661                                                val));
662                 TRY0(xmlTextWriterEndElement(writer)); /* counter */
663
664                 TRY0(xmlTextWriterEndElement(writer)); /* rrset */
665 #endif
666                 break;
667         }
668         return;
669 #ifdef HAVE_LIBXML2
670  error:
671         dumparg->result = ISC_R_FAILURE;
672 #endif
673
674 }
675
676 static void
677 opcodestat_dump(dns_opcode_t code, isc_uint64_t val, void *arg) {
678         FILE *fp;
679         isc_buffer_t b;
680         char codebuf[64];
681         stats_dumparg_t *dumparg = arg;
682 #ifdef HAVE_LIBXML2
683         xmlTextWriterPtr writer;
684         int xmlrc;
685 #endif
686
687         isc_buffer_init(&b, codebuf, sizeof(codebuf) - 1);
688         dns_opcode_totext(code, &b);
689         codebuf[isc_buffer_usedlength(&b)] = '\0';
690
691         switch (dumparg->type) {
692         case statsformat_file:
693                 fp = dumparg->arg;
694                 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, codebuf);
695                 break;
696         case statsformat_xml:
697 #ifdef HAVE_LIBXML2
698                 writer = dumparg->arg;
699
700                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "opcode"));
701
702                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
703                 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR codebuf));
704                 TRY0(xmlTextWriterEndElement(writer)); /* name */
705
706                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
707                 TRY0(xmlTextWriterWriteFormatString(writer,
708                                                "%" ISC_PRINT_QUADFORMAT "u",
709                                                val));
710                 TRY0(xmlTextWriterEndElement(writer)); /* counter */
711
712                 TRY0(xmlTextWriterEndElement(writer)); /* opcode */
713 #endif
714                 break;
715         }
716         return;
717
718 #ifdef HAVE_LIBXML2
719  error:
720         dumparg->result = ISC_R_FAILURE;
721         return;
722 #endif
723 }
724
725 #ifdef HAVE_LIBXML2
726
727 /* XXXMLG below here sucks. */
728
729
730 static isc_result_t
731 zone_xmlrender(dns_zone_t *zone, void *arg) {
732         char buf[1024 + 32];    /* sufficiently large for zone name and class */
733         dns_rdataclass_t rdclass;
734         isc_uint32_t serial;
735         xmlTextWriterPtr writer = arg;
736         isc_stats_t *zonestats;
737         isc_uint64_t nsstat_values[dns_nsstatscounter_max];
738         int xmlrc;
739         isc_result_t result;
740
741         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "zone"));
742
743         dns_zone_name(zone, buf, sizeof(buf));
744         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
745         TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR buf));
746         TRY0(xmlTextWriterEndElement(writer));
747
748         rdclass = dns_zone_getclass(zone);
749         dns_rdataclass_format(rdclass, buf, sizeof(buf));
750         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "rdataclass"));
751         TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR buf));
752         TRY0(xmlTextWriterEndElement(writer));
753
754         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "serial"));
755         if (dns_zone_getserial2(zone, &serial) == ISC_R_SUCCESS)
756                 TRY0(xmlTextWriterWriteFormatString(writer, "%u", serial));
757         else
758                 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-"));
759         TRY0(xmlTextWriterEndElement(writer));
760
761         zonestats = dns_zone_getrequeststats(zone);
762         if (zonestats != NULL) {
763                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
764                 result = dump_counters(zonestats, statsformat_xml, writer, NULL,
765                                       nsstats_xmldesc, dns_nsstatscounter_max,
766                                       nsstats_index, nsstat_values,
767                                       ISC_STATSDUMP_VERBOSE);
768                 if (result != ISC_R_SUCCESS)
769                         goto error;
770                 TRY0(xmlTextWriterEndElement(writer)); /* counters */
771         }
772
773         TRY0(xmlTextWriterEndElement(writer)); /* zone */
774
775         return (ISC_R_SUCCESS);
776  error:
777         return (ISC_R_FAILURE);
778 }
779
780 static isc_result_t
781 generatexml(ns_server_t *server, int *buflen, xmlChar **buf) {
782         char boottime[sizeof "yyyy-mm-ddThh:mm:ssZ"];
783         char nowstr[sizeof "yyyy-mm-ddThh:mm:ssZ"];
784         isc_time_t now;
785         xmlTextWriterPtr writer = NULL;
786         xmlDocPtr doc = NULL;
787         int xmlrc;
788         dns_view_t *view;
789         stats_dumparg_t dumparg;
790         dns_stats_t *cachestats;
791         isc_uint64_t nsstat_values[dns_nsstatscounter_max];
792         isc_uint64_t resstat_values[dns_resstatscounter_max];
793         isc_uint64_t zonestat_values[dns_zonestatscounter_max];
794         isc_uint64_t sockstat_values[isc_sockstatscounter_max];
795         isc_result_t result;
796
797         isc_time_now(&now);
798         isc_time_formatISO8601(&ns_g_boottime, boottime, sizeof boottime);
799         isc_time_formatISO8601(&now, nowstr, sizeof nowstr);
800
801         writer = xmlNewTextWriterDoc(&doc, 0);
802         if (writer == NULL)
803                 goto error;
804         TRY0(xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL));
805         TRY0(xmlTextWriterWritePI(writer, ISC_XMLCHAR "xml-stylesheet",
806                         ISC_XMLCHAR "type=\"text/xsl\" href=\"/bind9.xsl\""));
807         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "isc"));
808         TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version",
809                                          ISC_XMLCHAR "1.0"));
810
811         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "bind"));
812         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics"));
813         TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version",
814                                          ISC_XMLCHAR "2.2"));
815
816         /* Set common fields for statistics dump */
817         dumparg.type = statsformat_xml;
818         dumparg.arg = writer;
819
820         /*
821          * Start by rendering the views we know of here.  For each view we
822          * know of, call its rendering function.
823          */
824         view = ISC_LIST_HEAD(server->viewlist);
825         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "views"));
826         while (view != NULL) {
827                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "view"));
828
829                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
830                 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR view->name));
831                 TRY0(xmlTextWriterEndElement(writer));
832
833                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "zones"));
834                 result = dns_zt_apply(view->zonetable, ISC_TRUE, zone_xmlrender,
835                                       writer);
836                 if (result != ISC_R_SUCCESS)
837                         goto error;
838                 TRY0(xmlTextWriterEndElement(writer));
839
840                 if (view->resquerystats != NULL) {
841                         dumparg.result = ISC_R_SUCCESS;
842                         dns_rdatatypestats_dump(view->resquerystats,
843                                                 rdtypestat_dump, &dumparg, 0);
844                         if (dumparg.result != ISC_R_SUCCESS)
845                                 goto error;
846                 }
847
848                 if (view->resstats != NULL) {
849                         result = dump_counters(view->resstats, statsformat_xml,
850                                                writer, "resstat",
851                                                resstats_xmldesc,
852                                                dns_resstatscounter_max,
853                                                resstats_index, resstat_values,
854                                                ISC_STATSDUMP_VERBOSE);
855                         if (result != ISC_R_SUCCESS)
856                                 goto error;
857                 }
858
859                 cachestats = dns_db_getrrsetstats(view->cachedb);
860                 if (cachestats != NULL) {
861                         TRY0(xmlTextWriterStartElement(writer,
862                                                        ISC_XMLCHAR "cache"));
863                         TRY0(xmlTextWriterWriteAttribute(writer,
864                                          ISC_XMLCHAR "name",
865                                          ISC_XMLCHAR
866                                          dns_cache_getname(view->cache)));
867                         dumparg.result = ISC_R_SUCCESS;
868                         dns_rdatasetstats_dump(cachestats, rdatasetstats_dump,
869                                                &dumparg, 0);
870                         if (dumparg.result != ISC_R_SUCCESS)
871                                 goto error;
872                         TRY0(xmlTextWriterEndElement(writer)); /* cache */
873                 }
874
875                 TRY0(xmlTextWriterEndElement(writer)); /* view */
876
877                 view = ISC_LIST_NEXT(view, link);
878         }
879         TRY0(xmlTextWriterEndElement(writer)); /* views */
880
881         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "socketmgr"));
882         TRY0(isc_socketmgr_renderxml(ns_g_socketmgr, writer));
883         TRY0(xmlTextWriterEndElement(writer)); /* socketmgr */
884
885         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "taskmgr"));
886         TRY0(isc_taskmgr_renderxml(ns_g_taskmgr, writer));
887         TRY0(xmlTextWriterEndElement(writer)); /* taskmgr */
888
889         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "server"));
890         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "boot-time"));
891         TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR boottime));
892         TRY0(xmlTextWriterEndElement(writer));
893         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "current-time"));
894         TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR nowstr));
895         TRY0(xmlTextWriterEndElement(writer));
896
897         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "requests"));
898         dumparg.result = ISC_R_SUCCESS;
899         dns_opcodestats_dump(server->opcodestats, opcodestat_dump, &dumparg,
900                              0);
901         if (dumparg.result != ISC_R_SUCCESS)
902                 goto error;
903         TRY0(xmlTextWriterEndElement(writer)); /* requests */
904
905         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "queries-in"));
906         dumparg.result = ISC_R_SUCCESS;
907         dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump,
908                                 &dumparg, 0);
909         if (dumparg.result != ISC_R_SUCCESS)
910                 goto error;
911         TRY0(xmlTextWriterEndElement(writer)); /* queries-in */
912
913         result = dump_counters(server->nsstats, statsformat_xml, writer,
914                                "nsstat", nsstats_xmldesc,
915                                 dns_nsstatscounter_max,
916                                 nsstats_index, nsstat_values,
917                                 ISC_STATSDUMP_VERBOSE);
918         if (result != ISC_R_SUCCESS)
919                 goto error;
920
921         result = dump_counters(server->zonestats, statsformat_xml, writer,
922                                "zonestat", zonestats_xmldesc,
923                                dns_zonestatscounter_max, zonestats_index,
924                                zonestat_values, ISC_STATSDUMP_VERBOSE);
925         if (result != ISC_R_SUCCESS)
926                 goto error;
927
928         /*
929          * Most of the common resolver statistics entries are 0, so we don't
930          * use the verbose dump here.
931          */
932         result = dump_counters(server->resolverstats, statsformat_xml, writer,
933                                "resstat", resstats_xmldesc,
934                                dns_resstatscounter_max, resstats_index,
935                                resstat_values, 0);
936         if (result != ISC_R_SUCCESS)
937                 goto error;
938
939         result = dump_counters(server->sockstats, statsformat_xml, writer,
940                                "sockstat", sockstats_xmldesc,
941                                isc_sockstatscounter_max, sockstats_index,
942                                sockstat_values, ISC_STATSDUMP_VERBOSE);
943         if (result != ISC_R_SUCCESS)
944                 goto error;
945
946         TRY0(xmlTextWriterEndElement(writer)); /* server */
947
948         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "memory"));
949         TRY0(isc_mem_renderxml(writer));
950         TRY0(xmlTextWriterEndElement(writer)); /* memory */
951
952         TRY0(xmlTextWriterEndElement(writer)); /* statistics */
953         TRY0(xmlTextWriterEndElement(writer)); /* bind */
954         TRY0(xmlTextWriterEndElement(writer)); /* isc */
955
956         TRY0(xmlTextWriterEndDocument(writer));
957
958         xmlFreeTextWriter(writer);
959
960         xmlDocDumpFormatMemoryEnc(doc, buf, buflen, "UTF-8", 1);
961         if (*buf == NULL)
962                 goto error;
963         xmlFreeDoc(doc);
964         return (ISC_R_SUCCESS);
965
966  error:
967         if (writer != NULL)
968                 xmlFreeTextWriter(writer);
969         if (doc != NULL)
970                 xmlFreeDoc(doc);
971         return (ISC_R_FAILURE);
972 }
973
974 static void
975 wrap_xmlfree(isc_buffer_t *buffer, void *arg) {
976         UNUSED(arg);
977
978         xmlFree(isc_buffer_base(buffer));
979 }
980
981 static isc_result_t
982 render_index(const char *url, const char *querystring, void *arg,
983              unsigned int *retcode, const char **retmsg, const char **mimetype,
984              isc_buffer_t *b, isc_httpdfree_t **freecb,
985              void **freecb_args)
986 {
987         unsigned char *msg = NULL;
988         int msglen;
989         ns_server_t *server = arg;
990         isc_result_t result;
991
992         UNUSED(url);
993         UNUSED(querystring);
994
995         result = generatexml(server, &msglen, &msg);
996
997         if (result == ISC_R_SUCCESS) {
998                 *retcode = 200;
999                 *retmsg = "OK";
1000                 *mimetype = "text/xml";
1001                 isc_buffer_reinit(b, msg, msglen);
1002                 isc_buffer_add(b, msglen);
1003                 *freecb = wrap_xmlfree;
1004                 *freecb_args = NULL;
1005         }
1006
1007         return (result);
1008 }
1009
1010 #endif  /* HAVE_LIBXML2 */
1011
1012 static isc_result_t
1013 render_xsl(const char *url, const char *querystring, void *args,
1014            unsigned int *retcode, const char **retmsg, const char **mimetype,
1015            isc_buffer_t *b, isc_httpdfree_t **freecb,
1016            void **freecb_args)
1017 {
1018         UNUSED(url);
1019         UNUSED(querystring);
1020         UNUSED(args);
1021
1022         *retcode = 200;
1023         *retmsg = "OK";
1024         *mimetype = "text/xslt+xml";
1025         isc_buffer_reinit(b, xslmsg, strlen(xslmsg));
1026         isc_buffer_add(b, strlen(xslmsg));
1027         *freecb = NULL;
1028         *freecb_args = NULL;
1029
1030         return (ISC_R_SUCCESS);
1031 }
1032
1033 static void
1034 shutdown_listener(ns_statschannel_t *listener) {
1035         char socktext[ISC_SOCKADDR_FORMATSIZE];
1036         isc_sockaddr_format(&listener->address, socktext, sizeof(socktext));
1037         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,NS_LOGMODULE_SERVER,
1038                       ISC_LOG_NOTICE, "stopping statistics channel on %s",
1039                       socktext);
1040
1041         isc_httpdmgr_shutdown(&listener->httpdmgr);
1042 }
1043
1044 static isc_boolean_t
1045 client_ok(const isc_sockaddr_t *fromaddr, void *arg) {
1046         ns_statschannel_t *listener = arg;
1047         isc_netaddr_t netaddr;
1048         char socktext[ISC_SOCKADDR_FORMATSIZE];
1049         int match;
1050
1051         REQUIRE(listener != NULL);
1052
1053         isc_netaddr_fromsockaddr(&netaddr, fromaddr);
1054
1055         LOCK(&listener->lock);
1056         if (dns_acl_match(&netaddr, NULL, listener->acl, &ns_g_server->aclenv,
1057                           &match, NULL) == ISC_R_SUCCESS && match > 0) {
1058                 UNLOCK(&listener->lock);
1059                 return (ISC_TRUE);
1060         }
1061         UNLOCK(&listener->lock);
1062
1063         isc_sockaddr_format(fromaddr, socktext, sizeof(socktext));
1064         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1065                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
1066                       "rejected statistics connection from %s", socktext);
1067
1068         return (ISC_FALSE);
1069 }
1070
1071 static void
1072 destroy_listener(void *arg) {
1073         ns_statschannel_t *listener = arg;
1074
1075         REQUIRE(listener != NULL);
1076         REQUIRE(!ISC_LINK_LINKED(listener, link));
1077
1078         /* We don't have to acquire the lock here since it's already unlinked */
1079         dns_acl_detach(&listener->acl);
1080
1081         DESTROYLOCK(&listener->lock);
1082         isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener));
1083 }
1084
1085 static isc_result_t
1086 add_listener(ns_server_t *server, ns_statschannel_t **listenerp,
1087              const cfg_obj_t *listen_params, const cfg_obj_t *config,
1088              isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
1089              const char *socktext)
1090 {
1091         isc_result_t result;
1092         ns_statschannel_t *listener;
1093         isc_task_t *task = NULL;
1094         isc_socket_t *sock = NULL;
1095         const cfg_obj_t *allow;
1096         dns_acl_t *new_acl = NULL;
1097
1098         listener = isc_mem_get(server->mctx, sizeof(*listener));
1099         if (listener == NULL)
1100                 return (ISC_R_NOMEMORY);
1101
1102         listener->httpdmgr = NULL;
1103         listener->address = *addr;
1104         listener->acl = NULL;
1105         listener->mctx = NULL;
1106         ISC_LINK_INIT(listener, link);
1107
1108         result = isc_mutex_init(&listener->lock);
1109         if (result != ISC_R_SUCCESS) {
1110                 isc_mem_put(server->mctx, listener, sizeof(*listener));
1111                 return (ISC_R_FAILURE);
1112         }
1113
1114         isc_mem_attach(server->mctx, &listener->mctx);
1115
1116         allow = cfg_tuple_get(listen_params, "allow");
1117         if (allow != NULL && cfg_obj_islist(allow)) {
1118                 result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
1119                                             aclconfctx, listener->mctx, 0,
1120                                             &new_acl);
1121         } else
1122                 result = dns_acl_any(listener->mctx, &new_acl);
1123         if (result != ISC_R_SUCCESS)
1124                 goto cleanup;
1125         dns_acl_attach(new_acl, &listener->acl);
1126         dns_acl_detach(&new_acl);
1127
1128         result = isc_task_create(ns_g_taskmgr, 0, &task);
1129         if (result != ISC_R_SUCCESS)
1130                 goto cleanup;
1131         isc_task_setname(task, "statchannel", NULL);
1132
1133         result = isc_socket_create(ns_g_socketmgr, isc_sockaddr_pf(addr),
1134                                    isc_sockettype_tcp, &sock);
1135         if (result != ISC_R_SUCCESS)
1136                 goto cleanup;
1137         isc_socket_setname(sock, "statchannel", NULL);
1138
1139 #ifndef ISC_ALLOW_MAPPED
1140         isc_socket_ipv6only(sock, ISC_TRUE);
1141 #endif
1142
1143         result = isc_socket_bind(sock, addr, ISC_SOCKET_REUSEADDRESS);
1144         if (result != ISC_R_SUCCESS)
1145                 goto cleanup;
1146
1147         result = isc_httpdmgr_create(server->mctx, sock, task, client_ok,
1148                                      destroy_listener, listener, ns_g_timermgr,
1149                                      &listener->httpdmgr);
1150         if (result != ISC_R_SUCCESS)
1151                 goto cleanup;
1152
1153 #ifdef HAVE_LIBXML2
1154         isc_httpdmgr_addurl(listener->httpdmgr, "/", render_index, server);
1155 #endif
1156         isc_httpdmgr_addurl(listener->httpdmgr, "/bind9.xsl", render_xsl,
1157                             server);
1158
1159         *listenerp = listener;
1160         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1161                       NS_LOGMODULE_SERVER, ISC_LOG_NOTICE,
1162                       "statistics channel listening on %s", socktext);
1163
1164 cleanup:
1165         if (result != ISC_R_SUCCESS) {
1166                 if (listener->acl != NULL)
1167                         dns_acl_detach(&listener->acl);
1168                 DESTROYLOCK(&listener->lock);
1169                 isc_mem_putanddetach(&listener->mctx, listener,
1170                                      sizeof(*listener));
1171         }
1172         if (task != NULL)
1173                 isc_task_detach(&task);
1174         if (sock != NULL)
1175                 isc_socket_detach(&sock);
1176
1177         return (result);
1178 }
1179
1180 static void
1181 update_listener(ns_server_t *server, ns_statschannel_t **listenerp,
1182                 const cfg_obj_t *listen_params, const cfg_obj_t *config,
1183                 isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
1184                 const char *socktext)
1185 {
1186         ns_statschannel_t *listener;
1187         const cfg_obj_t *allow = NULL;
1188         dns_acl_t *new_acl = NULL;
1189         isc_result_t result = ISC_R_SUCCESS;
1190
1191         for (listener = ISC_LIST_HEAD(server->statschannels);
1192              listener != NULL;
1193              listener = ISC_LIST_NEXT(listener, link))
1194                 if (isc_sockaddr_equal(addr, &listener->address))
1195                         break;
1196
1197         if (listener == NULL) {
1198                 *listenerp = NULL;
1199                 return;
1200         }
1201
1202         /*
1203          * Now, keep the old access list unless a new one can be made.
1204          */
1205         allow = cfg_tuple_get(listen_params, "allow");
1206         if (allow != NULL && cfg_obj_islist(allow)) {
1207                 result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
1208                                             aclconfctx, listener->mctx, 0,
1209                                             &new_acl);
1210         } else
1211                 result = dns_acl_any(listener->mctx, &new_acl);
1212
1213         if (result == ISC_R_SUCCESS) {
1214                 LOCK(&listener->lock);
1215
1216                 dns_acl_detach(&listener->acl);
1217                 dns_acl_attach(new_acl, &listener->acl);
1218                 dns_acl_detach(&new_acl);
1219
1220                 UNLOCK(&listener->lock);
1221         } else {
1222                 cfg_obj_log(listen_params, ns_g_lctx, ISC_LOG_WARNING,
1223                             "couldn't install new acl for "
1224                             "statistics channel %s: %s",
1225                             socktext, isc_result_totext(result));
1226         }
1227
1228         *listenerp = listener;
1229 }
1230
1231 isc_result_t
1232 ns_statschannels_configure(ns_server_t *server, const cfg_obj_t *config,
1233                          cfg_aclconfctx_t *aclconfctx)
1234 {
1235         ns_statschannel_t *listener, *listener_next;
1236         ns_statschannellist_t new_listeners;
1237         const cfg_obj_t *statschannellist = NULL;
1238         const cfg_listelt_t *element, *element2;
1239         char socktext[ISC_SOCKADDR_FORMATSIZE];
1240
1241         RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS);
1242
1243         ISC_LIST_INIT(new_listeners);
1244
1245         /*
1246          * Get the list of named.conf 'statistics-channels' statements.
1247          */
1248         (void)cfg_map_get(config, "statistics-channels", &statschannellist);
1249
1250         /*
1251          * Run through the new address/port list, noting sockets that are
1252          * already being listened on and moving them to the new list.
1253          *
1254          * Identifying duplicate addr/port combinations is left to either
1255          * the underlying config code, or to the bind attempt getting an
1256          * address-in-use error.
1257          */
1258         if (statschannellist != NULL) {
1259 #ifndef HAVE_LIBXML2
1260                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1261                               NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
1262                               "statistics-channels specified but not effective "
1263                               "due to missing XML library");
1264 #endif
1265
1266                 for (element = cfg_list_first(statschannellist);
1267                      element != NULL;
1268                      element = cfg_list_next(element)) {
1269                         const cfg_obj_t *statschannel;
1270                         const cfg_obj_t *listenercfg = NULL;
1271
1272                         statschannel = cfg_listelt_value(element);
1273                         (void)cfg_map_get(statschannel, "inet",
1274                                           &listenercfg);
1275                         if (listenercfg == NULL)
1276                                 continue;
1277
1278                         for (element2 = cfg_list_first(listenercfg);
1279                              element2 != NULL;
1280                              element2 = cfg_list_next(element2)) {
1281                                 const cfg_obj_t *listen_params;
1282                                 const cfg_obj_t *obj;
1283                                 isc_sockaddr_t addr;
1284
1285                                 listen_params = cfg_listelt_value(element2);
1286
1287                                 obj = cfg_tuple_get(listen_params, "address");
1288                                 addr = *cfg_obj_assockaddr(obj);
1289                                 if (isc_sockaddr_getport(&addr) == 0)
1290                                         isc_sockaddr_setport(&addr, NS_STATSCHANNEL_HTTPPORT);
1291
1292                                 isc_sockaddr_format(&addr, socktext,
1293                                                     sizeof(socktext));
1294
1295                                 isc_log_write(ns_g_lctx,
1296                                               NS_LOGCATEGORY_GENERAL,
1297                                               NS_LOGMODULE_SERVER,
1298                                               ISC_LOG_DEBUG(9),
1299                                               "processing statistics "
1300                                               "channel %s",
1301                                               socktext);
1302
1303                                 update_listener(server, &listener,
1304                                                 listen_params, config, &addr,
1305                                                 aclconfctx, socktext);
1306
1307                                 if (listener != NULL) {
1308                                         /*
1309                                          * Remove the listener from the old
1310                                          * list, so it won't be shut down.
1311                                          */
1312                                         ISC_LIST_UNLINK(server->statschannels,
1313                                                         listener, link);
1314                                 } else {
1315                                         /*
1316                                          * This is a new listener.
1317                                          */
1318                                         isc_result_t r;
1319
1320                                         r = add_listener(server, &listener,
1321                                                          listen_params, config,
1322                                                          &addr, aclconfctx,
1323                                                          socktext);
1324                                         if (r != ISC_R_SUCCESS) {
1325                                                 cfg_obj_log(listen_params,
1326                                                             ns_g_lctx,
1327                                                             ISC_LOG_WARNING,
1328                                                             "couldn't allocate "
1329                                                             "statistics channel"
1330                                                             " %s: %s",
1331                                                             socktext,
1332                                                             isc_result_totext(r));
1333                                         }
1334                                 }
1335
1336                                 if (listener != NULL)
1337                                         ISC_LIST_APPEND(new_listeners, listener,
1338                                                         link);
1339                         }
1340                 }
1341         }
1342
1343         for (listener = ISC_LIST_HEAD(server->statschannels);
1344              listener != NULL;
1345              listener = listener_next) {
1346                 listener_next = ISC_LIST_NEXT(listener, link);
1347                 ISC_LIST_UNLINK(server->statschannels, listener, link);
1348                 shutdown_listener(listener);
1349         }
1350
1351         ISC_LIST_APPENDLIST(server->statschannels, new_listeners, link);
1352         return (ISC_R_SUCCESS);
1353 }
1354
1355 void
1356 ns_statschannels_shutdown(ns_server_t *server) {
1357         ns_statschannel_t *listener;
1358
1359         while ((listener = ISC_LIST_HEAD(server->statschannels)) != NULL) {
1360                 ISC_LIST_UNLINK(server->statschannels, listener, link);
1361                 shutdown_listener(listener);
1362         }
1363 }
1364
1365 isc_result_t
1366 ns_stats_dump(ns_server_t *server, FILE *fp) {
1367         isc_stdtime_t now;
1368         isc_result_t result;
1369         dns_view_t *view;
1370         dns_zone_t *zone, *next;
1371         stats_dumparg_t dumparg;
1372         isc_uint64_t nsstat_values[dns_nsstatscounter_max];
1373         isc_uint64_t resstat_values[dns_resstatscounter_max];
1374         isc_uint64_t zonestat_values[dns_zonestatscounter_max];
1375         isc_uint64_t sockstat_values[isc_sockstatscounter_max];
1376
1377         RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS);
1378
1379         /* Set common fields */
1380         dumparg.type = statsformat_file;
1381         dumparg.arg = fp;
1382
1383         isc_stdtime_get(&now);
1384         fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now);
1385
1386         fprintf(fp, "++ Incoming Requests ++\n");
1387         dns_opcodestats_dump(server->opcodestats, opcodestat_dump, &dumparg, 0);
1388
1389         fprintf(fp, "++ Incoming Queries ++\n");
1390         dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump,
1391                                 &dumparg, 0);
1392
1393         fprintf(fp, "++ Outgoing Queries ++\n");
1394         for (view = ISC_LIST_HEAD(server->viewlist);
1395              view != NULL;
1396              view = ISC_LIST_NEXT(view, link)) {
1397                 if (view->resquerystats == NULL)
1398                         continue;
1399                 if (strcmp(view->name, "_default") == 0)
1400                         fprintf(fp, "[View: default]\n");
1401                 else
1402                         fprintf(fp, "[View: %s]\n", view->name);
1403                 dns_rdatatypestats_dump(view->resquerystats, rdtypestat_dump,
1404                                         &dumparg, 0);
1405         }
1406
1407         fprintf(fp, "++ Name Server Statistics ++\n");
1408         (void) dump_counters(server->nsstats, statsformat_file, fp, NULL,
1409                              nsstats_desc, dns_nsstatscounter_max,
1410                              nsstats_index, nsstat_values, 0);
1411
1412         fprintf(fp, "++ Zone Maintenance Statistics ++\n");
1413         (void) dump_counters(server->zonestats, statsformat_file, fp, NULL,
1414                              zonestats_desc, dns_zonestatscounter_max,
1415                              zonestats_index, zonestat_values, 0);
1416
1417         fprintf(fp, "++ Resolver Statistics ++\n");
1418         fprintf(fp, "[Common]\n");
1419         (void) dump_counters(server->resolverstats, statsformat_file, fp, NULL,
1420                              resstats_desc, dns_resstatscounter_max,
1421                              resstats_index, resstat_values, 0);
1422         for (view = ISC_LIST_HEAD(server->viewlist);
1423              view != NULL;
1424              view = ISC_LIST_NEXT(view, link)) {
1425                 if (view->resstats == NULL)
1426                         continue;
1427                 if (strcmp(view->name, "_default") == 0)
1428                         fprintf(fp, "[View: default]\n");
1429                 else
1430                         fprintf(fp, "[View: %s]\n", view->name);
1431                 (void) dump_counters(view->resstats, statsformat_file, fp, NULL,
1432                                      resstats_desc, dns_resstatscounter_max,
1433                                      resstats_index, resstat_values, 0);
1434         }
1435
1436         fprintf(fp, "++ Cache DB RRsets ++\n");
1437         for (view = ISC_LIST_HEAD(server->viewlist);
1438              view != NULL;
1439              view = ISC_LIST_NEXT(view, link)) {
1440                 dns_stats_t *cachestats;
1441
1442                 cachestats = dns_db_getrrsetstats(view->cachedb);
1443                 if (cachestats == NULL)
1444                         continue;
1445                 if (strcmp(view->name, "_default") == 0)
1446                         fprintf(fp, "[View: default]\n");
1447                 else
1448                         fprintf(fp, "[View: %s (Cache: %s)]\n", view->name,
1449                                 dns_cache_getname(view->cache));
1450                 if (dns_view_iscacheshared(view)) {
1451                         /*
1452                          * Avoid dumping redundant statistics when the cache is
1453                          * shared.
1454                          */
1455                         continue;
1456                 }
1457                 dns_rdatasetstats_dump(cachestats, rdatasetstats_dump, &dumparg,
1458                                        0);
1459         }
1460
1461         fprintf(fp, "++ Socket I/O Statistics ++\n");
1462         (void) dump_counters(server->sockstats, statsformat_file, fp, NULL,
1463                              sockstats_desc, isc_sockstatscounter_max,
1464                              sockstats_index, sockstat_values, 0);
1465
1466         fprintf(fp, "++ Per Zone Query Statistics ++\n");
1467         zone = NULL;
1468         for (result = dns_zone_first(server->zonemgr, &zone);
1469              result == ISC_R_SUCCESS;
1470              next = NULL, result = dns_zone_next(zone, &next), zone = next)
1471         {
1472                 isc_stats_t *zonestats = dns_zone_getrequeststats(zone);
1473                 if (zonestats != NULL) {
1474                         char zonename[DNS_NAME_FORMATSIZE];
1475
1476                         dns_name_format(dns_zone_getorigin(zone),
1477                                         zonename, sizeof(zonename));
1478                         view = dns_zone_getview(zone);
1479
1480                         fprintf(fp, "[%s", zonename);
1481                         if (strcmp(view->name, "_default") != 0)
1482                                 fprintf(fp, " (view: %s)", view->name);
1483                         fprintf(fp, "]\n");
1484
1485                         (void) dump_counters(zonestats, statsformat_file, fp,
1486                                              NULL, nsstats_desc,
1487                                              dns_nsstatscounter_max,
1488                                              nsstats_index, nsstat_values, 0);
1489                 }
1490         }
1491
1492         fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now);
1493
1494         return (ISC_R_SUCCESS); /* this function currently always succeeds */
1495 }