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