statschannel.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008-2015  Internet Systems Consortium, Inc. ("ISC")
00003  *
00004  * Permission to use, copy, modify, and/or distribute this software for any
00005  * purpose with or without fee is hereby granted, provided that the above
00006  * copyright notice and this permission notice appear in all copies.
00007  *
00008  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00009  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00010  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00011  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00012  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00013  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00014  * PERFORMANCE OF THIS SOFTWARE.
00015  */
00016 
00017 /*! \file */
00018 
00019 #include <config.h>
00020 
00021 #include <isc/buffer.h>
00022 #include <isc/httpd.h>
00023 #include <isc/mem.h>
00024 #include <isc/once.h>
00025 #include <isc/print.h>
00026 #include <isc/socket.h>
00027 #include <isc/stats.h>
00028 #include <isc/string.h>
00029 #include <isc/task.h>
00030 
00031 #include <dns/cache.h>
00032 #include <dns/db.h>
00033 #include <dns/opcode.h>
00034 #include <dns/resolver.h>
00035 #include <dns/rdataclass.h>
00036 #include <dns/rdatatype.h>
00037 #include <dns/stats.h>
00038 #include <dns/view.h>
00039 #include <dns/zt.h>
00040 
00041 #include <named/log.h>
00042 #include <named/server.h>
00043 #include <named/statschannel.h>
00044 
00045 #ifdef HAVE_JSON_H
00046 #include <json/json.h>
00047 #endif
00048 
00049 #include "bind9.xsl.h"
00050 
00051 struct ns_statschannel {
00052         /* Unlocked */
00053         isc_httpdmgr_t                          *httpdmgr;
00054         isc_sockaddr_t                          address;
00055         isc_mem_t                               *mctx;
00056 
00057         /*
00058          * Locked by channel lock: can be referenced and modified by both
00059          * the server task and the channel task.
00060          */
00061         isc_mutex_t                             lock;
00062         dns_acl_t                               *acl;
00063 
00064         /* Locked by server task */
00065         ISC_LINK(struct ns_statschannel)        link;
00066 };
00067 
00068 typedef struct
00069 stats_dumparg {
00070         isc_statsformat_t       type;
00071         void                    *arg;           /* type dependent argument */
00072         int                     ncounters;      /* for general statistics */
00073         int                     *counterindices; /* for general statistics */
00074         isc_uint64_t            *countervalues;  /* for general statistics */
00075         isc_result_t            result;
00076 } stats_dumparg_t;
00077 
00078 static isc_once_t once = ISC_ONCE_INIT;
00079 
00080 #if defined(HAVE_LIBXML2) || defined(HAVE_JSON)
00081 #define EXTENDED_STATS
00082 #else
00083 #undef EXTENDED_STATS
00084 #endif
00085 
00086 /*%
00087  * Statistics descriptions.  These could be statistically initialized at
00088  * compile time, but we configure them run time in the init_desc() function
00089  * below so that they'll be less susceptible to counter name changes.
00090  */
00091 static const char *nsstats_desc[dns_nsstatscounter_max];
00092 static const char *resstats_desc[dns_resstatscounter_max];
00093 static const char *adbstats_desc[dns_adbstats_max];
00094 static const char *zonestats_desc[dns_zonestatscounter_max];
00095 static const char *sockstats_desc[isc_sockstatscounter_max];
00096 static const char *dnssecstats_desc[dns_dnssecstats_max];
00097 #if defined(EXTENDED_STATS)
00098 static const char *nsstats_xmldesc[dns_nsstatscounter_max];
00099 static const char *resstats_xmldesc[dns_resstatscounter_max];
00100 static const char *adbstats_xmldesc[dns_adbstats_max];
00101 static const char *zonestats_xmldesc[dns_zonestatscounter_max];
00102 static const char *sockstats_xmldesc[isc_sockstatscounter_max];
00103 static const char *dnssecstats_xmldesc[dns_dnssecstats_max];
00104 #else
00105 #define nsstats_xmldesc NULL
00106 #define resstats_xmldesc NULL
00107 #define adbstats_xmldesc NULL
00108 #define zonestats_xmldesc NULL
00109 #define sockstats_xmldesc NULL
00110 #define dnssecstats_xmldesc NULL
00111 #endif  /* EXTENDED_STATS */
00112 
00113 #define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0)
00114 
00115 /*%
00116  * Mapping arrays to represent statistics counters in the order of our
00117  * preference, regardless of the order of counter indices.  For example,
00118  * nsstats_desc[nsstats_index[0]] will be the description that is shown first.
00119  */
00120 static int nsstats_index[dns_nsstatscounter_max];
00121 static int resstats_index[dns_resstatscounter_max];
00122 static int adbstats_index[dns_adbstats_max];
00123 static int zonestats_index[dns_zonestatscounter_max];
00124 static int sockstats_index[isc_sockstatscounter_max];
00125 static int dnssecstats_index[dns_dnssecstats_max];
00126 
00127 static inline void
00128 set_desc(int counter, int maxcounter, const char *fdesc, const char **fdescs,
00129          const char *xdesc, const char **xdescs)
00130 {
00131         REQUIRE(counter < maxcounter);
00132         REQUIRE(fdescs != NULL && fdescs[counter] == NULL);
00133 #if defined(EXTENDED_STATS)
00134         REQUIRE(xdescs != NULL && xdescs[counter] == NULL);
00135 #endif
00136 
00137         fdescs[counter] = fdesc;
00138 #if defined(EXTENDED_STATS)
00139         xdescs[counter] = xdesc;
00140 #else
00141         UNUSED(xdesc);
00142         UNUSED(xdescs);
00143 #endif
00144 }
00145 
00146 static void
00147 init_desc(void) {
00148         int i;
00149 
00150         /* Initialize name server statistics */
00151         for (i = 0; i < dns_nsstatscounter_max; i++)
00152                 nsstats_desc[i] = NULL;
00153 #if defined(EXTENDED_STATS)
00154         for (i = 0; i < dns_nsstatscounter_max; i++)
00155                 nsstats_xmldesc[i] = NULL;
00156 #endif
00157 
00158 #define SET_NSSTATDESC(counterid, desc, xmldesc) \
00159         do { \
00160                 set_desc(dns_nsstatscounter_ ## counterid, \
00161                          dns_nsstatscounter_max, \
00162                          desc, nsstats_desc, xmldesc, nsstats_xmldesc); \
00163                 nsstats_index[i++] = dns_nsstatscounter_ ## counterid; \
00164         } while (0)
00165 
00166         i = 0;
00167         SET_NSSTATDESC(requestv4, "IPv4 requests received", "Requestv4");
00168         SET_NSSTATDESC(requestv6, "IPv6 requests received", "Requestv6");
00169         SET_NSSTATDESC(edns0in, "requests with EDNS(0) received", "ReqEdns0");
00170         SET_NSSTATDESC(badednsver,
00171                        "requests with unsupported EDNS version received",
00172                        "ReqBadEDNSVer");
00173         SET_NSSTATDESC(tsigin, "requests with TSIG received", "ReqTSIG");
00174         SET_NSSTATDESC(sig0in, "requests with SIG(0) received", "ReqSIG0");
00175         SET_NSSTATDESC(invalidsig, "requests with invalid signature",
00176                        "ReqBadSIG");
00177         SET_NSSTATDESC(requesttcp, "TCP requests received", "ReqTCP");
00178         SET_NSSTATDESC(authrej, "auth queries rejected", "AuthQryRej");
00179         SET_NSSTATDESC(recurserej, "recursive queries rejected", "RecQryRej");
00180         SET_NSSTATDESC(xfrrej, "transfer requests rejected", "XfrRej");
00181         SET_NSSTATDESC(updaterej, "update requests rejected", "UpdateRej");
00182         SET_NSSTATDESC(response, "responses sent", "Response");
00183         SET_NSSTATDESC(truncatedresp, "truncated responses sent",
00184                        "TruncatedResp");
00185         SET_NSSTATDESC(edns0out, "responses with EDNS(0) sent", "RespEDNS0");
00186         SET_NSSTATDESC(tsigout, "responses with TSIG sent", "RespTSIG");
00187         SET_NSSTATDESC(sig0out, "responses with SIG(0) sent", "RespSIG0");
00188         SET_NSSTATDESC(success, "queries resulted in successful answer",
00189                        "QrySuccess");
00190         SET_NSSTATDESC(authans, "queries resulted in authoritative answer",
00191                        "QryAuthAns");
00192         SET_NSSTATDESC(nonauthans,
00193                        "queries resulted in non authoritative answer",
00194                        "QryNoauthAns");
00195         SET_NSSTATDESC(referral, "queries resulted in referral answer",
00196                        "QryReferral");
00197         SET_NSSTATDESC(nxrrset, "queries resulted in nxrrset", "QryNxrrset");
00198         SET_NSSTATDESC(servfail, "queries resulted in SERVFAIL", "QrySERVFAIL");
00199         SET_NSSTATDESC(formerr, "queries resulted in FORMERR", "QryFORMERR");
00200         SET_NSSTATDESC(nxdomain, "queries resulted in NXDOMAIN", "QryNXDOMAIN");
00201         SET_NSSTATDESC(recursion, "queries caused recursion", "QryRecursion");
00202         SET_NSSTATDESC(duplicate, "duplicate queries received", "QryDuplicate");
00203         SET_NSSTATDESC(dropped, "queries dropped", "QryDropped");
00204         SET_NSSTATDESC(failure, "other query failures", "QryFailure");
00205         SET_NSSTATDESC(xfrdone, "requested transfers completed", "XfrReqDone");
00206         SET_NSSTATDESC(updatereqfwd, "update requests forwarded",
00207                        "UpdateReqFwd");
00208         SET_NSSTATDESC(updaterespfwd, "update responses forwarded",
00209                        "UpdateRespFwd");
00210         SET_NSSTATDESC(updatefwdfail, "update forward failed", "UpdateFwdFail");
00211         SET_NSSTATDESC(updatedone, "updates completed", "UpdateDone");
00212         SET_NSSTATDESC(updatefail, "updates failed", "UpdateFail");
00213         SET_NSSTATDESC(updatebadprereq,
00214                        "updates rejected due to prerequisite failure",
00215                        "UpdateBadPrereq");
00216         SET_NSSTATDESC(recursclients, "recursing clients",
00217                         "RecursClients");
00218         SET_NSSTATDESC(dns64, "queries answered by DNS64", "DNS64");
00219         SET_NSSTATDESC(ratedropped, "responses dropped for rate limits",
00220                        "RateDropped");
00221         SET_NSSTATDESC(rateslipped, "responses truncated for rate limits",
00222                        "RateSlipped");
00223         SET_NSSTATDESC(rpz_rewrites, "response policy zone rewrites",
00224                        "RPZRewrites");
00225         SET_NSSTATDESC(udp, "UDP queries received", "QryUDP");
00226         SET_NSSTATDESC(tcp, "TCP queries received", "QryTCP");
00227         SET_NSSTATDESC(nsidopt, "NSID option received", "NSIDOpt");
00228         SET_NSSTATDESC(expireopt, "Expire option received", "ExpireOpt");
00229         SET_NSSTATDESC(otheropt, "Other EDNS option received", "OtherOpt");
00230 #ifdef ISC_PLATFORM_USESIT
00231         SET_NSSTATDESC(sitopt, "source identity token option received",
00232                        "SitOpt");
00233         SET_NSSTATDESC(sitnew, "new source identity token requested",
00234                        "SitNew");
00235         SET_NSSTATDESC(sitbadsize, "source identity token - bad size",
00236                        "SitBadSize");
00237         SET_NSSTATDESC(sitbadtime, "source identity token - bad time",
00238                        "SitBadTime");
00239         SET_NSSTATDESC(sitnomatch, "source identity token - no match",
00240                        "SitNoMatch");
00241         SET_NSSTATDESC(sitmatch, "source identity token - match", "SitMatch");
00242 #endif
00243         SET_NSSTATDESC(ecsopt, "EDNS client subnet option recieved", "ECSOpt");
00244         INSIST(i == dns_nsstatscounter_max);
00245 
00246         /* Initialize resolver statistics */
00247         for (i = 0; i < dns_resstatscounter_max; i++)
00248                 resstats_desc[i] = NULL;
00249 #if defined(EXTENDED_STATS)
00250         for (i = 0; i < dns_resstatscounter_max; i++)
00251                 resstats_xmldesc[i] = NULL;
00252 #endif
00253 
00254 #define SET_RESSTATDESC(counterid, desc, xmldesc) \
00255         do { \
00256                 set_desc(dns_resstatscounter_ ## counterid, \
00257                          dns_resstatscounter_max, \
00258                          desc, resstats_desc, xmldesc, resstats_xmldesc); \
00259                 resstats_index[i++] = dns_resstatscounter_ ## counterid; \
00260         } while (0)
00261 
00262         i = 0;
00263         SET_RESSTATDESC(queryv4, "IPv4 queries sent", "Queryv4");
00264         SET_RESSTATDESC(queryv6, "IPv6 queries sent", "Queryv6");
00265         SET_RESSTATDESC(responsev4, "IPv4 responses received", "Responsev4");
00266         SET_RESSTATDESC(responsev6, "IPv6 responses received", "Responsev6");
00267         SET_RESSTATDESC(nxdomain, "NXDOMAIN received", "NXDOMAIN");
00268         SET_RESSTATDESC(servfail, "SERVFAIL received", "SERVFAIL");
00269         SET_RESSTATDESC(formerr, "FORMERR received", "FORMERR");
00270         SET_RESSTATDESC(othererror, "other errors received", "OtherError");
00271         SET_RESSTATDESC(edns0fail, "EDNS(0) query failures", "EDNS0Fail");
00272         SET_RESSTATDESC(mismatch, "mismatch responses received", "Mismatch");
00273         SET_RESSTATDESC(truncated, "truncated responses received", "Truncated");
00274         SET_RESSTATDESC(lame, "lame delegations received", "Lame");
00275         SET_RESSTATDESC(retry, "query retries", "Retry");
00276         SET_RESSTATDESC(dispabort, "queries aborted due to quota",
00277                         "QueryAbort");
00278         SET_RESSTATDESC(dispsockfail, "failures in opening query sockets",
00279                         "QuerySockFail");
00280         SET_RESSTATDESC(disprequdp, "UDP queries in progress", "QueryCurUDP");
00281         SET_RESSTATDESC(dispreqtcp, "TCP queries in progress", "QueryCurTCP");
00282         SET_RESSTATDESC(querytimeout, "query timeouts", "QueryTimeout");
00283         SET_RESSTATDESC(gluefetchv4, "IPv4 NS address fetches", "GlueFetchv4");
00284         SET_RESSTATDESC(gluefetchv6, "IPv6 NS address fetches", "GlueFetchv6");
00285         SET_RESSTATDESC(gluefetchv4fail, "IPv4 NS address fetch failed",
00286                         "GlueFetchv4Fail");
00287         SET_RESSTATDESC(gluefetchv6fail, "IPv6 NS address fetch failed",
00288                         "GlueFetchv6Fail");
00289         SET_RESSTATDESC(val, "DNSSEC validation attempted", "ValAttempt");
00290         SET_RESSTATDESC(valsuccess, "DNSSEC validation succeeded", "ValOk");
00291         SET_RESSTATDESC(valnegsuccess, "DNSSEC NX validation succeeded",
00292                         "ValNegOk");
00293         SET_RESSTATDESC(valfail, "DNSSEC validation failed", "ValFail");
00294         SET_RESSTATDESC(queryrtt0, "queries with RTT < "
00295                         DNS_RESOLVER_QRYRTTCLASS0STR "ms",
00296                         "QryRTT" DNS_RESOLVER_QRYRTTCLASS0STR);
00297         SET_RESSTATDESC(queryrtt1, "queries with RTT "
00298                         DNS_RESOLVER_QRYRTTCLASS0STR "-"
00299                         DNS_RESOLVER_QRYRTTCLASS1STR "ms",
00300                         "QryRTT" DNS_RESOLVER_QRYRTTCLASS1STR);
00301         SET_RESSTATDESC(queryrtt2, "queries with RTT "
00302                         DNS_RESOLVER_QRYRTTCLASS1STR "-"
00303                         DNS_RESOLVER_QRYRTTCLASS2STR "ms",
00304                         "QryRTT" DNS_RESOLVER_QRYRTTCLASS2STR);
00305         SET_RESSTATDESC(queryrtt3, "queries with RTT "
00306                         DNS_RESOLVER_QRYRTTCLASS2STR "-"
00307                         DNS_RESOLVER_QRYRTTCLASS3STR "ms",
00308                         "QryRTT" DNS_RESOLVER_QRYRTTCLASS3STR);
00309         SET_RESSTATDESC(queryrtt4, "queries with RTT "
00310                         DNS_RESOLVER_QRYRTTCLASS3STR "-"
00311                         DNS_RESOLVER_QRYRTTCLASS4STR "ms",
00312                         "QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR);
00313         SET_RESSTATDESC(queryrtt5, "queries with RTT > "
00314                         DNS_RESOLVER_QRYRTTCLASS4STR "ms",
00315                         "QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR "+");
00316         SET_RESSTATDESC(nfetch, "active fetches", "NumFetch");
00317         SET_RESSTATDESC(buckets, "bucket size", "BucketSize");
00318         SET_RESSTATDESC(refused, "REFUSED received", "REFUSED");
00319 #ifdef ISC_PLATFORM_USESIT
00320         SET_RESSTATDESC(sitcc, "SIT sent client cookie only",
00321                         "SitClientOut");
00322         SET_RESSTATDESC(sitout, "SIT sent with client and server cookie",
00323                         "SitOut");
00324         SET_RESSTATDESC(sitin, "SIT replies received", "SitIn");
00325         SET_RESSTATDESC(sitok, "SIT client cookie ok", "SitClientOk");
00326 #endif
00327         SET_RESSTATDESC(badvers, "bad EDNS version", "BadEDNSVersion");
00328 
00329         INSIST(i == dns_resstatscounter_max);
00330 
00331         /* Initialize adb statistics */
00332         for (i = 0; i < dns_adbstats_max; i++)
00333                 adbstats_desc[i] = NULL;
00334 #if defined(EXTENDED_STATS)
00335         for (i = 0; i < dns_adbstats_max; i++)
00336                 adbstats_xmldesc[i] = NULL;
00337 #endif
00338 
00339 #define SET_ADBSTATDESC(id, desc, xmldesc) \
00340         do { \
00341                 set_desc(dns_adbstats_ ## id, dns_adbstats_max, \
00342                          desc, adbstats_desc, xmldesc, adbstats_xmldesc); \
00343                 adbstats_index[i++] = dns_adbstats_ ## id; \
00344         } while (0)
00345         i = 0;
00346         SET_ADBSTATDESC(nentries, "Address hash table size", "nentries");
00347         SET_ADBSTATDESC(entriescnt, "Addresses in hash table", "entriescnt");
00348         SET_ADBSTATDESC(nnames, "Name hash table size", "nnames");
00349         SET_ADBSTATDESC(namescnt, "Names in hash table", "namescnt");
00350 
00351         INSIST(i == dns_adbstats_max);
00352 
00353         /* Initialize zone statistics */
00354         for (i = 0; i < dns_zonestatscounter_max; i++)
00355                 zonestats_desc[i] = NULL;
00356 #if defined(EXTENDED_STATS)
00357         for (i = 0; i < dns_zonestatscounter_max; i++)
00358                 zonestats_xmldesc[i] = NULL;
00359 #endif
00360 
00361 #define SET_ZONESTATDESC(counterid, desc, xmldesc) \
00362         do { \
00363                 set_desc(dns_zonestatscounter_ ## counterid, \
00364                          dns_zonestatscounter_max, \
00365                          desc, zonestats_desc, xmldesc, zonestats_xmldesc); \
00366                 zonestats_index[i++] = dns_zonestatscounter_ ## counterid; \
00367         } while (0)
00368 
00369         i = 0;
00370         SET_ZONESTATDESC(notifyoutv4, "IPv4 notifies sent", "NotifyOutv4");
00371         SET_ZONESTATDESC(notifyoutv6, "IPv6 notifies sent", "NotifyOutv6");
00372         SET_ZONESTATDESC(notifyinv4, "IPv4 notifies received", "NotifyInv4");
00373         SET_ZONESTATDESC(notifyinv6, "IPv6 notifies received", "NotifyInv6");
00374         SET_ZONESTATDESC(notifyrej, "notifies rejected", "NotifyRej");
00375         SET_ZONESTATDESC(soaoutv4, "IPv4 SOA queries sent", "SOAOutv4");
00376         SET_ZONESTATDESC(soaoutv6, "IPv6 SOA queries sent", "SOAOutv6");
00377         SET_ZONESTATDESC(axfrreqv4, "IPv4 AXFR requested", "AXFRReqv4");
00378         SET_ZONESTATDESC(axfrreqv6, "IPv6 AXFR requested", "AXFRReqv6");
00379         SET_ZONESTATDESC(ixfrreqv4, "IPv4 IXFR requested", "IXFRReqv4");
00380         SET_ZONESTATDESC(ixfrreqv6, "IPv6 IXFR requested", "IXFRReqv6");
00381         SET_ZONESTATDESC(xfrsuccess, "transfer requests succeeded",
00382                          "XfrSuccess");
00383         SET_ZONESTATDESC(xfrfail, "transfer requests failed", "XfrFail");
00384         INSIST(i == dns_zonestatscounter_max);
00385 
00386         /* Initialize socket statistics */
00387         for (i = 0; i < isc_sockstatscounter_max; i++)
00388                 sockstats_desc[i] = NULL;
00389 #if defined(EXTENDED_STATS)
00390         for (i = 0; i < isc_sockstatscounter_max; i++)
00391                 sockstats_xmldesc[i] = NULL;
00392 #endif
00393 
00394 #define SET_SOCKSTATDESC(counterid, desc, xmldesc) \
00395         do { \
00396                 set_desc(isc_sockstatscounter_ ## counterid, \
00397                          isc_sockstatscounter_max, \
00398                          desc, sockstats_desc, xmldesc, sockstats_xmldesc); \
00399                 sockstats_index[i++] = isc_sockstatscounter_ ## counterid; \
00400         } while (0)
00401 
00402         i = 0;
00403         SET_SOCKSTATDESC(udp4open, "UDP/IPv4 sockets opened", "UDP4Open");
00404         SET_SOCKSTATDESC(udp6open, "UDP/IPv6 sockets opened", "UDP6Open");
00405         SET_SOCKSTATDESC(tcp4open, "TCP/IPv4 sockets opened", "TCP4Open");
00406         SET_SOCKSTATDESC(tcp6open, "TCP/IPv6 sockets opened", "TCP6Open");
00407         SET_SOCKSTATDESC(unixopen, "Unix domain sockets opened", "UnixOpen");
00408         SET_SOCKSTATDESC(rawopen, "Raw sockets opened", "RawOpen");
00409         SET_SOCKSTATDESC(udp4openfail, "UDP/IPv4 socket open failures",
00410                          "UDP4OpenFail");
00411         SET_SOCKSTATDESC(udp6openfail, "UDP/IPv6 socket open failures",
00412                          "UDP6OpenFail");
00413         SET_SOCKSTATDESC(tcp4openfail, "TCP/IPv4 socket open failures",
00414                          "TCP4OpenFail");
00415         SET_SOCKSTATDESC(tcp6openfail, "TCP/IPv6 socket open failures",
00416                          "TCP6OpenFail");
00417         SET_SOCKSTATDESC(unixopenfail, "Unix domain socket open failures",
00418                          "UnixOpenFail");
00419         SET_SOCKSTATDESC(rawopenfail, "Raw socket open failures",
00420                          "RawOpenFail");
00421         SET_SOCKSTATDESC(udp4close, "UDP/IPv4 sockets closed", "UDP4Close");
00422         SET_SOCKSTATDESC(udp6close, "UDP/IPv6 sockets closed", "UDP6Close");
00423         SET_SOCKSTATDESC(tcp4close, "TCP/IPv4 sockets closed", "TCP4Close");
00424         SET_SOCKSTATDESC(tcp6close, "TCP/IPv6 sockets closed", "TCP6Close");
00425         SET_SOCKSTATDESC(unixclose, "Unix domain sockets closed", "UnixClose");
00426         SET_SOCKSTATDESC(fdwatchclose, "FDwatch sockets closed",
00427                          "FDWatchClose");
00428         SET_SOCKSTATDESC(rawclose, "Raw sockets closed", "RawClose");
00429         SET_SOCKSTATDESC(udp4bindfail, "UDP/IPv4 socket bind failures",
00430                          "UDP4BindFail");
00431         SET_SOCKSTATDESC(udp6bindfail, "UDP/IPv6 socket bind failures",
00432                          "UDP6BindFail");
00433         SET_SOCKSTATDESC(tcp4bindfail, "TCP/IPv4 socket bind failures",
00434                          "TCP4BindFail");
00435         SET_SOCKSTATDESC(tcp6bindfail, "TCP/IPv6 socket bind failures",
00436                          "TCP6BindFail");
00437         SET_SOCKSTATDESC(unixbindfail, "Unix domain socket bind failures",
00438                          "UnixBindFail");
00439         SET_SOCKSTATDESC(fdwatchbindfail, "FDwatch socket bind failures",
00440                          "FdwatchBindFail");
00441         SET_SOCKSTATDESC(udp4connectfail, "UDP/IPv4 socket connect failures",
00442                          "UDP4ConnFail");
00443         SET_SOCKSTATDESC(udp6connectfail, "UDP/IPv6 socket connect failures",
00444                          "UDP6ConnFail");
00445         SET_SOCKSTATDESC(tcp4connectfail, "TCP/IPv4 socket connect failures",
00446                          "TCP4ConnFail");
00447         SET_SOCKSTATDESC(tcp6connectfail, "TCP/IPv6 socket connect failures",
00448                          "TCP6ConnFail");
00449         SET_SOCKSTATDESC(unixconnectfail, "Unix domain socket connect failures",
00450                          "UnixConnFail");
00451         SET_SOCKSTATDESC(fdwatchconnectfail, "FDwatch socket connect failures",
00452                          "FDwatchConnFail");
00453         SET_SOCKSTATDESC(udp4connect, "UDP/IPv4 connections established",
00454                          "UDP4Conn");
00455         SET_SOCKSTATDESC(udp6connect, "UDP/IPv6 connections established",
00456                          "UDP6Conn");
00457         SET_SOCKSTATDESC(tcp4connect, "TCP/IPv4 connections established",
00458                          "TCP4Conn");
00459         SET_SOCKSTATDESC(tcp6connect, "TCP/IPv6 connections established",
00460                          "TCP6Conn");
00461         SET_SOCKSTATDESC(unixconnect, "Unix domain connections established",
00462                          "UnixConn");
00463         SET_SOCKSTATDESC(fdwatchconnect,
00464                          "FDwatch domain connections established",
00465                          "FDwatchConn");
00466         SET_SOCKSTATDESC(tcp4acceptfail, "TCP/IPv4 connection accept failures",
00467                          "TCP4AcceptFail");
00468         SET_SOCKSTATDESC(tcp6acceptfail, "TCP/IPv6 connection accept failures",
00469                          "TCP6AcceptFail");
00470         SET_SOCKSTATDESC(unixacceptfail,
00471                          "Unix domain connection accept failures",
00472                          "UnixAcceptFail");
00473         SET_SOCKSTATDESC(tcp4accept, "TCP/IPv4 connections accepted",
00474                          "TCP4Accept");
00475         SET_SOCKSTATDESC(tcp6accept, "TCP/IPv6 connections accepted",
00476                          "TCP6Accept");
00477         SET_SOCKSTATDESC(unixaccept, "Unix domain connections accepted",
00478                          "UnixAccept");
00479         SET_SOCKSTATDESC(udp4sendfail, "UDP/IPv4 send errors", "UDP4SendErr");
00480         SET_SOCKSTATDESC(udp6sendfail, "UDP/IPv6 send errors", "UDP6SendErr");
00481         SET_SOCKSTATDESC(tcp4sendfail, "TCP/IPv4 send errors", "TCP4SendErr");
00482         SET_SOCKSTATDESC(tcp6sendfail, "TCP/IPv6 send errors", "TCP6SendErr");
00483         SET_SOCKSTATDESC(unixsendfail, "Unix domain send errors",
00484                          "UnixSendErr");
00485         SET_SOCKSTATDESC(fdwatchsendfail, "FDwatch send errors",
00486                          "FDwatchSendErr");
00487         SET_SOCKSTATDESC(udp4recvfail, "UDP/IPv4 recv errors", "UDP4RecvErr");
00488         SET_SOCKSTATDESC(udp6recvfail, "UDP/IPv6 recv errors", "UDP6RecvErr");
00489         SET_SOCKSTATDESC(tcp4recvfail, "TCP/IPv4 recv errors", "TCP4RecvErr");
00490         SET_SOCKSTATDESC(tcp6recvfail, "TCP/IPv6 recv errors", "TCP6RecvErr");
00491         SET_SOCKSTATDESC(unixrecvfail, "Unix domain recv errors",
00492                          "UnixRecvErr");
00493         SET_SOCKSTATDESC(fdwatchrecvfail, "FDwatch recv errors",
00494                          "FDwatchRecvErr");
00495         SET_SOCKSTATDESC(rawrecvfail, "Raw recv errors", "RawRecvErr");
00496         SET_SOCKSTATDESC(udp4active, "UDP/IPv4 sockets active", "UDP4Active");
00497         SET_SOCKSTATDESC(udp6active, "UDP/IPv6 sockets active", "UDP6Active");
00498         SET_SOCKSTATDESC(tcp4active, "TCP/IPv4 sockets active", "TCP4Active");
00499         SET_SOCKSTATDESC(tcp6active, "TCP/IPv6 sockets active", "TCP6Active");
00500         SET_SOCKSTATDESC(unixactive, "Unix domain sockets active",
00501                          "UnixActive");
00502         SET_SOCKSTATDESC(rawactive, "Raw sockets active", "RawActive");
00503         INSIST(i == isc_sockstatscounter_max);
00504 
00505         /* Initialize DNSSEC statistics */
00506         for (i = 0; i < dns_dnssecstats_max; i++)
00507                 dnssecstats_desc[i] = NULL;
00508 #if defined(EXTENDED_STATS)
00509         for (i = 0; i < dns_dnssecstats_max; i++)
00510                 dnssecstats_xmldesc[i] = NULL;
00511 #endif
00512 
00513 #define SET_DNSSECSTATDESC(counterid, desc, xmldesc) \
00514         do { \
00515                 set_desc(dns_dnssecstats_ ## counterid, \
00516                          dns_dnssecstats_max, \
00517                          desc, dnssecstats_desc, \
00518                          xmldesc, dnssecstats_xmldesc); \
00519                 dnssecstats_index[i++] = dns_dnssecstats_ ## counterid; \
00520         } while (0)
00521 
00522         i = 0;
00523         SET_DNSSECSTATDESC(asis, "dnssec validation success with signer "
00524                            "\"as is\"", "DNSSECasis");
00525         SET_DNSSECSTATDESC(downcase, "dnssec validation success with signer "
00526                            "lower cased", "DNSSECdowncase");
00527         SET_DNSSECSTATDESC(wildcard, "dnssec validation of wildcard signature",
00528                            "DNSSECwild");
00529         SET_DNSSECSTATDESC(fail, "dnssec validation failures", "DNSSECfail");
00530         INSIST(i == dns_dnssecstats_max);
00531 
00532         /* Sanity check */
00533         for (i = 0; i < dns_nsstatscounter_max; i++)
00534                 INSIST(nsstats_desc[i] != NULL);
00535         for (i = 0; i < dns_resstatscounter_max; i++)
00536                 INSIST(resstats_desc[i] != NULL);
00537         for (i = 0; i < dns_adbstats_max; i++)
00538                 INSIST(adbstats_desc[i] != NULL);
00539         for (i = 0; i < dns_zonestatscounter_max; i++)
00540                 INSIST(zonestats_desc[i] != NULL);
00541         for (i = 0; i < isc_sockstatscounter_max; i++)
00542                 INSIST(sockstats_desc[i] != NULL);
00543         for (i = 0; i < dns_dnssecstats_max; i++)
00544                 INSIST(dnssecstats_desc[i] != NULL);
00545 #if defined(EXTENDED_STATS)
00546         for (i = 0; i < dns_nsstatscounter_max; i++)
00547                 INSIST(nsstats_xmldesc[i] != NULL);
00548         for (i = 0; i < dns_resstatscounter_max; i++)
00549                 INSIST(resstats_xmldesc[i] != NULL);
00550         for (i = 0; i < dns_adbstats_max; i++)
00551                 INSIST(adbstats_xmldesc[i] != NULL);
00552         for (i = 0; i < dns_zonestatscounter_max; i++)
00553                 INSIST(zonestats_xmldesc[i] != NULL);
00554         for (i = 0; i < isc_sockstatscounter_max; i++)
00555                 INSIST(sockstats_xmldesc[i] != NULL);
00556         for (i = 0; i < dns_dnssecstats_max; i++)
00557                 INSIST(dnssecstats_xmldesc[i] != NULL);
00558 #endif
00559 }
00560 
00561 /*%
00562  * Dump callback functions.
00563  */
00564 static void
00565 generalstat_dump(isc_statscounter_t counter, isc_uint64_t val, void *arg) {
00566         stats_dumparg_t *dumparg = arg;
00567 
00568         REQUIRE(counter < dumparg->ncounters);
00569         dumparg->countervalues[counter] = val;
00570 }
00571 
00572 static isc_result_t
00573 dump_counters(isc_stats_t *stats, isc_statsformat_t type, void *arg,
00574               const char *category, const char **desc, int ncounters,
00575               int *indices, isc_uint64_t *values, int options)
00576 {
00577         int i, idx;
00578         isc_uint64_t value;
00579         stats_dumparg_t dumparg;
00580         FILE *fp;
00581 #ifdef HAVE_LIBXML2
00582         xmlTextWriterPtr writer;
00583         int xmlrc;
00584 #endif
00585 #ifdef HAVE_JSON
00586         json_object *job, *cat, *counter;
00587 #endif
00588 
00589 #if !defined(EXTENDED_STATS)
00590         UNUSED(category);
00591 #endif
00592 
00593         dumparg.type = type;
00594         dumparg.ncounters = ncounters;
00595         dumparg.counterindices = indices;
00596         dumparg.countervalues = values;
00597 
00598         memset(values, 0, sizeof(values[0]) * ncounters);
00599         isc_stats_dump(stats, generalstat_dump, &dumparg, options);
00600 
00601 #ifdef HAVE_JSON
00602         cat = job = (json_object *) arg;
00603         if (ncounters > 0 && type == isc_statsformat_json) {
00604                 if (category != NULL) {
00605                         cat = json_object_new_object();
00606                         if (cat == NULL)
00607                                 return (ISC_R_NOMEMORY);
00608                         json_object_object_add(job, category, cat);
00609                 }
00610         }
00611 #endif
00612 
00613         for (i = 0; i < ncounters; i++) {
00614                 idx = indices[i];
00615                 value = values[idx];
00616 
00617                 if (value == 0 && (options & ISC_STATSDUMP_VERBOSE) == 0)
00618                         continue;
00619 
00620                 switch (dumparg.type) {
00621                 case isc_statsformat_file:
00622                         fp = arg;
00623                         fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
00624                                 value, desc[idx]);
00625                         break;
00626                 case isc_statsformat_xml:
00627 #ifdef HAVE_LIBXML2
00628                         writer = (xmlTextWriterPtr) arg;
00629 
00630                         if (category != NULL) {
00631                                 /* <NameOfCategory> */
00632                                 TRY0(xmlTextWriterStartElement(writer,
00633                                                                ISC_XMLCHAR
00634                                                                category));
00635 
00636                                 /* <name> inside category */
00637                                 TRY0(xmlTextWriterStartElement(writer,
00638                                                                ISC_XMLCHAR
00639                                                                "name"));
00640                                 TRY0(xmlTextWriterWriteString(writer,
00641                                                               ISC_XMLCHAR
00642                                                               desc[idx]));
00643                                 TRY0(xmlTextWriterEndElement(writer));
00644                                 /* </name> */
00645 
00646                                 /* <counter> */
00647                                 TRY0(xmlTextWriterStartElement(writer,
00648                                                                ISC_XMLCHAR
00649                                                                "counter"));
00650                                 TRY0(xmlTextWriterWriteFormatString(writer,
00651                                         "%" ISC_PRINT_QUADFORMAT "u", value));
00652 
00653                                 TRY0(xmlTextWriterEndElement(writer));
00654                                 /* </counter> */
00655                                 TRY0(xmlTextWriterEndElement(writer));
00656                                 /* </NameOfCategory> */
00657 
00658                         } else {
00659                                 TRY0(xmlTextWriterStartElement(writer,
00660                                                                ISC_XMLCHAR
00661                                                                "counter"));
00662                                 TRY0(xmlTextWriterWriteAttribute(writer,
00663                                                                  ISC_XMLCHAR
00664                                                                  "name",
00665                                                                  ISC_XMLCHAR
00666                                                                  desc[idx]));
00667                                 TRY0(xmlTextWriterWriteFormatString(writer,
00668                                         "%" ISC_PRINT_QUADFORMAT "u", value));
00669                                 TRY0(xmlTextWriterEndElement(writer));
00670                                 /* counter */
00671                         }
00672 
00673 #endif
00674                         break;
00675                 case isc_statsformat_json:
00676 #ifdef HAVE_JSON
00677                         counter = json_object_new_int64(value);
00678                         if (counter == NULL)
00679                                 return (ISC_R_NOMEMORY);
00680                         json_object_object_add(cat, desc[idx], counter);
00681 #endif
00682                         break;
00683                 }
00684         }
00685         return (ISC_R_SUCCESS);
00686 #ifdef HAVE_LIBXML2
00687  error:
00688         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
00689                       ISC_LOG_ERROR, "failed at dump_counters()");
00690         return (ISC_R_FAILURE);
00691 #endif
00692 }
00693 
00694 static void
00695 rdtypestat_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
00696         char typebuf[64];
00697         const char *typestr;
00698         stats_dumparg_t *dumparg = arg;
00699         FILE *fp;
00700 #ifdef HAVE_LIBXML2
00701         xmlTextWriterPtr writer;
00702         int xmlrc;
00703 #endif
00704 #ifdef HAVE_JSON
00705         json_object *zoneobj, *obj;
00706 #endif
00707 
00708         if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_OTHERTYPE)
00709             == 0) {
00710                 dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf,
00711                                      sizeof(typebuf));
00712                 typestr = typebuf;
00713         } else
00714                 typestr = "Others";
00715 
00716         switch (dumparg->type) {
00717         case isc_statsformat_file:
00718                 fp = dumparg->arg;
00719                 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, typestr);
00720                 break;
00721         case isc_statsformat_xml:
00722 #ifdef HAVE_LIBXML2
00723                 writer = dumparg->arg;
00724 
00725 
00726                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
00727                 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
00728                                                  ISC_XMLCHAR typestr));
00729 
00730                 TRY0(xmlTextWriterWriteFormatString(writer,
00731                                                "%" ISC_PRINT_QUADFORMAT "u",
00732                                                val));
00733 
00734                 TRY0(xmlTextWriterEndElement(writer)); /* type */
00735 #endif
00736                 break;
00737         case isc_statsformat_json:
00738 #ifdef HAVE_JSON
00739                 zoneobj = (json_object *) dumparg->arg;
00740                 obj = json_object_new_int64(val);
00741                 if (obj == NULL)
00742                         return;
00743                 json_object_object_add(zoneobj, typestr, obj);
00744 #endif
00745                 break;
00746         }
00747         return;
00748 #ifdef HAVE_LIBXML2
00749  error:
00750         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
00751                       ISC_LOG_ERROR, "failed at rdtypestat_dump()");
00752         dumparg->result = ISC_R_FAILURE;
00753         return;
00754 #endif
00755 }
00756 
00757 static void
00758 rdatasetstats_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
00759         stats_dumparg_t *dumparg = arg;
00760         FILE *fp;
00761         char typebuf[64];
00762         const char *typestr;
00763         isc_boolean_t nxrrset = ISC_FALSE;
00764         isc_boolean_t stale = ISC_FALSE;
00765 #ifdef HAVE_LIBXML2
00766         xmlTextWriterPtr writer;
00767         int xmlrc;
00768 #endif
00769 #ifdef HAVE_JSON
00770         json_object *zoneobj, *obj;
00771         char buf[1024];
00772 #endif
00773 
00774         if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_NXDOMAIN)
00775             != 0) {
00776                 typestr = "NXDOMAIN";
00777         } else if ((DNS_RDATASTATSTYPE_ATTR(type) &
00778                     DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) != 0) {
00779                 typestr = "Others";
00780         } else {
00781                 dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf,
00782                                      sizeof(typebuf));
00783                 typestr = typebuf;
00784         }
00785 
00786         if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_NXRRSET)
00787             != 0)
00788                 nxrrset = ISC_TRUE;
00789 
00790         if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_STALE)
00791             != 0)
00792                 stale = ISC_TRUE;
00793 
00794         switch (dumparg->type) {
00795         case isc_statsformat_file:
00796                 fp = dumparg->arg;
00797                 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s%s%s\n", val,
00798                         stale ? "#" : "", nxrrset ? "!" : "", typestr);
00799                 break;
00800         case isc_statsformat_xml:
00801 #ifdef HAVE_LIBXML2
00802                 writer = dumparg->arg;
00803 
00804                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "rrset"));
00805                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
00806                 TRY0(xmlTextWriterWriteFormatString(writer, "%s%s%s",
00807                                                stale ? "#" : "",
00808                                                nxrrset ? "!" : "", typestr));
00809                 TRY0(xmlTextWriterEndElement(writer)); /* name */
00810 
00811                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
00812                 TRY0(xmlTextWriterWriteFormatString(writer,
00813                                                "%" ISC_PRINT_QUADFORMAT "u",
00814                                                val));
00815                 TRY0(xmlTextWriterEndElement(writer)); /* counter */
00816 
00817                 TRY0(xmlTextWriterEndElement(writer)); /* rrset */
00818 #endif
00819                 break;
00820         case isc_statsformat_json:
00821 #ifdef HAVE_JSON
00822                 zoneobj = (json_object *) dumparg->arg;
00823                 sprintf(buf, "%s%s%s", stale ? "#" : "",
00824                                        nxrrset ? "!" : "", typestr);
00825                 obj = json_object_new_int64(val);
00826                 if (obj == NULL)
00827                         return;
00828                 json_object_object_add(zoneobj, buf, obj);
00829 #endif
00830                 break;
00831         }
00832         return;
00833 #ifdef HAVE_LIBXML2
00834  error:
00835         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
00836                       ISC_LOG_ERROR, "failed at rdatasetstats_dump()");
00837         dumparg->result = ISC_R_FAILURE;
00838 #endif
00839 
00840 }
00841 
00842 static void
00843 opcodestat_dump(dns_opcode_t code, isc_uint64_t val, void *arg) {
00844         FILE *fp;
00845         isc_buffer_t b;
00846         char codebuf[64];
00847         stats_dumparg_t *dumparg = arg;
00848 #ifdef HAVE_LIBXML2
00849         xmlTextWriterPtr writer;
00850         int xmlrc;
00851 #endif
00852 #ifdef HAVE_JSON
00853         json_object *zoneobj, *obj;
00854 #endif
00855 
00856         isc_buffer_init(&b, codebuf, sizeof(codebuf) - 1);
00857         dns_opcode_totext(code, &b);
00858         codebuf[isc_buffer_usedlength(&b)] = '\0';
00859 
00860         switch (dumparg->type) {
00861         case isc_statsformat_file:
00862                 fp = dumparg->arg;
00863                 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, codebuf);
00864                 break;
00865         case isc_statsformat_xml:
00866 #ifdef HAVE_LIBXML2
00867                 writer = dumparg->arg;
00868                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
00869                 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
00870                                                  ISC_XMLCHAR codebuf ));
00871                 TRY0(xmlTextWriterWriteFormatString(writer,
00872                                                        "%" ISC_PRINT_QUADFORMAT "u",
00873                                                        val));
00874                 TRY0(xmlTextWriterEndElement(writer)); /* counter */
00875 #endif
00876                 break;
00877         case isc_statsformat_json:
00878 #ifdef HAVE_JSON
00879                 zoneobj = (json_object *) dumparg->arg;
00880                 obj = json_object_new_int64(val);
00881                 if (obj == NULL)
00882                         return;
00883                 json_object_object_add(zoneobj, codebuf, obj);
00884 #endif
00885                 break;
00886         }
00887         return;
00888 
00889 #ifdef HAVE_LIBXML2
00890  error:
00891         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
00892                       ISC_LOG_ERROR, "failed at opcodestat_dump()");
00893         dumparg->result = ISC_R_FAILURE;
00894         return;
00895 #endif
00896 }
00897 
00898 #ifdef HAVE_LIBXML2
00899 /*
00900  * Which statistics to include when rendering to XML
00901  */
00902 #define STATS_XML_STATUS        0x00    /* display only common statistics */
00903 #define STATS_XML_SERVER        0x01
00904 #define STATS_XML_ZONES         0x02
00905 #define STATS_XML_TASKS         0x04
00906 #define STATS_XML_NET           0x08
00907 #define STATS_XML_MEM           0x10
00908 #define STATS_XML_ALL           0xff
00909 
00910 static isc_result_t
00911 zone_xmlrender(dns_zone_t *zone, void *arg) {
00912         isc_result_t result;
00913         char buf[1024 + 32];    /* sufficiently large for zone name and class */
00914         char *zone_name_only = NULL;
00915         dns_rdataclass_t rdclass;
00916         isc_uint32_t serial;
00917         xmlTextWriterPtr writer = arg;
00918         isc_stats_t *zonestats;
00919         dns_stats_t *rcvquerystats;
00920         dns_zonestat_level_t statlevel;
00921         isc_uint64_t nsstat_values[dns_nsstatscounter_max];
00922         int xmlrc;
00923         stats_dumparg_t dumparg;
00924 
00925         statlevel = dns_zone_getstatlevel(zone);
00926         if (statlevel == dns_zonestat_none)
00927                 return (ISC_R_SUCCESS);
00928 
00929         dumparg.type = isc_statsformat_xml;
00930         dumparg.arg = writer;
00931 
00932         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "zone"));
00933         dns_zone_name(zone, buf, sizeof(buf));
00934         zone_name_only = strtok(buf, "/");
00935         if(zone_name_only == NULL)
00936                 zone_name_only = buf;
00937 
00938         TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
00939                                          ISC_XMLCHAR zone_name_only));
00940         rdclass = dns_zone_getclass(zone);
00941         dns_rdataclass_format(rdclass, buf, sizeof(buf));
00942         TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "rdataclass",
00943                                          ISC_XMLCHAR buf));
00944 
00945         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "serial"));
00946         if (dns_zone_getserial2(zone, &serial) == ISC_R_SUCCESS)
00947                 TRY0(xmlTextWriterWriteFormatString(writer, "%u", serial));
00948         else
00949                 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-"));
00950         TRY0(xmlTextWriterEndElement(writer)); /* serial */
00951 
00952         zonestats = dns_zone_getrequeststats(zone);
00953         rcvquerystats = dns_zone_getrcvquerystats(zone);
00954         if (statlevel == dns_zonestat_full && zonestats != NULL) {
00955                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
00956                 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
00957                                                  ISC_XMLCHAR "rcode"));
00958 
00959                 result = dump_counters(zonestats, isc_statsformat_xml, writer,
00960                                        NULL, nsstats_xmldesc,
00961                                        dns_nsstatscounter_max, nsstats_index,
00962                                        nsstat_values, ISC_STATSDUMP_VERBOSE);
00963                 if (result != ISC_R_SUCCESS)
00964                         goto error;
00965                 /* counters type="rcode"*/
00966                 TRY0(xmlTextWriterEndElement(writer));
00967         }
00968 
00969         if (statlevel == dns_zonestat_full && rcvquerystats != NULL) {
00970                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
00971                 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
00972                                                  ISC_XMLCHAR "qtype"));
00973 
00974                 dumparg.result = ISC_R_SUCCESS;
00975                 dns_rdatatypestats_dump(rcvquerystats, rdtypestat_dump,
00976                                         &dumparg, 0);
00977                 if(dumparg.result != ISC_R_SUCCESS)
00978                         goto error;
00979 
00980                 /* counters type="qtype"*/
00981                 TRY0(xmlTextWriterEndElement(writer));
00982         }
00983 
00984         TRY0(xmlTextWriterEndElement(writer)); /* zone */
00985 
00986         return (ISC_R_SUCCESS);
00987  error:
00988         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
00989                       ISC_LOG_ERROR, "Failed at zone_xmlrender()");
00990         return (ISC_R_FAILURE);
00991 }
00992 
00993 static isc_result_t
00994 generatexml(ns_server_t *server, isc_uint32_t flags,
00995             int *buflen, xmlChar **buf)
00996 {
00997         char boottime[sizeof "yyyy-mm-ddThh:mm:ssZ"];
00998         char configtime[sizeof "yyyy-mm-ddThh:mm:ssZ"];
00999         char nowstr[sizeof "yyyy-mm-ddThh:mm:ssZ"];
01000         isc_time_t now;
01001         xmlTextWriterPtr writer = NULL;
01002         xmlDocPtr doc = NULL;
01003         int xmlrc;
01004         dns_view_t *view;
01005         stats_dumparg_t dumparg;
01006         dns_stats_t *cacherrstats;
01007         isc_uint64_t nsstat_values[dns_nsstatscounter_max];
01008         isc_uint64_t resstat_values[dns_resstatscounter_max];
01009         isc_uint64_t adbstat_values[dns_adbstats_max];
01010         isc_uint64_t zonestat_values[dns_zonestatscounter_max];
01011         isc_uint64_t sockstat_values[isc_sockstatscounter_max];
01012         isc_result_t result;
01013 
01014         isc_time_now(&now);
01015         isc_time_formatISO8601(&ns_g_boottime, boottime, sizeof boottime);
01016         isc_time_formatISO8601(&ns_g_configtime, configtime, sizeof configtime);
01017         isc_time_formatISO8601(&now, nowstr, sizeof nowstr);
01018 
01019         writer = xmlNewTextWriterDoc(&doc, 0);
01020         if (writer == NULL)
01021                 goto error;
01022         TRY0(xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL));
01023         TRY0(xmlTextWriterWritePI(writer, ISC_XMLCHAR "xml-stylesheet",
01024                         ISC_XMLCHAR "type=\"text/xsl\" href=\"/bind9.xsl\""));
01025         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics"));
01026         TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version",
01027                                          ISC_XMLCHAR "3.5"));
01028 
01029         /* Set common fields for statistics dump */
01030         dumparg.type = isc_statsformat_xml;
01031         dumparg.arg = writer;
01032 
01033         /* Render server information */
01034         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "server"));
01035         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "boot-time"));
01036         TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR boottime));
01037         TRY0(xmlTextWriterEndElement(writer)); /* boot-time */
01038         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "config-time"));
01039         TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR configtime));
01040         TRY0(xmlTextWriterEndElement(writer)); /* config-time */
01041         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "current-time"));
01042         TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR nowstr));
01043         TRY0(xmlTextWriterEndElement(writer));  /* current-time */
01044 
01045         if ((flags & STATS_XML_SERVER) != 0) {
01046                 dumparg.result = ISC_R_SUCCESS;
01047 
01048                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
01049                 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
01050                                                  ISC_XMLCHAR "opcode"));
01051 
01052                 dns_opcodestats_dump(server->opcodestats, opcodestat_dump,
01053                                      &dumparg, ISC_STATSDUMP_VERBOSE);
01054                 if (dumparg.result != ISC_R_SUCCESS)
01055                         goto error;
01056 
01057                 TRY0(xmlTextWriterEndElement(writer));
01058 
01059                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
01060                 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
01061                                                  ISC_XMLCHAR "qtype"));
01062 
01063                 dumparg.result = ISC_R_SUCCESS;
01064                 dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump,
01065                                         &dumparg, 0);
01066                 if (dumparg.result != ISC_R_SUCCESS)
01067                         goto error;
01068                 TRY0(xmlTextWriterEndElement(writer)); /* counters */
01069 
01070                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
01071                 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
01072                                                  ISC_XMLCHAR "nsstat"));
01073 
01074                 result = dump_counters(server->nsstats, isc_statsformat_xml,
01075                                        writer, NULL, nsstats_xmldesc,
01076                                        dns_nsstatscounter_max,
01077                                        nsstats_index, nsstat_values,
01078                                        ISC_STATSDUMP_VERBOSE);
01079                 if (result != ISC_R_SUCCESS)
01080                         goto error;
01081 
01082                 TRY0(xmlTextWriterEndElement(writer)); /* /nsstat */
01083 
01084                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
01085                 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
01086                                                  ISC_XMLCHAR "zonestat"));
01087 
01088                 result = dump_counters(server->zonestats, isc_statsformat_xml,
01089                                        writer, NULL, zonestats_xmldesc,
01090                                        dns_zonestatscounter_max,
01091                                        zonestats_index, zonestat_values,
01092                                        ISC_STATSDUMP_VERBOSE);
01093                 if (result != ISC_R_SUCCESS)
01094                         goto error;
01095 
01096                 TRY0(xmlTextWriterEndElement(writer)); /* /zonestat */
01097 
01098                 /*
01099                  * Most of the common resolver statistics entries are 0, so
01100                  * we don't use the verbose dump here.
01101                  */
01102                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
01103                 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
01104                                                  ISC_XMLCHAR "resstat"));
01105                 result = dump_counters(server->resolverstats,
01106                                        isc_statsformat_xml, writer,
01107                                        NULL, resstats_xmldesc,
01108                                        dns_resstatscounter_max,
01109                                        resstats_index, resstat_values, 0);
01110                 if (result != ISC_R_SUCCESS)
01111                         goto error;
01112                 TRY0(xmlTextWriterEndElement(writer)); /* resstat */
01113         }
01114 
01115         if ((flags & STATS_XML_NET) != 0) {
01116                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
01117                 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
01118                                                  ISC_XMLCHAR "sockstat"));
01119 
01120                 result = dump_counters(server->sockstats, isc_statsformat_xml,
01121                                        writer, NULL, sockstats_xmldesc,
01122                                        isc_sockstatscounter_max,
01123                                        sockstats_index, sockstat_values,
01124                                        ISC_STATSDUMP_VERBOSE);
01125                 if (result != ISC_R_SUCCESS)
01126                         goto error;
01127 
01128                 TRY0(xmlTextWriterEndElement(writer)); /* /sockstat */
01129         }
01130         TRY0(xmlTextWriterEndElement(writer)); /* /server */
01131 
01132         /*
01133          * Render views.  For each view we know of, call its
01134          * rendering function.
01135          */
01136         view = ISC_LIST_HEAD(server->viewlist);
01137         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "views"));
01138         while (view != NULL &&
01139                ((flags & (STATS_XML_SERVER | STATS_XML_ZONES)) != 0))
01140         {
01141                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "view"));
01142                 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
01143                                                  ISC_XMLCHAR view->name));
01144 
01145                 if ((flags & STATS_XML_ZONES) != 0) {
01146                         TRY0(xmlTextWriterStartElement(writer,
01147                                                        ISC_XMLCHAR "zones"));
01148                         result = dns_zt_apply(view->zonetable, ISC_TRUE,
01149                                               zone_xmlrender, writer);
01150                         if (result != ISC_R_SUCCESS)
01151                                 goto error;
01152                         TRY0(xmlTextWriterEndElement(writer)); /* /zones */
01153                 }
01154 
01155                 if ((flags & STATS_XML_SERVER) == 0) {
01156                         TRY0(xmlTextWriterEndElement(writer)); /* /view */
01157                         view = ISC_LIST_NEXT(view, link);
01158                         continue;
01159                 }
01160 
01161                 TRY0(xmlTextWriterStartElement(writer,
01162                                                ISC_XMLCHAR "counters"));
01163                 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
01164                                                  ISC_XMLCHAR "resqtype"));
01165 
01166                 if (view->resquerystats != NULL) {
01167                         dumparg.result = ISC_R_SUCCESS;
01168                         dns_rdatatypestats_dump(view->resquerystats,
01169                                                 rdtypestat_dump, &dumparg, 0);
01170                         if (dumparg.result != ISC_R_SUCCESS)
01171                                 goto error;
01172                 }
01173                 TRY0(xmlTextWriterEndElement(writer));
01174 
01175                 /* <resstats> */
01176                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
01177                 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
01178                                                  ISC_XMLCHAR "resstats"));
01179                 if (view->resstats != NULL) {
01180                         result = dump_counters(view->resstats,
01181                                                isc_statsformat_xml, writer,
01182                                                NULL, resstats_xmldesc,
01183                                                dns_resstatscounter_max,
01184                                                resstats_index, resstat_values,
01185                                                ISC_STATSDUMP_VERBOSE);
01186                         if (result != ISC_R_SUCCESS)
01187                                 goto error;
01188                 }
01189                 TRY0(xmlTextWriterEndElement(writer)); /* </resstats> */
01190 
01191                 cacherrstats = dns_db_getrrsetstats(view->cachedb);
01192                 if (cacherrstats != NULL) {
01193                         TRY0(xmlTextWriterStartElement(writer,
01194                                                        ISC_XMLCHAR "cache"));
01195                         TRY0(xmlTextWriterWriteAttribute(writer,
01196                                          ISC_XMLCHAR "name",
01197                                          ISC_XMLCHAR
01198                                          dns_cache_getname(view->cache)));
01199                         dumparg.result = ISC_R_SUCCESS;
01200                         dns_rdatasetstats_dump(cacherrstats, rdatasetstats_dump,
01201                                                &dumparg, 0);
01202                         if (dumparg.result != ISC_R_SUCCESS)
01203                                 goto error;
01204                         TRY0(xmlTextWriterEndElement(writer)); /* cache */
01205                 }
01206 
01207                 /* <adbstats> */
01208                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
01209                 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
01210                                                  ISC_XMLCHAR "adbstat"));
01211                 if (view->adbstats != NULL) {
01212                         result = dump_counters(view->adbstats,
01213                                                isc_statsformat_xml, writer,
01214                                                NULL, adbstats_xmldesc,
01215                                                dns_adbstats_max,
01216                                                adbstats_index, adbstat_values,
01217                                                ISC_STATSDUMP_VERBOSE);
01218                         if (result != ISC_R_SUCCESS)
01219                                 goto error;
01220                 }
01221                 TRY0(xmlTextWriterEndElement(writer)); /* </adbstats> */
01222 
01223                 /* <cachestats> */
01224                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
01225                 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
01226                                                  ISC_XMLCHAR "cachestats"));
01227                 TRY0(dns_cache_renderxml(view->cache, writer));
01228                 TRY0(xmlTextWriterEndElement(writer)); /* </cachestats> */
01229 
01230                 TRY0(xmlTextWriterEndElement(writer)); /* view */
01231 
01232                 view = ISC_LIST_NEXT(view, link);
01233         }
01234         TRY0(xmlTextWriterEndElement(writer)); /* /views */
01235 
01236         if ((flags & STATS_XML_NET) != 0) {
01237                 TRY0(xmlTextWriterStartElement(writer,
01238                                                ISC_XMLCHAR "socketmgr"));
01239                 TRY0(isc_socketmgr_renderxml(ns_g_socketmgr, writer));
01240                 TRY0(xmlTextWriterEndElement(writer)); /* /socketmgr */
01241         }
01242 
01243         if ((flags & STATS_XML_TASKS) != 0) {
01244                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "taskmgr"));
01245                 TRY0(isc_taskmgr_renderxml(ns_g_taskmgr, writer));
01246                 TRY0(xmlTextWriterEndElement(writer)); /* /taskmgr */
01247         }
01248 
01249         if ((flags & STATS_XML_MEM) != 0) {
01250                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "memory"));
01251                 TRY0(isc_mem_renderxml(writer));
01252                 TRY0(xmlTextWriterEndElement(writer)); /* /memory */
01253         }
01254 
01255         TRY0(xmlTextWriterEndElement(writer)); /* /statistics */
01256         TRY0(xmlTextWriterEndDocument(writer));
01257 
01258         xmlFreeTextWriter(writer);
01259 
01260         xmlDocDumpFormatMemoryEnc(doc, buf, buflen, "UTF-8", 0);
01261         if (*buf == NULL)
01262                 goto error;
01263         xmlFreeDoc(doc);
01264         return (ISC_R_SUCCESS);
01265 
01266  error:
01267         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
01268                       ISC_LOG_ERROR, "failed generating XML response");
01269         if (writer != NULL)
01270                 xmlFreeTextWriter(writer);
01271         if (doc != NULL)
01272                 xmlFreeDoc(doc);
01273         return (ISC_R_FAILURE);
01274 }
01275 
01276 static void
01277 wrap_xmlfree(isc_buffer_t *buffer, void *arg) {
01278         UNUSED(arg);
01279 
01280         xmlFree(isc_buffer_base(buffer));
01281 }
01282 
01283 static isc_result_t
01284 render_xml(isc_uint32_t flags, const char *url, isc_httpdurl_t *urlinfo,
01285            const char *querystring, const char *headers, void *arg,
01286            unsigned int *retcode, const char **retmsg,
01287            const char **mimetype, isc_buffer_t *b,
01288            isc_httpdfree_t **freecb, void **freecb_args)
01289 {
01290         unsigned char *msg = NULL;
01291         int msglen;
01292         ns_server_t *server = arg;
01293         isc_result_t result;
01294 
01295         UNUSED(url);
01296         UNUSED(urlinfo);
01297         UNUSED(headers);
01298         UNUSED(querystring);
01299 
01300         result = generatexml(server, flags, &msglen, &msg);
01301 
01302         if (result == ISC_R_SUCCESS) {
01303                 *retcode = 200;
01304                 *retmsg = "OK";
01305                 *mimetype = "text/xml";
01306                 isc_buffer_reinit(b, msg, msglen);
01307                 isc_buffer_add(b, msglen);
01308                 *freecb = wrap_xmlfree;
01309                 *freecb_args = NULL;
01310         } else
01311                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
01312                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
01313                               "failed at rendering XML()");
01314 
01315         return (result);
01316 }
01317 
01318 static isc_result_t
01319 render_xml_all(const char *url, isc_httpdurl_t *urlinfo,
01320                const char *querystring, const char *headers, void *arg,
01321                unsigned int *retcode, const char **retmsg,
01322                const char **mimetype, isc_buffer_t *b,
01323                isc_httpdfree_t **freecb, void **freecb_args)
01324 {
01325         return (render_xml(STATS_XML_ALL, url, urlinfo,
01326                            querystring, headers, arg,
01327                            retcode, retmsg, mimetype, b,
01328                            freecb, freecb_args));
01329 }
01330 
01331 static isc_result_t
01332 render_xml_status(const char *url, isc_httpdurl_t *urlinfo,
01333                   const char *querystring, const char *headers, void *arg,
01334                   unsigned int *retcode, const char **retmsg,
01335                   const char **mimetype, isc_buffer_t *b,
01336                   isc_httpdfree_t **freecb, void **freecb_args)
01337 {
01338         return (render_xml(STATS_XML_STATUS, url, urlinfo,
01339                            querystring, headers, arg,
01340                            retcode, retmsg, mimetype, b,
01341                            freecb, freecb_args));
01342 }
01343 
01344 static isc_result_t
01345 render_xml_server(const char *url, isc_httpdurl_t *urlinfo,
01346                   const char *querystring, const char *headers, void *arg,
01347                   unsigned int *retcode, const char **retmsg,
01348                   const char **mimetype, isc_buffer_t *b,
01349                   isc_httpdfree_t **freecb, void **freecb_args)
01350 {
01351         return (render_xml(STATS_XML_SERVER, url, urlinfo,
01352                            querystring, headers, arg,
01353                            retcode, retmsg, mimetype, b,
01354                            freecb, freecb_args));
01355 }
01356 
01357 static isc_result_t
01358 render_xml_zones(const char *url, isc_httpdurl_t *urlinfo,
01359                  const char *querystring, const char *headers, void *arg,
01360                  unsigned int *retcode, const char **retmsg,
01361                  const char **mimetype, isc_buffer_t *b,
01362                  isc_httpdfree_t **freecb, void **freecb_args)
01363 {
01364         return (render_xml(STATS_XML_ZONES, url, urlinfo,
01365                            querystring, headers, arg,
01366                            retcode, retmsg, mimetype, b,
01367                            freecb, freecb_args));
01368 }
01369 
01370 static isc_result_t
01371 render_xml_net(const char *url, isc_httpdurl_t *urlinfo,
01372                const char *querystring, const char *headers, void *arg,
01373                unsigned int *retcode, const char **retmsg,
01374                const char **mimetype, isc_buffer_t *b,
01375                isc_httpdfree_t **freecb, void **freecb_args)
01376 {
01377         return (render_xml(STATS_XML_NET, url, urlinfo,
01378                            querystring, headers, arg,
01379                            retcode, retmsg, mimetype, b,
01380                            freecb, freecb_args));
01381 }
01382 
01383 static isc_result_t
01384 render_xml_tasks(const char *url, isc_httpdurl_t *urlinfo,
01385                  const char *querystring, const char *headers, void *arg,
01386                  unsigned int *retcode, const char **retmsg,
01387                  const char **mimetype, isc_buffer_t *b,
01388                  isc_httpdfree_t **freecb, void **freecb_args)
01389 {
01390         return (render_xml(STATS_XML_TASKS, url, urlinfo,
01391                            querystring, headers, arg,
01392                            retcode, retmsg, mimetype, b,
01393                            freecb, freecb_args));
01394 }
01395 
01396 static isc_result_t
01397 render_xml_mem(const char *url, isc_httpdurl_t *urlinfo,
01398                const char *querystring, const char *headers, void *arg,
01399                unsigned int *retcode, const char **retmsg,
01400                const char **mimetype, isc_buffer_t *b,
01401                isc_httpdfree_t **freecb, void **freecb_args)
01402 {
01403         return (render_xml(STATS_XML_MEM, url, urlinfo,
01404                            querystring, headers, arg,
01405                            retcode, retmsg, mimetype, b,
01406                            freecb, freecb_args));
01407 }
01408 
01409 #endif  /* HAVE_LIBXML2 */
01410 
01411 #ifdef HAVE_JSON
01412 /*
01413  * Which statistics to include when rendering to JSON
01414  */
01415 #define STATS_JSON_STATUS       0x00    /* display only common statistics */
01416 #define STATS_JSON_SERVER       0x01
01417 #define STATS_JSON_ZONES        0x02
01418 #define STATS_JSON_TASKS        0x04
01419 #define STATS_JSON_NET          0x08
01420 #define STATS_JSON_MEM          0x10
01421 #define STATS_JSON_ALL          0xff
01422 
01423 #define CHECKMEM(m) do { \
01424         if (m == NULL) { \
01425                 result = ISC_R_NOMEMORY;\
01426                 goto error;\
01427         } \
01428 } while(0)
01429 
01430 static void
01431 wrap_jsonfree(isc_buffer_t *buffer, void *arg) {
01432         json_object_put(isc_buffer_base(buffer));
01433         if (arg != NULL)
01434                 json_object_put((json_object *) arg);
01435 }
01436 
01437 static json_object *
01438 addzone(char *name, char *class, isc_uint32_t serial,
01439         isc_boolean_t add_serial)
01440 {
01441         json_object *node = json_object_new_object();
01442 
01443         if (node == NULL)
01444                 return (NULL);
01445 
01446         json_object_object_add(node, "name", json_object_new_string(name));
01447         json_object_object_add(node, "class", json_object_new_string(class));
01448         if (add_serial)
01449                 json_object_object_add(node, "serial",
01450                                        json_object_new_int64(serial));
01451         return (node);
01452 }
01453 
01454 static isc_result_t
01455 zone_jsonrender(dns_zone_t *zone, void *arg) {
01456         isc_result_t result = ISC_R_SUCCESS;
01457         char buf[1024 + 32];    /* sufficiently large for zone name and class */
01458         char class[1024 + 32];  /* sufficiently large for zone name and class */
01459         char *zone_name_only = NULL;
01460         char *class_only = NULL;
01461         dns_rdataclass_t rdclass;
01462         isc_uint32_t serial;
01463         isc_uint64_t nsstat_values[dns_nsstatscounter_max];
01464         isc_stats_t *zonestats;
01465         dns_stats_t *rcvquerystats;
01466         json_object *zonearray = (json_object *) arg;
01467         json_object *zoneobj = NULL;
01468         dns_zonestat_level_t statlevel;
01469 
01470         statlevel = dns_zone_getstatlevel(zone);
01471         if (statlevel == dns_zonestat_none)
01472                 return (ISC_R_SUCCESS);
01473 
01474         dns_zone_name(zone, buf, sizeof(buf));
01475         zone_name_only = strtok(buf, "/");
01476         if(zone_name_only == NULL)
01477                 zone_name_only = buf;
01478 
01479         rdclass = dns_zone_getclass(zone);
01480         dns_rdataclass_format(rdclass, class, sizeof(class));
01481         class_only = class;
01482 
01483         if (dns_zone_getserial2(zone, &serial) != ISC_R_SUCCESS)
01484                 zoneobj = addzone(zone_name_only, class_only, 0, ISC_FALSE);
01485         else
01486                 zoneobj = addzone(zone_name_only, class_only, serial, ISC_TRUE);
01487 
01488         if (zoneobj == NULL)
01489                 return (ISC_R_NOMEMORY);
01490 
01491         zonestats = dns_zone_getrequeststats(zone);
01492         rcvquerystats = dns_zone_getrcvquerystats(zone);
01493         if (statlevel == dns_zonestat_full && zonestats != NULL) {
01494                 json_object *counters = json_object_new_object();
01495                 if (counters == NULL) {
01496                         result = ISC_R_NOMEMORY;
01497                         goto error;
01498                 }
01499 
01500                 result = dump_counters(zonestats, isc_statsformat_json,
01501                                        counters, NULL, nsstats_xmldesc,
01502                                        dns_nsstatscounter_max, nsstats_index,
01503                                        nsstat_values, 0);
01504                 if (result != ISC_R_SUCCESS) {
01505                         json_object_put(counters);
01506                         goto error;
01507                 }
01508 
01509                 if (json_object_get_object(counters)->count != 0)
01510                         json_object_object_add(zoneobj, "rcodes", counters);
01511                 else
01512                         json_object_put(counters);
01513         }
01514 
01515         if (statlevel == dns_zonestat_full && rcvquerystats != NULL) {
01516                 stats_dumparg_t dumparg;
01517                 json_object *counters = json_object_new_object();
01518                 CHECKMEM(counters);
01519 
01520                 dumparg.type = isc_statsformat_json;
01521                 dumparg.arg = counters;
01522                 dumparg.result = ISC_R_SUCCESS;
01523                 dns_rdatatypestats_dump(rcvquerystats, rdtypestat_dump,
01524                                         &dumparg, 0);
01525                 if (dumparg.result != ISC_R_SUCCESS) {
01526                         json_object_put(counters);
01527                         goto error;
01528                 }
01529 
01530                 if (json_object_get_object(counters)->count != 0)
01531                         json_object_object_add(zoneobj, "qtypes", counters);
01532                 else
01533                         json_object_put(counters);
01534         }
01535 
01536         json_object_array_add(zonearray, zoneobj);
01537         zoneobj = NULL;
01538         result = ISC_R_SUCCESS;
01539 
01540  error:
01541         if (zoneobj != NULL)
01542                 json_object_put(zoneobj);
01543         return (result);
01544 }
01545 
01546 static isc_result_t
01547 generatejson(ns_server_t *server, size_t *msglen,
01548              const char **msg, json_object **rootp, isc_uint32_t flags)
01549 {
01550         dns_view_t *view;
01551         isc_result_t result = ISC_R_SUCCESS;
01552         json_object *bindstats, *viewlist, *counters, *obj;
01553         isc_uint64_t nsstat_values[dns_nsstatscounter_max];
01554         isc_uint64_t resstat_values[dns_resstatscounter_max];
01555         isc_uint64_t adbstat_values[dns_adbstats_max];
01556         isc_uint64_t zonestat_values[dns_zonestatscounter_max];
01557         isc_uint64_t sockstat_values[isc_sockstatscounter_max];
01558         stats_dumparg_t dumparg;
01559         char boottime[sizeof "yyyy-mm-ddThh:mm:ssZ"];
01560         char configtime[sizeof "yyyy-mm-ddThh:mm:ssZ"];
01561         char nowstr[sizeof "yyyy-mm-ddThh:mm:ssZ"];
01562         isc_time_t now;
01563 
01564         REQUIRE(msglen != NULL);
01565         REQUIRE(msg != NULL && *msg == NULL);
01566         REQUIRE(rootp == NULL || *rootp == NULL);
01567 
01568         bindstats = json_object_new_object();
01569         if (bindstats == NULL)
01570                 return (ISC_R_NOMEMORY);
01571 
01572         /*
01573          * These statistics are included no matter which URL we use.
01574          */
01575         obj = json_object_new_string("1.1");
01576         CHECKMEM(obj);
01577         json_object_object_add(bindstats, "json-stats-version", obj);
01578 
01579         isc_time_now(&now);
01580         isc_time_formatISO8601(&ns_g_boottime,
01581                                boottime, sizeof(boottime));
01582         isc_time_formatISO8601(&ns_g_configtime,
01583                                configtime, sizeof configtime);
01584         isc_time_formatISO8601(&now, nowstr, sizeof(nowstr));
01585 
01586         obj = json_object_new_string(boottime);
01587         CHECKMEM(obj);
01588         json_object_object_add(bindstats, "boot-time", obj);
01589 
01590         obj = json_object_new_string(configtime);
01591         CHECKMEM(obj);
01592         json_object_object_add(bindstats, "config-time", obj);
01593 
01594         obj = json_object_new_string(nowstr);
01595         CHECKMEM(obj);
01596         json_object_object_add(bindstats, "current-time", obj);
01597 
01598         if ((flags & STATS_JSON_SERVER) != 0) {
01599                 /* OPCODE counters */
01600                 counters = json_object_new_object();
01601 
01602                 dumparg.result = ISC_R_SUCCESS;
01603                 dumparg.type = isc_statsformat_json;
01604                 dumparg.arg = counters;
01605 
01606                 dns_opcodestats_dump(server->opcodestats,
01607                                      opcodestat_dump, &dumparg,
01608                                      ISC_STATSDUMP_VERBOSE);
01609                 if (dumparg.result != ISC_R_SUCCESS) {
01610                         json_object_put(counters);
01611                         goto error;
01612                 }
01613 
01614                 if (json_object_get_object(counters)->count != 0)
01615                         json_object_object_add(bindstats, "opcodes", counters);
01616                 else
01617                         json_object_put(counters);
01618 
01619                 /* QTYPE counters */
01620                 counters = json_object_new_object();
01621 
01622                 dumparg.result = ISC_R_SUCCESS;
01623                 dumparg.arg = counters;
01624 
01625                 dns_rdatatypestats_dump(server->rcvquerystats,
01626                                         rdtypestat_dump, &dumparg, 0);
01627                 if (dumparg.result != ISC_R_SUCCESS) {
01628                         json_object_put(counters);
01629                         goto error;
01630                 }
01631 
01632                 if (json_object_get_object(counters)->count != 0)
01633                         json_object_object_add(bindstats, "qtypes", counters);
01634                 else
01635                         json_object_put(counters);
01636 
01637                 /* server stat counters */
01638                 counters = json_object_new_object();
01639 
01640                 dumparg.result = ISC_R_SUCCESS;
01641                 dumparg.arg = counters;
01642 
01643                 result = dump_counters(server->nsstats, isc_statsformat_json,
01644                                counters, NULL, nsstats_xmldesc,
01645                                dns_nsstatscounter_max,
01646                                nsstats_index, nsstat_values, 0);
01647                 if (result != ISC_R_SUCCESS) {
01648                         json_object_put(counters);
01649                         goto error;
01650                 }
01651 
01652                 if (json_object_get_object(counters)->count != 0)
01653                         json_object_object_add(bindstats, "nsstats", counters);
01654                 else
01655                         json_object_put(counters);
01656 
01657                 /* zone stat counters */
01658                 counters = json_object_new_object();
01659 
01660                 dumparg.result = ISC_R_SUCCESS;
01661                 dumparg.arg = counters;
01662 
01663                 result = dump_counters(server->zonestats, isc_statsformat_json,
01664                                counters, NULL, zonestats_xmldesc,
01665                                dns_zonestatscounter_max,
01666                                zonestats_index, zonestat_values, 0);
01667                 if (result != ISC_R_SUCCESS) {
01668                         json_object_put(counters);
01669                         goto error;
01670                 }
01671 
01672                 if (json_object_get_object(counters)->count != 0)
01673                         json_object_object_add(bindstats, "zonestats",
01674                                                counters);
01675                 else
01676                         json_object_put(counters);
01677 
01678                 /* resolver stat counters */
01679                 counters = json_object_new_object();
01680 
01681                 dumparg.result = ISC_R_SUCCESS;
01682                 dumparg.arg = counters;
01683 
01684                 result = dump_counters(server->resolverstats,
01685                                        isc_statsformat_json, counters, NULL,
01686                                        resstats_xmldesc,
01687                                        dns_resstatscounter_max,
01688                                        resstats_index, resstat_values, 0);
01689                 if (result != ISC_R_SUCCESS) {
01690                         json_object_put(counters);
01691                         goto error;
01692                 }
01693 
01694                 if (json_object_get_object(counters)->count != 0)
01695                         json_object_object_add(bindstats, "resstats", counters);
01696                 else
01697                         json_object_put(counters);
01698         }
01699 
01700         if ((flags & (STATS_JSON_ZONES | STATS_JSON_SERVER)) != 0) {
01701                 viewlist = json_object_new_object();
01702                 CHECKMEM(viewlist);
01703 
01704                 json_object_object_add(bindstats, "views", viewlist);
01705 
01706                 view = ISC_LIST_HEAD(server->viewlist);
01707                 while (view != NULL) {
01708                         json_object *za, *v = json_object_new_object();
01709 
01710                         CHECKMEM(v);
01711                         json_object_object_add(viewlist, view->name, v);
01712 
01713                         za = json_object_new_array();
01714                         CHECKMEM(za);
01715 
01716                         if ((flags & STATS_JSON_ZONES) != 0) {
01717                                 result = dns_zt_apply(view->zonetable, ISC_TRUE,
01718                                                       zone_jsonrender, za);
01719                                 if (result != ISC_R_SUCCESS) {
01720                                         goto error;
01721                                 }
01722                         }
01723 
01724                         if (json_object_array_length(za) != 0)
01725                                 json_object_object_add(v, "zones", za);
01726                         else
01727                                 json_object_put(za);
01728 
01729                         if ((flags & STATS_JSON_SERVER) != 0) {
01730                                 json_object *res;
01731                                 dns_stats_t *dstats;
01732                                 isc_stats_t *istats;
01733 
01734                                 res = json_object_new_object();
01735                                 CHECKMEM(res);
01736                                 json_object_object_add(v, "resolver", res);
01737 
01738                                 istats = view->resstats;
01739                                 if (istats != NULL) {
01740                                         counters = json_object_new_object();
01741                                         CHECKMEM(counters);
01742 
01743                                         result = dump_counters(istats,
01744                                                        isc_statsformat_json,
01745                                                        counters, NULL,
01746                                                        resstats_xmldesc,
01747                                                        dns_resstatscounter_max,
01748                                                        resstats_index,
01749                                                        resstat_values, 0);
01750                                         if (result != ISC_R_SUCCESS) {
01751                                                 json_object_put(counters);
01752                                                 result = dumparg.result;
01753                                                 goto error;
01754                                         }
01755 
01756                                         json_object_object_add(res, "stats",
01757                                                                counters);
01758                                 }
01759 
01760                                 dstats = view->resquerystats;
01761                                 if (dstats != NULL) {
01762                                         counters = json_object_new_object();
01763                                         CHECKMEM(counters);
01764 
01765                                         dumparg.arg = counters;
01766                                         dumparg.result = ISC_R_SUCCESS;
01767                                         dns_rdatatypestats_dump(dstats,
01768                                                                 rdtypestat_dump,
01769                                                                 &dumparg, 0);
01770                                         if (dumparg.result != ISC_R_SUCCESS) {
01771                                                 json_object_put(counters);
01772                                                 result = dumparg.result;
01773                                                 goto error;
01774                                         }
01775 
01776                                         json_object_object_add(res, "qtypes",
01777                                                                counters);
01778                                 }
01779 
01780                                 dstats = dns_db_getrrsetstats(view->cachedb);
01781                                 if (dstats != NULL) {
01782                                         counters = json_object_new_object();
01783                                         CHECKMEM(counters);
01784 
01785                                         dumparg.arg = counters;
01786                                         dumparg.result = ISC_R_SUCCESS;
01787                                         dns_rdatasetstats_dump(dstats,
01788                                                        rdatasetstats_dump,
01789                                                        &dumparg, 0);
01790                                         if (dumparg.result != ISC_R_SUCCESS) {
01791                                                 json_object_put(counters);
01792                                                 result = dumparg.result;
01793                                                 goto error;
01794                                         }
01795 
01796                                         json_object_object_add(res,
01797                                                                "cache",
01798                                                                counters);
01799                                 }
01800 
01801                                 counters = json_object_new_object();
01802                                 CHECKMEM(counters);
01803 
01804                                 result = dns_cache_renderjson(view->cache,
01805                                                               counters);
01806                                 if (result != ISC_R_SUCCESS) {
01807                                         json_object_put(counters);
01808                                         goto error;
01809                                 }
01810 
01811                                 json_object_object_add(res, "cachestats",
01812                                                        counters);
01813 
01814                                 istats = view->adbstats;
01815                                 if (istats != NULL) {
01816                                         counters = json_object_new_object();
01817                                         CHECKMEM(counters);
01818 
01819                                         result = dump_counters(istats,
01820                                                        isc_statsformat_json,
01821                                                        counters, NULL,
01822                                                        adbstats_xmldesc,
01823                                                        dns_adbstats_max,
01824                                                        adbstats_index,
01825                                                        adbstat_values, 0);
01826                                         if (result != ISC_R_SUCCESS) {
01827                                                 json_object_put(counters);
01828                                                 result = dumparg.result;
01829                                                 goto error;
01830                                         }
01831 
01832                                         json_object_object_add(res, "adb",
01833                                                                counters);
01834                                 }
01835                         }
01836 
01837                         view = ISC_LIST_NEXT(view, link);
01838                 }
01839         }
01840 
01841         if ((flags & STATS_JSON_NET) != 0) {
01842                 /* socket stat counters */
01843                 json_object *sockets;
01844                 counters = json_object_new_object();
01845 
01846                 dumparg.result = ISC_R_SUCCESS;
01847                 dumparg.arg = counters;
01848 
01849                 result = dump_counters(server->sockstats,
01850                                        isc_statsformat_json, counters,
01851                                        NULL, sockstats_xmldesc,
01852                                        isc_sockstatscounter_max,
01853                                        sockstats_index, sockstat_values, 0);
01854                 if (result != ISC_R_SUCCESS) {
01855                         json_object_put(counters);
01856                         goto error;
01857                 }
01858 
01859                 if (json_object_get_object(counters)->count != 0)
01860                         json_object_object_add(bindstats, "sockstats",
01861                                                counters);
01862                 else
01863                         json_object_put(counters);
01864 
01865                 sockets = json_object_new_object();
01866                 CHECKMEM(sockets);
01867 
01868                 result = isc_socketmgr_renderjson(ns_g_socketmgr, sockets);
01869                 if (result != ISC_R_SUCCESS) {
01870                         json_object_put(sockets);
01871                         goto error;
01872                 }
01873 
01874                 json_object_object_add(bindstats, "socketmgr", sockets);
01875         }
01876 
01877         if ((flags & STATS_JSON_TASKS) != 0) {
01878                 json_object *tasks = json_object_new_object();
01879                 CHECKMEM(tasks);
01880 
01881                 result = isc_taskmgr_renderjson(ns_g_taskmgr, tasks);
01882                 if (result != ISC_R_SUCCESS) {
01883                         json_object_put(tasks);
01884                         goto error;
01885                 }
01886 
01887                 json_object_object_add(bindstats, "taskmgr", tasks);
01888         }
01889 
01890         if ((flags & STATS_JSON_MEM) != 0) {
01891                 json_object *memory = json_object_new_object();
01892                 CHECKMEM(memory);
01893 
01894                 result = isc_mem_renderjson(memory);
01895                 if (result != ISC_R_SUCCESS) {
01896                         json_object_put(memory);
01897                         goto error;
01898                 }
01899 
01900                 json_object_object_add(bindstats, "memory", memory);
01901         }
01902 
01903         *msg = json_object_to_json_string_ext(bindstats,
01904                                               JSON_C_TO_STRING_PRETTY);
01905         *msglen = strlen(*msg);
01906 
01907         if (rootp != NULL) {
01908                 *rootp = bindstats;
01909                 bindstats = NULL;
01910         }
01911 
01912         result = ISC_R_SUCCESS;
01913 
01914   error:
01915         if (bindstats != NULL)
01916                 json_object_put(bindstats);
01917 
01918         return (result);
01919 }
01920 
01921 static isc_result_t
01922 render_json(isc_uint32_t flags,
01923             const char *url, isc_httpdurl_t *urlinfo,
01924             const char *querystring, const char *headers,
01925             void *arg, unsigned int *retcode, const char **retmsg,
01926             const char **mimetype, isc_buffer_t *b,
01927             isc_httpdfree_t **freecb, void **freecb_args)
01928 {
01929         isc_result_t result;
01930         json_object *bindstats = NULL;
01931         ns_server_t *server = arg;
01932         const char *msg = NULL;
01933         size_t msglen;
01934         char *p;
01935 
01936         UNUSED(url);
01937         UNUSED(urlinfo);
01938         UNUSED(headers);
01939         UNUSED(querystring);
01940 
01941         result = generatejson(server, &msglen, &msg, &bindstats, flags);
01942         if (result == ISC_R_SUCCESS) {
01943                 *retcode = 200;
01944                 *retmsg = "OK";
01945                 *mimetype = "application/json";
01946                 DE_CONST(msg, p);
01947                 isc_buffer_reinit(b, p, msglen);
01948                 isc_buffer_add(b, msglen);
01949                 *freecb = wrap_jsonfree;
01950                 *freecb_args = bindstats;
01951         } else
01952                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
01953                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
01954                               "failed at rendering JSON()");
01955 
01956         return (result);
01957 }
01958 
01959 static isc_result_t
01960 render_json_all(const char *url, isc_httpdurl_t *urlinfo,
01961                 const char *querystring, const char *headers, void *arg,
01962                 unsigned int *retcode, const char **retmsg,
01963                 const char **mimetype, isc_buffer_t *b,
01964                 isc_httpdfree_t **freecb, void **freecb_args)
01965 {
01966         return (render_json(STATS_JSON_ALL, url, urlinfo,
01967                             querystring, headers, arg,
01968                             retcode, retmsg, mimetype, b,
01969                             freecb, freecb_args));
01970 }
01971 
01972 static isc_result_t
01973 render_json_status(const char *url, isc_httpdurl_t *urlinfo,
01974                    const char *querystring, const char *headers, void *arg,
01975                    unsigned int *retcode, const char **retmsg,
01976                    const char **mimetype, isc_buffer_t *b,
01977                    isc_httpdfree_t **freecb, void **freecb_args)
01978 {
01979         return (render_json(STATS_JSON_STATUS, url, urlinfo,
01980                             querystring, headers, arg,
01981                             retcode, retmsg, mimetype, b,
01982                             freecb, freecb_args));
01983 }
01984 
01985 static isc_result_t
01986 render_json_server(const char *url, isc_httpdurl_t *urlinfo,
01987                    const char *querystring, const char *headers, void *arg,
01988                    unsigned int *retcode, const char **retmsg,
01989                    const char **mimetype, isc_buffer_t *b,
01990                    isc_httpdfree_t **freecb, void **freecb_args)
01991 {
01992         return (render_json(STATS_JSON_SERVER, url, urlinfo,
01993                             querystring, headers, arg,
01994                             retcode, retmsg, mimetype, b,
01995                             freecb, freecb_args));
01996 }
01997 
01998 static isc_result_t
01999 render_json_zones(const char *url, isc_httpdurl_t *urlinfo,
02000                   const char *querystring, const char *headers, void *arg,
02001                   unsigned int *retcode, const char **retmsg,
02002                   const char **mimetype, isc_buffer_t *b,
02003                   isc_httpdfree_t **freecb, void **freecb_args)
02004 {
02005         return (render_json(STATS_JSON_ZONES, url, urlinfo,
02006                             querystring, headers, arg,
02007                             retcode, retmsg, mimetype, b,
02008                             freecb, freecb_args));
02009 }
02010 static isc_result_t
02011 render_json_mem(const char *url, isc_httpdurl_t *urlinfo,
02012                 const char *querystring, const char *headers, void *arg,
02013                 unsigned int *retcode, const char **retmsg,
02014                 const char **mimetype, isc_buffer_t *b,
02015                 isc_httpdfree_t **freecb, void **freecb_args)
02016 {
02017         return (render_json(STATS_JSON_MEM, url, urlinfo,
02018                             querystring, headers, arg,
02019                             retcode, retmsg, mimetype, b,
02020                             freecb, freecb_args));
02021 }
02022 
02023 static isc_result_t
02024 render_json_tasks(const char *url, isc_httpdurl_t *urlinfo,
02025                   const char *querystring, const char *headers, void *arg,
02026                   unsigned int *retcode, const char **retmsg,
02027                   const char **mimetype, isc_buffer_t *b,
02028                   isc_httpdfree_t **freecb, void **freecb_args)
02029 {
02030         return (render_json(STATS_JSON_TASKS, url, urlinfo,
02031                             querystring, headers, arg,
02032                             retcode, retmsg, mimetype, b,
02033                             freecb, freecb_args));
02034 }
02035 
02036 static isc_result_t
02037 render_json_net(const char *url, isc_httpdurl_t *urlinfo,
02038                 const char *querystring, const char *headers, void *arg,
02039                 unsigned int *retcode, const char **retmsg,
02040                 const char **mimetype, isc_buffer_t *b,
02041                 isc_httpdfree_t **freecb, void **freecb_args)
02042 {
02043         return (render_json(STATS_JSON_NET, url, urlinfo,
02044                             querystring, headers, arg,
02045                             retcode, retmsg, mimetype, b,
02046                             freecb, freecb_args));
02047 }
02048 #endif /* HAVE_JSON */
02049 
02050 static isc_result_t
02051 render_xsl(const char *url, isc_httpdurl_t *urlinfo,
02052            const char *querystring, const char *headers,
02053            void *args, unsigned int *retcode, const char **retmsg,
02054            const char **mimetype, isc_buffer_t *b,
02055            isc_httpdfree_t **freecb, void **freecb_args)
02056 {
02057         isc_result_t result;
02058 
02059         UNUSED(url);
02060         UNUSED(querystring);
02061         UNUSED(args);
02062 
02063         *freecb = NULL;
02064         *freecb_args = NULL;
02065         *mimetype = "text/xslt+xml";
02066 
02067         if (urlinfo->isstatic) {
02068                 isc_time_t when;
02069                 char *p = strcasestr(headers, "If-Modified-Since: ");
02070 
02071                 if (p != NULL) {
02072                         time_t t1, t2;
02073                         p += strlen("If-Modified-Since: ");
02074                         result = isc_time_parsehttptimestamp(p, &when);
02075                         if (result != ISC_R_SUCCESS)
02076                                 goto send;
02077 
02078                         result = isc_time_secondsastimet(&when, &t1);
02079                         if (result != ISC_R_SUCCESS)
02080                                 goto send;
02081 
02082                         result = isc_time_secondsastimet(&urlinfo->loadtime,
02083                                                          &t2);
02084                         if (result != ISC_R_SUCCESS)
02085                                 goto send;
02086 
02087                         if (t1 < t2)
02088                                 goto send;
02089 
02090                         *retcode = 304;
02091                         *retmsg = "Not modified";
02092                         return (ISC_R_SUCCESS);
02093                 }
02094         }
02095 
02096  send:
02097         *retcode = 200;
02098         *retmsg = "OK";
02099         isc_buffer_reinit(b, xslmsg, strlen(xslmsg));
02100         isc_buffer_add(b, strlen(xslmsg));
02101 
02102         return (ISC_R_SUCCESS);
02103 }
02104 
02105 static void
02106 shutdown_listener(ns_statschannel_t *listener) {
02107         char socktext[ISC_SOCKADDR_FORMATSIZE];
02108         isc_sockaddr_format(&listener->address, socktext, sizeof(socktext));
02109         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
02110                       ISC_LOG_NOTICE, "stopping statistics channel on %s",
02111                       socktext);
02112 
02113         isc_httpdmgr_shutdown(&listener->httpdmgr);
02114 }
02115 
02116 static isc_boolean_t
02117 client_ok(const isc_sockaddr_t *fromaddr, void *arg) {
02118         ns_statschannel_t *listener = arg;
02119         isc_netaddr_t netaddr;
02120         char socktext[ISC_SOCKADDR_FORMATSIZE];
02121         int match;
02122 
02123         REQUIRE(listener != NULL);
02124 
02125         isc_netaddr_fromsockaddr(&netaddr, fromaddr);
02126 
02127         LOCK(&listener->lock);
02128         if (dns_acl_match(&netaddr, NULL, listener->acl, &ns_g_server->aclenv,
02129                           &match, NULL) == ISC_R_SUCCESS && match > 0) {
02130                 UNLOCK(&listener->lock);
02131                 return (ISC_TRUE);
02132         }
02133         UNLOCK(&listener->lock);
02134 
02135         isc_sockaddr_format(fromaddr, socktext, sizeof(socktext));
02136         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
02137                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
02138                       "rejected statistics connection from %s", socktext);
02139 
02140         return (ISC_FALSE);
02141 }
02142 
02143 static void
02144 destroy_listener(void *arg) {
02145         ns_statschannel_t *listener = arg;
02146 
02147         REQUIRE(listener != NULL);
02148         REQUIRE(!ISC_LINK_LINKED(listener, link));
02149 
02150         /* We don't have to acquire the lock here since it's already unlinked */
02151         dns_acl_detach(&listener->acl);
02152 
02153         DESTROYLOCK(&listener->lock);
02154         isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener));
02155 }
02156 
02157 static isc_result_t
02158 add_listener(ns_server_t *server, ns_statschannel_t **listenerp,
02159              const cfg_obj_t *listen_params, const cfg_obj_t *config,
02160              isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
02161              const char *socktext)
02162 {
02163         isc_result_t result;
02164         ns_statschannel_t *listener;
02165         isc_task_t *task = NULL;
02166         isc_socket_t *sock = NULL;
02167         const cfg_obj_t *allow;
02168         dns_acl_t *new_acl = NULL;
02169 
02170         listener = isc_mem_get(server->mctx, sizeof(*listener));
02171         if (listener == NULL)
02172                 return (ISC_R_NOMEMORY);
02173 
02174         listener->httpdmgr = NULL;
02175         listener->address = *addr;
02176         listener->acl = NULL;
02177         listener->mctx = NULL;
02178         ISC_LINK_INIT(listener, link);
02179 
02180         result = isc_mutex_init(&listener->lock);
02181         if (result != ISC_R_SUCCESS) {
02182                 isc_mem_put(server->mctx, listener, sizeof(*listener));
02183                 return (ISC_R_FAILURE);
02184         }
02185 
02186         isc_mem_attach(server->mctx, &listener->mctx);
02187 
02188         allow = cfg_tuple_get(listen_params, "allow");
02189         if (allow != NULL && cfg_obj_islist(allow)) {
02190                 result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
02191                                             aclconfctx, listener->mctx, 0,
02192                                             &new_acl);
02193         } else
02194                 result = dns_acl_any(listener->mctx, &new_acl);
02195         if (result != ISC_R_SUCCESS)
02196                 goto cleanup;
02197         dns_acl_attach(new_acl, &listener->acl);
02198         dns_acl_detach(&new_acl);
02199 
02200         result = isc_task_create(ns_g_taskmgr, 0, &task);
02201         if (result != ISC_R_SUCCESS)
02202                 goto cleanup;
02203         isc_task_setname(task, "statchannel", NULL);
02204 
02205         result = isc_socket_create(ns_g_socketmgr, isc_sockaddr_pf(addr),
02206                                    isc_sockettype_tcp, &sock);
02207         if (result != ISC_R_SUCCESS)
02208                 goto cleanup;
02209         isc_socket_setname(sock, "statchannel", NULL);
02210 
02211 #ifndef ISC_ALLOW_MAPPED
02212         isc_socket_ipv6only(sock, ISC_TRUE);
02213 #endif
02214 
02215         result = isc_socket_bind(sock, addr, ISC_SOCKET_REUSEADDRESS);
02216         if (result != ISC_R_SUCCESS)
02217                 goto cleanup;
02218 
02219         result = isc_httpdmgr_create(server->mctx, sock, task, client_ok,
02220                                      destroy_listener, listener, ns_g_timermgr,
02221                                      &listener->httpdmgr);
02222         if (result != ISC_R_SUCCESS)
02223                 goto cleanup;
02224 
02225 #ifdef HAVE_LIBXML2
02226         isc_httpdmgr_addurl(listener->httpdmgr, "/",
02227                             render_xml_all, server);
02228         isc_httpdmgr_addurl(listener->httpdmgr, "/xml",
02229                             render_xml_all, server);
02230         isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3",
02231                             render_xml_all, server);
02232         isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/status",
02233                             render_xml_status, server);
02234         isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/server",
02235                             render_xml_server, server);
02236         isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/zones",
02237                             render_xml_zones, server);
02238         isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/net",
02239                             render_xml_net, server);
02240         isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/tasks",
02241                             render_xml_tasks, server);
02242         isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/mem",
02243                             render_xml_mem, server);
02244 #endif
02245 #ifdef HAVE_JSON
02246         isc_httpdmgr_addurl(listener->httpdmgr, "/json",
02247                             render_json_all, server);
02248         isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1",
02249                             render_json_all, server);
02250         isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/status",
02251                             render_json_status, server);
02252         isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/server",
02253                             render_json_server, server);
02254         isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/zones",
02255                             render_json_zones, server);
02256         isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/tasks",
02257                             render_json_tasks, server);
02258         isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/net",
02259                             render_json_net, server);
02260         isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/mem",
02261                             render_json_mem, server);
02262 #endif
02263         isc_httpdmgr_addurl2(listener->httpdmgr, "/bind9.xsl", ISC_TRUE,
02264                              render_xsl, server);
02265 
02266         *listenerp = listener;
02267         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
02268                       NS_LOGMODULE_SERVER, ISC_LOG_NOTICE,
02269                       "statistics channel listening on %s", socktext);
02270 
02271 cleanup:
02272         if (result != ISC_R_SUCCESS) {
02273                 if (listener->acl != NULL)
02274                         dns_acl_detach(&listener->acl);
02275                 DESTROYLOCK(&listener->lock);
02276                 isc_mem_putanddetach(&listener->mctx, listener,
02277                                      sizeof(*listener));
02278         }
02279         if (task != NULL)
02280                 isc_task_detach(&task);
02281         if (sock != NULL)
02282                 isc_socket_detach(&sock);
02283 
02284         return (result);
02285 }
02286 
02287 static void
02288 update_listener(ns_server_t *server, ns_statschannel_t **listenerp,
02289                 const cfg_obj_t *listen_params, const cfg_obj_t *config,
02290                 isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
02291                 const char *socktext)
02292 {
02293         ns_statschannel_t *listener;
02294         const cfg_obj_t *allow = NULL;
02295         dns_acl_t *new_acl = NULL;
02296         isc_result_t result = ISC_R_SUCCESS;
02297 
02298         for (listener = ISC_LIST_HEAD(server->statschannels);
02299              listener != NULL;
02300              listener = ISC_LIST_NEXT(listener, link))
02301                 if (isc_sockaddr_equal(addr, &listener->address))
02302                         break;
02303 
02304         if (listener == NULL) {
02305                 *listenerp = NULL;
02306                 return;
02307         }
02308 
02309         /*
02310          * Now, keep the old access list unless a new one can be made.
02311          */
02312         allow = cfg_tuple_get(listen_params, "allow");
02313         if (allow != NULL && cfg_obj_islist(allow)) {
02314                 result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
02315                                             aclconfctx, listener->mctx, 0,
02316                                             &new_acl);
02317         } else
02318                 result = dns_acl_any(listener->mctx, &new_acl);
02319 
02320         if (result == ISC_R_SUCCESS) {
02321                 LOCK(&listener->lock);
02322 
02323                 dns_acl_detach(&listener->acl);
02324                 dns_acl_attach(new_acl, &listener->acl);
02325                 dns_acl_detach(&new_acl);
02326 
02327                 UNLOCK(&listener->lock);
02328         } else {
02329                 cfg_obj_log(listen_params, ns_g_lctx, ISC_LOG_WARNING,
02330                             "couldn't install new acl for "
02331                             "statistics channel %s: %s",
02332                             socktext, isc_result_totext(result));
02333         }
02334 
02335         *listenerp = listener;
02336 }
02337 
02338 isc_result_t
02339 ns_statschannels_configure(ns_server_t *server, const cfg_obj_t *config,
02340                          cfg_aclconfctx_t *aclconfctx)
02341 {
02342         ns_statschannel_t *listener, *listener_next;
02343         ns_statschannellist_t new_listeners;
02344         const cfg_obj_t *statschannellist = NULL;
02345         const cfg_listelt_t *element, *element2;
02346         char socktext[ISC_SOCKADDR_FORMATSIZE];
02347 
02348         RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS);
02349 
02350         ISC_LIST_INIT(new_listeners);
02351 
02352         /*
02353          * Get the list of named.conf 'statistics-channels' statements.
02354          */
02355         (void)cfg_map_get(config, "statistics-channels", &statschannellist);
02356 
02357         /*
02358          * Run through the new address/port list, noting sockets that are
02359          * already being listened on and moving them to the new list.
02360          *
02361          * Identifying duplicate addr/port combinations is left to either
02362          * the underlying config code, or to the bind attempt getting an
02363          * address-in-use error.
02364          */
02365         if (statschannellist != NULL) {
02366 #ifndef EXTENDED_STATS
02367                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
02368                               NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
02369                               "statistics-channels specified but not effective "
02370                               "due to missing XML and/or JSON library");
02371 #endif
02372 
02373                 for (element = cfg_list_first(statschannellist);
02374                      element != NULL;
02375                      element = cfg_list_next(element)) {
02376                         const cfg_obj_t *statschannel;
02377                         const cfg_obj_t *listenercfg = NULL;
02378 
02379                         statschannel = cfg_listelt_value(element);
02380                         (void)cfg_map_get(statschannel, "inet",
02381                                           &listenercfg);
02382                         if (listenercfg == NULL)
02383                                 continue;
02384 
02385                         for (element2 = cfg_list_first(listenercfg);
02386                              element2 != NULL;
02387                              element2 = cfg_list_next(element2)) {
02388                                 const cfg_obj_t *listen_params;
02389                                 const cfg_obj_t *obj;
02390                                 isc_sockaddr_t addr;
02391 
02392                                 listen_params = cfg_listelt_value(element2);
02393 
02394                                 obj = cfg_tuple_get(listen_params, "address");
02395                                 addr = *cfg_obj_assockaddr(obj);
02396                                 if (isc_sockaddr_getport(&addr) == 0)
02397                                         isc_sockaddr_setport(&addr,
02398                                                      NS_STATSCHANNEL_HTTPPORT);
02399 
02400                                 isc_sockaddr_format(&addr, socktext,
02401                                                     sizeof(socktext));
02402 
02403                                 isc_log_write(ns_g_lctx,
02404                                               NS_LOGCATEGORY_GENERAL,
02405                                               NS_LOGMODULE_SERVER,
02406                                               ISC_LOG_DEBUG(9),
02407                                               "processing statistics "
02408                                               "channel %s",
02409                                               socktext);
02410 
02411                                 update_listener(server, &listener,
02412                                                 listen_params, config, &addr,
02413                                                 aclconfctx, socktext);
02414 
02415                                 if (listener != NULL) {
02416                                         /*
02417                                          * Remove the listener from the old
02418                                          * list, so it won't be shut down.
02419                                          */
02420                                         ISC_LIST_UNLINK(server->statschannels,
02421                                                         listener, link);
02422                                 } else {
02423                                         /*
02424                                          * This is a new listener.
02425                                          */
02426                                         isc_result_t r;
02427 
02428                                         r = add_listener(server, &listener,
02429                                                          listen_params, config,
02430                                                          &addr, aclconfctx,
02431                                                          socktext);
02432                                         if (r != ISC_R_SUCCESS) {
02433                                                 cfg_obj_log(listen_params,
02434                                                             ns_g_lctx,
02435                                                             ISC_LOG_WARNING,
02436                                                             "couldn't allocate "
02437                                                             "statistics channel"
02438                                                             " %s: %s",
02439                                                             socktext,
02440                                                             isc_result_totext(r));
02441                                         }
02442                                 }
02443 
02444                                 if (listener != NULL)
02445                                         ISC_LIST_APPEND(new_listeners, listener,
02446                                                         link);
02447                         }
02448                 }
02449         }
02450 
02451         for (listener = ISC_LIST_HEAD(server->statschannels);
02452              listener != NULL;
02453              listener = listener_next) {
02454                 listener_next = ISC_LIST_NEXT(listener, link);
02455                 ISC_LIST_UNLINK(server->statschannels, listener, link);
02456                 shutdown_listener(listener);
02457         }
02458 
02459         ISC_LIST_APPENDLIST(server->statschannels, new_listeners, link);
02460         return (ISC_R_SUCCESS);
02461 }
02462 
02463 void
02464 ns_statschannels_shutdown(ns_server_t *server) {
02465         ns_statschannel_t *listener;
02466 
02467         while ((listener = ISC_LIST_HEAD(server->statschannels)) != NULL) {
02468                 ISC_LIST_UNLINK(server->statschannels, listener, link);
02469                 shutdown_listener(listener);
02470         }
02471 }
02472 
02473 isc_result_t
02474 ns_stats_dump(ns_server_t *server, FILE *fp) {
02475         isc_stdtime_t now;
02476         isc_result_t result;
02477         dns_view_t *view;
02478         dns_zone_t *zone, *next;
02479         stats_dumparg_t dumparg;
02480         isc_uint64_t nsstat_values[dns_nsstatscounter_max];
02481         isc_uint64_t resstat_values[dns_resstatscounter_max];
02482         isc_uint64_t adbstat_values[dns_adbstats_max];
02483         isc_uint64_t zonestat_values[dns_zonestatscounter_max];
02484         isc_uint64_t sockstat_values[isc_sockstatscounter_max];
02485 
02486         RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS);
02487 
02488         /* Set common fields */
02489         dumparg.type = isc_statsformat_file;
02490         dumparg.arg = fp;
02491 
02492         isc_stdtime_get(&now);
02493         fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now);
02494 
02495         fprintf(fp, "++ Incoming Requests ++\n");
02496         dns_opcodestats_dump(server->opcodestats, opcodestat_dump, &dumparg, 0);
02497 
02498         fprintf(fp, "++ Incoming Queries ++\n");
02499         dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump,
02500                                 &dumparg, 0);
02501 
02502         fprintf(fp, "++ Outgoing Queries ++\n");
02503         for (view = ISC_LIST_HEAD(server->viewlist);
02504              view != NULL;
02505              view = ISC_LIST_NEXT(view, link)) {
02506                 if (view->resquerystats == NULL)
02507                         continue;
02508                 if (strcmp(view->name, "_default") == 0)
02509                         fprintf(fp, "[View: default]\n");
02510                 else
02511                         fprintf(fp, "[View: %s]\n", view->name);
02512                 dns_rdatatypestats_dump(view->resquerystats, rdtypestat_dump,
02513                                         &dumparg, 0);
02514         }
02515 
02516         fprintf(fp, "++ Name Server Statistics ++\n");
02517         (void) dump_counters(server->nsstats, isc_statsformat_file, fp, NULL,
02518                              nsstats_desc, dns_nsstatscounter_max,
02519                              nsstats_index, nsstat_values, 0);
02520 
02521         fprintf(fp, "++ Zone Maintenance Statistics ++\n");
02522         (void) dump_counters(server->zonestats, isc_statsformat_file, fp, NULL,
02523                              zonestats_desc, dns_zonestatscounter_max,
02524                              zonestats_index, zonestat_values, 0);
02525 
02526         fprintf(fp, "++ Resolver Statistics ++\n");
02527         fprintf(fp, "[Common]\n");
02528         (void) dump_counters(server->resolverstats, isc_statsformat_file, fp,
02529                              NULL, resstats_desc, dns_resstatscounter_max,
02530                              resstats_index, resstat_values, 0);
02531         for (view = ISC_LIST_HEAD(server->viewlist);
02532              view != NULL;
02533              view = ISC_LIST_NEXT(view, link)) {
02534                 if (view->resstats == NULL)
02535                         continue;
02536                 if (strcmp(view->name, "_default") == 0)
02537                         fprintf(fp, "[View: default]\n");
02538                 else
02539                         fprintf(fp, "[View: %s]\n", view->name);
02540                 (void) dump_counters(view->resstats, isc_statsformat_file, fp,
02541                                      NULL, resstats_desc,
02542                                      dns_resstatscounter_max, resstats_index,
02543                                      resstat_values, 0);
02544         }
02545 
02546         fprintf(fp, "++ Cache Statistics ++\n");
02547         for (view = ISC_LIST_HEAD(server->viewlist);
02548              view != NULL;
02549              view = ISC_LIST_NEXT(view, link)) {
02550                 if (strcmp(view->name, "_default") == 0)
02551                         fprintf(fp, "[View: default]\n");
02552                 else
02553                         fprintf(fp, "[View: %s (Cache: %s)]\n", view->name,
02554                                 dns_cache_getname(view->cache));
02555                 /*
02556                  * Avoid dumping redundant statistics when the cache is shared.
02557                  */
02558                 if (dns_view_iscacheshared(view))
02559                         continue;
02560                 dns_cache_dumpstats(view->cache, fp);
02561         }
02562 
02563         fprintf(fp, "++ Cache DB RRsets ++\n");
02564         for (view = ISC_LIST_HEAD(server->viewlist);
02565              view != NULL;
02566              view = ISC_LIST_NEXT(view, link)) {
02567                 dns_stats_t *cacherrstats;
02568 
02569                 cacherrstats = dns_db_getrrsetstats(view->cachedb);
02570                 if (cacherrstats == NULL)
02571                         continue;
02572                 if (strcmp(view->name, "_default") == 0)
02573                         fprintf(fp, "[View: default]\n");
02574                 else
02575                         fprintf(fp, "[View: %s (Cache: %s)]\n", view->name,
02576                                 dns_cache_getname(view->cache));
02577                 if (dns_view_iscacheshared(view)) {
02578                         /*
02579                          * Avoid dumping redundant statistics when the cache is
02580                          * shared.
02581                          */
02582                         continue;
02583                 }
02584                 dns_rdatasetstats_dump(cacherrstats, rdatasetstats_dump,
02585                                        &dumparg, 0);
02586         }
02587 
02588         fprintf(fp, "++ ADB stats ++\n");
02589         for (view = ISC_LIST_HEAD(server->viewlist);
02590              view != NULL;
02591              view = ISC_LIST_NEXT(view, link)) {
02592                 if (view->adbstats == NULL)
02593                         continue;
02594                 if (strcmp(view->name, "_default") == 0)
02595                         fprintf(fp, "[View: default]\n");
02596                 else
02597                         fprintf(fp, "[View: %s]\n", view->name);
02598                 (void) dump_counters(view->adbstats, isc_statsformat_file, fp,
02599                                      NULL, adbstats_desc, dns_adbstats_max,
02600                                      adbstats_index, adbstat_values, 0);
02601         }
02602 
02603         fprintf(fp, "++ Socket I/O Statistics ++\n");
02604         (void) dump_counters(server->sockstats, isc_statsformat_file, fp, NULL,
02605                              sockstats_desc, isc_sockstatscounter_max,
02606                              sockstats_index, sockstat_values, 0);
02607 
02608         fprintf(fp, "++ Per Zone Query Statistics ++\n");
02609         zone = NULL;
02610         for (result = dns_zone_first(server->zonemgr, &zone);
02611              result == ISC_R_SUCCESS;
02612              next = NULL, result = dns_zone_next(zone, &next), zone = next)
02613         {
02614                 isc_stats_t *zonestats = dns_zone_getrequeststats(zone);
02615                 if (zonestats != NULL) {
02616                         char zonename[DNS_NAME_FORMATSIZE];
02617 
02618                         dns_name_format(dns_zone_getorigin(zone),
02619                                         zonename, sizeof(zonename));
02620                         view = dns_zone_getview(zone);
02621 
02622                         fprintf(fp, "[%s", zonename);
02623                         if (strcmp(view->name, "_default") != 0)
02624                                 fprintf(fp, " (view: %s)", view->name);
02625                         fprintf(fp, "]\n");
02626 
02627                         (void) dump_counters(zonestats, isc_statsformat_file,
02628                                              fp, NULL, nsstats_desc,
02629                                              dns_nsstatscounter_max,
02630                                              nsstats_index, nsstat_values, 0);
02631                 }
02632         }
02633 
02634         fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now);
02635 
02636         return (ISC_R_SUCCESS); /* this function currently always succeeds */
02637 }

Generated on Tue Apr 28 17:40:55 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha