1 /* $NetBSD: statschannel.c,v 1.10 2014/12/10 04:37:52 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2008-2014 Internet Systems Consortium, Inc. ("ISC") 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* Id: statschannel.c,v 1.28.224.1 2011/12/22 07:48:27 marka Exp */ 20 21 /*! \file */ 22 23 #include <config.h> 24 25 #include <isc/buffer.h> 26 #include <isc/httpd.h> 27 #include <isc/mem.h> 28 #include <isc/once.h> 29 #include <isc/print.h> 30 #include <isc/socket.h> 31 #include <isc/stats.h> 32 #include <isc/string.h> 33 #include <isc/task.h> 34 35 #include <dns/cache.h> 36 #include <dns/db.h> 37 #include <dns/opcode.h> 38 #include <dns/resolver.h> 39 #include <dns/rdataclass.h> 40 #include <dns/rdatatype.h> 41 #include <dns/stats.h> 42 #include <dns/view.h> 43 #include <dns/zt.h> 44 45 #include <named/log.h> 46 #include <named/server.h> 47 #include <named/statschannel.h> 48 49 #ifdef HAVE_JSON_H 50 #include <json/json.h> 51 #endif 52 53 #include "bind9.xsl.h" 54 55 struct ns_statschannel { 56 /* Unlocked */ 57 isc_httpdmgr_t *httpdmgr; 58 isc_sockaddr_t address; 59 isc_mem_t *mctx; 60 61 /* 62 * Locked by channel lock: can be referenced and modified by both 63 * the server task and the channel task. 64 */ 65 isc_mutex_t lock; 66 dns_acl_t *acl; 67 68 /* Locked by server task */ 69 ISC_LINK(struct ns_statschannel) link; 70 }; 71 72 typedef struct 73 stats_dumparg { 74 isc_statsformat_t type; 75 void *arg; /* type dependent argument */ 76 int ncounters; /* for general statistics */ 77 int *counterindices; /* for general statistics */ 78 isc_uint64_t *countervalues; /* for general statistics */ 79 isc_result_t result; 80 } stats_dumparg_t; 81 82 static isc_once_t once = ISC_ONCE_INIT; 83 84 #if defined(HAVE_LIBXML2) || defined(HAVE_JSON) 85 #define EXTENDED_STATS 86 #else 87 #undef EXTENDED_STATS 88 #endif 89 90 /*% 91 * Statistics descriptions. These could be statistically initialized at 92 * compile time, but we configure them run time in the init_desc() function 93 * below so that they'll be less susceptible to counter name changes. 94 */ 95 static const char *nsstats_desc[dns_nsstatscounter_max]; 96 static const char *resstats_desc[dns_resstatscounter_max]; 97 static const char *adbstats_desc[dns_adbstats_max]; 98 static const char *zonestats_desc[dns_zonestatscounter_max]; 99 static const char *sockstats_desc[isc_sockstatscounter_max]; 100 static const char *dnssecstats_desc[dns_dnssecstats_max]; 101 #if defined(EXTENDED_STATS) 102 static const char *nsstats_xmldesc[dns_nsstatscounter_max]; 103 static const char *resstats_xmldesc[dns_resstatscounter_max]; 104 static const char *adbstats_xmldesc[dns_adbstats_max]; 105 static const char *zonestats_xmldesc[dns_zonestatscounter_max]; 106 static const char *sockstats_xmldesc[isc_sockstatscounter_max]; 107 static const char *dnssecstats_xmldesc[dns_dnssecstats_max]; 108 #else 109 #define nsstats_xmldesc NULL 110 #define resstats_xmldesc NULL 111 #define adbstats_xmldesc NULL 112 #define zonestats_xmldesc NULL 113 #define sockstats_xmldesc NULL 114 #define dnssecstats_xmldesc NULL 115 #endif /* EXTENDED_STATS */ 116 117 #define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(/*CONSTCOND*/0) 118 119 /*% 120 * Mapping arrays to represent statistics counters in the order of our 121 * preference, regardless of the order of counter indices. For example, 122 * nsstats_desc[nsstats_index[0]] will be the description that is shown first. 123 */ 124 static int nsstats_index[dns_nsstatscounter_max]; 125 static int resstats_index[dns_resstatscounter_max]; 126 static int adbstats_index[dns_adbstats_max]; 127 static int zonestats_index[dns_zonestatscounter_max]; 128 static int sockstats_index[isc_sockstatscounter_max]; 129 static int dnssecstats_index[dns_dnssecstats_max]; 130 131 static inline void 132 set_desc(int counter, int maxcounter, const char *fdesc, const char **fdescs, 133 const char *xdesc, const char **xdescs) 134 { 135 REQUIRE(counter < maxcounter); 136 REQUIRE(fdescs != NULL && fdescs[counter] == NULL); 137 #if defined(EXTENDED_STATS) 138 REQUIRE(xdescs != NULL && xdescs[counter] == NULL); 139 #endif 140 141 fdescs[counter] = fdesc; 142 #if defined(EXTENDED_STATS) 143 xdescs[counter] = xdesc; 144 #else 145 UNUSED(xdesc); 146 UNUSED(xdescs); 147 #endif 148 } 149 150 static void 151 init_desc(void) { 152 int i; 153 154 /* Initialize name server statistics */ 155 for (i = 0; i < dns_nsstatscounter_max; i++) 156 nsstats_desc[i] = NULL; 157 #if defined(EXTENDED_STATS) 158 for (i = 0; i < dns_nsstatscounter_max; i++) 159 nsstats_xmldesc[i] = NULL; 160 #endif 161 162 #define SET_NSSTATDESC(counterid, desc, xmldesc) \ 163 do { \ 164 set_desc(dns_nsstatscounter_ ## counterid, \ 165 dns_nsstatscounter_max, \ 166 desc, nsstats_desc, xmldesc, nsstats_xmldesc); \ 167 nsstats_index[i++] = dns_nsstatscounter_ ## counterid; \ 168 } while (/*CONSTCOND*/0) 169 170 i = 0; 171 SET_NSSTATDESC(requestv4, "IPv4 requests received", "Requestv4"); 172 SET_NSSTATDESC(requestv6, "IPv6 requests received", "Requestv6"); 173 SET_NSSTATDESC(edns0in, "requests with EDNS(0) received", "ReqEdns0"); 174 SET_NSSTATDESC(badednsver, 175 "requests with unsupported EDNS version received", 176 "ReqBadEDNSVer"); 177 SET_NSSTATDESC(tsigin, "requests with TSIG received", "ReqTSIG"); 178 SET_NSSTATDESC(sig0in, "requests with SIG(0) received", "ReqSIG0"); 179 SET_NSSTATDESC(invalidsig, "requests with invalid signature", 180 "ReqBadSIG"); 181 SET_NSSTATDESC(requesttcp, "TCP requests received", "ReqTCP"); 182 SET_NSSTATDESC(authrej, "auth queries rejected", "AuthQryRej"); 183 SET_NSSTATDESC(recurserej, "recursive queries rejected", "RecQryRej"); 184 SET_NSSTATDESC(xfrrej, "transfer requests rejected", "XfrRej"); 185 SET_NSSTATDESC(updaterej, "update requests rejected", "UpdateRej"); 186 SET_NSSTATDESC(response, "responses sent", "Response"); 187 SET_NSSTATDESC(truncatedresp, "truncated responses sent", 188 "TruncatedResp"); 189 SET_NSSTATDESC(edns0out, "responses with EDNS(0) sent", "RespEDNS0"); 190 SET_NSSTATDESC(tsigout, "responses with TSIG sent", "RespTSIG"); 191 SET_NSSTATDESC(sig0out, "responses with SIG(0) sent", "RespSIG0"); 192 SET_NSSTATDESC(success, "queries resulted in successful answer", 193 "QrySuccess"); 194 SET_NSSTATDESC(authans, "queries resulted in authoritative answer", 195 "QryAuthAns"); 196 SET_NSSTATDESC(nonauthans, 197 "queries resulted in non authoritative answer", 198 "QryNoauthAns"); 199 SET_NSSTATDESC(referral, "queries resulted in referral answer", 200 "QryReferral"); 201 SET_NSSTATDESC(nxrrset, "queries resulted in nxrrset", "QryNxrrset"); 202 SET_NSSTATDESC(servfail, "queries resulted in SERVFAIL", "QrySERVFAIL"); 203 SET_NSSTATDESC(formerr, "queries resulted in FORMERR", "QryFORMERR"); 204 SET_NSSTATDESC(nxdomain, "queries resulted in NXDOMAIN", "QryNXDOMAIN"); 205 SET_NSSTATDESC(recursion, "queries caused recursion", "QryRecursion"); 206 SET_NSSTATDESC(duplicate, "duplicate queries received", "QryDuplicate"); 207 SET_NSSTATDESC(dropped, "queries dropped", "QryDropped"); 208 SET_NSSTATDESC(failure, "other query failures", "QryFailure"); 209 SET_NSSTATDESC(xfrdone, "requested transfers completed", "XfrReqDone"); 210 SET_NSSTATDESC(updatereqfwd, "update requests forwarded", 211 "UpdateReqFwd"); 212 SET_NSSTATDESC(updaterespfwd, "update responses forwarded", 213 "UpdateRespFwd"); 214 SET_NSSTATDESC(updatefwdfail, "update forward failed", "UpdateFwdFail"); 215 SET_NSSTATDESC(updatedone, "updates completed", "UpdateDone"); 216 SET_NSSTATDESC(updatefail, "updates failed", "UpdateFail"); 217 SET_NSSTATDESC(updatebadprereq, 218 "updates rejected due to prerequisite failure", 219 "UpdateBadPrereq"); 220 SET_NSSTATDESC(recursclients, "recursing clients", 221 "RecursClients"); 222 SET_NSSTATDESC(dns64, "queries answered by DNS64", "DNS64"); 223 SET_NSSTATDESC(ratedropped, "responses dropped for rate limits", 224 "RateDropped"); 225 SET_NSSTATDESC(rateslipped, "responses truncated for rate limits", 226 "RateSlipped"); 227 SET_NSSTATDESC(rpz_rewrites, "response policy zone rewrites", 228 "RPZRewrites"); 229 SET_NSSTATDESC(udp, "UDP queries received", "QryUDP"); 230 SET_NSSTATDESC(tcp, "TCP queries received", "QryTCP"); 231 SET_NSSTATDESC(nsidopt, "NSID option received", "NSIDOpt"); 232 SET_NSSTATDESC(expireopt, "Expire option recieved", "ExpireOpt"); 233 SET_NSSTATDESC(otheropt, "Other EDNS option recieved", "OtherOpt"); 234 #ifdef ISC_PLATFORM_USESIT 235 SET_NSSTATDESC(sitopt, "source identity token option received", 236 "SitOpt"); 237 SET_NSSTATDESC(sitnew, "new source identity token requested", 238 "SitNew"); 239 SET_NSSTATDESC(sitbadsize, "source identity token - bad size", 240 "SitBadSize"); 241 SET_NSSTATDESC(sitbadtime, "source identity token - bad time", 242 "SitBadTime"); 243 SET_NSSTATDESC(sitnomatch, "source identity token - no match", 244 "SitNoMatch"); 245 SET_NSSTATDESC(sitmatch, "source identity token - match", "SitMatch"); 246 #endif 247 INSIST(i == dns_nsstatscounter_max); 248 249 /* Initialize resolver statistics */ 250 for (i = 0; i < dns_resstatscounter_max; i++) 251 resstats_desc[i] = NULL; 252 #if defined(EXTENDED_STATS) 253 for (i = 0; i < dns_resstatscounter_max; i++) 254 resstats_xmldesc[i] = NULL; 255 #endif 256 257 #define SET_RESSTATDESC(counterid, desc, xmldesc) \ 258 do { \ 259 set_desc(dns_resstatscounter_ ## counterid, \ 260 dns_resstatscounter_max, \ 261 desc, resstats_desc, xmldesc, resstats_xmldesc); \ 262 resstats_index[i++] = dns_resstatscounter_ ## counterid; \ 263 } while (/*CONSTCOND*/0) 264 265 i = 0; 266 SET_RESSTATDESC(queryv4, "IPv4 queries sent", "Queryv4"); 267 SET_RESSTATDESC(queryv6, "IPv6 queries sent", "Queryv6"); 268 SET_RESSTATDESC(responsev4, "IPv4 responses received", "Responsev4"); 269 SET_RESSTATDESC(responsev6, "IPv6 responses received", "Responsev6"); 270 SET_RESSTATDESC(nxdomain, "NXDOMAIN received", "NXDOMAIN"); 271 SET_RESSTATDESC(servfail, "SERVFAIL received", "SERVFAIL"); 272 SET_RESSTATDESC(formerr, "FORMERR received", "FORMERR"); 273 SET_RESSTATDESC(othererror, "other errors received", "OtherError"); 274 SET_RESSTATDESC(edns0fail, "EDNS(0) query failures", "EDNS0Fail"); 275 SET_RESSTATDESC(mismatch, "mismatch responses received", "Mismatch"); 276 SET_RESSTATDESC(truncated, "truncated responses received", "Truncated"); 277 SET_RESSTATDESC(lame, "lame delegations received", "Lame"); 278 SET_RESSTATDESC(retry, "query retries", "Retry"); 279 SET_RESSTATDESC(dispabort, "queries aborted due to quota", 280 "QueryAbort"); 281 SET_RESSTATDESC(dispsockfail, "failures in opening query sockets", 282 "QuerySockFail"); 283 SET_RESSTATDESC(disprequdp, "UDP queries in progress", "QueryCurUDP"); 284 SET_RESSTATDESC(dispreqtcp, "TCP queries in progress", "QueryCurTCP"); 285 SET_RESSTATDESC(querytimeout, "query timeouts", "QueryTimeout"); 286 SET_RESSTATDESC(gluefetchv4, "IPv4 NS address fetches", "GlueFetchv4"); 287 SET_RESSTATDESC(gluefetchv6, "IPv6 NS address fetches", "GlueFetchv6"); 288 SET_RESSTATDESC(gluefetchv4fail, "IPv4 NS address fetch failed", 289 "GlueFetchv4Fail"); 290 SET_RESSTATDESC(gluefetchv6fail, "IPv6 NS address fetch failed", 291 "GlueFetchv6Fail"); 292 SET_RESSTATDESC(val, "DNSSEC validation attempted", "ValAttempt"); 293 SET_RESSTATDESC(valsuccess, "DNSSEC validation succeeded", "ValOk"); 294 SET_RESSTATDESC(valnegsuccess, "DNSSEC NX validation succeeded", 295 "ValNegOk"); 296 SET_RESSTATDESC(valfail, "DNSSEC validation failed", "ValFail"); 297 SET_RESSTATDESC(queryrtt0, "queries with RTT < " 298 DNS_RESOLVER_QRYRTTCLASS0STR "ms", 299 "QryRTT" DNS_RESOLVER_QRYRTTCLASS0STR); 300 SET_RESSTATDESC(queryrtt1, "queries with RTT " 301 DNS_RESOLVER_QRYRTTCLASS0STR "-" 302 DNS_RESOLVER_QRYRTTCLASS1STR "ms", 303 "QryRTT" DNS_RESOLVER_QRYRTTCLASS1STR); 304 SET_RESSTATDESC(queryrtt2, "queries with RTT " 305 DNS_RESOLVER_QRYRTTCLASS1STR "-" 306 DNS_RESOLVER_QRYRTTCLASS2STR "ms", 307 "QryRTT" DNS_RESOLVER_QRYRTTCLASS2STR); 308 SET_RESSTATDESC(queryrtt3, "queries with RTT " 309 DNS_RESOLVER_QRYRTTCLASS2STR "-" 310 DNS_RESOLVER_QRYRTTCLASS3STR "ms", 311 "QryRTT" DNS_RESOLVER_QRYRTTCLASS3STR); 312 SET_RESSTATDESC(queryrtt4, "queries with RTT " 313 DNS_RESOLVER_QRYRTTCLASS3STR "-" 314 DNS_RESOLVER_QRYRTTCLASS4STR "ms", 315 "QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR); 316 SET_RESSTATDESC(queryrtt5, "queries with RTT > " 317 DNS_RESOLVER_QRYRTTCLASS4STR "ms", 318 "QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR "+"); 319 SET_RESSTATDESC(nfetch, "active fetches", "NumFetch"); 320 SET_RESSTATDESC(buckets, "bucket size", "BucketSize"); 321 SET_RESSTATDESC(refused, "REFUSED received", "REFUSED"); 322 #ifdef ISC_PLATFORM_USESIT 323 SET_RESSTATDESC(sitcc, "SIT sent client cookie only", 324 "SitClientOut"); 325 SET_RESSTATDESC(sitout, "SIT sent with client and server cookie", 326 "SitOut"); 327 SET_RESSTATDESC(sitin, "SIT replies received", "SitIn"); 328 SET_RESSTATDESC(sitok, "SIT client cookie ok", "SitClientOk"); 329 #endif 330 SET_RESSTATDESC(badvers, "bad EDNS version", "BadEDNSVersion"); 331 332 INSIST(i == dns_resstatscounter_max); 333 334 /* Initialize adb statistics */ 335 for (i = 0; i < dns_adbstats_max; i++) 336 adbstats_desc[i] = NULL; 337 #if defined(EXTENDED_STATS) 338 for (i = 0; i < dns_adbstats_max; i++) 339 adbstats_xmldesc[i] = NULL; 340 #endif 341 342 #define SET_ADBSTATDESC(id, desc, xmldesc) \ 343 do { \ 344 set_desc(dns_adbstats_ ## id, dns_adbstats_max, \ 345 desc, adbstats_desc, xmldesc, adbstats_xmldesc); \ 346 adbstats_index[i++] = dns_adbstats_ ## id; \ 347 } while (/*CONSTCOND*/0) 348 i = 0; 349 SET_ADBSTATDESC(nentries, "Address hash table size", "nentries"); 350 SET_ADBSTATDESC(entriescnt, "Addresses in hash table", "entriescnt"); 351 SET_ADBSTATDESC(nnames, "Name hash table size", "nnames"); 352 SET_ADBSTATDESC(namescnt, "Names in hash table", "namescnt"); 353 354 INSIST(i == dns_adbstats_max); 355 356 /* Initialize zone statistics */ 357 for (i = 0; i < dns_zonestatscounter_max; i++) 358 zonestats_desc[i] = NULL; 359 #if defined(EXTENDED_STATS) 360 for (i = 0; i < dns_zonestatscounter_max; i++) 361 zonestats_xmldesc[i] = NULL; 362 #endif 363 364 #define SET_ZONESTATDESC(counterid, desc, xmldesc) \ 365 do { \ 366 set_desc(dns_zonestatscounter_ ## counterid, \ 367 dns_zonestatscounter_max, \ 368 desc, zonestats_desc, xmldesc, zonestats_xmldesc); \ 369 zonestats_index[i++] = dns_zonestatscounter_ ## counterid; \ 370 } while (/*CONSTCOND*/0) 371 372 i = 0; 373 SET_ZONESTATDESC(notifyoutv4, "IPv4 notifies sent", "NotifyOutv4"); 374 SET_ZONESTATDESC(notifyoutv6, "IPv6 notifies sent", "NotifyOutv6"); 375 SET_ZONESTATDESC(notifyinv4, "IPv4 notifies received", "NotifyInv4"); 376 SET_ZONESTATDESC(notifyinv6, "IPv6 notifies received", "NotifyInv6"); 377 SET_ZONESTATDESC(notifyrej, "notifies rejected", "NotifyRej"); 378 SET_ZONESTATDESC(soaoutv4, "IPv4 SOA queries sent", "SOAOutv4"); 379 SET_ZONESTATDESC(soaoutv6, "IPv6 SOA queries sent", "SOAOutv6"); 380 SET_ZONESTATDESC(axfrreqv4, "IPv4 AXFR requested", "AXFRReqv4"); 381 SET_ZONESTATDESC(axfrreqv6, "IPv6 AXFR requested", "AXFRReqv6"); 382 SET_ZONESTATDESC(ixfrreqv4, "IPv4 IXFR requested", "IXFRReqv4"); 383 SET_ZONESTATDESC(ixfrreqv6, "IPv6 IXFR requested", "IXFRReqv6"); 384 SET_ZONESTATDESC(xfrsuccess, "transfer requests succeeded", 385 "XfrSuccess"); 386 SET_ZONESTATDESC(xfrfail, "transfer requests failed", "XfrFail"); 387 INSIST(i == dns_zonestatscounter_max); 388 389 /* Initialize socket statistics */ 390 for (i = 0; i < isc_sockstatscounter_max; i++) 391 sockstats_desc[i] = NULL; 392 #if defined(EXTENDED_STATS) 393 for (i = 0; i < isc_sockstatscounter_max; i++) 394 sockstats_xmldesc[i] = NULL; 395 #endif 396 397 #define SET_SOCKSTATDESC(counterid, desc, xmldesc) \ 398 do { \ 399 set_desc(isc_sockstatscounter_ ## counterid, \ 400 isc_sockstatscounter_max, \ 401 desc, sockstats_desc, xmldesc, sockstats_xmldesc); \ 402 sockstats_index[i++] = isc_sockstatscounter_ ## counterid; \ 403 } while (/*CONSTCOND*/0) 404 405 i = 0; 406 SET_SOCKSTATDESC(udp4open, "UDP/IPv4 sockets opened", "UDP4Open"); 407 SET_SOCKSTATDESC(udp6open, "UDP/IPv6 sockets opened", "UDP6Open"); 408 SET_SOCKSTATDESC(tcp4open, "TCP/IPv4 sockets opened", "TCP4Open"); 409 SET_SOCKSTATDESC(tcp6open, "TCP/IPv6 sockets opened", "TCP6Open"); 410 SET_SOCKSTATDESC(unixopen, "Unix domain sockets opened", "UnixOpen"); 411 SET_SOCKSTATDESC(rawopen, "Raw sockets opened", "RawOpen"); 412 SET_SOCKSTATDESC(udp4openfail, "UDP/IPv4 socket open failures", 413 "UDP4OpenFail"); 414 SET_SOCKSTATDESC(udp6openfail, "UDP/IPv6 socket open failures", 415 "UDP6OpenFail"); 416 SET_SOCKSTATDESC(tcp4openfail, "TCP/IPv4 socket open failures", 417 "TCP4OpenFail"); 418 SET_SOCKSTATDESC(tcp6openfail, "TCP/IPv6 socket open failures", 419 "TCP6OpenFail"); 420 SET_SOCKSTATDESC(unixopenfail, "Unix domain socket open failures", 421 "UnixOpenFail"); 422 SET_SOCKSTATDESC(rawopenfail, "Raw socket open failures", 423 "RawOpenFail"); 424 SET_SOCKSTATDESC(udp4close, "UDP/IPv4 sockets closed", "UDP4Close"); 425 SET_SOCKSTATDESC(udp6close, "UDP/IPv6 sockets closed", "UDP6Close"); 426 SET_SOCKSTATDESC(tcp4close, "TCP/IPv4 sockets closed", "TCP4Close"); 427 SET_SOCKSTATDESC(tcp6close, "TCP/IPv6 sockets closed", "TCP6Close"); 428 SET_SOCKSTATDESC(unixclose, "Unix domain sockets closed", "UnixClose"); 429 SET_SOCKSTATDESC(fdwatchclose, "FDwatch sockets closed", 430 "FDWatchClose"); 431 SET_SOCKSTATDESC(rawclose, "Raw sockets closed", "RawClose"); 432 SET_SOCKSTATDESC(udp4bindfail, "UDP/IPv4 socket bind failures", 433 "UDP4BindFail"); 434 SET_SOCKSTATDESC(udp6bindfail, "UDP/IPv6 socket bind failures", 435 "UDP6BindFail"); 436 SET_SOCKSTATDESC(tcp4bindfail, "TCP/IPv4 socket bind failures", 437 "TCP4BindFail"); 438 SET_SOCKSTATDESC(tcp6bindfail, "TCP/IPv6 socket bind failures", 439 "TCP6BindFail"); 440 SET_SOCKSTATDESC(unixbindfail, "Unix domain socket bind failures", 441 "UnixBindFail"); 442 SET_SOCKSTATDESC(fdwatchbindfail, "FDwatch socket bind failures", 443 "FdwatchBindFail"); 444 SET_SOCKSTATDESC(udp4connectfail, "UDP/IPv4 socket connect failures", 445 "UDP4ConnFail"); 446 SET_SOCKSTATDESC(udp6connectfail, "UDP/IPv6 socket connect failures", 447 "UDP6ConnFail"); 448 SET_SOCKSTATDESC(tcp4connectfail, "TCP/IPv4 socket connect failures", 449 "TCP4ConnFail"); 450 SET_SOCKSTATDESC(tcp6connectfail, "TCP/IPv6 socket connect failures", 451 "TCP6ConnFail"); 452 SET_SOCKSTATDESC(unixconnectfail, "Unix domain socket connect failures", 453 "UnixConnFail"); 454 SET_SOCKSTATDESC(fdwatchconnectfail, "FDwatch socket connect failures", 455 "FDwatchConnFail"); 456 SET_SOCKSTATDESC(udp4connect, "UDP/IPv4 connections established", 457 "UDP4Conn"); 458 SET_SOCKSTATDESC(udp6connect, "UDP/IPv6 connections established", 459 "UDP6Conn"); 460 SET_SOCKSTATDESC(tcp4connect, "TCP/IPv4 connections established", 461 "TCP4Conn"); 462 SET_SOCKSTATDESC(tcp6connect, "TCP/IPv6 connections established", 463 "TCP6Conn"); 464 SET_SOCKSTATDESC(unixconnect, "Unix domain connections established", 465 "UnixConn"); 466 SET_SOCKSTATDESC(fdwatchconnect, 467 "FDwatch domain connections established", 468 "FDwatchConn"); 469 SET_SOCKSTATDESC(tcp4acceptfail, "TCP/IPv4 connection accept failures", 470 "TCP4AcceptFail"); 471 SET_SOCKSTATDESC(tcp6acceptfail, "TCP/IPv6 connection accept failures", 472 "TCP6AcceptFail"); 473 SET_SOCKSTATDESC(unixacceptfail, 474 "Unix domain connection accept failures", 475 "UnixAcceptFail"); 476 SET_SOCKSTATDESC(tcp4accept, "TCP/IPv4 connections accepted", 477 "TCP4Accept"); 478 SET_SOCKSTATDESC(tcp6accept, "TCP/IPv6 connections accepted", 479 "TCP6Accept"); 480 SET_SOCKSTATDESC(unixaccept, "Unix domain connections accepted", 481 "UnixAccept"); 482 SET_SOCKSTATDESC(udp4sendfail, "UDP/IPv4 send errors", "UDP4SendErr"); 483 SET_SOCKSTATDESC(udp6sendfail, "UDP/IPv6 send errors", "UDP6SendErr"); 484 SET_SOCKSTATDESC(tcp4sendfail, "TCP/IPv4 send errors", "TCP4SendErr"); 485 SET_SOCKSTATDESC(tcp6sendfail, "TCP/IPv6 send errors", "TCP6SendErr"); 486 SET_SOCKSTATDESC(unixsendfail, "Unix domain send errors", 487 "UnixSendErr"); 488 SET_SOCKSTATDESC(fdwatchsendfail, "FDwatch send errors", 489 "FDwatchSendErr"); 490 SET_SOCKSTATDESC(udp4recvfail, "UDP/IPv4 recv errors", "UDP4RecvErr"); 491 SET_SOCKSTATDESC(udp6recvfail, "UDP/IPv6 recv errors", "UDP6RecvErr"); 492 SET_SOCKSTATDESC(tcp4recvfail, "TCP/IPv4 recv errors", "TCP4RecvErr"); 493 SET_SOCKSTATDESC(tcp6recvfail, "TCP/IPv6 recv errors", "TCP6RecvErr"); 494 SET_SOCKSTATDESC(unixrecvfail, "Unix domain recv errors", 495 "UnixRecvErr"); 496 SET_SOCKSTATDESC(fdwatchrecvfail, "FDwatch recv errors", 497 "FDwatchRecvErr"); 498 SET_SOCKSTATDESC(rawrecvfail, "Raw recv errors", "RawRecvErr"); 499 SET_SOCKSTATDESC(udp4active, "UDP/IPv4 sockets active", "UDP4Active"); 500 SET_SOCKSTATDESC(udp6active, "UDP/IPv6 sockets active", "UDP6Active"); 501 SET_SOCKSTATDESC(tcp4active, "TCP/IPv4 sockets active", "TCP4Active"); 502 SET_SOCKSTATDESC(tcp6active, "TCP/IPv6 sockets active", "TCP6Active"); 503 SET_SOCKSTATDESC(unixactive, "Unix domain sockets active", 504 "UnixActive"); 505 SET_SOCKSTATDESC(rawactive, "Raw sockets active", "RawActive"); 506 INSIST(i == isc_sockstatscounter_max); 507 508 /* Initialize DNSSEC statistics */ 509 for (i = 0; i < dns_dnssecstats_max; i++) 510 dnssecstats_desc[i] = NULL; 511 #if defined(EXTENDED_STATS) 512 for (i = 0; i < dns_dnssecstats_max; i++) 513 dnssecstats_xmldesc[i] = NULL; 514 #endif 515 516 #define SET_DNSSECSTATDESC(counterid, desc, xmldesc) \ 517 do { \ 518 set_desc(dns_dnssecstats_ ## counterid, \ 519 dns_dnssecstats_max, \ 520 desc, dnssecstats_desc, \ 521 xmldesc, dnssecstats_xmldesc); \ 522 dnssecstats_index[i++] = dns_dnssecstats_ ## counterid; \ 523 } while (/*CONSTCOND*/0) 524 525 i = 0; 526 SET_DNSSECSTATDESC(asis, "dnssec validation success with signer " 527 "\"as is\"", "DNSSECasis"); 528 SET_DNSSECSTATDESC(downcase, "dnssec validation success with signer " 529 "lower cased", "DNSSECdowncase"); 530 SET_DNSSECSTATDESC(wildcard, "dnssec validation of wildcard signature", 531 "DNSSECwild"); 532 SET_DNSSECSTATDESC(fail, "dnssec validation failures", "DNSSECfail"); 533 INSIST(i == dns_dnssecstats_max); 534 535 /* Sanity check */ 536 for (i = 0; i < dns_nsstatscounter_max; i++) 537 INSIST(nsstats_desc[i] != NULL); 538 for (i = 0; i < dns_resstatscounter_max; i++) 539 INSIST(resstats_desc[i] != NULL); 540 for (i = 0; i < dns_adbstats_max; i++) 541 INSIST(adbstats_desc[i] != NULL); 542 for (i = 0; i < dns_zonestatscounter_max; i++) 543 INSIST(zonestats_desc[i] != NULL); 544 for (i = 0; i < isc_sockstatscounter_max; i++) 545 INSIST(sockstats_desc[i] != NULL); 546 for (i = 0; i < dns_dnssecstats_max; i++) 547 INSIST(dnssecstats_desc[i] != NULL); 548 #if defined(EXTENDED_STATS) 549 for (i = 0; i < dns_nsstatscounter_max; i++) 550 INSIST(nsstats_xmldesc[i] != NULL); 551 for (i = 0; i < dns_resstatscounter_max; i++) 552 INSIST(resstats_xmldesc[i] != NULL); 553 for (i = 0; i < dns_adbstats_max; i++) 554 INSIST(adbstats_xmldesc[i] != NULL); 555 for (i = 0; i < dns_zonestatscounter_max; i++) 556 INSIST(zonestats_xmldesc[i] != NULL); 557 for (i = 0; i < isc_sockstatscounter_max; i++) 558 INSIST(sockstats_xmldesc[i] != NULL); 559 for (i = 0; i < dns_dnssecstats_max; i++) 560 INSIST(dnssecstats_xmldesc[i] != NULL); 561 #endif 562 } 563 564 /*% 565 * Dump callback functions. 566 */ 567 static void 568 generalstat_dump(isc_statscounter_t counter, isc_uint64_t val, void *arg) { 569 stats_dumparg_t *dumparg = arg; 570 571 REQUIRE(counter < dumparg->ncounters); 572 dumparg->countervalues[counter] = val; 573 } 574 575 static isc_result_t 576 dump_counters(isc_stats_t *stats, isc_statsformat_t type, void *arg, 577 const char *category, const char **desc, int ncounters, 578 int *indices, isc_uint64_t *values, int options) 579 { 580 int i, index; 581 isc_uint64_t value; 582 stats_dumparg_t dumparg; 583 FILE *fp; 584 #ifdef HAVE_LIBXML2 585 xmlTextWriterPtr writer; 586 int xmlrc; 587 #endif 588 #ifdef HAVE_JSON 589 json_object *job, *cat, *counter; 590 #endif 591 592 #if !defined(EXTENDED_STATS) 593 UNUSED(category); 594 #endif 595 596 dumparg.type = type; 597 dumparg.ncounters = ncounters; 598 dumparg.counterindices = indices; 599 dumparg.countervalues = values; 600 601 memset(values, 0, sizeof(values[0]) * ncounters); 602 isc_stats_dump(stats, generalstat_dump, &dumparg, options); 603 604 #ifdef HAVE_JSON 605 cat = job = (json_object *) arg; 606 if (ncounters > 0 && type == isc_statsformat_json) { 607 if (category != NULL) { 608 cat = json_object_new_object(); 609 if (cat == NULL) 610 return (ISC_R_NOMEMORY); 611 json_object_object_add(job, category, cat); 612 } 613 } 614 #endif 615 616 for (i = 0; i < ncounters; i++) { 617 index = indices[i]; 618 value = values[index]; 619 620 if (value == 0 && (options & ISC_STATSDUMP_VERBOSE) == 0) 621 continue; 622 623 switch (dumparg.type) { 624 case isc_statsformat_file: 625 fp = arg; 626 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", 627 value, desc[index]); 628 break; 629 case isc_statsformat_xml: 630 #ifdef HAVE_LIBXML2 631 writer = (xmlTextWriterPtr) arg; 632 633 if (category != NULL) { 634 /* <NameOfCategory> */ 635 TRY0(xmlTextWriterStartElement(writer, 636 ISC_XMLCHAR 637 category)); 638 639 /* <name> inside category */ 640 TRY0(xmlTextWriterStartElement(writer, 641 ISC_XMLCHAR 642 "name")); 643 TRY0(xmlTextWriterWriteString(writer, 644 ISC_XMLCHAR 645 desc[index])); 646 TRY0(xmlTextWriterEndElement(writer)); 647 /* </name> */ 648 649 /* <counter> */ 650 TRY0(xmlTextWriterStartElement(writer, 651 ISC_XMLCHAR 652 "counter")); 653 TRY0(xmlTextWriterWriteFormatString(writer, 654 "%" ISC_PRINT_QUADFORMAT "u", value)); 655 656 TRY0(xmlTextWriterEndElement(writer)); 657 /* </counter> */ 658 TRY0(xmlTextWriterEndElement(writer)); 659 /* </NameOfCategory> */ 660 661 } else { 662 TRY0(xmlTextWriterStartElement(writer, 663 ISC_XMLCHAR 664 "counter")); 665 TRY0(xmlTextWriterWriteAttribute(writer, 666 ISC_XMLCHAR 667 "name", 668 ISC_XMLCHAR 669 desc[index])); 670 TRY0(xmlTextWriterWriteFormatString(writer, 671 "%" ISC_PRINT_QUADFORMAT "u", value)); 672 TRY0(xmlTextWriterEndElement(writer)); 673 /* counter */ 674 } 675 676 #endif 677 break; 678 case isc_statsformat_json: 679 #ifdef HAVE_JSON 680 counter = json_object_new_int64(value); 681 if (counter == NULL) 682 return (ISC_R_NOMEMORY); 683 json_object_object_add(cat, desc[index], counter); 684 #endif 685 break; 686 } 687 } 688 return (ISC_R_SUCCESS); 689 #ifdef HAVE_LIBXML2 690 error: 691 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 692 ISC_LOG_ERROR, "failed at dump_counters()"); 693 return (ISC_R_FAILURE); 694 #endif 695 } 696 697 static void 698 rdtypestat_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) { 699 char typebuf[64]; 700 const char *typestr; 701 stats_dumparg_t *dumparg = arg; 702 FILE *fp; 703 #ifdef HAVE_LIBXML2 704 xmlTextWriterPtr writer; 705 int xmlrc; 706 #endif 707 #ifdef HAVE_JSON 708 json_object *zoneobj, *obj; 709 #endif 710 711 if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) 712 == 0) { 713 dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf, 714 sizeof(typebuf)); 715 typestr = typebuf; 716 } else 717 typestr = "Others"; 718 719 switch (dumparg->type) { 720 case isc_statsformat_file: 721 fp = dumparg->arg; 722 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, typestr); 723 break; 724 case isc_statsformat_xml: 725 #ifdef HAVE_LIBXML2 726 writer = dumparg->arg; 727 728 729 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter")); 730 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", 731 ISC_XMLCHAR typestr)); 732 733 TRY0(xmlTextWriterWriteFormatString(writer, 734 "%" ISC_PRINT_QUADFORMAT "u", 735 val)); 736 737 TRY0(xmlTextWriterEndElement(writer)); /* type */ 738 #endif 739 break; 740 case isc_statsformat_json: 741 #ifdef HAVE_JSON 742 zoneobj = (json_object *) dumparg->arg; 743 obj = json_object_new_int64(val); 744 if (obj == NULL) 745 return; 746 json_object_object_add(zoneobj, typestr, obj); 747 #endif 748 break; 749 } 750 return; 751 #ifdef HAVE_LIBXML2 752 error: 753 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 754 ISC_LOG_ERROR, "failed at rdtypestat_dump()"); 755 dumparg->result = ISC_R_FAILURE; 756 return; 757 #endif 758 } 759 760 static void 761 rdatasetstats_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) { 762 stats_dumparg_t *dumparg = arg; 763 FILE *fp; 764 char typebuf[64]; 765 const char *typestr; 766 isc_boolean_t nxrrset = ISC_FALSE; 767 isc_boolean_t stale = ISC_FALSE; 768 #ifdef HAVE_LIBXML2 769 xmlTextWriterPtr writer; 770 int xmlrc; 771 #endif 772 #ifdef HAVE_JSON 773 json_object *zoneobj, *obj; 774 char buf[1024]; 775 #endif 776 777 if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_NXDOMAIN) 778 != 0) { 779 typestr = "NXDOMAIN"; 780 } else if ((DNS_RDATASTATSTYPE_ATTR(type) & 781 DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) != 0) { 782 typestr = "Others"; 783 } else { 784 dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf, 785 sizeof(typebuf)); 786 typestr = typebuf; 787 } 788 789 if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_NXRRSET) 790 != 0) 791 nxrrset = ISC_TRUE; 792 793 if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_STALE) 794 != 0) 795 stale = ISC_TRUE; 796 797 switch (dumparg->type) { 798 case isc_statsformat_file: 799 fp = dumparg->arg; 800 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s%s%s\n", val, 801 stale ? "#" : "", nxrrset ? "!" : "", typestr); 802 break; 803 case isc_statsformat_xml: 804 #ifdef HAVE_LIBXML2 805 writer = dumparg->arg; 806 807 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "rrset")); 808 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name")); 809 TRY0(xmlTextWriterWriteFormatString(writer, "%s%s%s", 810 stale ? "#" : "", 811 nxrrset ? "!" : "", typestr)); 812 TRY0(xmlTextWriterEndElement(writer)); /* name */ 813 814 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter")); 815 TRY0(xmlTextWriterWriteFormatString(writer, 816 "%" ISC_PRINT_QUADFORMAT "u", 817 val)); 818 TRY0(xmlTextWriterEndElement(writer)); /* counter */ 819 820 TRY0(xmlTextWriterEndElement(writer)); /* rrset */ 821 #endif 822 break; 823 case isc_statsformat_json: 824 #ifdef HAVE_JSON 825 zoneobj = (json_object *) dumparg->arg; 826 sprintf(buf, "%s%s%s", stale ? "#" : "", 827 nxrrset ? "!" : "", typestr); 828 obj = json_object_new_int64(val); 829 if (obj == NULL) 830 return; 831 json_object_object_add(zoneobj, buf, obj); 832 #endif 833 break; 834 } 835 return; 836 #ifdef HAVE_LIBXML2 837 error: 838 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 839 ISC_LOG_ERROR, "failed at rdatasetstats_dump()"); 840 dumparg->result = ISC_R_FAILURE; 841 #endif 842 843 } 844 845 static void 846 opcodestat_dump(dns_opcode_t code, isc_uint64_t val, void *arg) { 847 FILE *fp; 848 isc_buffer_t b; 849 char codebuf[64]; 850 stats_dumparg_t *dumparg = arg; 851 #ifdef HAVE_LIBXML2 852 xmlTextWriterPtr writer; 853 int xmlrc; 854 #endif 855 #ifdef HAVE_JSON 856 json_object *zoneobj, *obj; 857 #endif 858 859 isc_buffer_init(&b, codebuf, sizeof(codebuf) - 1); 860 dns_opcode_totext(code, &b); 861 codebuf[isc_buffer_usedlength(&b)] = '\0'; 862 863 switch (dumparg->type) { 864 case isc_statsformat_file: 865 fp = dumparg->arg; 866 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, codebuf); 867 break; 868 case isc_statsformat_xml: 869 #ifdef HAVE_LIBXML2 870 writer = dumparg->arg; 871 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter")); 872 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", 873 ISC_XMLCHAR codebuf )); 874 TRY0(xmlTextWriterWriteFormatString(writer, 875 "%" ISC_PRINT_QUADFORMAT "u", 876 val)); 877 TRY0(xmlTextWriterEndElement(writer)); /* counter */ 878 #endif 879 break; 880 case isc_statsformat_json: 881 #ifdef HAVE_JSON 882 zoneobj = (json_object *) dumparg->arg; 883 obj = json_object_new_int64(val); 884 if (obj == NULL) 885 return; 886 json_object_object_add(zoneobj, codebuf, obj); 887 #endif 888 break; 889 } 890 return; 891 892 #ifdef HAVE_LIBXML2 893 error: 894 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 895 ISC_LOG_ERROR, "failed at opcodestat_dump()"); 896 dumparg->result = ISC_R_FAILURE; 897 return; 898 #endif 899 } 900 901 #ifdef HAVE_LIBXML2 902 /* 903 * Which statistics to include when rendering to XML 904 */ 905 #define STATS_XML_STATUS 0x00 /* display only common statistics */ 906 #define STATS_XML_SERVER 0x01 907 #define STATS_XML_ZONES 0x02 908 #define STATS_XML_TASKS 0x04 909 #define STATS_XML_NET 0x08 910 #define STATS_XML_MEM 0x10 911 #define STATS_XML_ALL 0xff 912 913 static isc_result_t 914 zone_xmlrender(dns_zone_t *zone, void *arg) { 915 isc_result_t result; 916 char buf[1024 + 32]; /* sufficiently large for zone name and class */ 917 char *zone_name_only = NULL; 918 dns_rdataclass_t rdclass; 919 isc_uint32_t serial; 920 xmlTextWriterPtr writer = arg; 921 isc_stats_t *zonestats; 922 dns_stats_t *rcvquerystats; 923 dns_zonestat_level_t statlevel; 924 isc_uint64_t nsstat_values[dns_nsstatscounter_max]; 925 int xmlrc; 926 stats_dumparg_t dumparg; 927 928 statlevel = dns_zone_getstatlevel(zone); 929 if (statlevel == dns_zonestat_none) 930 return (ISC_R_SUCCESS); 931 932 dumparg.type = isc_statsformat_xml; 933 dumparg.arg = writer; 934 935 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "zone")); 936 dns_zone_name(zone, buf, sizeof(buf)); 937 zone_name_only = strtok(buf, "/"); 938 if(zone_name_only == NULL) 939 zone_name_only = buf; 940 941 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", 942 ISC_XMLCHAR zone_name_only)); 943 rdclass = dns_zone_getclass(zone); 944 dns_rdataclass_format(rdclass, buf, sizeof(buf)); 945 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "rdataclass", 946 ISC_XMLCHAR buf)); 947 948 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "serial")); 949 if (dns_zone_getserial2(zone, &serial) == ISC_R_SUCCESS) 950 TRY0(xmlTextWriterWriteFormatString(writer, "%u", serial)); 951 else 952 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); 953 TRY0(xmlTextWriterEndElement(writer)); /* serial */ 954 955 zonestats = dns_zone_getrequeststats(zone); 956 rcvquerystats = dns_zone_getrcvquerystats(zone); 957 if (statlevel == dns_zonestat_full && zonestats != NULL) { 958 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 959 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 960 ISC_XMLCHAR "rcode")); 961 962 result = dump_counters(zonestats, isc_statsformat_xml, writer, 963 NULL, nsstats_xmldesc, 964 dns_nsstatscounter_max, nsstats_index, 965 nsstat_values, ISC_STATSDUMP_VERBOSE); 966 if (result != ISC_R_SUCCESS) 967 goto error; 968 /* counters type="rcode"*/ 969 TRY0(xmlTextWriterEndElement(writer)); 970 } 971 972 if (statlevel == dns_zonestat_full && rcvquerystats != NULL) { 973 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 974 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 975 ISC_XMLCHAR "qtype")); 976 977 dumparg.result = ISC_R_SUCCESS; 978 dns_rdatatypestats_dump(rcvquerystats, rdtypestat_dump, 979 &dumparg, 0); 980 if(dumparg.result != ISC_R_SUCCESS) 981 goto error; 982 983 /* counters type="qtype"*/ 984 TRY0(xmlTextWriterEndElement(writer)); 985 } 986 987 TRY0(xmlTextWriterEndElement(writer)); /* zone */ 988 989 return (ISC_R_SUCCESS); 990 error: 991 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 992 ISC_LOG_ERROR, "Failed at zone_xmlrender()"); 993 return (ISC_R_FAILURE); 994 } 995 996 static isc_result_t 997 generatexml(ns_server_t *server, isc_uint32_t flags, 998 int *buflen, xmlChar **buf) 999 { 1000 char boottime[sizeof "yyyy-mm-ddThh:mm:ssZ"]; 1001 char configtime[sizeof "yyyy-mm-ddThh:mm:ssZ"]; 1002 char nowstr[sizeof "yyyy-mm-ddThh:mm:ssZ"]; 1003 isc_time_t now; 1004 xmlTextWriterPtr writer = NULL; 1005 xmlDocPtr doc = NULL; 1006 int xmlrc; 1007 dns_view_t *view; 1008 stats_dumparg_t dumparg; 1009 dns_stats_t *cacherrstats; 1010 isc_uint64_t nsstat_values[dns_nsstatscounter_max]; 1011 isc_uint64_t resstat_values[dns_resstatscounter_max]; 1012 isc_uint64_t adbstat_values[dns_adbstats_max]; 1013 isc_uint64_t zonestat_values[dns_zonestatscounter_max]; 1014 isc_uint64_t sockstat_values[isc_sockstatscounter_max]; 1015 isc_result_t result; 1016 1017 isc_time_now(&now); 1018 isc_time_formatISO8601(&ns_g_boottime, boottime, sizeof boottime); 1019 isc_time_formatISO8601(&ns_g_configtime, configtime, sizeof configtime); 1020 isc_time_formatISO8601(&now, nowstr, sizeof nowstr); 1021 1022 writer = xmlNewTextWriterDoc(&doc, 0); 1023 if (writer == NULL) 1024 goto error; 1025 TRY0(xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL)); 1026 TRY0(xmlTextWriterWritePI(writer, ISC_XMLCHAR "xml-stylesheet", 1027 ISC_XMLCHAR "type=\"text/xsl\" href=\"/bind9.xsl\"")); 1028 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics")); 1029 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version", 1030 ISC_XMLCHAR "3.5")); 1031 1032 /* Set common fields for statistics dump */ 1033 dumparg.type = isc_statsformat_xml; 1034 dumparg.arg = writer; 1035 1036 /* Render server information */ 1037 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "server")); 1038 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "boot-time")); 1039 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR boottime)); 1040 TRY0(xmlTextWriterEndElement(writer)); /* boot-time */ 1041 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "config-time")); 1042 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR configtime)); 1043 TRY0(xmlTextWriterEndElement(writer)); /* config-time */ 1044 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "current-time")); 1045 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR nowstr)); 1046 TRY0(xmlTextWriterEndElement(writer)); /* current-time */ 1047 1048 if ((flags & STATS_XML_SERVER) != 0) { 1049 dumparg.result = ISC_R_SUCCESS; 1050 1051 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1052 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1053 ISC_XMLCHAR "opcode")); 1054 1055 dns_opcodestats_dump(server->opcodestats, opcodestat_dump, 1056 &dumparg, ISC_STATSDUMP_VERBOSE); 1057 if (dumparg.result != ISC_R_SUCCESS) 1058 goto error; 1059 1060 TRY0(xmlTextWriterEndElement(writer)); 1061 1062 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1063 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1064 ISC_XMLCHAR "qtype")); 1065 1066 dumparg.result = ISC_R_SUCCESS; 1067 dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump, 1068 &dumparg, 0); 1069 if (dumparg.result != ISC_R_SUCCESS) 1070 goto error; 1071 TRY0(xmlTextWriterEndElement(writer)); /* counters */ 1072 1073 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1074 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1075 ISC_XMLCHAR "nsstat")); 1076 1077 result = dump_counters(server->nsstats, isc_statsformat_xml, 1078 writer, NULL, nsstats_xmldesc, 1079 dns_nsstatscounter_max, 1080 nsstats_index, nsstat_values, 1081 ISC_STATSDUMP_VERBOSE); 1082 if (result != ISC_R_SUCCESS) 1083 goto error; 1084 1085 TRY0(xmlTextWriterEndElement(writer)); /* /nsstat */ 1086 1087 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1088 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1089 ISC_XMLCHAR "zonestat")); 1090 1091 result = dump_counters(server->zonestats, isc_statsformat_xml, 1092 writer, NULL, zonestats_xmldesc, 1093 dns_zonestatscounter_max, 1094 zonestats_index, zonestat_values, 1095 ISC_STATSDUMP_VERBOSE); 1096 if (result != ISC_R_SUCCESS) 1097 goto error; 1098 1099 TRY0(xmlTextWriterEndElement(writer)); /* /zonestat */ 1100 1101 /* 1102 * Most of the common resolver statistics entries are 0, so 1103 * we don't use the verbose dump here. 1104 */ 1105 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1106 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1107 ISC_XMLCHAR "resstat")); 1108 result = dump_counters(server->resolverstats, 1109 isc_statsformat_xml, writer, 1110 NULL, resstats_xmldesc, 1111 dns_resstatscounter_max, 1112 resstats_index, resstat_values, 0); 1113 if (result != ISC_R_SUCCESS) 1114 goto error; 1115 TRY0(xmlTextWriterEndElement(writer)); /* resstat */ 1116 } 1117 1118 if ((flags & STATS_XML_NET) != 0) { 1119 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1120 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1121 ISC_XMLCHAR "sockstat")); 1122 1123 result = dump_counters(server->sockstats, isc_statsformat_xml, 1124 writer, NULL, sockstats_xmldesc, 1125 isc_sockstatscounter_max, 1126 sockstats_index, sockstat_values, 1127 ISC_STATSDUMP_VERBOSE); 1128 if (result != ISC_R_SUCCESS) 1129 goto error; 1130 1131 TRY0(xmlTextWriterEndElement(writer)); /* /sockstat */ 1132 } 1133 TRY0(xmlTextWriterEndElement(writer)); /* /server */ 1134 1135 /* 1136 * Render views. For each view we know of, call its 1137 * rendering function. 1138 */ 1139 view = ISC_LIST_HEAD(server->viewlist); 1140 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "views")); 1141 while (view != NULL && 1142 ((flags & (STATS_XML_SERVER | STATS_XML_ZONES)) != 0)) 1143 { 1144 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "view")); 1145 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", 1146 ISC_XMLCHAR view->name)); 1147 1148 if ((flags & STATS_XML_ZONES) != 0) { 1149 TRY0(xmlTextWriterStartElement(writer, 1150 ISC_XMLCHAR "zones")); 1151 result = dns_zt_apply(view->zonetable, ISC_TRUE, 1152 zone_xmlrender, writer); 1153 if (result != ISC_R_SUCCESS) 1154 goto error; 1155 TRY0(xmlTextWriterEndElement(writer)); /* /zones */ 1156 } 1157 1158 if ((flags & STATS_XML_SERVER) == 0) { 1159 TRY0(xmlTextWriterEndElement(writer)); /* /view */ 1160 view = ISC_LIST_NEXT(view, link); 1161 continue; 1162 } 1163 1164 TRY0(xmlTextWriterStartElement(writer, 1165 ISC_XMLCHAR "counters")); 1166 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1167 ISC_XMLCHAR "resqtype")); 1168 1169 if (view->resquerystats != NULL) { 1170 dumparg.result = ISC_R_SUCCESS; 1171 dns_rdatatypestats_dump(view->resquerystats, 1172 rdtypestat_dump, &dumparg, 0); 1173 if (dumparg.result != ISC_R_SUCCESS) 1174 goto error; 1175 } 1176 TRY0(xmlTextWriterEndElement(writer)); 1177 1178 /* <resstats> */ 1179 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1180 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1181 ISC_XMLCHAR "resstats")); 1182 if (view->resstats != NULL) { 1183 result = dump_counters(view->resstats, 1184 isc_statsformat_xml, writer, 1185 NULL, resstats_xmldesc, 1186 dns_resstatscounter_max, 1187 resstats_index, resstat_values, 1188 ISC_STATSDUMP_VERBOSE); 1189 if (result != ISC_R_SUCCESS) 1190 goto error; 1191 } 1192 TRY0(xmlTextWriterEndElement(writer)); /* </resstats> */ 1193 1194 cacherrstats = dns_db_getrrsetstats(view->cachedb); 1195 if (cacherrstats != NULL) { 1196 TRY0(xmlTextWriterStartElement(writer, 1197 ISC_XMLCHAR "cache")); 1198 TRY0(xmlTextWriterWriteAttribute(writer, 1199 ISC_XMLCHAR "name", 1200 ISC_XMLCHAR 1201 dns_cache_getname(view->cache))); 1202 dumparg.result = ISC_R_SUCCESS; 1203 dns_rdatasetstats_dump(cacherrstats, rdatasetstats_dump, 1204 &dumparg, 0); 1205 if (dumparg.result != ISC_R_SUCCESS) 1206 goto error; 1207 TRY0(xmlTextWriterEndElement(writer)); /* cache */ 1208 } 1209 1210 /* <adbstats> */ 1211 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1212 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1213 ISC_XMLCHAR "adbstat")); 1214 if (view->adbstats != NULL) { 1215 result = dump_counters(view->adbstats, 1216 isc_statsformat_xml, writer, 1217 NULL, adbstats_xmldesc, 1218 dns_adbstats_max, 1219 adbstats_index, adbstat_values, 1220 ISC_STATSDUMP_VERBOSE); 1221 if (result != ISC_R_SUCCESS) 1222 goto error; 1223 } 1224 TRY0(xmlTextWriterEndElement(writer)); /* </adbstats> */ 1225 1226 /* <cachestats> */ 1227 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1228 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1229 ISC_XMLCHAR "cachestats")); 1230 TRY0(dns_cache_renderxml(view->cache, writer)); 1231 TRY0(xmlTextWriterEndElement(writer)); /* </cachestats> */ 1232 1233 TRY0(xmlTextWriterEndElement(writer)); /* view */ 1234 1235 view = ISC_LIST_NEXT(view, link); 1236 } 1237 TRY0(xmlTextWriterEndElement(writer)); /* /views */ 1238 1239 if ((flags & STATS_XML_NET) != 0) { 1240 TRY0(xmlTextWriterStartElement(writer, 1241 ISC_XMLCHAR "socketmgr")); 1242 TRY0(isc_socketmgr_renderxml(ns_g_socketmgr, writer)); 1243 TRY0(xmlTextWriterEndElement(writer)); /* /socketmgr */ 1244 } 1245 1246 if ((flags & STATS_XML_TASKS) != 0) { 1247 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "taskmgr")); 1248 TRY0(isc_taskmgr_renderxml(ns_g_taskmgr, writer)); 1249 TRY0(xmlTextWriterEndElement(writer)); /* /taskmgr */ 1250 } 1251 1252 if ((flags & STATS_XML_MEM) != 0) { 1253 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "memory")); 1254 TRY0(isc_mem_renderxml(writer)); 1255 TRY0(xmlTextWriterEndElement(writer)); /* /memory */ 1256 } 1257 1258 TRY0(xmlTextWriterEndElement(writer)); /* /statistics */ 1259 TRY0(xmlTextWriterEndDocument(writer)); 1260 1261 xmlFreeTextWriter(writer); 1262 1263 xmlDocDumpFormatMemoryEnc(doc, buf, buflen, "UTF-8", 0); 1264 if (*buf == NULL) 1265 goto error; 1266 xmlFreeDoc(doc); 1267 return (ISC_R_SUCCESS); 1268 1269 error: 1270 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 1271 ISC_LOG_ERROR, "failed generating XML response"); 1272 if (writer != NULL) 1273 xmlFreeTextWriter(writer); 1274 if (doc != NULL) 1275 xmlFreeDoc(doc); 1276 return (ISC_R_FAILURE); 1277 } 1278 1279 static void 1280 wrap_xmlfree(isc_buffer_t *buffer, void *arg) { 1281 UNUSED(arg); 1282 1283 xmlFree(isc_buffer_base(buffer)); 1284 } 1285 1286 static isc_result_t 1287 render_xml(isc_uint32_t flags, const char *url, isc_httpdurl_t *urlinfo, 1288 const char *querystring, const char *headers, void *arg, 1289 unsigned int *retcode, const char **retmsg, 1290 const char **mimetype, isc_buffer_t *b, 1291 isc_httpdfree_t **freecb, void **freecb_args) 1292 { 1293 unsigned char *msg = NULL; 1294 int msglen; 1295 ns_server_t *server = arg; 1296 isc_result_t result; 1297 1298 UNUSED(url); 1299 UNUSED(urlinfo); 1300 UNUSED(headers); 1301 UNUSED(querystring); 1302 1303 result = generatexml(server, flags, &msglen, &msg); 1304 1305 if (result == ISC_R_SUCCESS) { 1306 *retcode = 200; 1307 *retmsg = "OK"; 1308 *mimetype = "text/xml"; 1309 isc_buffer_reinit(b, msg, msglen); 1310 isc_buffer_add(b, msglen); 1311 *freecb = wrap_xmlfree; 1312 *freecb_args = NULL; 1313 } else 1314 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1315 NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 1316 "failed at rendering XML()"); 1317 1318 return (result); 1319 } 1320 1321 static isc_result_t 1322 render_xml_all(const char *url, isc_httpdurl_t *urlinfo, 1323 const char *querystring, const char *headers, void *arg, 1324 unsigned int *retcode, const char **retmsg, 1325 const char **mimetype, isc_buffer_t *b, 1326 isc_httpdfree_t **freecb, void **freecb_args) 1327 { 1328 return (render_xml(STATS_XML_ALL, url, urlinfo, 1329 querystring, headers, arg, 1330 retcode, retmsg, mimetype, b, 1331 freecb, freecb_args)); 1332 } 1333 1334 static isc_result_t 1335 render_xml_status(const char *url, isc_httpdurl_t *urlinfo, 1336 const char *querystring, const char *headers, void *arg, 1337 unsigned int *retcode, const char **retmsg, 1338 const char **mimetype, isc_buffer_t *b, 1339 isc_httpdfree_t **freecb, void **freecb_args) 1340 { 1341 return (render_xml(STATS_XML_STATUS, url, urlinfo, 1342 querystring, headers, arg, 1343 retcode, retmsg, mimetype, b, 1344 freecb, freecb_args)); 1345 } 1346 1347 static isc_result_t 1348 render_xml_server(const char *url, isc_httpdurl_t *urlinfo, 1349 const char *querystring, const char *headers, void *arg, 1350 unsigned int *retcode, const char **retmsg, 1351 const char **mimetype, isc_buffer_t *b, 1352 isc_httpdfree_t **freecb, void **freecb_args) 1353 { 1354 return (render_xml(STATS_XML_SERVER, url, urlinfo, 1355 querystring, headers, arg, 1356 retcode, retmsg, mimetype, b, 1357 freecb, freecb_args)); 1358 } 1359 1360 static isc_result_t 1361 render_xml_zones(const char *url, isc_httpdurl_t *urlinfo, 1362 const char *querystring, const char *headers, void *arg, 1363 unsigned int *retcode, const char **retmsg, 1364 const char **mimetype, isc_buffer_t *b, 1365 isc_httpdfree_t **freecb, void **freecb_args) 1366 { 1367 return (render_xml(STATS_XML_ZONES, url, urlinfo, 1368 querystring, headers, arg, 1369 retcode, retmsg, mimetype, b, 1370 freecb, freecb_args)); 1371 } 1372 1373 static isc_result_t 1374 render_xml_net(const char *url, isc_httpdurl_t *urlinfo, 1375 const char *querystring, const char *headers, void *arg, 1376 unsigned int *retcode, const char **retmsg, 1377 const char **mimetype, isc_buffer_t *b, 1378 isc_httpdfree_t **freecb, void **freecb_args) 1379 { 1380 return (render_xml(STATS_XML_NET, url, urlinfo, 1381 querystring, headers, arg, 1382 retcode, retmsg, mimetype, b, 1383 freecb, freecb_args)); 1384 } 1385 1386 static isc_result_t 1387 render_xml_tasks(const char *url, isc_httpdurl_t *urlinfo, 1388 const char *querystring, const char *headers, void *arg, 1389 unsigned int *retcode, const char **retmsg, 1390 const char **mimetype, isc_buffer_t *b, 1391 isc_httpdfree_t **freecb, void **freecb_args) 1392 { 1393 return (render_xml(STATS_XML_TASKS, url, urlinfo, 1394 querystring, headers, arg, 1395 retcode, retmsg, mimetype, b, 1396 freecb, freecb_args)); 1397 } 1398 1399 static isc_result_t 1400 render_xml_mem(const char *url, isc_httpdurl_t *urlinfo, 1401 const char *querystring, const char *headers, void *arg, 1402 unsigned int *retcode, const char **retmsg, 1403 const char **mimetype, isc_buffer_t *b, 1404 isc_httpdfree_t **freecb, void **freecb_args) 1405 { 1406 return (render_xml(STATS_XML_MEM, url, urlinfo, 1407 querystring, headers, arg, 1408 retcode, retmsg, mimetype, b, 1409 freecb, freecb_args)); 1410 } 1411 1412 #endif /* HAVE_LIBXML2 */ 1413 1414 #ifdef HAVE_JSON 1415 /* 1416 * Which statistics to include when rendering to JSON 1417 */ 1418 #define STATS_JSON_STATUS 0x00 /* display only common statistics */ 1419 #define STATS_JSON_SERVER 0x01 1420 #define STATS_JSON_ZONES 0x02 1421 #define STATS_JSON_TASKS 0x04 1422 #define STATS_JSON_NET 0x08 1423 #define STATS_JSON_MEM 0x10 1424 #define STATS_JSON_ALL 0xff 1425 1426 #define CHECKMEM(m) do { \ 1427 if (m == NULL) { \ 1428 result = ISC_R_NOMEMORY;\ 1429 goto error;\ 1430 } \ 1431 } while(/*CONSTCOND*/0) 1432 1433 static void 1434 wrap_jsonfree(isc_buffer_t *buffer, void *arg) { 1435 json_object_put(isc_buffer_base(buffer)); 1436 if (arg != NULL) 1437 json_object_put((json_object *) arg); 1438 } 1439 1440 static json_object * 1441 addzone(char *name, char *class, isc_uint32_t serial) { 1442 json_object *node = json_object_new_object(); 1443 1444 if (node == NULL) 1445 return (NULL); 1446 1447 json_object_object_add(node, "name", json_object_new_string(name)); 1448 json_object_object_add(node, "class", json_object_new_string(class)); 1449 json_object_object_add(node, "serial", json_object_new_int64(serial)); 1450 return (node); 1451 } 1452 1453 static isc_result_t 1454 zone_jsonrender(dns_zone_t *zone, void *arg) { 1455 isc_result_t result = ISC_R_SUCCESS; 1456 char buf[1024 + 32]; /* sufficiently large for zone name and class */ 1457 char class[1024 + 32]; /* sufficiently large for zone name and class */ 1458 char *zone_name_only = NULL; 1459 char *class_only = NULL; 1460 dns_rdataclass_t rdclass; 1461 isc_uint32_t serial; 1462 isc_uint64_t nsstat_values[dns_nsstatscounter_max]; 1463 isc_stats_t *zonestats; 1464 dns_stats_t *rcvquerystats; 1465 json_object *zonearray = (json_object *) arg; 1466 json_object *zoneobj = NULL; 1467 dns_zonestat_level_t statlevel; 1468 1469 statlevel = dns_zone_getstatlevel(zone); 1470 if (statlevel == dns_zonestat_none) 1471 return (ISC_R_SUCCESS); 1472 1473 dns_zone_name(zone, buf, sizeof(buf)); 1474 zone_name_only = strtok(buf, "/"); 1475 if(zone_name_only == NULL) 1476 zone_name_only = buf; 1477 1478 rdclass = dns_zone_getclass(zone); 1479 dns_rdataclass_format(rdclass, class, sizeof(class)); 1480 class_only = class; 1481 1482 if (dns_zone_getserial2(zone, &serial) != ISC_R_SUCCESS) 1483 serial = -1; 1484 1485 zoneobj = addzone(zone_name_only, class_only, serial); 1486 if (zoneobj == NULL) 1487 return (ISC_R_NOMEMORY); 1488 1489 zonestats = dns_zone_getrequeststats(zone); 1490 rcvquerystats = dns_zone_getrcvquerystats(zone); 1491 if (statlevel == dns_zonestat_full && zonestats != NULL) { 1492 json_object *counters = json_object_new_object(); 1493 if (counters == NULL) { 1494 result = ISC_R_NOMEMORY; 1495 goto error; 1496 } 1497 1498 result = dump_counters(zonestats, isc_statsformat_json, 1499 counters, NULL, nsstats_xmldesc, 1500 dns_nsstatscounter_max, nsstats_index, 1501 nsstat_values, 0); 1502 if (result != ISC_R_SUCCESS) { 1503 json_object_put(counters); 1504 goto error; 1505 } 1506 1507 if (json_object_get_object(counters)->count != 0) 1508 json_object_object_add(zoneobj, "rcodes", counters); 1509 else 1510 json_object_put(counters); 1511 } 1512 1513 if (statlevel == dns_zonestat_full && rcvquerystats != NULL) { 1514 stats_dumparg_t dumparg; 1515 json_object *counters = json_object_new_object(); 1516 CHECKMEM(counters); 1517 1518 dumparg.type = isc_statsformat_json; 1519 dumparg.arg = counters; 1520 dumparg.result = ISC_R_SUCCESS; 1521 dns_rdatatypestats_dump(rcvquerystats, rdtypestat_dump, 1522 &dumparg, 0); 1523 if (dumparg.result != ISC_R_SUCCESS) { 1524 json_object_put(counters); 1525 goto error; 1526 } 1527 1528 if (json_object_get_object(counters)->count != 0) 1529 json_object_object_add(zoneobj, "qtypes", counters); 1530 else 1531 json_object_put(counters); 1532 } 1533 1534 json_object_array_add(zonearray, zoneobj); 1535 zoneobj = NULL; 1536 result = ISC_R_SUCCESS; 1537 1538 error: 1539 if (zoneobj != NULL) 1540 json_object_put(zoneobj); 1541 return (result); 1542 } 1543 1544 static isc_result_t 1545 generatejson(ns_server_t *server, size_t *msglen, 1546 const char **msg, json_object **rootp, isc_uint32_t flags) 1547 { 1548 dns_view_t *view; 1549 isc_result_t result = ISC_R_SUCCESS; 1550 json_object *bindstats, *viewlist, *counters, *obj; 1551 isc_uint64_t nsstat_values[dns_nsstatscounter_max]; 1552 isc_uint64_t resstat_values[dns_resstatscounter_max]; 1553 isc_uint64_t adbstat_values[dns_adbstats_max]; 1554 isc_uint64_t zonestat_values[dns_zonestatscounter_max]; 1555 isc_uint64_t sockstat_values[isc_sockstatscounter_max]; 1556 stats_dumparg_t dumparg; 1557 char boottime[sizeof "yyyy-mm-ddThh:mm:ssZ"]; 1558 char configtime[sizeof "yyyy-mm-ddThh:mm:ssZ"]; 1559 char nowstr[sizeof "yyyy-mm-ddThh:mm:ssZ"]; 1560 isc_time_t now; 1561 1562 REQUIRE(msglen != NULL); 1563 REQUIRE(msg != NULL && *msg == NULL); 1564 REQUIRE(rootp == NULL || *rootp == NULL); 1565 1566 bindstats = json_object_new_object(); 1567 if (bindstats == NULL) 1568 return (ISC_R_NOMEMORY); 1569 1570 /* 1571 * These statistics are included no matter which URL we use. 1572 */ 1573 obj = json_object_new_string("1.0"); 1574 CHECKMEM(obj); 1575 json_object_object_add(bindstats, "json-stats-version", obj); 1576 1577 isc_time_now(&now); 1578 isc_time_formatISO8601(&ns_g_boottime, 1579 boottime, sizeof(boottime)); 1580 isc_time_formatISO8601(&ns_g_configtime, 1581 configtime, sizeof configtime); 1582 isc_time_formatISO8601(&now, nowstr, sizeof(nowstr)); 1583 1584 obj = json_object_new_string(boottime); 1585 CHECKMEM(obj); 1586 json_object_object_add(bindstats, "boot-time", obj); 1587 1588 obj = json_object_new_string(configtime); 1589 CHECKMEM(obj); 1590 json_object_object_add(bindstats, "config-time", obj); 1591 1592 obj = json_object_new_string(nowstr); 1593 CHECKMEM(obj); 1594 json_object_object_add(bindstats, "current-time", obj); 1595 1596 if ((flags & STATS_JSON_SERVER) != 0) { 1597 /* OPCODE counters */ 1598 counters = json_object_new_object(); 1599 1600 dumparg.result = ISC_R_SUCCESS; 1601 dumparg.type = isc_statsformat_json; 1602 dumparg.arg = counters; 1603 1604 dns_opcodestats_dump(server->opcodestats, 1605 opcodestat_dump, &dumparg, 1606 ISC_STATSDUMP_VERBOSE); 1607 if (dumparg.result != ISC_R_SUCCESS) { 1608 json_object_put(counters); 1609 goto error; 1610 } 1611 1612 if (json_object_get_object(counters)->count != 0) 1613 json_object_object_add(bindstats, "opcodes", counters); 1614 else 1615 json_object_put(counters); 1616 1617 /* QTYPE counters */ 1618 counters = json_object_new_object(); 1619 1620 dumparg.result = ISC_R_SUCCESS; 1621 dumparg.arg = counters; 1622 1623 dns_rdatatypestats_dump(server->rcvquerystats, 1624 rdtypestat_dump, &dumparg, 0); 1625 if (dumparg.result != ISC_R_SUCCESS) { 1626 json_object_put(counters); 1627 goto error; 1628 } 1629 1630 if (json_object_get_object(counters)->count != 0) 1631 json_object_object_add(bindstats, "qtypes", counters); 1632 else 1633 json_object_put(counters); 1634 1635 /* server stat counters */ 1636 counters = json_object_new_object(); 1637 1638 dumparg.result = ISC_R_SUCCESS; 1639 dumparg.arg = counters; 1640 1641 result = dump_counters(server->nsstats, isc_statsformat_json, 1642 counters, NULL, nsstats_xmldesc, 1643 dns_nsstatscounter_max, 1644 nsstats_index, nsstat_values, 0); 1645 if (result != ISC_R_SUCCESS) { 1646 json_object_put(counters); 1647 goto error; 1648 } 1649 1650 if (json_object_get_object(counters)->count != 0) 1651 json_object_object_add(bindstats, "nsstats", counters); 1652 else 1653 json_object_put(counters); 1654 1655 /* zone stat counters */ 1656 counters = json_object_new_object(); 1657 1658 dumparg.result = ISC_R_SUCCESS; 1659 dumparg.arg = counters; 1660 1661 result = dump_counters(server->zonestats, isc_statsformat_json, 1662 counters, NULL, zonestats_xmldesc, 1663 dns_zonestatscounter_max, 1664 zonestats_index, zonestat_values, 0); 1665 if (result != ISC_R_SUCCESS) { 1666 json_object_put(counters); 1667 goto error; 1668 } 1669 1670 if (json_object_get_object(counters)->count != 0) 1671 json_object_object_add(bindstats, "zonestats", 1672 counters); 1673 else 1674 json_object_put(counters); 1675 1676 /* resolver stat counters */ 1677 counters = json_object_new_object(); 1678 1679 dumparg.result = ISC_R_SUCCESS; 1680 dumparg.arg = counters; 1681 1682 result = dump_counters(server->resolverstats, 1683 isc_statsformat_json, counters, NULL, 1684 resstats_xmldesc, 1685 dns_resstatscounter_max, 1686 resstats_index, resstat_values, 0); 1687 if (result != ISC_R_SUCCESS) { 1688 json_object_put(counters); 1689 goto error; 1690 } 1691 1692 if (json_object_get_object(counters)->count != 0) 1693 json_object_object_add(bindstats, "resstats", counters); 1694 else 1695 json_object_put(counters); 1696 } 1697 1698 if ((flags & (STATS_JSON_ZONES | STATS_JSON_SERVER)) != 0) { 1699 viewlist = json_object_new_object(); 1700 CHECKMEM(viewlist); 1701 1702 json_object_object_add(bindstats, "views", viewlist); 1703 1704 view = ISC_LIST_HEAD(server->viewlist); 1705 while (view != NULL) { 1706 json_object *za, *v = json_object_new_object(); 1707 1708 CHECKMEM(v); 1709 json_object_object_add(viewlist, view->name, v); 1710 1711 za = json_object_new_array(); 1712 CHECKMEM(za); 1713 1714 if ((flags & STATS_JSON_ZONES) != 0) { 1715 result = dns_zt_apply(view->zonetable, ISC_TRUE, 1716 zone_jsonrender, za); 1717 if (result != ISC_R_SUCCESS) { 1718 goto error; 1719 } 1720 } 1721 1722 if (json_object_array_length(za) != 0) 1723 json_object_object_add(v, "zones", za); 1724 else 1725 json_object_put(za); 1726 1727 if ((flags & STATS_JSON_SERVER) != 0) { 1728 json_object *res; 1729 dns_stats_t *dstats; 1730 isc_stats_t *istats; 1731 1732 res = json_object_new_object(); 1733 CHECKMEM(res); 1734 json_object_object_add(v, "resolver", res); 1735 1736 istats = view->resstats; 1737 if (istats != NULL) { 1738 counters = json_object_new_object(); 1739 CHECKMEM(counters); 1740 1741 result = dump_counters(istats, 1742 isc_statsformat_json, 1743 counters, NULL, 1744 resstats_xmldesc, 1745 dns_resstatscounter_max, 1746 resstats_index, 1747 resstat_values, 0); 1748 if (result != ISC_R_SUCCESS) { 1749 json_object_put(counters); 1750 result = dumparg.result; 1751 goto error; 1752 } 1753 1754 json_object_object_add(res, "stats", 1755 counters); 1756 } 1757 1758 dstats = view->resquerystats; 1759 if (dstats != NULL) { 1760 counters = json_object_new_object(); 1761 CHECKMEM(counters); 1762 1763 dumparg.arg = counters; 1764 dumparg.result = ISC_R_SUCCESS; 1765 dns_rdatatypestats_dump(dstats, 1766 rdtypestat_dump, 1767 &dumparg, 0); 1768 if (dumparg.result != ISC_R_SUCCESS) { 1769 json_object_put(counters); 1770 result = dumparg.result; 1771 goto error; 1772 } 1773 1774 json_object_object_add(res, "qtypes", 1775 counters); 1776 } 1777 1778 dstats = dns_db_getrrsetstats(view->cachedb); 1779 if (dstats != NULL) { 1780 counters = json_object_new_object(); 1781 CHECKMEM(counters); 1782 1783 dumparg.arg = counters; 1784 dumparg.result = ISC_R_SUCCESS; 1785 dns_rdatasetstats_dump(dstats, 1786 rdatasetstats_dump, 1787 &dumparg, 0); 1788 if (dumparg.result != ISC_R_SUCCESS) { 1789 json_object_put(counters); 1790 result = dumparg.result; 1791 goto error; 1792 } 1793 1794 json_object_object_add(res, 1795 "cache", 1796 counters); 1797 } 1798 1799 counters = json_object_new_object(); 1800 CHECKMEM(counters); 1801 1802 result = dns_cache_renderjson(view->cache, 1803 counters); 1804 if (result != ISC_R_SUCCESS) { 1805 json_object_put(counters); 1806 goto error; 1807 } 1808 1809 json_object_object_add(res, "cachestats", 1810 counters); 1811 1812 istats = view->adbstats; 1813 if (istats != NULL) { 1814 counters = json_object_new_object(); 1815 CHECKMEM(counters); 1816 1817 result = dump_counters(istats, 1818 isc_statsformat_json, 1819 counters, NULL, 1820 adbstats_xmldesc, 1821 dns_adbstats_max, 1822 adbstats_index, 1823 adbstat_values, 0); 1824 if (result != ISC_R_SUCCESS) { 1825 json_object_put(counters); 1826 result = dumparg.result; 1827 goto error; 1828 } 1829 1830 json_object_object_add(res, "adb", 1831 counters); 1832 } 1833 } 1834 1835 view = ISC_LIST_NEXT(view, link); 1836 } 1837 } 1838 1839 if ((flags & STATS_JSON_NET) != 0) { 1840 /* socket stat counters */ 1841 json_object *sockets; 1842 counters = json_object_new_object(); 1843 1844 dumparg.result = ISC_R_SUCCESS; 1845 dumparg.arg = counters; 1846 1847 result = dump_counters(server->sockstats, 1848 isc_statsformat_json, counters, 1849 NULL, sockstats_xmldesc, 1850 isc_sockstatscounter_max, 1851 sockstats_index, sockstat_values, 0); 1852 if (result != ISC_R_SUCCESS) { 1853 json_object_put(counters); 1854 goto error; 1855 } 1856 1857 if (json_object_get_object(counters)->count != 0) 1858 json_object_object_add(bindstats, "sockstats", 1859 counters); 1860 else 1861 json_object_put(counters); 1862 1863 sockets = json_object_new_object(); 1864 CHECKMEM(sockets); 1865 1866 result = isc_socketmgr_renderjson(ns_g_socketmgr, sockets); 1867 if (result != ISC_R_SUCCESS) { 1868 json_object_put(sockets); 1869 goto error; 1870 } 1871 1872 json_object_object_add(bindstats, "socketmgr", sockets); 1873 } 1874 1875 if ((flags & STATS_JSON_TASKS) != 0) { 1876 json_object *tasks = json_object_new_object(); 1877 CHECKMEM(tasks); 1878 1879 result = isc_taskmgr_renderjson(ns_g_taskmgr, tasks); 1880 if (result != ISC_R_SUCCESS) { 1881 json_object_put(tasks); 1882 goto error; 1883 } 1884 1885 json_object_object_add(bindstats, "taskmgr", tasks); 1886 } 1887 1888 if ((flags & STATS_JSON_MEM) != 0) { 1889 json_object *memory = json_object_new_object(); 1890 CHECKMEM(memory); 1891 1892 result = isc_mem_renderjson(memory); 1893 if (result != ISC_R_SUCCESS) { 1894 json_object_put(memory); 1895 goto error; 1896 } 1897 1898 json_object_object_add(bindstats, "memory", memory); 1899 } 1900 1901 *msg = json_object_to_json_string_ext(bindstats, 1902 JSON_C_TO_STRING_PRETTY); 1903 *msglen = strlen(*msg); 1904 1905 if (rootp != NULL) { 1906 *rootp = bindstats; 1907 bindstats = NULL; 1908 } 1909 1910 result = ISC_R_SUCCESS; 1911 1912 error: 1913 if (bindstats != NULL) 1914 json_object_put(bindstats); 1915 1916 return (result); 1917 } 1918 1919 static isc_result_t 1920 render_json(isc_uint32_t flags, 1921 const char *url, isc_httpdurl_t *urlinfo, 1922 const char *querystring, const char *headers, 1923 void *arg, unsigned int *retcode, const char **retmsg, 1924 const char **mimetype, isc_buffer_t *b, 1925 isc_httpdfree_t **freecb, void **freecb_args) 1926 { 1927 isc_result_t result; 1928 json_object *bindstats = NULL; 1929 ns_server_t *server = arg; 1930 const char *msg = NULL; 1931 size_t msglen; 1932 char *p; 1933 1934 UNUSED(url); 1935 UNUSED(urlinfo); 1936 UNUSED(headers); 1937 UNUSED(querystring); 1938 1939 result = generatejson(server, &msglen, &msg, &bindstats, flags); 1940 if (result == ISC_R_SUCCESS) { 1941 *retcode = 200; 1942 *retmsg = "OK"; 1943 *mimetype = "application/json"; 1944 DE_CONST(msg, p); 1945 isc_buffer_reinit(b, p, msglen); 1946 isc_buffer_add(b, msglen); 1947 *freecb = wrap_jsonfree; 1948 *freecb_args = bindstats; 1949 } else 1950 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1951 NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 1952 "failed at rendering JSON()"); 1953 1954 return (result); 1955 } 1956 1957 static isc_result_t 1958 render_json_all(const char *url, isc_httpdurl_t *urlinfo, 1959 const char *querystring, const char *headers, void *arg, 1960 unsigned int *retcode, const char **retmsg, 1961 const char **mimetype, isc_buffer_t *b, 1962 isc_httpdfree_t **freecb, void **freecb_args) 1963 { 1964 return (render_json(STATS_JSON_ALL, url, urlinfo, 1965 querystring, headers, arg, 1966 retcode, retmsg, mimetype, b, 1967 freecb, freecb_args)); 1968 } 1969 1970 static isc_result_t 1971 render_json_status(const char *url, isc_httpdurl_t *urlinfo, 1972 const char *querystring, const char *headers, void *arg, 1973 unsigned int *retcode, const char **retmsg, 1974 const char **mimetype, isc_buffer_t *b, 1975 isc_httpdfree_t **freecb, void **freecb_args) 1976 { 1977 return (render_json(STATS_JSON_STATUS, url, urlinfo, 1978 querystring, headers, arg, 1979 retcode, retmsg, mimetype, b, 1980 freecb, freecb_args)); 1981 } 1982 1983 static isc_result_t 1984 render_json_server(const char *url, isc_httpdurl_t *urlinfo, 1985 const char *querystring, const char *headers, void *arg, 1986 unsigned int *retcode, const char **retmsg, 1987 const char **mimetype, isc_buffer_t *b, 1988 isc_httpdfree_t **freecb, void **freecb_args) 1989 { 1990 return (render_json(STATS_JSON_SERVER, url, urlinfo, 1991 querystring, headers, arg, 1992 retcode, retmsg, mimetype, b, 1993 freecb, freecb_args)); 1994 } 1995 1996 static isc_result_t 1997 render_json_zones(const char *url, isc_httpdurl_t *urlinfo, 1998 const char *querystring, const char *headers, void *arg, 1999 unsigned int *retcode, const char **retmsg, 2000 const char **mimetype, isc_buffer_t *b, 2001 isc_httpdfree_t **freecb, void **freecb_args) 2002 { 2003 return (render_json(STATS_JSON_ZONES, url, urlinfo, 2004 querystring, headers, arg, 2005 retcode, retmsg, mimetype, b, 2006 freecb, freecb_args)); 2007 } 2008 static isc_result_t 2009 render_json_mem(const char *url, isc_httpdurl_t *urlinfo, 2010 const char *querystring, const char *headers, void *arg, 2011 unsigned int *retcode, const char **retmsg, 2012 const char **mimetype, isc_buffer_t *b, 2013 isc_httpdfree_t **freecb, void **freecb_args) 2014 { 2015 return (render_json(STATS_JSON_MEM, url, urlinfo, 2016 querystring, headers, arg, 2017 retcode, retmsg, mimetype, b, 2018 freecb, freecb_args)); 2019 } 2020 2021 static isc_result_t 2022 render_json_tasks(const char *url, isc_httpdurl_t *urlinfo, 2023 const char *querystring, const char *headers, void *arg, 2024 unsigned int *retcode, const char **retmsg, 2025 const char **mimetype, isc_buffer_t *b, 2026 isc_httpdfree_t **freecb, void **freecb_args) 2027 { 2028 return (render_json(STATS_JSON_TASKS, url, urlinfo, 2029 querystring, headers, arg, 2030 retcode, retmsg, mimetype, b, 2031 freecb, freecb_args)); 2032 } 2033 2034 static isc_result_t 2035 render_json_net(const char *url, isc_httpdurl_t *urlinfo, 2036 const char *querystring, const char *headers, void *arg, 2037 unsigned int *retcode, const char **retmsg, 2038 const char **mimetype, isc_buffer_t *b, 2039 isc_httpdfree_t **freecb, void **freecb_args) 2040 { 2041 return (render_json(STATS_JSON_NET, url, urlinfo, 2042 querystring, headers, arg, 2043 retcode, retmsg, mimetype, b, 2044 freecb, freecb_args)); 2045 } 2046 #endif /* HAVE_JSON */ 2047 2048 static isc_result_t 2049 render_xsl(const char *url, isc_httpdurl_t *urlinfo, 2050 const char *querystring, const char *headers, 2051 void *args, unsigned int *retcode, const char **retmsg, 2052 const char **mimetype, isc_buffer_t *b, 2053 isc_httpdfree_t **freecb, void **freecb_args) 2054 { 2055 isc_result_t result; 2056 2057 UNUSED(url); 2058 UNUSED(querystring); 2059 UNUSED(args); 2060 2061 *freecb = NULL; 2062 *freecb_args = NULL; 2063 *mimetype = "text/xslt+xml"; 2064 2065 if (urlinfo->isstatic) { 2066 isc_time_t when; 2067 char *p = strcasestr(headers, "If-Modified-Since: "); 2068 2069 if (p != NULL) { 2070 time_t t1, t2; 2071 p += strlen("If-Modified-Since: "); 2072 result = isc_time_parsehttptimestamp(p, &when); 2073 if (result != ISC_R_SUCCESS) 2074 goto send; 2075 2076 result = isc_time_secondsastimet(&when, &t1); 2077 if (result != ISC_R_SUCCESS) 2078 goto send; 2079 2080 result = isc_time_secondsastimet(&urlinfo->loadtime, 2081 &t2); 2082 if (result != ISC_R_SUCCESS) 2083 goto send; 2084 2085 if (t1 < t2) 2086 goto send; 2087 2088 *retcode = 304; 2089 *retmsg = "Not modified"; 2090 return (ISC_R_SUCCESS); 2091 } 2092 } 2093 2094 send: 2095 *retcode = 200; 2096 *retmsg = "OK"; 2097 isc_buffer_reinit(b, xslmsg, strlen(xslmsg)); 2098 isc_buffer_add(b, strlen(xslmsg)); 2099 2100 return (ISC_R_SUCCESS); 2101 } 2102 2103 static void 2104 shutdown_listener(ns_statschannel_t *listener) { 2105 char socktext[ISC_SOCKADDR_FORMATSIZE]; 2106 isc_sockaddr_format(&listener->address, socktext, sizeof(socktext)); 2107 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 2108 ISC_LOG_NOTICE, "stopping statistics channel on %s", 2109 socktext); 2110 2111 isc_httpdmgr_shutdown(&listener->httpdmgr); 2112 } 2113 2114 static isc_boolean_t 2115 client_ok(const isc_sockaddr_t *fromaddr, void *arg) { 2116 ns_statschannel_t *listener = arg; 2117 isc_netaddr_t netaddr; 2118 char socktext[ISC_SOCKADDR_FORMATSIZE]; 2119 int match; 2120 2121 REQUIRE(listener != NULL); 2122 2123 isc_netaddr_fromsockaddr(&netaddr, fromaddr); 2124 2125 LOCK(&listener->lock); 2126 if (dns_acl_match(&netaddr, NULL, listener->acl, &ns_g_server->aclenv, 2127 &match, NULL) == ISC_R_SUCCESS && match > 0) { 2128 UNLOCK(&listener->lock); 2129 return (ISC_TRUE); 2130 } 2131 UNLOCK(&listener->lock); 2132 2133 isc_sockaddr_format(fromaddr, socktext, sizeof(socktext)); 2134 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2135 NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 2136 "rejected statistics connection from %s", socktext); 2137 2138 return (ISC_FALSE); 2139 } 2140 2141 static void 2142 destroy_listener(void *arg) { 2143 ns_statschannel_t *listener = arg; 2144 2145 REQUIRE(listener != NULL); 2146 REQUIRE(!ISC_LINK_LINKED(listener, link)); 2147 2148 /* We don't have to acquire the lock here since it's already unlinked */ 2149 dns_acl_detach(&listener->acl); 2150 2151 DESTROYLOCK(&listener->lock); 2152 isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener)); 2153 } 2154 2155 static isc_result_t 2156 add_listener(ns_server_t *server, ns_statschannel_t **listenerp, 2157 const cfg_obj_t *listen_params, const cfg_obj_t *config, 2158 isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, 2159 const char *socktext) 2160 { 2161 isc_result_t result; 2162 ns_statschannel_t *listener; 2163 isc_task_t *task = NULL; 2164 isc_socket_t *sock = NULL; 2165 const cfg_obj_t *allow; 2166 dns_acl_t *new_acl = NULL; 2167 2168 listener = isc_mem_get(server->mctx, sizeof(*listener)); 2169 if (listener == NULL) 2170 return (ISC_R_NOMEMORY); 2171 2172 listener->httpdmgr = NULL; 2173 listener->address = *addr; 2174 listener->acl = NULL; 2175 listener->mctx = NULL; 2176 ISC_LINK_INIT(listener, link); 2177 2178 result = isc_mutex_init(&listener->lock); 2179 if (result != ISC_R_SUCCESS) { 2180 isc_mem_put(server->mctx, listener, sizeof(*listener)); 2181 return (ISC_R_FAILURE); 2182 } 2183 2184 isc_mem_attach(server->mctx, &listener->mctx); 2185 2186 allow = cfg_tuple_get(listen_params, "allow"); 2187 if (allow != NULL && cfg_obj_islist(allow)) { 2188 result = cfg_acl_fromconfig(allow, config, ns_g_lctx, 2189 aclconfctx, listener->mctx, 0, 2190 &new_acl); 2191 } else 2192 result = dns_acl_any(listener->mctx, &new_acl); 2193 if (result != ISC_R_SUCCESS) 2194 goto cleanup; 2195 dns_acl_attach(new_acl, &listener->acl); 2196 dns_acl_detach(&new_acl); 2197 2198 result = isc_task_create(ns_g_taskmgr, 0, &task); 2199 if (result != ISC_R_SUCCESS) 2200 goto cleanup; 2201 isc_task_setname(task, "statchannel", NULL); 2202 2203 result = isc_socket_create(ns_g_socketmgr, isc_sockaddr_pf(addr), 2204 isc_sockettype_tcp, &sock); 2205 if (result != ISC_R_SUCCESS) 2206 goto cleanup; 2207 isc_socket_setname(sock, "statchannel", NULL); 2208 2209 #ifndef ISC_ALLOW_MAPPED 2210 isc_socket_ipv6only(sock, ISC_TRUE); 2211 #endif 2212 2213 result = isc_socket_bind(sock, addr, ISC_SOCKET_REUSEADDRESS); 2214 if (result != ISC_R_SUCCESS) 2215 goto cleanup; 2216 2217 result = isc_httpdmgr_create(server->mctx, sock, task, client_ok, 2218 destroy_listener, listener, ns_g_timermgr, 2219 &listener->httpdmgr); 2220 if (result != ISC_R_SUCCESS) 2221 goto cleanup; 2222 2223 #ifdef HAVE_LIBXML2 2224 isc_httpdmgr_addurl(listener->httpdmgr, "/", 2225 render_xml_all, server); 2226 isc_httpdmgr_addurl(listener->httpdmgr, "/xml", 2227 render_xml_all, server); 2228 isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3", 2229 render_xml_all, server); 2230 isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/status", 2231 render_xml_status, server); 2232 isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/server", 2233 render_xml_server, server); 2234 isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/zones", 2235 render_xml_zones, server); 2236 isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/net", 2237 render_xml_net, server); 2238 isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/tasks", 2239 render_xml_tasks, server); 2240 isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/mem", 2241 render_xml_mem, server); 2242 #endif 2243 #ifdef HAVE_JSON 2244 isc_httpdmgr_addurl(listener->httpdmgr, "/json", 2245 render_json_all, server); 2246 isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1", 2247 render_json_all, server); 2248 isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/status", 2249 render_json_status, server); 2250 isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/server", 2251 render_json_server, server); 2252 isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/zones", 2253 render_json_zones, server); 2254 isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/tasks", 2255 render_json_tasks, server); 2256 isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/net", 2257 render_json_net, server); 2258 isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/mem", 2259 render_json_mem, server); 2260 #endif 2261 isc_httpdmgr_addurl2(listener->httpdmgr, "/bind9.xsl", ISC_TRUE, 2262 render_xsl, server); 2263 2264 *listenerp = listener; 2265 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2266 NS_LOGMODULE_SERVER, ISC_LOG_NOTICE, 2267 "statistics channel listening on %s", socktext); 2268 2269 cleanup: 2270 if (result != ISC_R_SUCCESS) { 2271 if (listener->acl != NULL) 2272 dns_acl_detach(&listener->acl); 2273 DESTROYLOCK(&listener->lock); 2274 isc_mem_putanddetach(&listener->mctx, listener, 2275 sizeof(*listener)); 2276 } 2277 if (task != NULL) 2278 isc_task_detach(&task); 2279 if (sock != NULL) 2280 isc_socket_detach(&sock); 2281 2282 return (result); 2283 } 2284 2285 static void 2286 update_listener(ns_server_t *server, ns_statschannel_t **listenerp, 2287 const cfg_obj_t *listen_params, const cfg_obj_t *config, 2288 isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, 2289 const char *socktext) 2290 { 2291 ns_statschannel_t *listener; 2292 const cfg_obj_t *allow = NULL; 2293 dns_acl_t *new_acl = NULL; 2294 isc_result_t result = ISC_R_SUCCESS; 2295 2296 for (listener = ISC_LIST_HEAD(server->statschannels); 2297 listener != NULL; 2298 listener = ISC_LIST_NEXT(listener, link)) 2299 if (isc_sockaddr_equal(addr, &listener->address)) 2300 break; 2301 2302 if (listener == NULL) { 2303 *listenerp = NULL; 2304 return; 2305 } 2306 2307 /* 2308 * Now, keep the old access list unless a new one can be made. 2309 */ 2310 allow = cfg_tuple_get(listen_params, "allow"); 2311 if (allow != NULL && cfg_obj_islist(allow)) { 2312 result = cfg_acl_fromconfig(allow, config, ns_g_lctx, 2313 aclconfctx, listener->mctx, 0, 2314 &new_acl); 2315 } else 2316 result = dns_acl_any(listener->mctx, &new_acl); 2317 2318 if (result == ISC_R_SUCCESS) { 2319 LOCK(&listener->lock); 2320 2321 dns_acl_detach(&listener->acl); 2322 dns_acl_attach(new_acl, &listener->acl); 2323 dns_acl_detach(&new_acl); 2324 2325 UNLOCK(&listener->lock); 2326 } else { 2327 cfg_obj_log(listen_params, ns_g_lctx, ISC_LOG_WARNING, 2328 "couldn't install new acl for " 2329 "statistics channel %s: %s", 2330 socktext, isc_result_totext(result)); 2331 } 2332 2333 *listenerp = listener; 2334 } 2335 2336 isc_result_t 2337 ns_statschannels_configure(ns_server_t *server, const cfg_obj_t *config, 2338 cfg_aclconfctx_t *aclconfctx) 2339 { 2340 ns_statschannel_t *listener, *listener_next; 2341 ns_statschannellist_t new_listeners; 2342 const cfg_obj_t *statschannellist = NULL; 2343 const cfg_listelt_t *element, *element2; 2344 char socktext[ISC_SOCKADDR_FORMATSIZE]; 2345 2346 RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS); 2347 2348 ISC_LIST_INIT(new_listeners); 2349 2350 /* 2351 * Get the list of named.conf 'statistics-channels' statements. 2352 */ 2353 (void)cfg_map_get(config, "statistics-channels", &statschannellist); 2354 2355 /* 2356 * Run through the new address/port list, noting sockets that are 2357 * already being listened on and moving them to the new list. 2358 * 2359 * Identifying duplicate addr/port combinations is left to either 2360 * the underlying config code, or to the bind attempt getting an 2361 * address-in-use error. 2362 */ 2363 if (statschannellist != NULL) { 2364 #ifndef EXTENDED_STATS 2365 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2366 NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 2367 "statistics-channels specified but not effective " 2368 "due to missing XML and/or JSON library"); 2369 #endif 2370 2371 for (element = cfg_list_first(statschannellist); 2372 element != NULL; 2373 element = cfg_list_next(element)) { 2374 const cfg_obj_t *statschannel; 2375 const cfg_obj_t *listenercfg = NULL; 2376 2377 statschannel = cfg_listelt_value(element); 2378 (void)cfg_map_get(statschannel, "inet", 2379 &listenercfg); 2380 if (listenercfg == NULL) 2381 continue; 2382 2383 for (element2 = cfg_list_first(listenercfg); 2384 element2 != NULL; 2385 element2 = cfg_list_next(element2)) { 2386 const cfg_obj_t *listen_params; 2387 const cfg_obj_t *obj; 2388 isc_sockaddr_t addr; 2389 2390 listen_params = cfg_listelt_value(element2); 2391 2392 obj = cfg_tuple_get(listen_params, "address"); 2393 addr = *cfg_obj_assockaddr(obj); 2394 if (isc_sockaddr_getport(&addr) == 0) 2395 isc_sockaddr_setport(&addr, 2396 NS_STATSCHANNEL_HTTPPORT); 2397 2398 isc_sockaddr_format(&addr, socktext, 2399 sizeof(socktext)); 2400 2401 isc_log_write(ns_g_lctx, 2402 NS_LOGCATEGORY_GENERAL, 2403 NS_LOGMODULE_SERVER, 2404 ISC_LOG_DEBUG(9), 2405 "processing statistics " 2406 "channel %s", 2407 socktext); 2408 2409 update_listener(server, &listener, 2410 listen_params, config, &addr, 2411 aclconfctx, socktext); 2412 2413 if (listener != NULL) { 2414 /* 2415 * Remove the listener from the old 2416 * list, so it won't be shut down. 2417 */ 2418 ISC_LIST_UNLINK(server->statschannels, 2419 listener, link); 2420 } else { 2421 /* 2422 * This is a new listener. 2423 */ 2424 isc_result_t r; 2425 2426 r = add_listener(server, &listener, 2427 listen_params, config, 2428 &addr, aclconfctx, 2429 socktext); 2430 if (r != ISC_R_SUCCESS) { 2431 cfg_obj_log(listen_params, 2432 ns_g_lctx, 2433 ISC_LOG_WARNING, 2434 "couldn't allocate " 2435 "statistics channel" 2436 " %s: %s", 2437 socktext, 2438 isc_result_totext(r)); 2439 } 2440 } 2441 2442 if (listener != NULL) 2443 ISC_LIST_APPEND(new_listeners, listener, 2444 link); 2445 } 2446 } 2447 } 2448 2449 for (listener = ISC_LIST_HEAD(server->statschannels); 2450 listener != NULL; 2451 listener = listener_next) { 2452 listener_next = ISC_LIST_NEXT(listener, link); 2453 ISC_LIST_UNLINK(server->statschannels, listener, link); 2454 shutdown_listener(listener); 2455 } 2456 2457 ISC_LIST_APPENDLIST(server->statschannels, new_listeners, link); 2458 return (ISC_R_SUCCESS); 2459 } 2460 2461 void 2462 ns_statschannels_shutdown(ns_server_t *server) { 2463 ns_statschannel_t *listener; 2464 2465 while ((listener = ISC_LIST_HEAD(server->statschannels)) != NULL) { 2466 ISC_LIST_UNLINK(server->statschannels, listener, link); 2467 shutdown_listener(listener); 2468 } 2469 } 2470 2471 isc_result_t 2472 ns_stats_dump(ns_server_t *server, FILE *fp) { 2473 isc_stdtime_t now; 2474 isc_result_t result; 2475 dns_view_t *view; 2476 dns_zone_t *zone, *next; 2477 stats_dumparg_t dumparg; 2478 isc_uint64_t nsstat_values[dns_nsstatscounter_max]; 2479 isc_uint64_t resstat_values[dns_resstatscounter_max]; 2480 isc_uint64_t adbstat_values[dns_adbstats_max]; 2481 isc_uint64_t zonestat_values[dns_zonestatscounter_max]; 2482 isc_uint64_t sockstat_values[isc_sockstatscounter_max]; 2483 2484 RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS); 2485 2486 /* Set common fields */ 2487 dumparg.type = isc_statsformat_file; 2488 dumparg.arg = fp; 2489 2490 isc_stdtime_get(&now); 2491 fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now); 2492 2493 fprintf(fp, "++ Incoming Requests ++\n"); 2494 dns_opcodestats_dump(server->opcodestats, opcodestat_dump, &dumparg, 0); 2495 2496 fprintf(fp, "++ Incoming Queries ++\n"); 2497 dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump, 2498 &dumparg, 0); 2499 2500 fprintf(fp, "++ Outgoing Queries ++\n"); 2501 for (view = ISC_LIST_HEAD(server->viewlist); 2502 view != NULL; 2503 view = ISC_LIST_NEXT(view, link)) { 2504 if (view->resquerystats == NULL) 2505 continue; 2506 if (strcmp(view->name, "_default") == 0) 2507 fprintf(fp, "[View: default]\n"); 2508 else 2509 fprintf(fp, "[View: %s]\n", view->name); 2510 dns_rdatatypestats_dump(view->resquerystats, rdtypestat_dump, 2511 &dumparg, 0); 2512 } 2513 2514 fprintf(fp, "++ Name Server Statistics ++\n"); 2515 (void) dump_counters(server->nsstats, isc_statsformat_file, fp, NULL, 2516 nsstats_desc, dns_nsstatscounter_max, 2517 nsstats_index, nsstat_values, 0); 2518 2519 fprintf(fp, "++ Zone Maintenance Statistics ++\n"); 2520 (void) dump_counters(server->zonestats, isc_statsformat_file, fp, NULL, 2521 zonestats_desc, dns_zonestatscounter_max, 2522 zonestats_index, zonestat_values, 0); 2523 2524 fprintf(fp, "++ Resolver Statistics ++\n"); 2525 fprintf(fp, "[Common]\n"); 2526 (void) dump_counters(server->resolverstats, isc_statsformat_file, fp, 2527 NULL, resstats_desc, dns_resstatscounter_max, 2528 resstats_index, resstat_values, 0); 2529 for (view = ISC_LIST_HEAD(server->viewlist); 2530 view != NULL; 2531 view = ISC_LIST_NEXT(view, link)) { 2532 if (view->resstats == NULL) 2533 continue; 2534 if (strcmp(view->name, "_default") == 0) 2535 fprintf(fp, "[View: default]\n"); 2536 else 2537 fprintf(fp, "[View: %s]\n", view->name); 2538 (void) dump_counters(view->resstats, isc_statsformat_file, fp, 2539 NULL, resstats_desc, 2540 dns_resstatscounter_max, resstats_index, 2541 resstat_values, 0); 2542 } 2543 2544 fprintf(fp, "++ Cache Statistics ++\n"); 2545 for (view = ISC_LIST_HEAD(server->viewlist); 2546 view != NULL; 2547 view = ISC_LIST_NEXT(view, link)) { 2548 if (strcmp(view->name, "_default") == 0) 2549 fprintf(fp, "[View: default]\n"); 2550 else 2551 fprintf(fp, "[View: %s (Cache: %s)]\n", view->name, 2552 dns_cache_getname(view->cache)); 2553 /* 2554 * Avoid dumping redundant statistics when the cache is shared. 2555 */ 2556 if (dns_view_iscacheshared(view)) 2557 continue; 2558 dns_cache_dumpstats(view->cache, fp); 2559 } 2560 2561 fprintf(fp, "++ Cache DB RRsets ++\n"); 2562 for (view = ISC_LIST_HEAD(server->viewlist); 2563 view != NULL; 2564 view = ISC_LIST_NEXT(view, link)) { 2565 dns_stats_t *cacherrstats; 2566 2567 cacherrstats = dns_db_getrrsetstats(view->cachedb); 2568 if (cacherrstats == NULL) 2569 continue; 2570 if (strcmp(view->name, "_default") == 0) 2571 fprintf(fp, "[View: default]\n"); 2572 else 2573 fprintf(fp, "[View: %s (Cache: %s)]\n", view->name, 2574 dns_cache_getname(view->cache)); 2575 if (dns_view_iscacheshared(view)) { 2576 /* 2577 * Avoid dumping redundant statistics when the cache is 2578 * shared. 2579 */ 2580 continue; 2581 } 2582 dns_rdatasetstats_dump(cacherrstats, rdatasetstats_dump, 2583 &dumparg, 0); 2584 } 2585 2586 fprintf(fp, "++ ADB stats ++\n"); 2587 for (view = ISC_LIST_HEAD(server->viewlist); 2588 view != NULL; 2589 view = ISC_LIST_NEXT(view, link)) { 2590 if (view->adbstats == NULL) 2591 continue; 2592 if (strcmp(view->name, "_default") == 0) 2593 fprintf(fp, "[View: default]\n"); 2594 else 2595 fprintf(fp, "[View: %s]\n", view->name); 2596 (void) dump_counters(view->adbstats, isc_statsformat_file, fp, 2597 NULL, adbstats_desc, dns_adbstats_max, 2598 adbstats_index, adbstat_values, 0); 2599 } 2600 2601 fprintf(fp, "++ Socket I/O Statistics ++\n"); 2602 (void) dump_counters(server->sockstats, isc_statsformat_file, fp, NULL, 2603 sockstats_desc, isc_sockstatscounter_max, 2604 sockstats_index, sockstat_values, 0); 2605 2606 fprintf(fp, "++ Per Zone Query Statistics ++\n"); 2607 zone = NULL; 2608 for (result = dns_zone_first(server->zonemgr, &zone); 2609 result == ISC_R_SUCCESS; 2610 next = NULL, result = dns_zone_next(zone, &next), zone = next) 2611 { 2612 isc_stats_t *zonestats = dns_zone_getrequeststats(zone); 2613 if (zonestats != NULL) { 2614 char zonename[DNS_NAME_FORMATSIZE]; 2615 2616 dns_name_format(dns_zone_getorigin(zone), 2617 zonename, sizeof(zonename)); 2618 view = dns_zone_getview(zone); 2619 2620 fprintf(fp, "[%s", zonename); 2621 if (strcmp(view->name, "_default") != 0) 2622 fprintf(fp, " (view: %s)", view->name); 2623 fprintf(fp, "]\n"); 2624 2625 (void) dump_counters(zonestats, isc_statsformat_file, 2626 fp, NULL, nsstats_desc, 2627 dns_nsstatscounter_max, 2628 nsstats_index, nsstat_values, 0); 2629 } 2630 } 2631 2632 fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now); 2633 2634 return (ISC_R_SUCCESS); /* this function currently always succeeds */ 2635 } 2636