1 /* $NetBSD: statschannel.c,v 1.19 2026/04/08 00:15:44 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /*! \file */ 17 18 #include <inttypes.h> 19 #include <stdbool.h> 20 21 #include <isc/buffer.h> 22 #include <isc/httpd.h> 23 #include <isc/mem.h> 24 #include <isc/once.h> 25 #include <isc/stats.h> 26 #include <isc/string.h> 27 #include <isc/util.h> 28 29 #include <dns/adb.h> 30 #include <dns/cache.h> 31 #include <dns/db.h> 32 #include <dns/opcode.h> 33 #include <dns/rcode.h> 34 #include <dns/rdataclass.h> 35 #include <dns/rdatatype.h> 36 #include <dns/resolver.h> 37 #include <dns/stats.h> 38 #include <dns/transport.h> 39 #include <dns/view.h> 40 #include <dns/xfrin.h> 41 #include <dns/zt.h> 42 43 #include <ns/stats.h> 44 45 #include <named/log.h> 46 #include <named/server.h> 47 #include <named/statschannel.h> 48 49 #if HAVE_JSON_C 50 #include <json_object.h> 51 #include <linkhash.h> 52 #endif /* HAVE_JSON_C */ 53 54 #if HAVE_LIBXML2 55 #include <libxml/xmlwriter.h> 56 #define ISC_XMLCHAR (const xmlChar *) 57 #endif /* HAVE_LIBXML2 */ 58 59 #include "xsl_p.h" 60 61 #define STATS_XML_VERSION_MAJOR "3" 62 #define STATS_XML_VERSION_MINOR "14" 63 #define STATS_XML_VERSION STATS_XML_VERSION_MAJOR "." STATS_XML_VERSION_MINOR 64 65 #define STATS_JSON_VERSION_MAJOR "1" 66 #define STATS_JSON_VERSION_MINOR "8" 67 #define STATS_JSON_VERSION STATS_JSON_VERSION_MAJOR "." STATS_JSON_VERSION_MINOR 68 69 struct named_statschannel { 70 /* Unlocked */ 71 isc_httpdmgr_t *httpdmgr; 72 isc_sockaddr_t address; 73 isc_mem_t *mctx; 74 75 /* 76 * Locked by channel lock 77 */ 78 isc_mutex_t lock; 79 dns_acl_t *acl; 80 81 /* Locked by main loop. */ 82 ISC_LINK(struct named_statschannel) link; 83 }; 84 85 typedef struct stats_dumparg { 86 isc_statsformat_t type; 87 void *arg; /* type dependent argument */ 88 int ncounters; /* for general statistics */ 89 int *counterindices; /* for general statistics */ 90 uint64_t *countervalues; /* for general statistics */ 91 isc_result_t result; 92 } stats_dumparg_t; 93 94 static isc_once_t once = ISC_ONCE_INIT; 95 96 #if defined(HAVE_LIBXML2) || defined(HAVE_JSON_C) 97 #define EXTENDED_STATS 98 #else /* if defined(HAVE_LIBXML2) || defined(HAVE_JSON_C) */ 99 #undef EXTENDED_STATS 100 #endif /* if defined(HAVE_LIBXML2) || defined(HAVE_JSON_C) */ 101 102 #ifdef EXTENDED_STATS 103 static const char * 104 user_zonetype(dns_zone_t *zone) { 105 dns_zonetype_t ztype; 106 dns_view_t *view; 107 static const struct zt { 108 const dns_zonetype_t type; 109 const char *const string; 110 } typemap[] = { { dns_zone_none, "none" }, 111 { dns_zone_primary, "primary" }, 112 { dns_zone_secondary, "secondary" }, 113 { dns_zone_mirror, "mirror" }, 114 { dns_zone_stub, "stub" }, 115 { dns_zone_staticstub, "static-stub" }, 116 { dns_zone_key, "key" }, 117 { dns_zone_dlz, "dlz" }, 118 { dns_zone_redirect, "redirect" }, 119 { 0, NULL } }; 120 const struct zt *tp; 121 122 if ((dns_zone_getoptions(zone) & DNS_ZONEOPT_AUTOEMPTY) != 0) { 123 return "builtin"; 124 } 125 126 view = dns_zone_getview(zone); 127 if (view != NULL && strcmp(view->name, "_bind") == 0) { 128 return "builtin"; 129 } 130 131 ztype = dns_zone_gettype(zone); 132 for (tp = typemap; tp->string != NULL && tp->type != ztype; tp++) { 133 /* empty */ 134 } 135 return tp->string; 136 } 137 #endif /* ifdef EXTENDED_STATS */ 138 139 /*% 140 * Statistics descriptions. These could be statistically initialized at 141 * compile time, but we configure them run time in the init_desc() function 142 * below so that they'll be less susceptible to counter name changes. 143 */ 144 static const char *nsstats_desc[ns_statscounter_max]; 145 static const char *resstats_desc[dns_resstatscounter_max]; 146 static const char *adbstats_desc[dns_adbstats_max]; 147 static const char *zonestats_desc[dns_zonestatscounter_max]; 148 static const char *sockstats_desc[isc_sockstatscounter_max]; 149 static const char *dnssecstats_desc[dns_dnssecstats_max]; 150 static const char *udpinsizestats_desc[dns_sizecounter_in_max]; 151 static const char *udpoutsizestats_desc[dns_sizecounter_out_max]; 152 static const char *tcpinsizestats_desc[dns_sizecounter_in_max]; 153 static const char *tcpoutsizestats_desc[dns_sizecounter_out_max]; 154 static const char *dnstapstats_desc[dns_dnstapcounter_max]; 155 static const char *gluecachestats_desc[dns_gluecachestatscounter_max]; 156 #if defined(EXTENDED_STATS) 157 static const char *nsstats_xmldesc[ns_statscounter_max]; 158 static const char *resstats_xmldesc[dns_resstatscounter_max]; 159 static const char *adbstats_xmldesc[dns_adbstats_max]; 160 static const char *zonestats_xmldesc[dns_zonestatscounter_max]; 161 static const char *sockstats_xmldesc[isc_sockstatscounter_max]; 162 static const char *dnssecstats_xmldesc[dns_dnssecstats_max]; 163 static const char *udpinsizestats_xmldesc[dns_sizecounter_in_max]; 164 static const char *udpoutsizestats_xmldesc[dns_sizecounter_out_max]; 165 static const char *tcpinsizestats_xmldesc[dns_sizecounter_in_max]; 166 static const char *tcpoutsizestats_xmldesc[dns_sizecounter_out_max]; 167 static const char *dnstapstats_xmldesc[dns_dnstapcounter_max]; 168 static const char *gluecachestats_xmldesc[dns_gluecachestatscounter_max]; 169 #else /* if defined(EXTENDED_STATS) */ 170 #define nsstats_xmldesc NULL 171 #define resstats_xmldesc NULL 172 #define adbstats_xmldesc NULL 173 #define zonestats_xmldesc NULL 174 #define sockstats_xmldesc NULL 175 #define dnssecstats_xmldesc NULL 176 #define udpinsizestats_xmldesc NULL 177 #define udpoutsizestats_xmldesc NULL 178 #define tcpinsizestats_xmldesc NULL 179 #define tcpoutsizestats_xmldesc NULL 180 #define dnstapstats_xmldesc NULL 181 #define gluecachestats_xmldesc NULL 182 #endif /* EXTENDED_STATS */ 183 184 #define TRY0(a) \ 185 do { \ 186 xmlrc = (a); \ 187 if (xmlrc < 0) \ 188 goto cleanup; \ 189 } while (0) 190 191 /*% 192 * Mapping arrays to represent statistics counters in the order of our 193 * preference, regardless of the order of counter indices. For example, 194 * nsstats_desc[nsstats_index[0]] will be the description that is shown first. 195 */ 196 static int nsstats_index[ns_statscounter_max]; 197 static int resstats_index[dns_resstatscounter_max]; 198 static int adbstats_index[dns_adbstats_max]; 199 static int zonestats_index[dns_zonestatscounter_max]; 200 static int sockstats_index[isc_sockstatscounter_max]; 201 static int dnssecstats_index[dns_dnssecstats_max]; 202 static int udpinsizestats_index[dns_sizecounter_in_max]; 203 static int udpoutsizestats_index[dns_sizecounter_out_max]; 204 static int tcpinsizestats_index[dns_sizecounter_in_max]; 205 static int tcpoutsizestats_index[dns_sizecounter_out_max]; 206 static int dnstapstats_index[dns_dnstapcounter_max]; 207 static int gluecachestats_index[dns_gluecachestatscounter_max]; 208 209 static void 210 set_desc(int counter, int maxcounter, const char *fdesc, const char **fdescs, 211 const char *xdesc, const char **xdescs) { 212 REQUIRE(counter < maxcounter); 213 REQUIRE(fdescs != NULL && fdescs[counter] == NULL); 214 #if defined(EXTENDED_STATS) 215 REQUIRE(xdescs != NULL && xdescs[counter] == NULL); 216 #endif /* if defined(EXTENDED_STATS) */ 217 218 fdescs[counter] = fdesc; 219 #if defined(EXTENDED_STATS) 220 xdescs[counter] = xdesc; 221 #else /* if defined(EXTENDED_STATS) */ 222 UNUSED(xdesc); 223 UNUSED(xdescs); 224 #endif /* if defined(EXTENDED_STATS) */ 225 } 226 227 static const char * 228 get_histo_desc(const char *prefix, int i, int inf, bool ext) { 229 static char buf[(DNS_SIZEHISTO_MAXIN + DNS_SIZEHISTO_MAXOUT) * 80]; 230 static size_t used = 0; 231 char *desc = buf + used; 232 size_t space = sizeof(buf) - used; 233 int min = DNS_SIZEHISTO_QUANTUM * i; 234 int max = DNS_SIZEHISTO_QUANTUM * (i + 1) - 1; 235 int len = 0; 236 237 if (!ext && i < inf) { 238 len = snprintf(desc, space, "%s %u-%u bytes", prefix, min, max); 239 } else if (!ext && i >= inf) { 240 len = snprintf(desc, space, "%s %u+ bytes", prefix, min); 241 } else if (ext && i < inf) { 242 len = snprintf(desc, space, "%u-%u", min, max); 243 } else if (ext && i >= inf) { 244 len = snprintf(desc, space, "%u+", min); 245 } 246 INSIST(0 < len && (size_t)len < space); 247 used += len + 1; 248 return desc; 249 } 250 251 static void 252 init_desc(void) { 253 int i; 254 255 /* Initialize name server statistics */ 256 for (i = 0; i < ns_statscounter_max; i++) { 257 nsstats_desc[i] = NULL; 258 } 259 #if defined(EXTENDED_STATS) 260 for (i = 0; i < ns_statscounter_max; i++) { 261 nsstats_xmldesc[i] = NULL; 262 } 263 #endif /* if defined(EXTENDED_STATS) */ 264 265 #define SET_NSSTATDESC(counterid, desc, xmldesc) \ 266 do { \ 267 set_desc(ns_statscounter_##counterid, ns_statscounter_max, \ 268 desc, nsstats_desc, xmldesc, nsstats_xmldesc); \ 269 nsstats_index[i++] = ns_statscounter_##counterid; \ 270 } while (0) 271 272 i = 0; 273 SET_NSSTATDESC(requestv4, "IPv4 requests received", "Requestv4"); 274 SET_NSSTATDESC(requestv6, "IPv6 requests received", "Requestv6"); 275 SET_NSSTATDESC(edns0in, "requests with EDNS(0) received", "ReqEdns0"); 276 SET_NSSTATDESC(badednsver, 277 "requests with unsupported EDNS version received", 278 "ReqBadEDNSVer"); 279 SET_NSSTATDESC(tsigin, "requests with TSIG received", "ReqTSIG"); 280 SET_NSSTATDESC(sig0in, "requests with SIG(0) received", "ReqSIG0"); 281 SET_NSSTATDESC(invalidsig, "requests with invalid signature", 282 "ReqBadSIG"); 283 SET_NSSTATDESC(requesttcp, "TCP requests received", "ReqTCP"); 284 SET_NSSTATDESC(tcphighwater, "TCP connection high-water", 285 "TCPConnHighWater"); 286 SET_NSSTATDESC(authrej, "auth queries rejected", "AuthQryRej"); 287 SET_NSSTATDESC(recurserej, "recursive queries rejected", "RecQryRej"); 288 SET_NSSTATDESC(xfrrej, "transfer requests rejected", "XfrRej"); 289 SET_NSSTATDESC(updaterej, "update requests rejected", "UpdateRej"); 290 SET_NSSTATDESC(response, "responses sent", "Response"); 291 SET_NSSTATDESC(truncatedresp, "truncated responses sent", 292 "TruncatedResp"); 293 SET_NSSTATDESC(edns0out, "responses with EDNS(0) sent", "RespEDNS0"); 294 SET_NSSTATDESC(tsigout, "responses with TSIG sent", "RespTSIG"); 295 SET_NSSTATDESC(sig0out, "responses with SIG(0) sent", "RespSIG0"); 296 SET_NSSTATDESC(success, "queries resulted in successful answer", 297 "QrySuccess"); 298 SET_NSSTATDESC(authans, "queries resulted in authoritative answer", 299 "QryAuthAns"); 300 SET_NSSTATDESC(nonauthans, 301 "queries resulted in non authoritative answer", 302 "QryNoauthAns"); 303 SET_NSSTATDESC(referral, "queries resulted in referral answer", 304 "QryReferral"); 305 SET_NSSTATDESC(nxrrset, "queries resulted in nxrrset", "QryNxrrset"); 306 SET_NSSTATDESC(servfail, "queries resulted in SERVFAIL", "QrySERVFAIL"); 307 SET_NSSTATDESC(formerr, "queries resulted in FORMERR", "QryFORMERR"); 308 SET_NSSTATDESC(nxdomain, "queries resulted in NXDOMAIN", "QryNXDOMAIN"); 309 SET_NSSTATDESC(recursion, "queries caused recursion", "QryRecursion"); 310 SET_NSSTATDESC(duplicate, "duplicate queries received", "QryDuplicate"); 311 SET_NSSTATDESC(dropped, "queries dropped", "QryDropped"); 312 SET_NSSTATDESC(failure, "other query failures", "QryFailure"); 313 SET_NSSTATDESC(xfrdone, "requested transfers completed", "XfrReqDone"); 314 SET_NSSTATDESC(updatereqfwd, "update requests forwarded", 315 "UpdateReqFwd"); 316 SET_NSSTATDESC(updaterespfwd, "update responses forwarded", 317 "UpdateRespFwd"); 318 SET_NSSTATDESC(updatefwdfail, "update forward failed", "UpdateFwdFail"); 319 SET_NSSTATDESC(updatedone, "updates completed", "UpdateDone"); 320 SET_NSSTATDESC(updatefail, "updates failed", "UpdateFail"); 321 SET_NSSTATDESC(updatebadprereq, 322 "updates rejected due to prerequisite failure", 323 "UpdateBadPrereq"); 324 SET_NSSTATDESC(recurshighwater, "Recursive clients high-water", 325 "RecursHighwater"); 326 SET_NSSTATDESC(recursclients, "recursing clients", "RecursClients"); 327 SET_NSSTATDESC(dns64, "queries answered by DNS64", "DNS64"); 328 SET_NSSTATDESC(ratedropped, "responses dropped for rate limits", 329 "RateDropped"); 330 SET_NSSTATDESC(rateslipped, "responses truncated for rate limits", 331 "RateSlipped"); 332 SET_NSSTATDESC(rpz_rewrites, "response policy zone rewrites", 333 "RPZRewrites"); 334 SET_NSSTATDESC(udp, "UDP queries received", "QryUDP"); 335 SET_NSSTATDESC(tcp, "TCP queries received", "QryTCP"); 336 SET_NSSTATDESC(nsidopt, "NSID option received", "NSIDOpt"); 337 SET_NSSTATDESC(expireopt, "Expire option received", "ExpireOpt"); 338 SET_NSSTATDESC(keepaliveopt, "EDNS TCP keepalive option received", 339 "KeepAliveOpt"); 340 SET_NSSTATDESC(padopt, "EDNS padding option received", "PadOpt"); 341 SET_NSSTATDESC(otheropt, "Other EDNS option received", "OtherOpt"); 342 SET_NSSTATDESC(cookiein, "COOKIE option received", "CookieIn"); 343 SET_NSSTATDESC(cookienew, "COOKIE - client only", "CookieNew"); 344 SET_NSSTATDESC(cookiebadsize, "COOKIE - bad size", "CookieBadSize"); 345 SET_NSSTATDESC(cookiebadtime, "COOKIE - bad time", "CookieBadTime"); 346 SET_NSSTATDESC(cookienomatch, "COOKIE - no match", "CookieNoMatch"); 347 SET_NSSTATDESC(cookiematch, "COOKIE - match", "CookieMatch"); 348 SET_NSSTATDESC(ecsopt, "EDNS client subnet option received", "ECSOpt"); 349 SET_NSSTATDESC(nxdomainredirect, 350 "queries resulted in NXDOMAIN that were redirected", 351 "QryNXRedir"); 352 SET_NSSTATDESC(nxdomainredirect_rlookup, 353 "queries resulted in NXDOMAIN that were redirected and " 354 "resulted in a successful remote lookup", 355 "QryNXRedirRLookup"); 356 SET_NSSTATDESC(badcookie, "sent badcookie response", "QryBADCOOKIE"); 357 SET_NSSTATDESC(nxdomainsynth, "synthesized a NXDOMAIN response", 358 "SynthNXDOMAIN"); 359 SET_NSSTATDESC(nodatasynth, "synthesized a no-data response", 360 "SynthNODATA"); 361 SET_NSSTATDESC(wildcardsynth, "synthesized a wildcard response", 362 "SynthWILDCARD"); 363 SET_NSSTATDESC(trystale, 364 "attempts to use stale cache data after lookup failure", 365 "QryTryStale"); 366 SET_NSSTATDESC(usedstale, 367 "successful uses of stale cache data after lookup " 368 "failure", 369 "QryUsedStale"); 370 SET_NSSTATDESC(prefetch, "queries triggered prefetch", "Prefetch"); 371 SET_NSSTATDESC(keytagopt, "Keytag option received", "KeyTagOpt"); 372 SET_NSSTATDESC(reclimitdropped, 373 "queries dropped due to recursive client limit", 374 "RecLimitDropped"); 375 SET_NSSTATDESC(updatequota, "Update quota exceeded", "UpdateQuota"); 376 377 INSIST(i == ns_statscounter_max); 378 379 /* Initialize resolver statistics */ 380 for (i = 0; i < dns_resstatscounter_max; i++) { 381 resstats_desc[i] = NULL; 382 } 383 #if defined(EXTENDED_STATS) 384 for (i = 0; i < dns_resstatscounter_max; i++) { 385 resstats_xmldesc[i] = NULL; 386 } 387 #endif /* if defined(EXTENDED_STATS) */ 388 389 #define SET_RESSTATDESC(counterid, desc, xmldesc) \ 390 do { \ 391 set_desc(dns_resstatscounter_##counterid, \ 392 dns_resstatscounter_max, desc, resstats_desc, \ 393 xmldesc, resstats_xmldesc); \ 394 resstats_index[i++] = dns_resstatscounter_##counterid; \ 395 } while (0) 396 397 i = 0; 398 SET_RESSTATDESC(queryv4, "IPv4 queries sent", "Queryv4"); 399 SET_RESSTATDESC(queryv6, "IPv6 queries sent", "Queryv6"); 400 SET_RESSTATDESC(responsev4, "IPv4 responses received", "Responsev4"); 401 SET_RESSTATDESC(responsev6, "IPv6 responses received", "Responsev6"); 402 SET_RESSTATDESC(nxdomain, "NXDOMAIN received", "NXDOMAIN"); 403 SET_RESSTATDESC(servfail, "SERVFAIL received", "SERVFAIL"); 404 SET_RESSTATDESC(formerr, "FORMERR received", "FORMERR"); 405 SET_RESSTATDESC(othererror, "other errors received", "OtherError"); 406 SET_RESSTATDESC(edns0fail, "EDNS(0) query failures", "EDNS0Fail"); 407 SET_RESSTATDESC(mismatch, "mismatch responses received", "Mismatch"); 408 SET_RESSTATDESC(truncated, "truncated responses received", "Truncated"); 409 SET_RESSTATDESC(lame, "lame delegations received", "Lame"); 410 SET_RESSTATDESC(retry, "query retries", "Retry"); 411 SET_RESSTATDESC(dispabort, "queries aborted due to quota", 412 "QueryAbort"); 413 SET_RESSTATDESC(dispsockfail, "failures in opening query sockets", 414 "QuerySockFail"); 415 SET_RESSTATDESC(disprequdp, "UDP queries in progress", "QueryCurUDP"); 416 SET_RESSTATDESC(dispreqtcp, "TCP queries in progress", "QueryCurTCP"); 417 SET_RESSTATDESC(querytimeout, "query timeouts", "QueryTimeout"); 418 SET_RESSTATDESC(gluefetchv4, "IPv4 NS address fetches", "GlueFetchv4"); 419 SET_RESSTATDESC(gluefetchv6, "IPv6 NS address fetches", "GlueFetchv6"); 420 SET_RESSTATDESC(gluefetchv4fail, "IPv4 NS address fetch failed", 421 "GlueFetchv4Fail"); 422 SET_RESSTATDESC(gluefetchv6fail, "IPv6 NS address fetch failed", 423 "GlueFetchv6Fail"); 424 SET_RESSTATDESC(val, "DNSSEC validation attempted", "ValAttempt"); 425 SET_RESSTATDESC(valsuccess, "DNSSEC validation succeeded", "ValOk"); 426 SET_RESSTATDESC(valnegsuccess, "DNSSEC NX validation succeeded", 427 "ValNegOk"); 428 SET_RESSTATDESC(valfail, "DNSSEC validation failed", "ValFail"); 429 SET_RESSTATDESC(queryrtt0, 430 "queries with RTT < " DNS_RESOLVER_QRYRTTCLASS0STR "ms", 431 "QryRTT" DNS_RESOLVER_QRYRTTCLASS0STR); 432 SET_RESSTATDESC(queryrtt1, 433 "queries with RTT " DNS_RESOLVER_QRYRTTCLASS0STR 434 "-" DNS_RESOLVER_QRYRTTCLASS1STR "ms", 435 "QryRTT" DNS_RESOLVER_QRYRTTCLASS1STR); 436 SET_RESSTATDESC(queryrtt2, 437 "queries with RTT " DNS_RESOLVER_QRYRTTCLASS1STR 438 "-" DNS_RESOLVER_QRYRTTCLASS2STR "ms", 439 "QryRTT" DNS_RESOLVER_QRYRTTCLASS2STR); 440 SET_RESSTATDESC(queryrtt3, 441 "queries with RTT " DNS_RESOLVER_QRYRTTCLASS2STR 442 "-" DNS_RESOLVER_QRYRTTCLASS3STR "ms", 443 "QryRTT" DNS_RESOLVER_QRYRTTCLASS3STR); 444 SET_RESSTATDESC(queryrtt4, 445 "queries with RTT " DNS_RESOLVER_QRYRTTCLASS3STR 446 "-" DNS_RESOLVER_QRYRTTCLASS4STR "ms", 447 "QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR); 448 SET_RESSTATDESC(queryrtt5, 449 "queries with RTT > " DNS_RESOLVER_QRYRTTCLASS4STR "ms", 450 "QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR "+"); 451 SET_RESSTATDESC(nfetch, "active fetches", "NumFetch"); 452 SET_RESSTATDESC(buckets, "bucket size", "BucketSize"); 453 SET_RESSTATDESC(refused, "REFUSED received", "REFUSED"); 454 SET_RESSTATDESC(cookienew, "COOKIE send with client cookie only", 455 "ClientCookieOut"); 456 SET_RESSTATDESC(cookieout, "COOKIE sent with client and server cookie", 457 "ServerCookieOut"); 458 SET_RESSTATDESC(cookiein, "COOKIE replies received", "CookieIn"); 459 SET_RESSTATDESC(cookieok, "COOKIE client ok", "CookieClientOk"); 460 SET_RESSTATDESC(badvers, "bad EDNS version", "BadEDNSVersion"); 461 SET_RESSTATDESC(badcookie, "bad cookie rcode", "BadCookieRcode"); 462 SET_RESSTATDESC(zonequota, "spilled due to zone quota", "ZoneQuota"); 463 SET_RESSTATDESC(serverquota, "spilled due to server quota", 464 "ServerQuota"); 465 SET_RESSTATDESC(clientquota, "spilled due to clients per query quota", 466 "ClientQuota"); 467 SET_RESSTATDESC(nextitem, "waited for next item", "NextItem"); 468 SET_RESSTATDESC(priming, "priming queries", "Priming"); 469 470 INSIST(i == dns_resstatscounter_max); 471 472 /* Initialize adb statistics */ 473 for (i = 0; i < dns_adbstats_max; i++) { 474 adbstats_desc[i] = NULL; 475 } 476 #if defined(EXTENDED_STATS) 477 for (i = 0; i < dns_adbstats_max; i++) { 478 adbstats_xmldesc[i] = NULL; 479 } 480 #endif /* if defined(EXTENDED_STATS) */ 481 482 #define SET_ADBSTATDESC(id, desc, xmldesc) \ 483 do { \ 484 set_desc(dns_adbstats_##id, dns_adbstats_max, desc, \ 485 adbstats_desc, xmldesc, adbstats_xmldesc); \ 486 adbstats_index[i++] = dns_adbstats_##id; \ 487 } while (0) 488 i = 0; 489 SET_ADBSTATDESC(nentries, "Address hash table size", "nentries"); 490 SET_ADBSTATDESC(entriescnt, "Addresses in hash table", "entriescnt"); 491 SET_ADBSTATDESC(nnames, "Name hash table size", "nnames"); 492 SET_ADBSTATDESC(namescnt, "Names in hash table", "namescnt"); 493 494 INSIST(i == dns_adbstats_max); 495 496 /* Initialize zone statistics */ 497 for (i = 0; i < dns_zonestatscounter_max; i++) { 498 zonestats_desc[i] = NULL; 499 } 500 #if defined(EXTENDED_STATS) 501 for (i = 0; i < dns_zonestatscounter_max; i++) { 502 zonestats_xmldesc[i] = NULL; 503 } 504 #endif /* if defined(EXTENDED_STATS) */ 505 506 #define SET_ZONESTATDESC(counterid, desc, xmldesc) \ 507 do { \ 508 set_desc(dns_zonestatscounter_##counterid, \ 509 dns_zonestatscounter_max, desc, zonestats_desc, \ 510 xmldesc, zonestats_xmldesc); \ 511 zonestats_index[i++] = dns_zonestatscounter_##counterid; \ 512 } while (0) 513 514 i = 0; 515 SET_ZONESTATDESC(notifyoutv4, "IPv4 notifies sent", "NotifyOutv4"); 516 SET_ZONESTATDESC(notifyoutv6, "IPv6 notifies sent", "NotifyOutv6"); 517 SET_ZONESTATDESC(notifyinv4, "IPv4 notifies received", "NotifyInv4"); 518 SET_ZONESTATDESC(notifyinv6, "IPv6 notifies received", "NotifyInv6"); 519 SET_ZONESTATDESC(notifyrej, "notifies rejected", "NotifyRej"); 520 SET_ZONESTATDESC(soaoutv4, "IPv4 SOA queries sent", "SOAOutv4"); 521 SET_ZONESTATDESC(soaoutv6, "IPv6 SOA queries sent", "SOAOutv6"); 522 SET_ZONESTATDESC(axfrreqv4, "IPv4 AXFR requested", "AXFRReqv4"); 523 SET_ZONESTATDESC(axfrreqv6, "IPv6 AXFR requested", "AXFRReqv6"); 524 SET_ZONESTATDESC(ixfrreqv4, "IPv4 IXFR requested", "IXFRReqv4"); 525 SET_ZONESTATDESC(ixfrreqv6, "IPv6 IXFR requested", "IXFRReqv6"); 526 SET_ZONESTATDESC(xfrsuccess, "transfer requests succeeded", 527 "XfrSuccess"); 528 SET_ZONESTATDESC(xfrfail, "transfer requests failed", "XfrFail"); 529 INSIST(i == dns_zonestatscounter_max); 530 531 /* Initialize socket statistics */ 532 for (i = 0; i < isc_sockstatscounter_max; i++) { 533 sockstats_desc[i] = NULL; 534 } 535 #if defined(EXTENDED_STATS) 536 for (i = 0; i < isc_sockstatscounter_max; i++) { 537 sockstats_xmldesc[i] = NULL; 538 } 539 #endif /* if defined(EXTENDED_STATS) */ 540 541 #define SET_SOCKSTATDESC(counterid, desc, xmldesc) \ 542 do { \ 543 set_desc(isc_sockstatscounter_##counterid, \ 544 isc_sockstatscounter_max, desc, sockstats_desc, \ 545 xmldesc, sockstats_xmldesc); \ 546 sockstats_index[i++] = isc_sockstatscounter_##counterid; \ 547 } while (0) 548 549 i = 0; 550 SET_SOCKSTATDESC(udp4open, "UDP/IPv4 sockets opened", "UDP4Open"); 551 SET_SOCKSTATDESC(udp6open, "UDP/IPv6 sockets opened", "UDP6Open"); 552 SET_SOCKSTATDESC(tcp4open, "TCP/IPv4 sockets opened", "TCP4Open"); 553 SET_SOCKSTATDESC(tcp6open, "TCP/IPv6 sockets opened", "TCP6Open"); 554 SET_SOCKSTATDESC(udp4openfail, "UDP/IPv4 socket open failures", 555 "UDP4OpenFail"); 556 SET_SOCKSTATDESC(udp6openfail, "UDP/IPv6 socket open failures", 557 "UDP6OpenFail"); 558 SET_SOCKSTATDESC(tcp4openfail, "TCP/IPv4 socket open failures", 559 "TCP4OpenFail"); 560 SET_SOCKSTATDESC(tcp6openfail, "TCP/IPv6 socket open failures", 561 "TCP6OpenFail"); 562 SET_SOCKSTATDESC(udp4close, "UDP/IPv4 sockets closed", "UDP4Close"); 563 SET_SOCKSTATDESC(udp6close, "UDP/IPv6 sockets closed", "UDP6Close"); 564 SET_SOCKSTATDESC(tcp4close, "TCP/IPv4 sockets closed", "TCP4Close"); 565 SET_SOCKSTATDESC(tcp6close, "TCP/IPv6 sockets closed", "TCP6Close"); 566 SET_SOCKSTATDESC(udp4bindfail, "UDP/IPv4 socket bind failures", 567 "UDP4BindFail"); 568 SET_SOCKSTATDESC(udp6bindfail, "UDP/IPv6 socket bind failures", 569 "UDP6BindFail"); 570 SET_SOCKSTATDESC(tcp4bindfail, "TCP/IPv4 socket bind failures", 571 "TCP4BindFail"); 572 SET_SOCKSTATDESC(tcp6bindfail, "TCP/IPv6 socket bind failures", 573 "TCP6BindFail"); 574 SET_SOCKSTATDESC(udp4connectfail, "UDP/IPv4 socket connect failures", 575 "UDP4ConnFail"); 576 SET_SOCKSTATDESC(udp6connectfail, "UDP/IPv6 socket connect failures", 577 "UDP6ConnFail"); 578 SET_SOCKSTATDESC(tcp4connectfail, "TCP/IPv4 socket connect failures", 579 "TCP4ConnFail"); 580 SET_SOCKSTATDESC(tcp6connectfail, "TCP/IPv6 socket connect failures", 581 "TCP6ConnFail"); 582 SET_SOCKSTATDESC(udp4connect, "UDP/IPv4 connections established", 583 "UDP4Conn"); 584 SET_SOCKSTATDESC(udp6connect, "UDP/IPv6 connections established", 585 "UDP6Conn"); 586 SET_SOCKSTATDESC(tcp4connect, "TCP/IPv4 connections established", 587 "TCP4Conn"); 588 SET_SOCKSTATDESC(tcp6connect, "TCP/IPv6 connections established", 589 "TCP6Conn"); 590 SET_SOCKSTATDESC(tcp4acceptfail, "TCP/IPv4 connection accept failures", 591 "TCP4AcceptFail"); 592 SET_SOCKSTATDESC(tcp6acceptfail, "TCP/IPv6 connection accept failures", 593 "TCP6AcceptFail"); 594 SET_SOCKSTATDESC(tcp4accept, "TCP/IPv4 connections accepted", 595 "TCP4Accept"); 596 SET_SOCKSTATDESC(tcp6accept, "TCP/IPv6 connections accepted", 597 "TCP6Accept"); 598 SET_SOCKSTATDESC(udp4sendfail, "UDP/IPv4 send errors", "UDP4SendErr"); 599 SET_SOCKSTATDESC(udp6sendfail, "UDP/IPv6 send errors", "UDP6SendErr"); 600 SET_SOCKSTATDESC(tcp4sendfail, "TCP/IPv4 send errors", "TCP4SendErr"); 601 SET_SOCKSTATDESC(tcp6sendfail, "TCP/IPv6 send errors", "TCP6SendErr"); 602 SET_SOCKSTATDESC(udp4recvfail, "UDP/IPv4 recv errors", "UDP4RecvErr"); 603 SET_SOCKSTATDESC(udp6recvfail, "UDP/IPv6 recv errors", "UDP6RecvErr"); 604 SET_SOCKSTATDESC(tcp4recvfail, "TCP/IPv4 recv errors", "TCP4RecvErr"); 605 SET_SOCKSTATDESC(tcp6recvfail, "TCP/IPv6 recv errors", "TCP6RecvErr"); 606 SET_SOCKSTATDESC(udp4active, "UDP/IPv4 sockets active", "UDP4Active"); 607 SET_SOCKSTATDESC(udp6active, "UDP/IPv6 sockets active", "UDP6Active"); 608 SET_SOCKSTATDESC(tcp4active, "TCP/IPv4 sockets active", "TCP4Active"); 609 SET_SOCKSTATDESC(tcp6active, "TCP/IPv6 sockets active", "TCP6Active"); 610 SET_SOCKSTATDESC(tcp4clients, "TCP/IPv4 clients currently connected", 611 "TCP4Clients"); 612 SET_SOCKSTATDESC(tcp6clients, "TCP/IPv6 clients currently connected", 613 "TCP6Clients"); 614 INSIST(i == isc_sockstatscounter_max); 615 616 /* Initialize DNSSEC statistics */ 617 for (i = 0; i < dns_dnssecstats_max; i++) { 618 dnssecstats_desc[i] = NULL; 619 } 620 #if defined(EXTENDED_STATS) 621 for (i = 0; i < dns_dnssecstats_max; i++) { 622 dnssecstats_xmldesc[i] = NULL; 623 } 624 #endif /* if defined(EXTENDED_STATS) */ 625 626 #define SET_DNSSECSTATDESC(counterid, desc, xmldesc) \ 627 do { \ 628 set_desc(dns_dnssecstats_##counterid, dns_dnssecstats_max, \ 629 desc, dnssecstats_desc, xmldesc, \ 630 dnssecstats_xmldesc); \ 631 dnssecstats_index[i++] = dns_dnssecstats_##counterid; \ 632 } while (0) 633 634 i = 0; 635 SET_DNSSECSTATDESC(asis, 636 "dnssec validation success with signer " 637 "\"as is\"", 638 "DNSSECasis"); 639 SET_DNSSECSTATDESC(downcase, 640 "dnssec validation success with signer " 641 "lower cased", 642 "DNSSECdowncase"); 643 SET_DNSSECSTATDESC(wildcard, "dnssec validation of wildcard signature", 644 "DNSSECwild"); 645 SET_DNSSECSTATDESC(fail, "dnssec validation failures", "DNSSECfail"); 646 INSIST(i == dns_dnssecstats_max); 647 648 /* Initialize dnstap statistics */ 649 for (i = 0; i < dns_dnstapcounter_max; i++) { 650 dnstapstats_desc[i] = NULL; 651 } 652 #if defined(EXTENDED_STATS) 653 for (i = 0; i < dns_dnstapcounter_max; i++) { 654 dnstapstats_xmldesc[i] = NULL; 655 } 656 #endif /* if defined(EXTENDED_STATS) */ 657 658 #define SET_DNSTAPSTATDESC(counterid, desc, xmldesc) \ 659 do { \ 660 set_desc(dns_dnstapcounter_##counterid, dns_dnstapcounter_max, \ 661 desc, dnstapstats_desc, xmldesc, \ 662 dnstapstats_xmldesc); \ 663 dnstapstats_index[i++] = dns_dnstapcounter_##counterid; \ 664 } while (0) 665 i = 0; 666 SET_DNSTAPSTATDESC(success, "dnstap messages written", "DNSTAPsuccess"); 667 SET_DNSTAPSTATDESC(drop, "dnstap messages dropped", "DNSTAPdropped"); 668 INSIST(i == dns_dnstapcounter_max); 669 670 #define SET_GLUECACHESTATDESC(counterid, desc, xmldesc) \ 671 do { \ 672 set_desc(dns_gluecachestatscounter_##counterid, \ 673 dns_gluecachestatscounter_max, desc, \ 674 gluecachestats_desc, xmldesc, \ 675 gluecachestats_xmldesc); \ 676 gluecachestats_index[i++] = \ 677 dns_gluecachestatscounter_##counterid; \ 678 } while (0) 679 i = 0; 680 SET_GLUECACHESTATDESC(hits_present, "Hits for present glue (cached)", 681 "GLUECACHEhitspresent"); 682 SET_GLUECACHESTATDESC(hits_absent, 683 "Hits for non-existent glue (cached)", 684 "GLUECACHEhitsabsent"); 685 SET_GLUECACHESTATDESC(inserts_present, 686 "Miss-plus-cache-inserts for present glue", 687 "GLUECACHEinsertspresent"); 688 SET_GLUECACHESTATDESC(inserts_absent, 689 "Miss-plus-cache-inserts for non-existent glue", 690 "GLUECACHEinsertsabsent"); 691 INSIST(i == dns_gluecachestatscounter_max); 692 693 /* Sanity check */ 694 for (i = 0; i < ns_statscounter_max; i++) { 695 INSIST(nsstats_desc[i] != NULL); 696 } 697 for (i = 0; i < dns_resstatscounter_max; i++) { 698 INSIST(resstats_desc[i] != NULL); 699 } 700 for (i = 0; i < dns_adbstats_max; i++) { 701 INSIST(adbstats_desc[i] != NULL); 702 } 703 for (i = 0; i < dns_zonestatscounter_max; i++) { 704 INSIST(zonestats_desc[i] != NULL); 705 } 706 for (i = 0; i < isc_sockstatscounter_max; i++) { 707 INSIST(sockstats_desc[i] != NULL); 708 } 709 for (i = 0; i < dns_dnssecstats_max; i++) { 710 INSIST(dnssecstats_desc[i] != NULL); 711 } 712 for (i = 0; i < dns_dnstapcounter_max; i++) { 713 INSIST(dnstapstats_desc[i] != NULL); 714 } 715 for (i = 0; i < dns_gluecachestatscounter_max; i++) { 716 INSIST(gluecachestats_desc[i] != NULL); 717 } 718 #if defined(EXTENDED_STATS) 719 for (i = 0; i < ns_statscounter_max; i++) { 720 INSIST(nsstats_xmldesc[i] != NULL); 721 } 722 for (i = 0; i < dns_resstatscounter_max; i++) { 723 INSIST(resstats_xmldesc[i] != NULL); 724 } 725 for (i = 0; i < dns_adbstats_max; i++) { 726 INSIST(adbstats_xmldesc[i] != NULL); 727 } 728 for (i = 0; i < dns_zonestatscounter_max; i++) { 729 INSIST(zonestats_xmldesc[i] != NULL); 730 } 731 for (i = 0; i < isc_sockstatscounter_max; i++) { 732 INSIST(sockstats_xmldesc[i] != NULL); 733 } 734 for (i = 0; i < dns_dnssecstats_max; i++) { 735 INSIST(dnssecstats_xmldesc[i] != NULL); 736 } 737 for (i = 0; i < dns_dnstapcounter_max; i++) { 738 INSIST(dnstapstats_xmldesc[i] != NULL); 739 } 740 for (i = 0; i < dns_gluecachestatscounter_max; i++) { 741 INSIST(gluecachestats_xmldesc[i] != NULL); 742 } 743 #endif /* if defined(EXTENDED_STATS) */ 744 745 /* Initialize traffic size statistics */ 746 747 for (i = 0; i < DNS_SIZEHISTO_MAXOUT; i++) { 748 udpoutsizestats_index[i] = i; 749 tcpoutsizestats_index[i] = i; 750 udpoutsizestats_desc[i] = get_histo_desc( 751 "responses sent", i, DNS_SIZEHISTO_MAXOUT, false); 752 tcpoutsizestats_desc[i] = udpoutsizestats_desc[i]; 753 #if defined(EXTENDED_STATS) 754 udpoutsizestats_xmldesc[i] = get_histo_desc( 755 "responses sent", i, DNS_SIZEHISTO_MAXOUT, true); 756 tcpoutsizestats_xmldesc[i] = udpoutsizestats_xmldesc[i]; 757 #endif /* if defined(EXTENDED_STATS) */ 758 } 759 760 for (i = 0; i <= DNS_SIZEHISTO_MAXIN; i++) { 761 udpinsizestats_index[i] = i; 762 tcpinsizestats_index[i] = i; 763 udpinsizestats_desc[i] = get_histo_desc( 764 "requests received", i, DNS_SIZEHISTO_MAXIN, false); 765 tcpinsizestats_desc[i] = udpinsizestats_desc[i]; 766 #if defined(EXTENDED_STATS) 767 if (i < DNS_SIZEHISTO_MAXIN) { 768 udpinsizestats_xmldesc[i] = udpoutsizestats_xmldesc[i]; 769 tcpinsizestats_xmldesc[i] = tcpoutsizestats_xmldesc[i]; 770 } else { 771 udpinsizestats_xmldesc[i] = 772 get_histo_desc("requests received", i, 773 DNS_SIZEHISTO_MAXIN, true); 774 tcpinsizestats_xmldesc[i] = udpinsizestats_xmldesc[i]; 775 } 776 #endif /* if defined(EXTENDED_STATS) */ 777 } 778 } 779 780 /*% 781 * Dump callback functions. 782 */ 783 784 static isc_result_t 785 dump_counters(isc_statsformat_t type, void *arg, const char *category, 786 const char **desc, int ncounters, int *indices, uint64_t *values, 787 int options); 788 789 static void 790 generalstat_dump(isc_statscounter_t counter, uint64_t val, void *arg) { 791 stats_dumparg_t *dumparg = arg; 792 793 REQUIRE(counter < dumparg->ncounters); 794 dumparg->countervalues[counter] = val; 795 } 796 797 static isc_result_t 798 dump_stats(isc_stats_t *stats, isc_statsformat_t type, void *arg, 799 const char *category, const char **desc, int ncounters, int *indices, 800 uint64_t *values, int options) { 801 stats_dumparg_t dumparg; 802 803 dumparg.type = type; 804 dumparg.ncounters = ncounters; 805 dumparg.counterindices = indices; 806 dumparg.countervalues = values; 807 808 memset(values, 0, sizeof(values[0]) * ncounters); 809 isc_stats_dump(stats, generalstat_dump, &dumparg, options); 810 811 return dump_counters(type, arg, category, desc, ncounters, indices, 812 values, options); 813 } 814 815 #if defined(EXTENDED_STATS) 816 static isc_result_t 817 dump_histo(isc_histomulti_t *hm, isc_statsformat_t type, void *arg, 818 const char *category, const char **desc, int ncounters, int *indices, 819 uint64_t *values, int options) { 820 isc_histo_t *hg = NULL; 821 822 isc_histomulti_merge(&hg, hm); 823 for (int i = 0; i < ncounters; i++) { 824 isc_histo_get(hg, i, NULL, NULL, &values[i]); 825 } 826 isc_histo_destroy(&hg); 827 828 return dump_counters(type, arg, category, desc, ncounters, indices, 829 values, options); 830 } 831 #endif /* defined(EXTENDED_STATS) */ 832 833 static isc_result_t 834 dump_counters(isc_statsformat_t type, void *arg, const char *category, 835 const char **desc, int ncounters, int *indices, uint64_t *values, 836 int options) { 837 int i, idx; 838 uint64_t value; 839 FILE *fp; 840 #ifdef HAVE_LIBXML2 841 void *writer; 842 int xmlrc; 843 #endif /* ifdef HAVE_LIBXML2 */ 844 #ifdef HAVE_JSON_C 845 json_object *job, *cat, *counter; 846 #endif /* ifdef HAVE_JSON_C */ 847 848 #if !defined(EXTENDED_STATS) 849 UNUSED(category); 850 #endif /* if !defined(EXTENDED_STATS) */ 851 852 #ifdef HAVE_JSON_C 853 cat = job = (json_object *)arg; 854 if (ncounters > 0 && type == isc_statsformat_json) { 855 if (category != NULL) { 856 cat = json_object_new_object(); 857 if (cat == NULL) { 858 return ISC_R_NOMEMORY; 859 } 860 json_object_object_add(job, category, cat); 861 } 862 } 863 #endif /* ifdef HAVE_JSON_C */ 864 865 for (i = 0; i < ncounters; i++) { 866 idx = indices[i]; 867 value = values[idx]; 868 869 if (value == 0 && (options & ISC_STATSDUMP_VERBOSE) == 0) { 870 continue; 871 } 872 873 switch (type) { 874 case isc_statsformat_file: 875 fp = arg; 876 fprintf(fp, "%20" PRIu64 " %s\n", value, desc[idx]); 877 break; 878 case isc_statsformat_xml: 879 #ifdef HAVE_LIBXML2 880 writer = arg; 881 882 if (category != NULL) { 883 /* <NameOfCategory> */ 884 TRY0(xmlTextWriterStartElement( 885 writer, ISC_XMLCHAR category)); 886 887 /* <name> inside category */ 888 TRY0(xmlTextWriterStartElement( 889 writer, ISC_XMLCHAR "name")); 890 TRY0(xmlTextWriterWriteString( 891 writer, ISC_XMLCHAR desc[idx])); 892 TRY0(xmlTextWriterEndElement(writer)); 893 /* </name> */ 894 895 /* <counter> */ 896 TRY0(xmlTextWriterStartElement( 897 writer, ISC_XMLCHAR "counter")); 898 TRY0(xmlTextWriterWriteFormatString( 899 writer, "%" PRIu64, value)); 900 901 TRY0(xmlTextWriterEndElement(writer)); 902 /* </counter> */ 903 TRY0(xmlTextWriterEndElement(writer)); 904 /* </NameOfCategory> */ 905 } else { 906 TRY0(xmlTextWriterStartElement( 907 writer, ISC_XMLCHAR "counter")); 908 TRY0(xmlTextWriterWriteAttribute( 909 writer, ISC_XMLCHAR "name", 910 ISC_XMLCHAR desc[idx])); 911 TRY0(xmlTextWriterWriteFormatString( 912 writer, "%" PRIu64, value)); 913 TRY0(xmlTextWriterEndElement(writer)); 914 /* counter */ 915 } 916 917 #endif /* ifdef HAVE_LIBXML2 */ 918 break; 919 case isc_statsformat_json: 920 #ifdef HAVE_JSON_C 921 counter = json_object_new_int64(value); 922 if (counter == NULL) { 923 return ISC_R_NOMEMORY; 924 } 925 json_object_object_add(cat, desc[idx], counter); 926 #endif /* ifdef HAVE_JSON_C */ 927 break; 928 } 929 } 930 return ISC_R_SUCCESS; 931 #ifdef HAVE_LIBXML2 932 cleanup: 933 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 934 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, 935 "failed at dump_counters()"); 936 return ISC_R_FAILURE; 937 #endif /* ifdef HAVE_LIBXML2 */ 938 } 939 940 static void 941 rdtypestat_dump(dns_rdatastatstype_t type, uint64_t val, void *arg) { 942 char typebuf[64]; 943 const char *typestr; 944 stats_dumparg_t *dumparg = arg; 945 FILE *fp; 946 #ifdef HAVE_LIBXML2 947 void *writer; 948 int xmlrc; 949 #endif /* ifdef HAVE_LIBXML2 */ 950 #ifdef HAVE_JSON_C 951 json_object *zoneobj, *obj; 952 #endif /* ifdef HAVE_JSON_C */ 953 954 if ((DNS_RDATASTATSTYPE_ATTR(type) & 955 DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) == 0) 956 { 957 dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf, 958 sizeof(typebuf)); 959 typestr = typebuf; 960 } else { 961 typestr = "Others"; 962 } 963 964 switch (dumparg->type) { 965 case isc_statsformat_file: 966 fp = dumparg->arg; 967 fprintf(fp, "%20" PRIu64 " %s\n", val, typestr); 968 break; 969 case isc_statsformat_xml: 970 #ifdef HAVE_LIBXML2 971 writer = dumparg->arg; 972 973 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter")); 974 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", 975 ISC_XMLCHAR typestr)); 976 977 TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, val)); 978 979 TRY0(xmlTextWriterEndElement(writer)); /* type */ 980 #endif /* ifdef HAVE_LIBXML2 */ 981 break; 982 case isc_statsformat_json: 983 #ifdef HAVE_JSON_C 984 zoneobj = (json_object *)dumparg->arg; 985 obj = json_object_new_int64(val); 986 if (obj == NULL) { 987 return; 988 } 989 json_object_object_add(zoneobj, typestr, obj); 990 #endif /* ifdef HAVE_JSON_C */ 991 break; 992 } 993 return; 994 #ifdef HAVE_LIBXML2 995 cleanup: 996 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 997 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, 998 "failed at rdtypestat_dump()"); 999 dumparg->result = ISC_R_FAILURE; 1000 return; 1001 #endif /* ifdef HAVE_LIBXML2 */ 1002 } 1003 1004 static bool 1005 rdatastatstype_attr(dns_rdatastatstype_t type, unsigned int attr) { 1006 return (DNS_RDATASTATSTYPE_ATTR(type) & attr) != 0; 1007 } 1008 1009 static void 1010 rdatasetstats_dump(dns_rdatastatstype_t type, uint64_t val, void *arg) { 1011 stats_dumparg_t *dumparg = arg; 1012 FILE *fp; 1013 char typebuf[64]; 1014 const char *typestr; 1015 bool nxrrset = false; 1016 bool stale = false; 1017 bool ancient = false; 1018 #ifdef HAVE_LIBXML2 1019 void *writer; 1020 int xmlrc; 1021 #endif /* ifdef HAVE_LIBXML2 */ 1022 #ifdef HAVE_JSON_C 1023 json_object *zoneobj, *obj; 1024 char buf[1024]; 1025 #endif /* ifdef HAVE_JSON_C */ 1026 1027 if ((DNS_RDATASTATSTYPE_ATTR(type) & 1028 DNS_RDATASTATSTYPE_ATTR_NXDOMAIN) != 0) 1029 { 1030 typestr = "NXDOMAIN"; 1031 } else if ((DNS_RDATASTATSTYPE_ATTR(type) & 1032 DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) != 0) 1033 { 1034 typestr = "Others"; 1035 } else { 1036 dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf, 1037 sizeof(typebuf)); 1038 typestr = typebuf; 1039 } 1040 1041 nxrrset = rdatastatstype_attr(type, DNS_RDATASTATSTYPE_ATTR_NXRRSET); 1042 stale = rdatastatstype_attr(type, DNS_RDATASTATSTYPE_ATTR_STALE); 1043 ancient = rdatastatstype_attr(type, DNS_RDATASTATSTYPE_ATTR_ANCIENT); 1044 1045 switch (dumparg->type) { 1046 case isc_statsformat_file: 1047 fp = dumparg->arg; 1048 fprintf(fp, "%20" PRIu64 " %s%s%s%s\n", val, ancient ? "~" : "", 1049 stale ? "#" : "", nxrrset ? "!" : "", typestr); 1050 break; 1051 case isc_statsformat_xml: 1052 #ifdef HAVE_LIBXML2 1053 writer = dumparg->arg; 1054 1055 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "rrset")); 1056 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name")); 1057 TRY0(xmlTextWriterWriteFormatString( 1058 writer, "%s%s%s%s", ancient ? "~" : "", 1059 stale ? "#" : "", nxrrset ? "!" : "", typestr)); 1060 TRY0(xmlTextWriterEndElement(writer)); /* name */ 1061 1062 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter")); 1063 TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, val)); 1064 TRY0(xmlTextWriterEndElement(writer)); /* counter */ 1065 1066 TRY0(xmlTextWriterEndElement(writer)); /* rrset */ 1067 #endif /* ifdef HAVE_LIBXML2 */ 1068 break; 1069 case isc_statsformat_json: 1070 #ifdef HAVE_JSON_C 1071 zoneobj = (json_object *)dumparg->arg; 1072 snprintf(buf, sizeof(buf), "%s%s%s%s", ancient ? "~" : "", 1073 stale ? "#" : "", nxrrset ? "!" : "", typestr); 1074 obj = json_object_new_int64(val); 1075 if (obj == NULL) { 1076 return; 1077 } 1078 json_object_object_add(zoneobj, buf, obj); 1079 #endif /* ifdef HAVE_JSON_C */ 1080 break; 1081 } 1082 return; 1083 #ifdef HAVE_LIBXML2 1084 cleanup: 1085 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 1086 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, 1087 "failed at rdatasetstats_dump()"); 1088 dumparg->result = ISC_R_FAILURE; 1089 #endif /* ifdef HAVE_LIBXML2 */ 1090 } 1091 1092 static void 1093 opcodestat_dump(dns_opcode_t code, uint64_t val, void *arg) { 1094 FILE *fp; 1095 isc_buffer_t b; 1096 char codebuf[64]; 1097 stats_dumparg_t *dumparg = arg; 1098 #ifdef HAVE_LIBXML2 1099 void *writer; 1100 int xmlrc; 1101 #endif /* ifdef HAVE_LIBXML2 */ 1102 #ifdef HAVE_JSON_C 1103 json_object *zoneobj, *obj; 1104 #endif /* ifdef HAVE_JSON_C */ 1105 1106 isc_buffer_init(&b, codebuf, sizeof(codebuf) - 1); 1107 dns_opcode_totext(code, &b); 1108 codebuf[isc_buffer_usedlength(&b)] = '\0'; 1109 1110 switch (dumparg->type) { 1111 case isc_statsformat_file: 1112 fp = dumparg->arg; 1113 fprintf(fp, "%20" PRIu64 " %s\n", val, codebuf); 1114 break; 1115 case isc_statsformat_xml: 1116 #ifdef HAVE_LIBXML2 1117 writer = dumparg->arg; 1118 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter")); 1119 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", 1120 ISC_XMLCHAR codebuf)); 1121 TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, val)); 1122 TRY0(xmlTextWriterEndElement(writer)); /* counter */ 1123 #endif /* ifdef HAVE_LIBXML2 */ 1124 break; 1125 case isc_statsformat_json: 1126 #ifdef HAVE_JSON_C 1127 zoneobj = (json_object *)dumparg->arg; 1128 obj = json_object_new_int64(val); 1129 if (obj == NULL) { 1130 return; 1131 } 1132 json_object_object_add(zoneobj, codebuf, obj); 1133 #endif /* ifdef HAVE_JSON_C */ 1134 break; 1135 } 1136 return; 1137 1138 #ifdef HAVE_LIBXML2 1139 cleanup: 1140 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 1141 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, 1142 "failed at opcodestat_dump()"); 1143 dumparg->result = ISC_R_FAILURE; 1144 return; 1145 #endif /* ifdef HAVE_LIBXML2 */ 1146 } 1147 1148 static void 1149 rcodestat_dump(dns_rcode_t code, uint64_t val, void *arg) { 1150 FILE *fp; 1151 isc_buffer_t b; 1152 char codebuf[64]; 1153 stats_dumparg_t *dumparg = arg; 1154 #ifdef HAVE_LIBXML2 1155 void *writer; 1156 int xmlrc; 1157 #endif /* ifdef HAVE_LIBXML2 */ 1158 #ifdef HAVE_JSON_C 1159 json_object *zoneobj, *obj; 1160 #endif /* ifdef HAVE_JSON_C */ 1161 1162 isc_buffer_init(&b, codebuf, sizeof(codebuf) - 1); 1163 dns_rcode_totext(code, &b); 1164 codebuf[isc_buffer_usedlength(&b)] = '\0'; 1165 1166 switch (dumparg->type) { 1167 case isc_statsformat_file: 1168 fp = dumparg->arg; 1169 fprintf(fp, "%20" PRIu64 " %s\n", val, codebuf); 1170 break; 1171 case isc_statsformat_xml: 1172 #ifdef HAVE_LIBXML2 1173 writer = dumparg->arg; 1174 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter")); 1175 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", 1176 ISC_XMLCHAR codebuf)); 1177 TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, val)); 1178 TRY0(xmlTextWriterEndElement(writer)); /* counter */ 1179 #endif /* ifdef HAVE_LIBXML2 */ 1180 break; 1181 case isc_statsformat_json: 1182 #ifdef HAVE_JSON_C 1183 zoneobj = (json_object *)dumparg->arg; 1184 obj = json_object_new_int64(val); 1185 if (obj == NULL) { 1186 return; 1187 } 1188 json_object_object_add(zoneobj, codebuf, obj); 1189 #endif /* ifdef HAVE_JSON_C */ 1190 break; 1191 } 1192 return; 1193 1194 #ifdef HAVE_LIBXML2 1195 cleanup: 1196 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 1197 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, 1198 "failed at rcodestat_dump()"); 1199 dumparg->result = ISC_R_FAILURE; 1200 return; 1201 #endif /* ifdef HAVE_LIBXML2 */ 1202 } 1203 1204 #if defined(EXTENDED_STATS) 1205 static void 1206 dnssecsignstat_dump(uint32_t kval, uint64_t val, void *arg) { 1207 FILE *fp; 1208 char tagbuf[64]; 1209 stats_dumparg_t *dumparg = arg; 1210 #ifdef HAVE_LIBXML2 1211 xmlTextWriterPtr writer; 1212 int xmlrc; 1213 #endif /* ifdef HAVE_LIBXML2 */ 1214 #ifdef HAVE_JSON_C 1215 json_object *zoneobj, *obj; 1216 #endif /* ifdef HAVE_JSON_C */ 1217 1218 /* 1219 * kval is '(algorithm << 16) | keyid'. 1220 */ 1221 snprintf(tagbuf, sizeof(tagbuf), "%u+%u", (kval >> 16) & 0xff, 1222 kval & 0xffff); 1223 1224 switch (dumparg->type) { 1225 case isc_statsformat_file: 1226 fp = dumparg->arg; 1227 fprintf(fp, "%20" PRIu64 " %s\n", val, tagbuf); 1228 break; 1229 case isc_statsformat_xml: 1230 #ifdef HAVE_LIBXML2 1231 writer = dumparg->arg; 1232 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter")); 1233 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", 1234 ISC_XMLCHAR tagbuf)); 1235 TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, val)); 1236 TRY0(xmlTextWriterEndElement(writer)); /* counter */ 1237 #endif /* ifdef HAVE_LIBXML2 */ 1238 break; 1239 case isc_statsformat_json: 1240 #ifdef HAVE_JSON_C 1241 zoneobj = (json_object *)dumparg->arg; 1242 obj = json_object_new_int64(val); 1243 if (obj == NULL) { 1244 return; 1245 } 1246 json_object_object_add(zoneobj, tagbuf, obj); 1247 #endif /* ifdef HAVE_JSON_C */ 1248 break; 1249 } 1250 return; 1251 #ifdef HAVE_LIBXML2 1252 cleanup: 1253 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 1254 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, 1255 "failed at dnssecsignstat_dump()"); 1256 dumparg->result = ISC_R_FAILURE; 1257 return; 1258 #endif /* ifdef HAVE_LIBXML2 */ 1259 } 1260 #endif /* defined(EXTENDED_STATS) */ 1261 1262 #ifdef HAVE_LIBXML2 1263 /* 1264 * Which statistics to include when rendering to XML 1265 */ 1266 #define STATS_XML_STATUS 0x00 /* display only common statistics */ 1267 #define STATS_XML_SERVER 0x01 1268 #define STATS_XML_ZONES 0x02 1269 #define STATS_XML_XFRINS 0x04 1270 #define STATS_XML_NET 0x08 1271 #define STATS_XML_MEM 0x10 1272 #define STATS_XML_TRAFFIC 0x20 1273 #define STATS_XML_ALL 0xff 1274 1275 static isc_result_t 1276 zone_xmlrender(dns_zone_t *zone, void *arg) { 1277 isc_result_t result; 1278 char buf[1024 + 32]; /* sufficiently large for zone name and class */ 1279 dns_rdataclass_t rdclass; 1280 uint32_t serial; 1281 xmlTextWriterPtr writer = arg; 1282 dns_zonestat_level_t statlevel; 1283 int xmlrc; 1284 stats_dumparg_t dumparg; 1285 const char *ztype; 1286 isc_time_t timestamp; 1287 1288 statlevel = dns_zone_getstatlevel(zone); 1289 if (statlevel == dns_zonestat_none) { 1290 return ISC_R_SUCCESS; 1291 } 1292 1293 dumparg.type = isc_statsformat_xml; 1294 dumparg.arg = writer; 1295 1296 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "zone")); 1297 1298 dns_zone_nameonly(zone, buf, sizeof(buf)); 1299 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", 1300 ISC_XMLCHAR buf)); 1301 1302 rdclass = dns_zone_getclass(zone); 1303 dns_rdataclass_format(rdclass, buf, sizeof(buf)); 1304 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "rdataclass", 1305 ISC_XMLCHAR buf)); 1306 1307 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "type")); 1308 ztype = user_zonetype(zone); 1309 if (ztype != NULL) { 1310 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR ztype)); 1311 } else { 1312 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "unknown")); 1313 } 1314 TRY0(xmlTextWriterEndElement(writer)); /* type */ 1315 1316 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "serial")); 1317 if (dns_zone_getserial(zone, &serial) == ISC_R_SUCCESS) { 1318 TRY0(xmlTextWriterWriteFormatString(writer, "%u", serial)); 1319 } else { 1320 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); 1321 } 1322 TRY0(xmlTextWriterEndElement(writer)); /* serial */ 1323 1324 /* 1325 * Export zone timers to the statistics channel in XML format. For 1326 * primary zones, only include the loaded time. For secondary zones, 1327 * also include the expire and refresh times. 1328 */ 1329 CHECK(dns_zone_getloadtime(zone, ×tamp)); 1330 1331 isc_time_formatISO8601(×tamp, buf, 64); 1332 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "loaded")); 1333 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR buf)); 1334 TRY0(xmlTextWriterEndElement(writer)); 1335 1336 if (dns_zone_gettype(zone) == dns_zone_secondary) { 1337 CHECK(dns_zone_getexpiretime(zone, ×tamp)); 1338 isc_time_formatISO8601(×tamp, buf, 64); 1339 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "expires")); 1340 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR buf)); 1341 TRY0(xmlTextWriterEndElement(writer)); 1342 1343 CHECK(dns_zone_getrefreshtime(zone, ×tamp)); 1344 isc_time_formatISO8601(×tamp, buf, 64); 1345 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "refresh")); 1346 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR buf)); 1347 TRY0(xmlTextWriterEndElement(writer)); 1348 } 1349 1350 if (statlevel == dns_zonestat_full) { 1351 isc_stats_t *zonestats; 1352 isc_stats_t *gluecachestats; 1353 dns_stats_t *rcvquerystats; 1354 dns_stats_t *dnssecsignstats; 1355 uint64_t nsstat_values[ns_statscounter_max]; 1356 uint64_t gluecachestats_values[dns_gluecachestatscounter_max]; 1357 1358 zonestats = dns_zone_getrequeststats(zone); 1359 if (zonestats != NULL) { 1360 TRY0(xmlTextWriterStartElement(writer, 1361 ISC_XMLCHAR "counters")); 1362 TRY0(xmlTextWriterWriteAttribute(writer, 1363 ISC_XMLCHAR "type", 1364 ISC_XMLCHAR "rcode")); 1365 1366 CHECK(dump_stats(zonestats, isc_statsformat_xml, writer, 1367 NULL, nsstats_xmldesc, 1368 ns_statscounter_max, nsstats_index, 1369 nsstat_values, ISC_STATSDUMP_VERBOSE)); 1370 /* counters type="rcode"*/ 1371 TRY0(xmlTextWriterEndElement(writer)); 1372 } 1373 1374 gluecachestats = dns_zone_getgluecachestats(zone); 1375 if (gluecachestats != NULL) { 1376 TRY0(xmlTextWriterStartElement(writer, 1377 ISC_XMLCHAR "counters")); 1378 TRY0(xmlTextWriterWriteAttribute( 1379 writer, ISC_XMLCHAR "type", 1380 ISC_XMLCHAR "gluecache")); 1381 1382 CHECK(dump_stats(gluecachestats, isc_statsformat_xml, 1383 writer, NULL, gluecachestats_xmldesc, 1384 dns_gluecachestatscounter_max, 1385 gluecachestats_index, 1386 gluecachestats_values, 1387 ISC_STATSDUMP_VERBOSE)); 1388 /* counters type="rcode"*/ 1389 TRY0(xmlTextWriterEndElement(writer)); 1390 } 1391 1392 rcvquerystats = dns_zone_getrcvquerystats(zone); 1393 if (rcvquerystats != NULL) { 1394 TRY0(xmlTextWriterStartElement(writer, 1395 ISC_XMLCHAR "counters")); 1396 TRY0(xmlTextWriterWriteAttribute(writer, 1397 ISC_XMLCHAR "type", 1398 ISC_XMLCHAR "qtype")); 1399 1400 dumparg.result = ISC_R_SUCCESS; 1401 dns_rdatatypestats_dump(rcvquerystats, rdtypestat_dump, 1402 &dumparg, 0); 1403 CHECK(dumparg.result); 1404 1405 /* counters type="qtype"*/ 1406 TRY0(xmlTextWriterEndElement(writer)); 1407 } 1408 1409 dnssecsignstats = dns_zone_getdnssecsignstats(zone); 1410 if (dnssecsignstats != NULL) { 1411 /* counters type="dnssec-sign"*/ 1412 TRY0(xmlTextWriterStartElement(writer, 1413 ISC_XMLCHAR "counters")); 1414 TRY0(xmlTextWriterWriteAttribute( 1415 writer, ISC_XMLCHAR "type", 1416 ISC_XMLCHAR "dnssec-sign")); 1417 1418 dumparg.result = ISC_R_SUCCESS; 1419 dns_dnssecsignstats_dump( 1420 dnssecsignstats, dns_dnssecsignstats_sign, 1421 dnssecsignstat_dump, &dumparg, 0); 1422 CHECK(dumparg.result); 1423 1424 /* counters type="dnssec-sign"*/ 1425 TRY0(xmlTextWriterEndElement(writer)); 1426 1427 /* counters type="dnssec-refresh"*/ 1428 TRY0(xmlTextWriterStartElement(writer, 1429 ISC_XMLCHAR "counters")); 1430 TRY0(xmlTextWriterWriteAttribute( 1431 writer, ISC_XMLCHAR "type", 1432 ISC_XMLCHAR "dnssec-refresh")); 1433 1434 dumparg.result = ISC_R_SUCCESS; 1435 dns_dnssecsignstats_dump( 1436 dnssecsignstats, dns_dnssecsignstats_refresh, 1437 dnssecsignstat_dump, &dumparg, 0); 1438 CHECK(dumparg.result); 1439 1440 /* counters type="dnssec-refresh"*/ 1441 TRY0(xmlTextWriterEndElement(writer)); 1442 } 1443 } 1444 1445 TRY0(xmlTextWriterEndElement(writer)); /* zone */ 1446 1447 return ISC_R_SUCCESS; 1448 cleanup: 1449 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 1450 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, 1451 "Failed at zone_xmlrender()"); 1452 return ISC_R_FAILURE; 1453 } 1454 1455 static isc_result_t 1456 xfrin_xmlrender(dns_zone_t *zone, void *arg) { 1457 char buf[1024 + 32]; /* sufficiently large for zone name and class */ 1458 dns_rdataclass_t rdclass; 1459 const char *ztype; 1460 uint32_t serial; 1461 isc_sockaddr_t addr; 1462 const isc_sockaddr_t *addrp = NULL; 1463 char addr_buf[ISC_SOCKADDR_FORMATSIZE]; 1464 dns_transport_type_t transport_type; 1465 xmlTextWriterPtr writer = arg; 1466 dns_zonestat_level_t statlevel; 1467 int xmlrc; 1468 dns_xfrin_t *xfr = NULL; 1469 bool is_firstrefresh, is_running, is_deferred, is_presoa, is_pending; 1470 bool needs_refresh; 1471 bool is_first_data_received, is_ixfr; 1472 unsigned int nmsg = 0; 1473 unsigned int nrecs = 0; 1474 uint64_t nbytes = 0; 1475 uint64_t rate = 0; 1476 1477 statlevel = dns_zone_getstatlevel(zone); 1478 if (statlevel == dns_zonestat_none) { 1479 return ISC_R_SUCCESS; 1480 } 1481 1482 if (dns_zone_getxfr(zone, &xfr, &is_firstrefresh, &is_running, 1483 &is_deferred, &is_presoa, &is_pending, 1484 &needs_refresh) != ISC_R_SUCCESS) 1485 { 1486 /* 1487 * Failed to get information about the zone's incoming transfer 1488 * (if any), but we still want to continue generating the 1489 * remaining parts of the output. 1490 */ 1491 return ISC_R_SUCCESS; 1492 } 1493 1494 if (!is_running && !is_deferred && !is_presoa && !is_pending && 1495 !needs_refresh) 1496 { 1497 if (xfr != NULL) { 1498 dns_xfrin_detach(&xfr); 1499 } 1500 /* No ongoing/queued transfer. */ 1501 return ISC_R_SUCCESS; 1502 } 1503 1504 if (is_running && xfr == NULL) { 1505 /* The transfer is finished, and it's shutting down. */ 1506 return ISC_R_SUCCESS; 1507 } 1508 1509 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "xfrin")); 1510 1511 dns_zone_nameonly(zone, buf, sizeof(buf)); 1512 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", 1513 ISC_XMLCHAR buf)); 1514 1515 rdclass = dns_zone_getclass(zone); 1516 dns_rdataclass_format(rdclass, buf, sizeof(buf)); 1517 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "class", 1518 ISC_XMLCHAR buf)); 1519 1520 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "type")); 1521 ztype = user_zonetype(zone); 1522 if (ztype != NULL) { 1523 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR ztype)); 1524 } else { 1525 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); 1526 } 1527 TRY0(xmlTextWriterEndElement(writer)); 1528 1529 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "serial")); 1530 if (dns_zone_getserial(zone, &serial) == ISC_R_SUCCESS) { 1531 TRY0(xmlTextWriterWriteFormatString(writer, "%u", serial)); 1532 } else { 1533 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); 1534 } 1535 TRY0(xmlTextWriterEndElement(writer)); 1536 1537 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "remoteserial")); 1538 if (is_running) { 1539 serial = dns_xfrin_getendserial(xfr); 1540 if (serial != 0) { 1541 TRY0(xmlTextWriterWriteFormatString(writer, "%u", 1542 serial)); 1543 } else { 1544 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); 1545 } 1546 } else { 1547 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); 1548 } 1549 TRY0(xmlTextWriterEndElement(writer)); 1550 1551 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "firstrefresh")); 1552 TRY0(xmlTextWriterWriteString( 1553 writer, ISC_XMLCHAR(is_firstrefresh ? "Yes" : "No"))); 1554 TRY0(xmlTextWriterEndElement(writer)); 1555 1556 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "state")); 1557 if (is_running) { 1558 const char *xfr_state = NULL; 1559 1560 dns_xfrin_getstate(xfr, &xfr_state, &is_first_data_received, 1561 &is_ixfr); 1562 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR xfr_state)); 1563 } else if (is_deferred) { 1564 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "Deferred")); 1565 } else if (is_presoa) { 1566 TRY0(xmlTextWriterWriteString(writer, 1567 ISC_XMLCHAR "Refresh SOA")); 1568 } else if (is_pending) { 1569 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "Pending")); 1570 } else if (needs_refresh) { 1571 TRY0(xmlTextWriterWriteString(writer, 1572 ISC_XMLCHAR "Needs Refresh")); 1573 } else { 1574 UNREACHABLE(); 1575 } 1576 TRY0(xmlTextWriterEndElement(writer)); 1577 1578 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "refreshqueued")); 1579 TRY0(xmlTextWriterWriteString( 1580 writer, 1581 ISC_XMLCHAR(is_running && needs_refresh ? "Yes" : "No"))); 1582 TRY0(xmlTextWriterEndElement(writer)); 1583 1584 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "localaddr")); 1585 if (is_running) { 1586 addrp = dns_xfrin_getsourceaddr(xfr); 1587 isc_sockaddr_format(addrp, addr_buf, sizeof(addr_buf)); 1588 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR addr_buf)); 1589 } else if (is_presoa) { 1590 dns_zone_getsourceaddr(zone, &addr); 1591 isc_sockaddr_format(&addr, addr_buf, sizeof(addr_buf)); 1592 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR addr_buf)); 1593 } else { 1594 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); 1595 } 1596 TRY0(xmlTextWriterEndElement(writer)); 1597 1598 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "remoteaddr")); 1599 if (is_running) { 1600 addrp = dns_xfrin_getprimaryaddr(xfr); 1601 isc_sockaddr_format(addrp, addr_buf, sizeof(addr_buf)); 1602 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR addr_buf)); 1603 } else if (is_presoa) { 1604 if (dns_zone_getprimaryaddr(zone, &addr) == ISC_R_SUCCESS) { 1605 isc_sockaddr_format(&addr, addr_buf, sizeof(addr_buf)); 1606 TRY0(xmlTextWriterWriteString(writer, 1607 ISC_XMLCHAR addr_buf)); 1608 } else { 1609 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); 1610 } 1611 } else { 1612 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); 1613 } 1614 TRY0(xmlTextWriterEndElement(writer)); 1615 1616 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "soatransport")); 1617 if (is_running || is_presoa) { 1618 if (is_running) { 1619 transport_type = dns_xfrin_getsoatransporttype(xfr); 1620 } else { 1621 transport_type = dns_zone_getrequesttransporttype(zone); 1622 } 1623 if (transport_type == DNS_TRANSPORT_UDP) { 1624 TRY0(xmlTextWriterWriteString(writer, 1625 ISC_XMLCHAR "UDP")); 1626 } else if (transport_type == DNS_TRANSPORT_TCP) { 1627 TRY0(xmlTextWriterWriteString(writer, 1628 ISC_XMLCHAR "TCP")); 1629 } else if (transport_type == DNS_TRANSPORT_TLS) { 1630 TRY0(xmlTextWriterWriteString(writer, 1631 ISC_XMLCHAR "TLS")); 1632 } else if (transport_type == DNS_TRANSPORT_NONE) { 1633 TRY0(xmlTextWriterWriteString(writer, 1634 ISC_XMLCHAR "None")); 1635 } else { 1636 /* We don't expect any other SOA transport type. */ 1637 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); 1638 } 1639 } else { 1640 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); 1641 } 1642 TRY0(xmlTextWriterEndElement(writer)); 1643 1644 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "transport")); 1645 if (is_running) { 1646 transport_type = dns_xfrin_gettransporttype(xfr); 1647 if (transport_type == DNS_TRANSPORT_TCP) { 1648 TRY0(xmlTextWriterWriteString(writer, 1649 ISC_XMLCHAR "TCP")); 1650 } else if (transport_type == DNS_TRANSPORT_TLS) { 1651 TRY0(xmlTextWriterWriteString(writer, 1652 ISC_XMLCHAR "TLS")); 1653 } else { 1654 /* We don't expect any other transport type. */ 1655 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); 1656 } 1657 } else { 1658 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); 1659 } 1660 TRY0(xmlTextWriterEndElement(writer)); 1661 1662 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tsigkeyname")); 1663 if (is_running) { 1664 const dns_name_t *tsigkeyname = dns_xfrin_gettsigkeyname(xfr); 1665 char tsigkeyname_buf[DNS_NAME_FORMATSIZE]; 1666 1667 if (tsigkeyname != NULL) { 1668 dns_name_format(tsigkeyname, tsigkeyname_buf, 1669 sizeof(tsigkeyname_buf)); 1670 TRY0(xmlTextWriterWriteString( 1671 writer, ISC_XMLCHAR tsigkeyname_buf)); 1672 } 1673 } 1674 TRY0(xmlTextWriterEndElement(writer)); 1675 1676 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "duration")); 1677 if (is_running || is_deferred || is_presoa || is_pending) { 1678 isc_time_t start = is_running ? dns_xfrin_getstarttime(xfr) 1679 : dns_zone_getxfrintime(zone); 1680 isc_time_t now = isc_time_now(); 1681 isc_time_t diff; 1682 uint32_t sec; 1683 1684 isc_time_subtract(&now, &start, &diff); 1685 sec = isc_time_seconds(&diff); 1686 TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu32, sec)); 1687 } else { 1688 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "0")); 1689 } 1690 TRY0(xmlTextWriterEndElement(writer)); 1691 1692 if (is_running) { 1693 dns_xfrin_getstats(xfr, &nmsg, &nrecs, &nbytes, &rate); 1694 } 1695 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "nmsg")); 1696 TRY0(xmlTextWriterWriteFormatString(writer, "%u", nmsg)); 1697 TRY0(xmlTextWriterEndElement(writer)); 1698 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "nrecs")); 1699 TRY0(xmlTextWriterWriteFormatString(writer, "%u", nrecs)); 1700 TRY0(xmlTextWriterEndElement(writer)); 1701 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "nbytes")); 1702 TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, nbytes)); 1703 TRY0(xmlTextWriterEndElement(writer)); 1704 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "rate")); 1705 TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, rate)); 1706 TRY0(xmlTextWriterEndElement(writer)); 1707 1708 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "ixfr")); 1709 if (is_running && is_first_data_received) { 1710 TRY0(xmlTextWriterWriteString( 1711 writer, ISC_XMLCHAR(is_ixfr ? "Yes" : "No"))); 1712 } else { 1713 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "")); 1714 } 1715 TRY0(xmlTextWriterEndElement(writer)); 1716 1717 TRY0(xmlTextWriterEndElement(writer)); /* xfrin */ 1718 1719 if (xfr != NULL) { 1720 dns_xfrin_detach(&xfr); 1721 } 1722 1723 return ISC_R_SUCCESS; 1724 1725 cleanup: 1726 if (xfr != NULL) { 1727 dns_xfrin_detach(&xfr); 1728 } 1729 1730 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 1731 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, 1732 "Failed at xfrin_xmlrender()"); 1733 1734 return ISC_R_FAILURE; 1735 } 1736 1737 static isc_result_t 1738 generatexml(named_server_t *server, uint32_t flags, int *buflen, 1739 xmlChar **buf) { 1740 char boottime[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"]; 1741 char configtime[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"]; 1742 char nowstr[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"]; 1743 isc_time_t now = isc_time_now(); 1744 xmlTextWriterPtr writer = NULL; 1745 xmlDocPtr doc = NULL; 1746 int xmlrc; 1747 dns_view_t *view; 1748 stats_dumparg_t dumparg; 1749 dns_stats_t *cacherrstats; 1750 uint64_t nsstat_values[ns_statscounter_max]; 1751 uint64_t resstat_values[dns_resstatscounter_max]; 1752 uint64_t adbstat_values[dns_adbstats_max]; 1753 uint64_t zonestat_values[dns_zonestatscounter_max]; 1754 uint64_t sockstat_values[isc_sockstatscounter_max]; 1755 uint64_t udpinsizestat_values[DNS_SIZEHISTO_MAXIN + 1]; 1756 uint64_t udpoutsizestat_values[DNS_SIZEHISTO_MAXOUT + 1]; 1757 uint64_t tcpinsizestat_values[DNS_SIZEHISTO_MAXIN + 1]; 1758 uint64_t tcpoutsizestat_values[DNS_SIZEHISTO_MAXOUT + 1]; 1759 #ifdef HAVE_DNSTAP 1760 uint64_t dnstapstat_values[dns_dnstapcounter_max]; 1761 #endif /* ifdef HAVE_DNSTAP */ 1762 isc_result_t result; 1763 1764 isc_time_formatISO8601ms(&named_g_boottime, boottime, sizeof boottime); 1765 isc_time_formatISO8601ms(&named_g_configtime, configtime, 1766 sizeof configtime); 1767 isc_time_formatISO8601ms(&now, nowstr, sizeof nowstr); 1768 1769 writer = xmlNewTextWriterDoc(&doc, 0); 1770 if (writer == NULL) { 1771 goto cleanup; 1772 } 1773 TRY0(xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL)); 1774 TRY0(xmlTextWriterWritePI(writer, ISC_XMLCHAR "xml-stylesheet", 1775 ISC_XMLCHAR "type=\"text/xsl\" " 1776 "href=\"/bind9.xsl\"")); 1777 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics")); 1778 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version", 1779 ISC_XMLCHAR STATS_XML_VERSION)); 1780 1781 /* Set common fields for statistics dump */ 1782 dumparg.type = isc_statsformat_xml; 1783 dumparg.arg = writer; 1784 1785 /* Render server information */ 1786 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "server")); 1787 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "boot-time")); 1788 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR boottime)); 1789 TRY0(xmlTextWriterEndElement(writer)); /* boot-time */ 1790 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "config-time")); 1791 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR configtime)); 1792 TRY0(xmlTextWriterEndElement(writer)); /* config-time */ 1793 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "current-time")); 1794 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR nowstr)); 1795 TRY0(xmlTextWriterEndElement(writer)); /* current-time */ 1796 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "version")); 1797 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR PACKAGE_VERSION)); 1798 TRY0(xmlTextWriterEndElement(writer)); /* version */ 1799 1800 if ((flags & STATS_XML_SERVER) != 0) { 1801 dumparg.result = ISC_R_SUCCESS; 1802 1803 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1804 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1805 ISC_XMLCHAR "opcode")); 1806 1807 dns_opcodestats_dump(server->sctx->opcodestats, opcodestat_dump, 1808 &dumparg, ISC_STATSDUMP_VERBOSE); 1809 CHECK(dumparg.result); 1810 1811 TRY0(xmlTextWriterEndElement(writer)); 1812 1813 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1814 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1815 ISC_XMLCHAR "rcode")); 1816 1817 dns_rcodestats_dump(server->sctx->rcodestats, rcodestat_dump, 1818 &dumparg, ISC_STATSDUMP_VERBOSE); 1819 CHECK(dumparg.result); 1820 1821 TRY0(xmlTextWriterEndElement(writer)); 1822 1823 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1824 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1825 ISC_XMLCHAR "qtype")); 1826 1827 dumparg.result = ISC_R_SUCCESS; 1828 dns_rdatatypestats_dump(server->sctx->rcvquerystats, 1829 rdtypestat_dump, &dumparg, 0); 1830 CHECK(dumparg.result); 1831 1832 TRY0(xmlTextWriterEndElement(writer)); /* counters */ 1833 1834 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1835 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1836 ISC_XMLCHAR "nsstat")); 1837 1838 CHECK(dump_stats(ns_stats_get(server->sctx->nsstats), 1839 isc_statsformat_xml, writer, NULL, 1840 nsstats_xmldesc, ns_statscounter_max, 1841 nsstats_index, nsstat_values, 1842 ISC_STATSDUMP_VERBOSE)); 1843 1844 TRY0(xmlTextWriterEndElement(writer)); /* /nsstat */ 1845 1846 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1847 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1848 ISC_XMLCHAR "zonestat")); 1849 1850 CHECK(dump_stats(server->zonestats, isc_statsformat_xml, writer, 1851 NULL, zonestats_xmldesc, 1852 dns_zonestatscounter_max, zonestats_index, 1853 zonestat_values, ISC_STATSDUMP_VERBOSE)); 1854 1855 TRY0(xmlTextWriterEndElement(writer)); /* /zonestat */ 1856 1857 /* 1858 * Most of the common resolver statistics entries are 0, so 1859 * we don't use the verbose dump here. 1860 */ 1861 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1862 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1863 ISC_XMLCHAR "resstat")); 1864 CHECK(dump_stats(server->resolverstats, isc_statsformat_xml, 1865 writer, NULL, resstats_xmldesc, 1866 dns_resstatscounter_max, resstats_index, 1867 resstat_values, 0)); 1868 1869 TRY0(xmlTextWriterEndElement(writer)); /* resstat */ 1870 1871 #ifdef HAVE_DNSTAP 1872 if (server->dtenv != NULL) { 1873 isc_stats_t *dnstapstats = NULL; 1874 TRY0(xmlTextWriterStartElement(writer, 1875 ISC_XMLCHAR "counters")); 1876 TRY0(xmlTextWriterWriteAttribute(writer, 1877 ISC_XMLCHAR "type", 1878 ISC_XMLCHAR "dnstap")); 1879 dns_dt_getstats(named_g_server->dtenv, &dnstapstats); 1880 result = dump_stats( 1881 dnstapstats, isc_statsformat_xml, writer, NULL, 1882 dnstapstats_xmldesc, dns_dnstapcounter_max, 1883 dnstapstats_index, dnstapstat_values, 0); 1884 isc_stats_detach(&dnstapstats); 1885 CHECK(result); 1886 1887 TRY0(xmlTextWriterEndElement(writer)); /* dnstap */ 1888 } 1889 #endif /* ifdef HAVE_DNSTAP */ 1890 } 1891 1892 if ((flags & STATS_XML_NET) != 0) { 1893 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1894 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1895 ISC_XMLCHAR "sockstat")); 1896 1897 CHECK(dump_stats(server->sockstats, isc_statsformat_xml, writer, 1898 NULL, sockstats_xmldesc, 1899 isc_sockstatscounter_max, sockstats_index, 1900 sockstat_values, ISC_STATSDUMP_VERBOSE)); 1901 1902 TRY0(xmlTextWriterEndElement(writer)); /* /sockstat */ 1903 } 1904 TRY0(xmlTextWriterEndElement(writer)); /* /server */ 1905 1906 if ((flags & STATS_XML_TRAFFIC) != 0) { 1907 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "traffic")); 1908 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "ipv4")); 1909 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "udp")); 1910 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1911 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1912 ISC_XMLCHAR "request-size")); 1913 1914 CHECK(dump_histo(server->sctx->udpinstats4, isc_statsformat_xml, 1915 writer, NULL, udpinsizestats_xmldesc, 1916 dns_sizecounter_in_max, udpinsizestats_index, 1917 udpinsizestat_values, 0)); 1918 1919 TRY0(xmlTextWriterEndElement(writer)); /* </counters> */ 1920 1921 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1922 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1923 ISC_XMLCHAR "response-size")); 1924 1925 CHECK(dump_histo( 1926 server->sctx->udpoutstats4, isc_statsformat_xml, writer, 1927 NULL, udpoutsizestats_xmldesc, dns_sizecounter_out_max, 1928 udpoutsizestats_index, udpoutsizestat_values, 0)); 1929 1930 TRY0(xmlTextWriterEndElement(writer)); /* </counters> */ 1931 TRY0(xmlTextWriterEndElement(writer)); /* </udp> */ 1932 1933 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tcp")); 1934 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1935 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1936 ISC_XMLCHAR "request-size")); 1937 1938 CHECK(dump_histo(server->sctx->tcpinstats4, isc_statsformat_xml, 1939 writer, NULL, tcpinsizestats_xmldesc, 1940 dns_sizecounter_in_max, tcpinsizestats_index, 1941 tcpinsizestat_values, 0)); 1942 1943 TRY0(xmlTextWriterEndElement(writer)); /* </counters> */ 1944 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1945 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1946 ISC_XMLCHAR "response-size")); 1947 1948 CHECK(dump_histo( 1949 server->sctx->tcpoutstats4, isc_statsformat_xml, writer, 1950 NULL, tcpoutsizestats_xmldesc, dns_sizecounter_out_max, 1951 tcpoutsizestats_index, tcpoutsizestat_values, 0)); 1952 1953 TRY0(xmlTextWriterEndElement(writer)); /* </counters> */ 1954 TRY0(xmlTextWriterEndElement(writer)); /* </tcp> */ 1955 TRY0(xmlTextWriterEndElement(writer)); /* </ipv4> */ 1956 1957 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "ipv6")); 1958 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "udp")); 1959 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1960 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1961 ISC_XMLCHAR "request-size")); 1962 1963 CHECK(dump_histo(server->sctx->udpinstats6, isc_statsformat_xml, 1964 writer, NULL, udpinsizestats_xmldesc, 1965 dns_sizecounter_in_max, udpinsizestats_index, 1966 udpinsizestat_values, 0)); 1967 1968 TRY0(xmlTextWriterEndElement(writer)); /* </counters> */ 1969 1970 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1971 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1972 ISC_XMLCHAR "response-size")); 1973 1974 CHECK(dump_histo( 1975 server->sctx->udpoutstats6, isc_statsformat_xml, writer, 1976 NULL, udpoutsizestats_xmldesc, dns_sizecounter_out_max, 1977 udpoutsizestats_index, udpoutsizestat_values, 0)); 1978 1979 TRY0(xmlTextWriterEndElement(writer)); /* </counters> */ 1980 TRY0(xmlTextWriterEndElement(writer)); /* </udp> */ 1981 1982 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tcp")); 1983 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1984 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1985 ISC_XMLCHAR "request-size")); 1986 1987 CHECK(dump_histo(server->sctx->tcpinstats6, isc_statsformat_xml, 1988 writer, NULL, tcpinsizestats_xmldesc, 1989 dns_sizecounter_in_max, tcpinsizestats_index, 1990 tcpinsizestat_values, 0)); 1991 1992 TRY0(xmlTextWriterEndElement(writer)); /* </counters> */ 1993 1994 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 1995 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 1996 ISC_XMLCHAR "response-size")); 1997 1998 CHECK(dump_histo( 1999 server->sctx->tcpoutstats6, isc_statsformat_xml, writer, 2000 NULL, tcpoutsizestats_xmldesc, dns_sizecounter_out_max, 2001 tcpoutsizestats_index, tcpoutsizestat_values, 0)); 2002 2003 TRY0(xmlTextWriterEndElement(writer)); /* </counters> */ 2004 TRY0(xmlTextWriterEndElement(writer)); /* </tcp> */ 2005 TRY0(xmlTextWriterEndElement(writer)); /* </ipv6> */ 2006 TRY0(xmlTextWriterEndElement(writer)); /* </traffic> */ 2007 } 2008 2009 /* 2010 * Render views. For each view we know of, call its 2011 * rendering function. 2012 */ 2013 view = ISC_LIST_HEAD(server->viewlist); 2014 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "views")); 2015 while (view != NULL && ((flags & (STATS_XML_SERVER | STATS_XML_ZONES | 2016 STATS_XML_XFRINS)) != 0)) 2017 { 2018 isc_stats_t *istats = NULL; 2019 dns_stats_t *dstats = NULL; 2020 dns_adb_t *adb = NULL; 2021 2022 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "view")); 2023 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", 2024 ISC_XMLCHAR view->name)); 2025 2026 if ((flags & STATS_XML_ZONES) != 0) { 2027 TRY0(xmlTextWriterStartElement(writer, 2028 ISC_XMLCHAR "zones")); 2029 CHECK(dns_view_apply(view, true, NULL, zone_xmlrender, 2030 writer)); 2031 TRY0(xmlTextWriterEndElement(writer)); /* /zones */ 2032 } 2033 2034 if ((flags & STATS_XML_XFRINS) != 0) { 2035 TRY0(xmlTextWriterStartElement(writer, 2036 ISC_XMLCHAR "xfrins")); 2037 CHECK(dns_zt_apply(view->zonetable, true, NULL, 2038 xfrin_xmlrender, writer)); 2039 TRY0(xmlTextWriterEndElement(writer)); /* /xfrins */ 2040 } 2041 2042 if ((flags & STATS_XML_SERVER) == 0) { 2043 TRY0(xmlTextWriterEndElement(writer)); /* /view */ 2044 view = ISC_LIST_NEXT(view, link); 2045 continue; 2046 } 2047 2048 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 2049 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 2050 ISC_XMLCHAR "resqtype")); 2051 2052 dns_resolver_getquerystats(view->resolver, &dstats); 2053 if (dstats != NULL) { 2054 dumparg.result = ISC_R_SUCCESS; 2055 dns_rdatatypestats_dump(dstats, rdtypestat_dump, 2056 &dumparg, 0); 2057 CHECK(dumparg.result); 2058 } 2059 dns_stats_detach(&dstats); 2060 TRY0(xmlTextWriterEndElement(writer)); 2061 2062 /* <resstats> */ 2063 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 2064 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 2065 ISC_XMLCHAR "resstats")); 2066 dns_resolver_getstats(view->resolver, &istats); 2067 if (istats != NULL) { 2068 CHECK(dump_stats(istats, isc_statsformat_xml, writer, 2069 NULL, resstats_xmldesc, 2070 dns_resstatscounter_max, 2071 resstats_index, resstat_values, 2072 ISC_STATSDUMP_VERBOSE)); 2073 } 2074 isc_stats_detach(&istats); 2075 TRY0(xmlTextWriterEndElement(writer)); /* </resstats> */ 2076 2077 cacherrstats = dns_db_getrrsetstats(view->cachedb); 2078 if (cacherrstats != NULL) { 2079 TRY0(xmlTextWriterStartElement(writer, 2080 ISC_XMLCHAR "cache")); 2081 TRY0(xmlTextWriterWriteAttribute( 2082 writer, ISC_XMLCHAR "name", 2083 ISC_XMLCHAR dns_cache_getname(view->cache))); 2084 dumparg.result = ISC_R_SUCCESS; 2085 dns_rdatasetstats_dump(cacherrstats, rdatasetstats_dump, 2086 &dumparg, 0); 2087 CHECK(dumparg.result); 2088 TRY0(xmlTextWriterEndElement(writer)); /* cache */ 2089 } 2090 2091 /* <adbstats> */ 2092 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 2093 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 2094 ISC_XMLCHAR "adbstat")); 2095 dns_view_getadb(view, &adb); 2096 if (adb != NULL) { 2097 result = dump_stats(dns_adb_getstats(adb), 2098 isc_statsformat_xml, writer, NULL, 2099 adbstats_xmldesc, dns_adbstats_max, 2100 adbstats_index, adbstat_values, 2101 ISC_STATSDUMP_VERBOSE); 2102 dns_adb_detach(&adb); 2103 CHECK(result); 2104 } 2105 TRY0(xmlTextWriterEndElement(writer)); /* </adbstats> */ 2106 2107 /* <cachestats> */ 2108 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); 2109 TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", 2110 ISC_XMLCHAR "cachestats")); 2111 TRY0(dns_cache_renderxml(view->cache, writer)); 2112 TRY0(xmlTextWriterEndElement(writer)); /* </cachestats> */ 2113 2114 TRY0(xmlTextWriterEndElement(writer)); /* view */ 2115 2116 view = ISC_LIST_NEXT(view, link); 2117 } 2118 TRY0(xmlTextWriterEndElement(writer)); /* /views */ 2119 2120 if ((flags & STATS_XML_MEM) != 0) { 2121 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "memory")); 2122 TRY0(isc_mem_renderxml(writer)); 2123 TRY0(xmlTextWriterEndElement(writer)); /* /memory */ 2124 } 2125 2126 TRY0(xmlTextWriterEndElement(writer)); /* /statistics */ 2127 TRY0(xmlTextWriterEndDocument(writer)); 2128 2129 xmlDocDumpFormatMemoryEnc(doc, buf, buflen, "UTF-8", 0); 2130 if (*buf == NULL) { 2131 goto cleanup; 2132 } 2133 2134 xmlFreeTextWriter(writer); 2135 xmlFreeDoc(doc); 2136 return ISC_R_SUCCESS; 2137 2138 cleanup: 2139 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 2140 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, 2141 "failed generating XML response"); 2142 if (writer != NULL) { 2143 xmlFreeTextWriter(writer); 2144 } 2145 if (doc != NULL) { 2146 xmlFreeDoc(doc); 2147 } 2148 return ISC_R_FAILURE; 2149 } 2150 2151 static void 2152 wrap_xmlfree(isc_buffer_t *buffer, void *arg) { 2153 UNUSED(arg); 2154 2155 xmlFree(isc_buffer_base(buffer)); 2156 } 2157 2158 static isc_result_t 2159 render_xml(uint32_t flags, void *arg, unsigned int *retcode, 2160 const char **retmsg, const char **mimetype, isc_buffer_t *b, 2161 isc_httpdfree_t **freecb, void **freecb_args) { 2162 unsigned char *msg = NULL; 2163 int msglen; 2164 named_server_t *server = arg; 2165 isc_result_t result; 2166 2167 result = generatexml(server, flags, &msglen, &msg); 2168 2169 if (result == ISC_R_SUCCESS) { 2170 *retcode = 200; 2171 *retmsg = "OK"; 2172 *mimetype = "text/xml"; 2173 isc_buffer_reinit(b, msg, msglen); 2174 isc_buffer_add(b, msglen); 2175 *freecb = wrap_xmlfree; 2176 *freecb_args = NULL; 2177 } else { 2178 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 2179 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, 2180 "failed at rendering XML()"); 2181 } 2182 2183 return result; 2184 } 2185 2186 static isc_result_t 2187 render_xml_all(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, 2188 void *arg, unsigned int *retcode, const char **retmsg, 2189 const char **mimetype, isc_buffer_t *b, isc_httpdfree_t **freecb, 2190 void **freecb_args) { 2191 UNUSED(httpd); 2192 UNUSED(urlinfo); 2193 return render_xml(STATS_XML_ALL, arg, retcode, retmsg, mimetype, b, 2194 freecb, freecb_args); 2195 } 2196 2197 static isc_result_t 2198 render_xml_status(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, 2199 void *arg, unsigned int *retcode, const char **retmsg, 2200 const char **mimetype, isc_buffer_t *b, 2201 isc_httpdfree_t **freecb, void **freecb_args) { 2202 UNUSED(httpd); 2203 UNUSED(urlinfo); 2204 return render_xml(STATS_XML_STATUS, arg, retcode, retmsg, mimetype, b, 2205 freecb, freecb_args); 2206 } 2207 2208 static isc_result_t 2209 render_xml_server(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, 2210 void *arg, unsigned int *retcode, const char **retmsg, 2211 const char **mimetype, isc_buffer_t *b, 2212 isc_httpdfree_t **freecb, void **freecb_args) { 2213 UNUSED(httpd); 2214 UNUSED(urlinfo); 2215 return render_xml(STATS_XML_SERVER, arg, retcode, retmsg, mimetype, b, 2216 freecb, freecb_args); 2217 } 2218 2219 static isc_result_t 2220 render_xml_zones(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, 2221 void *arg, unsigned int *retcode, const char **retmsg, 2222 const char **mimetype, isc_buffer_t *b, 2223 isc_httpdfree_t **freecb, void **freecb_args) { 2224 UNUSED(httpd); 2225 UNUSED(urlinfo); 2226 return render_xml(STATS_XML_ZONES, arg, retcode, retmsg, mimetype, b, 2227 freecb, freecb_args); 2228 } 2229 2230 static isc_result_t 2231 render_xml_xfrins(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, 2232 void *arg, unsigned int *retcode, const char **retmsg, 2233 const char **mimetype, isc_buffer_t *b, 2234 isc_httpdfree_t **freecb, void **freecb_args) { 2235 UNUSED(httpd); 2236 UNUSED(urlinfo); 2237 return render_xml(STATS_XML_XFRINS, arg, retcode, retmsg, mimetype, b, 2238 freecb, freecb_args); 2239 } 2240 2241 static isc_result_t 2242 render_xml_net(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, 2243 void *arg, unsigned int *retcode, const char **retmsg, 2244 const char **mimetype, isc_buffer_t *b, isc_httpdfree_t **freecb, 2245 void **freecb_args) { 2246 UNUSED(httpd); 2247 UNUSED(urlinfo); 2248 return render_xml(STATS_XML_NET, arg, retcode, retmsg, mimetype, b, 2249 freecb, freecb_args); 2250 } 2251 2252 static isc_result_t 2253 render_xml_mem(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, 2254 void *arg, unsigned int *retcode, const char **retmsg, 2255 const char **mimetype, isc_buffer_t *b, isc_httpdfree_t **freecb, 2256 void **freecb_args) { 2257 UNUSED(httpd); 2258 UNUSED(urlinfo); 2259 return render_xml(STATS_XML_MEM, arg, retcode, retmsg, mimetype, b, 2260 freecb, freecb_args); 2261 } 2262 2263 static isc_result_t 2264 render_xml_traffic(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, 2265 void *arg, unsigned int *retcode, const char **retmsg, 2266 const char **mimetype, isc_buffer_t *b, 2267 isc_httpdfree_t **freecb, void **freecb_args) { 2268 UNUSED(httpd); 2269 UNUSED(urlinfo); 2270 return render_xml(STATS_XML_TRAFFIC, arg, retcode, retmsg, mimetype, b, 2271 freecb, freecb_args); 2272 } 2273 2274 #endif /* HAVE_LIBXML2 */ 2275 2276 #ifdef HAVE_JSON_C 2277 /* 2278 * Which statistics to include when rendering to JSON 2279 */ 2280 #define STATS_JSON_STATUS 0x00 /* display only common statistics */ 2281 #define STATS_JSON_SERVER 0x01 2282 #define STATS_JSON_ZONES 0x02 2283 #define STATS_JSON_XFRINS 0x04 2284 #define STATS_JSON_NET 0x08 2285 #define STATS_JSON_MEM 0x10 2286 #define STATS_JSON_TRAFFIC 0x20 2287 #define STATS_JSON_ALL 0xff 2288 2289 #define CHECKMEM(m) \ 2290 do { \ 2291 if (m == NULL) { \ 2292 result = ISC_R_NOMEMORY; \ 2293 goto cleanup; \ 2294 } \ 2295 } while (0) 2296 2297 static void 2298 wrap_jsonfree(isc_buffer_t *buffer, void *arg) { 2299 json_object_put(isc_buffer_base(buffer)); 2300 if (arg != NULL) { 2301 json_object_put((json_object *)arg); 2302 } 2303 } 2304 2305 static json_object * 2306 addzone(char *name, char *classname, const char *ztype, uint32_t serial, 2307 bool add_serial) { 2308 json_object *node = json_object_new_object(); 2309 2310 if (node == NULL) { 2311 return NULL; 2312 } 2313 2314 json_object_object_add(node, "name", json_object_new_string(name)); 2315 json_object_object_add(node, "class", 2316 json_object_new_string(classname)); 2317 if (add_serial) { 2318 json_object_object_add(node, "serial", 2319 json_object_new_int64(serial)); 2320 } 2321 if (ztype != NULL) { 2322 json_object_object_add(node, "type", 2323 json_object_new_string(ztype)); 2324 } 2325 return node; 2326 } 2327 2328 static isc_result_t 2329 zone_jsonrender(dns_zone_t *zone, void *arg) { 2330 isc_result_t result = ISC_R_SUCCESS; 2331 char buf[1024 + 32]; /* sufficiently large for zone name and class */ 2332 char classbuf[64]; /* sufficiently large for class */ 2333 char *zone_name_only = NULL; 2334 char *class_only = NULL; 2335 dns_rdataclass_t rdclass; 2336 uint32_t serial; 2337 json_object *zonearray = (json_object *)arg; 2338 json_object *zoneobj = NULL; 2339 dns_zonestat_level_t statlevel; 2340 isc_time_t timestamp; 2341 2342 statlevel = dns_zone_getstatlevel(zone); 2343 if (statlevel == dns_zonestat_none) { 2344 return ISC_R_SUCCESS; 2345 } 2346 2347 dns_zone_nameonly(zone, buf, sizeof(buf)); 2348 zone_name_only = buf; 2349 2350 rdclass = dns_zone_getclass(zone); 2351 dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf)); 2352 class_only = classbuf; 2353 2354 if (dns_zone_getserial(zone, &serial) != ISC_R_SUCCESS) { 2355 zoneobj = addzone(zone_name_only, class_only, 2356 user_zonetype(zone), 0, false); 2357 } else { 2358 zoneobj = addzone(zone_name_only, class_only, 2359 user_zonetype(zone), serial, true); 2360 } 2361 2362 if (zoneobj == NULL) { 2363 return ISC_R_NOMEMORY; 2364 } 2365 2366 /* 2367 * Export zone timers to the statistics channel in JSON format. 2368 * For primary zones, only include the loaded time. For secondary 2369 * zones, also include the expire and refresh times. 2370 */ 2371 2372 CHECK(dns_zone_getloadtime(zone, ×tamp)); 2373 2374 isc_time_formatISO8601(×tamp, buf, 64); 2375 json_object_object_add(zoneobj, "loaded", json_object_new_string(buf)); 2376 2377 if (dns_zone_gettype(zone) == dns_zone_secondary) { 2378 CHECK(dns_zone_getexpiretime(zone, ×tamp)); 2379 isc_time_formatISO8601(×tamp, buf, 64); 2380 json_object_object_add(zoneobj, "expires", 2381 json_object_new_string(buf)); 2382 2383 CHECK(dns_zone_getrefreshtime(zone, ×tamp)); 2384 isc_time_formatISO8601(×tamp, buf, 64); 2385 json_object_object_add(zoneobj, "refresh", 2386 json_object_new_string(buf)); 2387 } 2388 2389 if (statlevel == dns_zonestat_full) { 2390 isc_stats_t *zonestats; 2391 isc_stats_t *gluecachestats; 2392 dns_stats_t *rcvquerystats; 2393 dns_stats_t *dnssecsignstats; 2394 uint64_t nsstat_values[ns_statscounter_max]; 2395 uint64_t gluecachestats_values[dns_gluecachestatscounter_max]; 2396 2397 zonestats = dns_zone_getrequeststats(zone); 2398 if (zonestats != NULL) { 2399 json_object *counters = json_object_new_object(); 2400 if (counters == NULL) { 2401 result = ISC_R_NOMEMORY; 2402 goto cleanup; 2403 } 2404 2405 result = dump_stats(zonestats, isc_statsformat_json, 2406 counters, NULL, nsstats_xmldesc, 2407 ns_statscounter_max, nsstats_index, 2408 nsstat_values, 0); 2409 if (result != ISC_R_SUCCESS) { 2410 json_object_put(counters); 2411 goto cleanup; 2412 } 2413 2414 if (json_object_get_object(counters)->count != 0) { 2415 json_object_object_add(zoneobj, "rcodes", 2416 counters); 2417 } else { 2418 json_object_put(counters); 2419 } 2420 } 2421 2422 gluecachestats = dns_zone_getgluecachestats(zone); 2423 if (gluecachestats != NULL) { 2424 json_object *counters = json_object_new_object(); 2425 if (counters == NULL) { 2426 result = ISC_R_NOMEMORY; 2427 goto cleanup; 2428 } 2429 2430 result = dump_stats( 2431 gluecachestats, isc_statsformat_json, counters, 2432 NULL, gluecachestats_xmldesc, 2433 dns_gluecachestatscounter_max, 2434 gluecachestats_index, gluecachestats_values, 0); 2435 if (result != ISC_R_SUCCESS) { 2436 json_object_put(counters); 2437 goto cleanup; 2438 } 2439 2440 if (json_object_get_object(counters)->count != 0) { 2441 json_object_object_add(zoneobj, "gluecache", 2442 counters); 2443 } else { 2444 json_object_put(counters); 2445 } 2446 } 2447 2448 rcvquerystats = dns_zone_getrcvquerystats(zone); 2449 if (rcvquerystats != NULL) { 2450 stats_dumparg_t dumparg; 2451 json_object *counters = json_object_new_object(); 2452 CHECKMEM(counters); 2453 2454 dumparg.type = isc_statsformat_json; 2455 dumparg.arg = counters; 2456 dumparg.result = ISC_R_SUCCESS; 2457 dns_rdatatypestats_dump(rcvquerystats, rdtypestat_dump, 2458 &dumparg, 0); 2459 if (dumparg.result != ISC_R_SUCCESS) { 2460 json_object_put(counters); 2461 goto cleanup; 2462 } 2463 2464 if (json_object_get_object(counters)->count != 0) { 2465 json_object_object_add(zoneobj, "qtypes", 2466 counters); 2467 } else { 2468 json_object_put(counters); 2469 } 2470 } 2471 2472 dnssecsignstats = dns_zone_getdnssecsignstats(zone); 2473 if (dnssecsignstats != NULL) { 2474 stats_dumparg_t dumparg; 2475 json_object *sign_counters = json_object_new_object(); 2476 CHECKMEM(sign_counters); 2477 2478 dumparg.type = isc_statsformat_json; 2479 dumparg.arg = sign_counters; 2480 dumparg.result = ISC_R_SUCCESS; 2481 dns_dnssecsignstats_dump( 2482 dnssecsignstats, dns_dnssecsignstats_sign, 2483 dnssecsignstat_dump, &dumparg, 0); 2484 if (dumparg.result != ISC_R_SUCCESS) { 2485 json_object_put(sign_counters); 2486 goto cleanup; 2487 } 2488 2489 if (json_object_get_object(sign_counters)->count != 0) { 2490 json_object_object_add(zoneobj, "dnssec-sign", 2491 sign_counters); 2492 } else { 2493 json_object_put(sign_counters); 2494 } 2495 2496 json_object *refresh_counters = 2497 json_object_new_object(); 2498 CHECKMEM(refresh_counters); 2499 2500 dumparg.type = isc_statsformat_json; 2501 dumparg.arg = refresh_counters; 2502 dumparg.result = ISC_R_SUCCESS; 2503 dns_dnssecsignstats_dump( 2504 dnssecsignstats, dns_dnssecsignstats_refresh, 2505 dnssecsignstat_dump, &dumparg, 0); 2506 if (dumparg.result != ISC_R_SUCCESS) { 2507 json_object_put(refresh_counters); 2508 goto cleanup; 2509 } 2510 2511 if (json_object_get_object(refresh_counters)->count != 2512 0) 2513 { 2514 json_object_object_add(zoneobj, 2515 "dnssec-refresh", 2516 refresh_counters); 2517 } else { 2518 json_object_put(refresh_counters); 2519 } 2520 } 2521 } 2522 2523 json_object_array_add(zonearray, zoneobj); 2524 zoneobj = NULL; 2525 result = ISC_R_SUCCESS; 2526 2527 cleanup: 2528 if (zoneobj != NULL) { 2529 json_object_put(zoneobj); 2530 } 2531 return result; 2532 } 2533 2534 static isc_result_t 2535 xfrin_jsonrender(dns_zone_t *zone, void *arg) { 2536 isc_result_t result; 2537 char buf[1024 + 32]; /* sufficiently large for zone name and class */ 2538 char classbuf[64]; /* sufficiently large for class */ 2539 char *zone_name_only = NULL; 2540 char *class_only = NULL; 2541 dns_rdataclass_t rdclass; 2542 uint32_t serial; 2543 json_object *xfrinarray = (json_object *)arg; 2544 json_object *xfrinobj = NULL; 2545 isc_sockaddr_t addr; 2546 const isc_sockaddr_t *addrp = NULL; 2547 char addr_buf[ISC_SOCKADDR_FORMATSIZE]; 2548 dns_transport_type_t transport_type; 2549 dns_zonestat_level_t statlevel; 2550 dns_xfrin_t *xfr = NULL; 2551 bool is_firstrefresh, is_running, is_deferred, is_presoa, is_pending; 2552 bool needs_refresh; 2553 bool is_first_data_received, is_ixfr; 2554 unsigned int nmsg = 0; 2555 unsigned int nrecs = 0; 2556 uint64_t nbytes = 0; 2557 uint64_t rate = 0; 2558 2559 statlevel = dns_zone_getstatlevel(zone); 2560 if (statlevel == dns_zonestat_none) { 2561 return ISC_R_SUCCESS; 2562 } 2563 2564 dns_zone_nameonly(zone, buf, sizeof(buf)); 2565 zone_name_only = buf; 2566 2567 rdclass = dns_zone_getclass(zone); 2568 dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf)); 2569 class_only = classbuf; 2570 2571 if (dns_zone_getserial(zone, &serial) != ISC_R_SUCCESS) { 2572 xfrinobj = addzone(zone_name_only, class_only, 2573 user_zonetype(zone), 0, false); 2574 } else { 2575 xfrinobj = addzone(zone_name_only, class_only, 2576 user_zonetype(zone), serial, true); 2577 } 2578 2579 if (xfrinobj == NULL) { 2580 result = ISC_R_NOMEMORY; 2581 goto cleanup; 2582 } 2583 2584 result = dns_zone_getxfr(zone, &xfr, &is_firstrefresh, &is_running, 2585 &is_deferred, &is_presoa, &is_pending, 2586 &needs_refresh); 2587 if (result != ISC_R_SUCCESS) { 2588 result = ISC_R_SUCCESS; 2589 goto cleanup; 2590 } 2591 2592 if (!is_running && !is_deferred && !is_presoa && !is_pending && 2593 !needs_refresh) 2594 { 2595 /* No ongoing/queued transfer. */ 2596 goto cleanup; 2597 } 2598 2599 if (is_running && xfr == NULL) { 2600 /* The transfer is finished, and it's shutting down. */ 2601 goto cleanup; 2602 } 2603 2604 if (is_running) { 2605 serial = dns_xfrin_getendserial(xfr); 2606 if (serial != 0) { 2607 json_object_object_add(xfrinobj, "remoteserial", 2608 json_object_new_int64(serial)); 2609 } 2610 } 2611 2612 json_object_object_add( 2613 xfrinobj, "firstrefresh", 2614 json_object_new_string(is_firstrefresh ? "Yes" : "No")); 2615 2616 if (is_running) { 2617 const char *xfr_state = NULL; 2618 2619 dns_xfrin_getstate(xfr, &xfr_state, &is_first_data_received, 2620 &is_ixfr); 2621 json_object_object_add(xfrinobj, "state", 2622 json_object_new_string(xfr_state)); 2623 } else if (is_deferred) { 2624 json_object_object_add(xfrinobj, "state", 2625 json_object_new_string("Deferred")); 2626 } else if (is_presoa) { 2627 json_object_object_add(xfrinobj, "state", 2628 json_object_new_string("Refresh SOA")); 2629 } else if (is_pending) { 2630 json_object_object_add(xfrinobj, "state", 2631 json_object_new_string("Pending")); 2632 } else if (needs_refresh) { 2633 json_object_object_add(xfrinobj, "state", 2634 json_object_new_string("Needs Refresh")); 2635 } else { 2636 UNREACHABLE(); 2637 } 2638 2639 json_object_object_add( 2640 xfrinobj, "refreshqueued", 2641 json_object_new_string(is_running && needs_refresh ? "Yes" 2642 : "No")); 2643 2644 if (is_running) { 2645 addrp = dns_xfrin_getsourceaddr(xfr); 2646 isc_sockaddr_format(addrp, addr_buf, sizeof(addr_buf)); 2647 json_object_object_add(xfrinobj, "localaddr", 2648 json_object_new_string(addr_buf)); 2649 } else if (is_presoa) { 2650 dns_zone_getsourceaddr(zone, &addr); 2651 isc_sockaddr_format(&addr, addr_buf, sizeof(addr_buf)); 2652 json_object_object_add(xfrinobj, "localaddr", 2653 json_object_new_string(addr_buf)); 2654 } else { 2655 json_object_object_add(xfrinobj, "localaddr", 2656 json_object_new_string("-")); 2657 } 2658 2659 if (is_running) { 2660 addrp = dns_xfrin_getprimaryaddr(xfr); 2661 isc_sockaddr_format(addrp, addr_buf, sizeof(addr_buf)); 2662 json_object_object_add(xfrinobj, "remoteaddr", 2663 json_object_new_string(addr_buf)); 2664 } else if (is_presoa) { 2665 if (dns_zone_getprimaryaddr(zone, &addr) == ISC_R_SUCCESS) { 2666 isc_sockaddr_format(&addr, addr_buf, sizeof(addr_buf)); 2667 json_object_object_add( 2668 xfrinobj, "remoteaddr", 2669 json_object_new_string(addr_buf)); 2670 } else { 2671 json_object_object_add(xfrinobj, "remoteaddr", 2672 json_object_new_string("-")); 2673 } 2674 } else { 2675 json_object_object_add(xfrinobj, "remoteaddr", 2676 json_object_new_string("-")); 2677 } 2678 2679 if (is_running || is_presoa) { 2680 if (is_running) { 2681 transport_type = dns_xfrin_getsoatransporttype(xfr); 2682 } else { 2683 transport_type = dns_zone_getrequesttransporttype(zone); 2684 } 2685 2686 if (transport_type == DNS_TRANSPORT_UDP) { 2687 json_object_object_add(xfrinobj, "soatransport", 2688 json_object_new_string("UDP")); 2689 } else if (transport_type == DNS_TRANSPORT_TCP) { 2690 json_object_object_add(xfrinobj, "soatransport", 2691 json_object_new_string("TCP")); 2692 } else if (transport_type == DNS_TRANSPORT_TLS) { 2693 json_object_object_add(xfrinobj, "soatransport", 2694 json_object_new_string("TLS")); 2695 } else if (transport_type == DNS_TRANSPORT_NONE) { 2696 json_object_object_add(xfrinobj, "soatransport", 2697 json_object_new_string("None")); 2698 } else { 2699 /* We don't expect any other SOA transport type. */ 2700 json_object_object_add(xfrinobj, "soatransport", 2701 json_object_new_string("-")); 2702 } 2703 } else { 2704 json_object_object_add(xfrinobj, "soatransport", 2705 json_object_new_string("-")); 2706 } 2707 2708 if (is_running) { 2709 transport_type = dns_xfrin_gettransporttype(xfr); 2710 if (transport_type == DNS_TRANSPORT_TCP) { 2711 json_object_object_add(xfrinobj, "transport", 2712 json_object_new_string("TCP")); 2713 } else if (transport_type == DNS_TRANSPORT_TLS) { 2714 json_object_object_add(xfrinobj, "transport", 2715 json_object_new_string("TLS")); 2716 } else { 2717 /* We don't expect any other transport type. */ 2718 json_object_object_add(xfrinobj, "transport", 2719 json_object_new_string("-")); 2720 } 2721 } else { 2722 json_object_object_add(xfrinobj, "transport", 2723 json_object_new_string("-")); 2724 } 2725 2726 if (is_running) { 2727 const dns_name_t *tsigkeyname = dns_xfrin_gettsigkeyname(xfr); 2728 char tsigkeyname_buf[DNS_NAME_FORMATSIZE]; 2729 2730 if (tsigkeyname != NULL) { 2731 dns_name_format(tsigkeyname, tsigkeyname_buf, 2732 sizeof(tsigkeyname_buf)); 2733 json_object_object_add( 2734 xfrinobj, "tsigkeyname", 2735 json_object_new_string(tsigkeyname_buf)); 2736 } else { 2737 json_object_object_add(xfrinobj, "tsigkeyname", NULL); 2738 } 2739 } else { 2740 json_object_object_add(xfrinobj, "tsigkeyname", NULL); 2741 } 2742 2743 if (is_running || is_deferred || is_presoa || is_pending) { 2744 isc_time_t start = is_running ? dns_xfrin_getstarttime(xfr) 2745 : dns_zone_getxfrintime(zone); 2746 isc_time_t now = isc_time_now(); 2747 isc_time_t diff; 2748 uint32_t sec; 2749 2750 isc_time_subtract(&now, &start, &diff); 2751 sec = isc_time_seconds(&diff); 2752 json_object_object_add(xfrinobj, "duration", 2753 json_object_new_int64((int64_t)sec)); 2754 } else { 2755 json_object_object_add(xfrinobj, "duration", 2756 json_object_new_int64(0)); 2757 } 2758 2759 if (is_running) { 2760 dns_xfrin_getstats(xfr, &nmsg, &nrecs, &nbytes, &rate); 2761 } 2762 json_object_object_add(xfrinobj, "nmsg", 2763 json_object_new_int64((int64_t)nmsg)); 2764 json_object_object_add(xfrinobj, "nrecs", 2765 json_object_new_int64((int64_t)nrecs)); 2766 json_object_object_add( 2767 xfrinobj, "nbytes", 2768 json_object_new_int64(nbytes > INT64_MAX ? INT64_MAX 2769 : (int64_t)nbytes)); 2770 json_object_object_add(xfrinobj, "rate", 2771 json_object_new_int64(rate > INT64_MAX 2772 ? INT64_MAX 2773 : (int64_t)rate)); 2774 2775 if (is_running && is_first_data_received) { 2776 json_object_object_add( 2777 xfrinobj, "ixfr", 2778 json_object_new_string(is_ixfr ? "Yes" : "No")); 2779 } else { 2780 json_object_object_add(xfrinobj, "ixfr", 2781 json_object_new_string("")); 2782 } 2783 2784 json_object_array_add(xfrinarray, xfrinobj); 2785 xfrinobj = NULL; 2786 result = ISC_R_SUCCESS; 2787 2788 cleanup: 2789 if (xfr != NULL) { 2790 dns_xfrin_detach(&xfr); 2791 } 2792 if (xfrinobj != NULL) { 2793 json_object_put(xfrinobj); 2794 } 2795 return result; 2796 } 2797 2798 static isc_result_t 2799 generatejson(named_server_t *server, size_t *msglen, const char **msg, 2800 json_object **rootp, uint32_t flags) { 2801 dns_view_t *view; 2802 isc_result_t result = ISC_R_SUCCESS; 2803 json_object *bindstats, *viewlist, *counters, *obj; 2804 json_object *traffic = NULL; 2805 json_object *udpreq4 = NULL, *udpresp4 = NULL; 2806 json_object *tcpreq4 = NULL, *tcpresp4 = NULL; 2807 json_object *udpreq6 = NULL, *udpresp6 = NULL; 2808 json_object *tcpreq6 = NULL, *tcpresp6 = NULL; 2809 uint64_t nsstat_values[ns_statscounter_max]; 2810 uint64_t resstat_values[dns_resstatscounter_max]; 2811 uint64_t adbstat_values[dns_adbstats_max]; 2812 uint64_t zonestat_values[dns_zonestatscounter_max]; 2813 uint64_t sockstat_values[isc_sockstatscounter_max]; 2814 uint64_t udpinsizestat_values[dns_sizecounter_in_max]; 2815 uint64_t udpoutsizestat_values[dns_sizecounter_out_max]; 2816 uint64_t tcpinsizestat_values[dns_sizecounter_in_max]; 2817 uint64_t tcpoutsizestat_values[dns_sizecounter_out_max]; 2818 #ifdef HAVE_DNSTAP 2819 uint64_t dnstapstat_values[dns_dnstapcounter_max]; 2820 #endif /* ifdef HAVE_DNSTAP */ 2821 stats_dumparg_t dumparg; 2822 char boottime[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"]; 2823 char configtime[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"]; 2824 char nowstr[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"]; 2825 isc_time_t now; 2826 2827 REQUIRE(msglen != NULL); 2828 REQUIRE(msg != NULL && *msg == NULL); 2829 REQUIRE(rootp == NULL || *rootp == NULL); 2830 2831 bindstats = json_object_new_object(); 2832 if (bindstats == NULL) { 2833 return ISC_R_NOMEMORY; 2834 } 2835 2836 /* 2837 * These statistics are included no matter which URL we use. 2838 */ 2839 obj = json_object_new_string(STATS_JSON_VERSION); 2840 CHECKMEM(obj); 2841 json_object_object_add(bindstats, "json-stats-version", obj); 2842 2843 now = isc_time_now(); 2844 isc_time_formatISO8601ms(&named_g_boottime, boottime, sizeof(boottime)); 2845 isc_time_formatISO8601ms(&named_g_configtime, configtime, 2846 sizeof configtime); 2847 isc_time_formatISO8601ms(&now, nowstr, sizeof(nowstr)); 2848 2849 obj = json_object_new_string(boottime); 2850 CHECKMEM(obj); 2851 json_object_object_add(bindstats, "boot-time", obj); 2852 2853 obj = json_object_new_string(configtime); 2854 CHECKMEM(obj); 2855 json_object_object_add(bindstats, "config-time", obj); 2856 2857 obj = json_object_new_string(nowstr); 2858 CHECKMEM(obj); 2859 json_object_object_add(bindstats, "current-time", obj); 2860 obj = json_object_new_string(PACKAGE_VERSION); 2861 CHECKMEM(obj); 2862 json_object_object_add(bindstats, "version", obj); 2863 2864 if ((flags & STATS_JSON_SERVER) != 0) { 2865 /* OPCODE counters */ 2866 counters = json_object_new_object(); 2867 2868 dumparg.result = ISC_R_SUCCESS; 2869 dumparg.type = isc_statsformat_json; 2870 dumparg.arg = counters; 2871 2872 dns_opcodestats_dump(server->sctx->opcodestats, opcodestat_dump, 2873 &dumparg, ISC_STATSDUMP_VERBOSE); 2874 if (dumparg.result != ISC_R_SUCCESS) { 2875 json_object_put(counters); 2876 goto cleanup; 2877 } 2878 2879 if (json_object_get_object(counters)->count != 0) { 2880 json_object_object_add(bindstats, "opcodes", counters); 2881 } else { 2882 json_object_put(counters); 2883 } 2884 2885 /* OPCODE counters */ 2886 counters = json_object_new_object(); 2887 2888 dumparg.type = isc_statsformat_json; 2889 dumparg.arg = counters; 2890 2891 dns_rcodestats_dump(server->sctx->rcodestats, rcodestat_dump, 2892 &dumparg, ISC_STATSDUMP_VERBOSE); 2893 if (dumparg.result != ISC_R_SUCCESS) { 2894 json_object_put(counters); 2895 goto cleanup; 2896 } 2897 2898 if (json_object_get_object(counters)->count != 0) { 2899 json_object_object_add(bindstats, "rcodes", counters); 2900 } else { 2901 json_object_put(counters); 2902 } 2903 2904 /* QTYPE counters */ 2905 counters = json_object_new_object(); 2906 2907 dumparg.result = ISC_R_SUCCESS; 2908 dumparg.arg = counters; 2909 2910 dns_rdatatypestats_dump(server->sctx->rcvquerystats, 2911 rdtypestat_dump, &dumparg, 0); 2912 if (dumparg.result != ISC_R_SUCCESS) { 2913 json_object_put(counters); 2914 goto cleanup; 2915 } 2916 2917 if (json_object_get_object(counters)->count != 0) { 2918 json_object_object_add(bindstats, "qtypes", counters); 2919 } else { 2920 json_object_put(counters); 2921 } 2922 2923 /* server stat counters */ 2924 counters = json_object_new_object(); 2925 2926 dumparg.result = ISC_R_SUCCESS; 2927 dumparg.arg = counters; 2928 2929 result = dump_stats(ns_stats_get(server->sctx->nsstats), 2930 isc_statsformat_json, counters, NULL, 2931 nsstats_xmldesc, ns_statscounter_max, 2932 nsstats_index, nsstat_values, 0); 2933 if (result != ISC_R_SUCCESS) { 2934 json_object_put(counters); 2935 goto cleanup; 2936 } 2937 2938 if (json_object_get_object(counters)->count != 0) { 2939 json_object_object_add(bindstats, "nsstats", counters); 2940 } else { 2941 json_object_put(counters); 2942 } 2943 2944 /* zone stat counters */ 2945 counters = json_object_new_object(); 2946 2947 dumparg.result = ISC_R_SUCCESS; 2948 dumparg.arg = counters; 2949 2950 result = dump_stats(server->zonestats, isc_statsformat_json, 2951 counters, NULL, zonestats_xmldesc, 2952 dns_zonestatscounter_max, zonestats_index, 2953 zonestat_values, 0); 2954 if (result != ISC_R_SUCCESS) { 2955 json_object_put(counters); 2956 goto cleanup; 2957 } 2958 2959 if (json_object_get_object(counters)->count != 0) { 2960 json_object_object_add(bindstats, "zonestats", 2961 counters); 2962 } else { 2963 json_object_put(counters); 2964 } 2965 2966 /* resolver stat counters */ 2967 counters = json_object_new_object(); 2968 2969 dumparg.result = ISC_R_SUCCESS; 2970 dumparg.arg = counters; 2971 2972 result = dump_stats(server->resolverstats, isc_statsformat_json, 2973 counters, NULL, resstats_xmldesc, 2974 dns_resstatscounter_max, resstats_index, 2975 resstat_values, 0); 2976 if (result != ISC_R_SUCCESS) { 2977 json_object_put(counters); 2978 goto cleanup; 2979 } 2980 2981 if (json_object_get_object(counters)->count != 0) { 2982 json_object_object_add(bindstats, "resstats", counters); 2983 } else { 2984 json_object_put(counters); 2985 } 2986 2987 #ifdef HAVE_DNSTAP 2988 /* dnstap stat counters */ 2989 if (named_g_server->dtenv != NULL) { 2990 isc_stats_t *dnstapstats = NULL; 2991 dns_dt_getstats(named_g_server->dtenv, &dnstapstats); 2992 counters = json_object_new_object(); 2993 dumparg.result = ISC_R_SUCCESS; 2994 dumparg.arg = counters; 2995 result = dump_stats(dnstapstats, isc_statsformat_json, 2996 counters, NULL, dnstapstats_xmldesc, 2997 dns_dnstapcounter_max, 2998 dnstapstats_index, 2999 dnstapstat_values, 0); 3000 isc_stats_detach(&dnstapstats); 3001 if (result != ISC_R_SUCCESS) { 3002 json_object_put(counters); 3003 goto cleanup; 3004 } 3005 3006 if (json_object_get_object(counters)->count != 0) { 3007 json_object_object_add(bindstats, "dnstapstats", 3008 counters); 3009 } else { 3010 json_object_put(counters); 3011 } 3012 } 3013 #endif /* ifdef HAVE_DNSTAP */ 3014 } 3015 3016 if ((flags & 3017 (STATS_JSON_SERVER | STATS_JSON_ZONES | STATS_JSON_XFRINS)) != 0) 3018 { 3019 viewlist = json_object_new_object(); 3020 CHECKMEM(viewlist); 3021 3022 json_object_object_add(bindstats, "views", viewlist); 3023 3024 view = ISC_LIST_HEAD(server->viewlist); 3025 while (view != NULL) { 3026 json_object *za, *xa, *v = json_object_new_object(); 3027 dns_adb_t *adb = NULL; 3028 3029 CHECKMEM(v); 3030 json_object_object_add(viewlist, view->name, v); 3031 3032 za = json_object_new_array(); 3033 CHECKMEM(za); 3034 3035 if ((flags & STATS_JSON_ZONES) != 0) { 3036 CHECK(dns_view_apply(view, true, NULL, 3037 zone_jsonrender, za)); 3038 } 3039 3040 if (json_object_array_length(za) != 0) { 3041 json_object_object_add(v, "zones", za); 3042 } else { 3043 json_object_put(za); 3044 } 3045 3046 xa = json_object_new_array(); 3047 CHECKMEM(xa); 3048 3049 if ((flags & STATS_JSON_XFRINS) != 0) { 3050 CHECK(dns_zt_apply(view->zonetable, true, NULL, 3051 xfrin_jsonrender, xa)); 3052 } 3053 3054 if (json_object_array_length(xa) != 0) { 3055 json_object_object_add(v, "xfrins", xa); 3056 } else { 3057 json_object_put(xa); 3058 } 3059 3060 if ((flags & STATS_JSON_SERVER) != 0) { 3061 json_object *res = NULL; 3062 dns_stats_t *dstats = NULL; 3063 isc_stats_t *istats = NULL; 3064 3065 res = json_object_new_object(); 3066 CHECKMEM(res); 3067 json_object_object_add(v, "resolver", res); 3068 3069 dns_resolver_getstats(view->resolver, &istats); 3070 if (istats != NULL) { 3071 counters = json_object_new_object(); 3072 CHECKMEM(counters); 3073 3074 result = dump_stats( 3075 istats, isc_statsformat_json, 3076 counters, NULL, 3077 resstats_xmldesc, 3078 dns_resstatscounter_max, 3079 resstats_index, resstat_values, 3080 0); 3081 if (result != ISC_R_SUCCESS) { 3082 json_object_put(counters); 3083 result = dumparg.result; 3084 goto cleanup; 3085 } 3086 3087 json_object_object_add(res, "stats", 3088 counters); 3089 isc_stats_detach(&istats); 3090 } 3091 3092 dns_resolver_getquerystats(view->resolver, 3093 &dstats); 3094 if (dstats != NULL) { 3095 counters = json_object_new_object(); 3096 CHECKMEM(counters); 3097 3098 dumparg.arg = counters; 3099 dumparg.result = ISC_R_SUCCESS; 3100 dns_rdatatypestats_dump(dstats, 3101 rdtypestat_dump, 3102 &dumparg, 0); 3103 if (dumparg.result != ISC_R_SUCCESS) { 3104 json_object_put(counters); 3105 result = dumparg.result; 3106 goto cleanup; 3107 } 3108 3109 json_object_object_add(res, "qtypes", 3110 counters); 3111 dns_stats_detach(&dstats); 3112 } 3113 3114 dstats = dns_db_getrrsetstats(view->cachedb); 3115 if (dstats != NULL) { 3116 counters = json_object_new_object(); 3117 CHECKMEM(counters); 3118 3119 dumparg.arg = counters; 3120 dumparg.result = ISC_R_SUCCESS; 3121 dns_rdatasetstats_dump( 3122 dstats, rdatasetstats_dump, 3123 &dumparg, 0); 3124 if (dumparg.result != ISC_R_SUCCESS) { 3125 json_object_put(counters); 3126 result = dumparg.result; 3127 goto cleanup; 3128 } 3129 3130 json_object_object_add(res, "cache", 3131 counters); 3132 } 3133 3134 counters = json_object_new_object(); 3135 CHECKMEM(counters); 3136 3137 result = dns_cache_renderjson(view->cache, 3138 counters); 3139 if (result != ISC_R_SUCCESS) { 3140 json_object_put(counters); 3141 goto cleanup; 3142 } 3143 3144 json_object_object_add(res, "cachestats", 3145 counters); 3146 3147 dns_view_getadb(view, &adb); 3148 if (adb != NULL) { 3149 istats = dns_adb_getstats(adb); 3150 dns_adb_detach(&adb); 3151 } 3152 if (istats != NULL) { 3153 counters = json_object_new_object(); 3154 CHECKMEM(counters); 3155 3156 result = dump_stats( 3157 istats, isc_statsformat_json, 3158 counters, NULL, 3159 adbstats_xmldesc, 3160 dns_adbstats_max, 3161 adbstats_index, adbstat_values, 3162 0); 3163 if (result != ISC_R_SUCCESS) { 3164 json_object_put(counters); 3165 result = dumparg.result; 3166 goto cleanup; 3167 } 3168 3169 json_object_object_add(res, "adb", 3170 counters); 3171 } 3172 } 3173 3174 view = ISC_LIST_NEXT(view, link); 3175 } 3176 } 3177 3178 if ((flags & STATS_JSON_NET) != 0) { 3179 /* socket stat counters */ 3180 counters = json_object_new_object(); 3181 3182 dumparg.result = ISC_R_SUCCESS; 3183 dumparg.arg = counters; 3184 3185 result = dump_stats(server->sockstats, isc_statsformat_json, 3186 counters, NULL, sockstats_xmldesc, 3187 isc_sockstatscounter_max, sockstats_index, 3188 sockstat_values, 0); 3189 if (result != ISC_R_SUCCESS) { 3190 json_object_put(counters); 3191 goto cleanup; 3192 } 3193 3194 if (json_object_get_object(counters)->count != 0) { 3195 json_object_object_add(bindstats, "sockstats", 3196 counters); 3197 } else { 3198 json_object_put(counters); 3199 } 3200 } 3201 3202 if ((flags & STATS_JSON_MEM) != 0) { 3203 json_object *memory = json_object_new_object(); 3204 CHECKMEM(memory); 3205 3206 result = isc_mem_renderjson(memory); 3207 if (result != ISC_R_SUCCESS) { 3208 json_object_put(memory); 3209 goto cleanup; 3210 } 3211 3212 json_object_object_add(bindstats, "memory", memory); 3213 } 3214 3215 if ((flags & STATS_JSON_TRAFFIC) != 0) { 3216 traffic = json_object_new_object(); 3217 CHECKMEM(traffic); 3218 3219 udpreq4 = json_object_new_object(); 3220 CHECKMEM(udpreq4); 3221 3222 udpresp4 = json_object_new_object(); 3223 CHECKMEM(udpresp4); 3224 3225 tcpreq4 = json_object_new_object(); 3226 CHECKMEM(tcpreq4); 3227 3228 tcpresp4 = json_object_new_object(); 3229 CHECKMEM(tcpresp4); 3230 3231 udpreq6 = json_object_new_object(); 3232 CHECKMEM(udpreq6); 3233 3234 udpresp6 = json_object_new_object(); 3235 CHECKMEM(udpresp6); 3236 3237 tcpreq6 = json_object_new_object(); 3238 CHECKMEM(tcpreq6); 3239 3240 tcpresp6 = json_object_new_object(); 3241 CHECKMEM(tcpresp6); 3242 3243 CHECK(dump_histo(server->sctx->udpinstats4, 3244 isc_statsformat_json, udpreq4, NULL, 3245 udpinsizestats_xmldesc, dns_sizecounter_in_max, 3246 udpinsizestats_index, udpinsizestat_values, 3247 0)); 3248 3249 CHECK(dump_histo(server->sctx->udpoutstats4, 3250 isc_statsformat_json, udpresp4, NULL, 3251 udpoutsizestats_xmldesc, 3252 dns_sizecounter_out_max, udpoutsizestats_index, 3253 udpoutsizestat_values, 0)); 3254 3255 CHECK(dump_histo(server->sctx->tcpinstats4, 3256 isc_statsformat_json, tcpreq4, NULL, 3257 tcpinsizestats_xmldesc, dns_sizecounter_in_max, 3258 tcpinsizestats_index, tcpinsizestat_values, 3259 0)); 3260 3261 CHECK(dump_histo(server->sctx->tcpoutstats4, 3262 isc_statsformat_json, tcpresp4, NULL, 3263 tcpoutsizestats_xmldesc, 3264 dns_sizecounter_out_max, tcpoutsizestats_index, 3265 tcpoutsizestat_values, 0)); 3266 3267 CHECK(dump_histo(server->sctx->udpinstats6, 3268 isc_statsformat_json, udpreq6, NULL, 3269 udpinsizestats_xmldesc, dns_sizecounter_in_max, 3270 udpinsizestats_index, udpinsizestat_values, 3271 0)); 3272 3273 CHECK(dump_histo(server->sctx->udpoutstats6, 3274 isc_statsformat_json, udpresp6, NULL, 3275 udpoutsizestats_xmldesc, 3276 dns_sizecounter_out_max, udpoutsizestats_index, 3277 udpoutsizestat_values, 0)); 3278 3279 CHECK(dump_histo(server->sctx->tcpinstats6, 3280 isc_statsformat_json, tcpreq6, NULL, 3281 tcpinsizestats_xmldesc, dns_sizecounter_in_max, 3282 tcpinsizestats_index, tcpinsizestat_values, 3283 0)); 3284 3285 CHECK(dump_histo(server->sctx->tcpoutstats6, 3286 isc_statsformat_json, tcpresp6, NULL, 3287 tcpoutsizestats_xmldesc, 3288 dns_sizecounter_out_max, tcpoutsizestats_index, 3289 tcpoutsizestat_values, 0)); 3290 3291 json_object_object_add(traffic, 3292 "dns-udp-requests-sizes-received-ipv4", 3293 udpreq4); 3294 json_object_object_add( 3295 traffic, "dns-udp-responses-sizes-sent-ipv4", udpresp4); 3296 json_object_object_add(traffic, 3297 "dns-tcp-requests-sizes-received-ipv4", 3298 tcpreq4); 3299 json_object_object_add( 3300 traffic, "dns-tcp-responses-sizes-sent-ipv4", tcpresp4); 3301 json_object_object_add(traffic, 3302 "dns-udp-requests-sizes-received-ipv6", 3303 udpreq6); 3304 json_object_object_add( 3305 traffic, "dns-udp-responses-sizes-sent-ipv6", udpresp6); 3306 json_object_object_add(traffic, 3307 "dns-tcp-requests-sizes-received-ipv6", 3308 tcpreq6); 3309 json_object_object_add( 3310 traffic, "dns-tcp-responses-sizes-sent-ipv6", tcpresp6); 3311 json_object_object_add(bindstats, "traffic", traffic); 3312 udpreq4 = NULL; 3313 udpresp4 = NULL; 3314 tcpreq4 = NULL; 3315 tcpresp4 = NULL; 3316 udpreq6 = NULL; 3317 udpresp6 = NULL; 3318 tcpreq6 = NULL; 3319 tcpresp6 = NULL; 3320 traffic = NULL; 3321 } 3322 3323 *msg = json_object_to_json_string_ext(bindstats, 3324 JSON_C_TO_STRING_PRETTY); 3325 *msglen = strlen(*msg); 3326 3327 if (rootp != NULL) { 3328 *rootp = bindstats; 3329 bindstats = NULL; 3330 } 3331 3332 result = ISC_R_SUCCESS; 3333 3334 cleanup: 3335 if (udpreq4 != NULL) { 3336 json_object_put(udpreq4); 3337 } 3338 if (udpresp4 != NULL) { 3339 json_object_put(udpresp4); 3340 } 3341 if (tcpreq4 != NULL) { 3342 json_object_put(tcpreq4); 3343 } 3344 if (tcpresp4 != NULL) { 3345 json_object_put(tcpresp4); 3346 } 3347 if (udpreq6 != NULL) { 3348 json_object_put(udpreq6); 3349 } 3350 if (udpresp6 != NULL) { 3351 json_object_put(udpresp6); 3352 } 3353 if (tcpreq6 != NULL) { 3354 json_object_put(tcpreq6); 3355 } 3356 if (tcpresp6 != NULL) { 3357 json_object_put(tcpresp6); 3358 } 3359 if (traffic != NULL) { 3360 json_object_put(traffic); 3361 } 3362 if (bindstats != NULL) { 3363 json_object_put(bindstats); 3364 } 3365 3366 return result; 3367 } 3368 3369 static isc_result_t 3370 render_json(uint32_t flags, void *arg, unsigned int *retcode, 3371 const char **retmsg, const char **mimetype, isc_buffer_t *b, 3372 isc_httpdfree_t **freecb, void **freecb_args) { 3373 isc_result_t result; 3374 json_object *bindstats = NULL; 3375 named_server_t *server = arg; 3376 const char *msg = NULL; 3377 size_t msglen = 0; 3378 char *p; 3379 3380 result = generatejson(server, &msglen, &msg, &bindstats, flags); 3381 if (result == ISC_R_SUCCESS) { 3382 *retcode = 200; 3383 *retmsg = "OK"; 3384 *mimetype = "application/json"; 3385 p = UNCONST(msg); 3386 isc_buffer_reinit(b, p, msglen); 3387 isc_buffer_add(b, msglen); 3388 *freecb = wrap_jsonfree; 3389 *freecb_args = bindstats; 3390 } else { 3391 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 3392 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, 3393 "failed at rendering JSON()"); 3394 } 3395 3396 return result; 3397 } 3398 3399 static isc_result_t 3400 render_json_all(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, 3401 void *arg, unsigned int *retcode, const char **retmsg, 3402 const char **mimetype, isc_buffer_t *b, 3403 isc_httpdfree_t **freecb, void **freecb_args) { 3404 UNUSED(httpd); 3405 UNUSED(urlinfo); 3406 return render_json(STATS_JSON_ALL, arg, retcode, retmsg, mimetype, b, 3407 freecb, freecb_args); 3408 } 3409 3410 static isc_result_t 3411 render_json_status(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, 3412 void *arg, unsigned int *retcode, const char **retmsg, 3413 const char **mimetype, isc_buffer_t *b, 3414 isc_httpdfree_t **freecb, void **freecb_args) { 3415 UNUSED(httpd); 3416 UNUSED(urlinfo); 3417 return render_json(STATS_JSON_STATUS, arg, retcode, retmsg, mimetype, b, 3418 freecb, freecb_args); 3419 } 3420 3421 static isc_result_t 3422 render_json_server(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, 3423 void *arg, unsigned int *retcode, const char **retmsg, 3424 const char **mimetype, isc_buffer_t *b, 3425 isc_httpdfree_t **freecb, void **freecb_args) { 3426 UNUSED(httpd); 3427 UNUSED(urlinfo); 3428 return render_json(STATS_JSON_SERVER, arg, retcode, retmsg, mimetype, b, 3429 freecb, freecb_args); 3430 } 3431 3432 static isc_result_t 3433 render_json_zones(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, 3434 void *arg, unsigned int *retcode, const char **retmsg, 3435 const char **mimetype, isc_buffer_t *b, 3436 isc_httpdfree_t **freecb, void **freecb_args) { 3437 UNUSED(httpd); 3438 UNUSED(urlinfo); 3439 return render_json(STATS_JSON_ZONES, arg, retcode, retmsg, mimetype, b, 3440 freecb, freecb_args); 3441 } 3442 3443 static isc_result_t 3444 render_json_xfrins(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, 3445 void *arg, unsigned int *retcode, const char **retmsg, 3446 const char **mimetype, isc_buffer_t *b, 3447 isc_httpdfree_t **freecb, void **freecb_args) { 3448 UNUSED(httpd); 3449 UNUSED(urlinfo); 3450 return render_json(STATS_JSON_XFRINS, arg, retcode, retmsg, mimetype, b, 3451 freecb, freecb_args); 3452 } 3453 3454 static isc_result_t 3455 render_json_mem(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, 3456 void *arg, unsigned int *retcode, const char **retmsg, 3457 const char **mimetype, isc_buffer_t *b, 3458 isc_httpdfree_t **freecb, void **freecb_args) { 3459 UNUSED(httpd); 3460 UNUSED(urlinfo); 3461 return render_json(STATS_JSON_MEM, arg, retcode, retmsg, mimetype, b, 3462 freecb, freecb_args); 3463 } 3464 3465 static isc_result_t 3466 render_json_net(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, 3467 void *arg, unsigned int *retcode, const char **retmsg, 3468 const char **mimetype, isc_buffer_t *b, 3469 isc_httpdfree_t **freecb, void **freecb_args) { 3470 UNUSED(httpd); 3471 UNUSED(urlinfo); 3472 return render_json(STATS_JSON_NET, arg, retcode, retmsg, mimetype, b, 3473 freecb, freecb_args); 3474 } 3475 3476 static isc_result_t 3477 render_json_traffic(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, 3478 void *arg, unsigned int *retcode, const char **retmsg, 3479 const char **mimetype, isc_buffer_t *b, 3480 isc_httpdfree_t **freecb, void **freecb_args) { 3481 UNUSED(httpd); 3482 UNUSED(urlinfo); 3483 return render_json(STATS_JSON_TRAFFIC, arg, retcode, retmsg, mimetype, 3484 b, freecb, freecb_args); 3485 } 3486 3487 #endif /* HAVE_JSON_C */ 3488 3489 #if HAVE_LIBXML2 3490 /* 3491 * This is only needed if we have libxml2 and was confusingly returned if 3492 * neither of libxml2 or json-c is configured. 3493 */ 3494 static isc_result_t 3495 render_xsl(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, void *args, 3496 unsigned int *retcode, const char **retmsg, const char **mimetype, 3497 isc_buffer_t *b, isc_httpdfree_t **freecb, void **freecb_args) { 3498 isc_result_t result; 3499 char *p = NULL; 3500 3501 UNUSED(httpd); 3502 UNUSED(args); 3503 3504 *freecb = NULL; 3505 *freecb_args = NULL; 3506 *mimetype = "text/xslt+xml"; 3507 3508 if (isc_httpdurl_isstatic(urlinfo)) { 3509 time_t t1, t2; 3510 const isc_time_t *when; 3511 const isc_time_t *loadtime; 3512 3513 when = isc_httpd_if_modified_since(httpd); 3514 3515 if (isc_time_isepoch(when)) { 3516 goto send; 3517 } 3518 3519 result = isc_time_secondsastimet(when, &t1); 3520 if (result != ISC_R_SUCCESS) { 3521 goto send; 3522 } 3523 3524 loadtime = isc_httpdurl_loadtime(urlinfo); 3525 3526 result = isc_time_secondsastimet(loadtime, &t2); 3527 if (result != ISC_R_SUCCESS) { 3528 goto send; 3529 } 3530 3531 if (t1 < t2) { 3532 goto send; 3533 } 3534 3535 *retcode = 304; 3536 *retmsg = "Not modified"; 3537 goto end; 3538 } 3539 3540 send: 3541 *retcode = 200; 3542 *retmsg = "OK"; 3543 p = UNCONST(xslmsg); 3544 isc_buffer_reinit(b, p, strlen(xslmsg)); 3545 isc_buffer_add(b, strlen(xslmsg)); 3546 end: 3547 return ISC_R_SUCCESS; 3548 } 3549 #endif 3550 3551 static void 3552 shutdown_listener(named_statschannel_t *listener) { 3553 char socktext[ISC_SOCKADDR_FORMATSIZE]; 3554 isc_sockaddr_format(&listener->address, socktext, sizeof(socktext)); 3555 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 3556 NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE, 3557 "stopping statistics channel on %s", socktext); 3558 3559 isc_httpdmgr_shutdown(&listener->httpdmgr); 3560 } 3561 3562 #if defined(HAVE_LIBXML2) || defined(HAVE_JSON_C) 3563 static bool 3564 client_ok(const isc_sockaddr_t *fromaddr, void *arg) { 3565 named_statschannel_t *listener = arg; 3566 dns_aclenv_t *env = 3567 ns_interfacemgr_getaclenv(named_g_server->interfacemgr); 3568 isc_netaddr_t netaddr; 3569 char socktext[ISC_SOCKADDR_FORMATSIZE]; 3570 int match; 3571 3572 REQUIRE(listener != NULL); 3573 3574 isc_netaddr_fromsockaddr(&netaddr, fromaddr); 3575 3576 LOCK(&listener->lock); 3577 if ((dns_acl_match(&netaddr, NULL, listener->acl, env, &match, NULL) == 3578 ISC_R_SUCCESS) && 3579 match > 0) 3580 { 3581 UNLOCK(&listener->lock); 3582 return true; 3583 } 3584 UNLOCK(&listener->lock); 3585 3586 isc_sockaddr_format(fromaddr, socktext, sizeof(socktext)); 3587 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 3588 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, 3589 "rejected statistics connection from %s", socktext); 3590 3591 return false; 3592 } 3593 #endif 3594 3595 #if defined(HAVE_LIBXML2) || defined(HAVE_JSON_C) 3596 static void 3597 destroy_listener(void *arg) { 3598 named_statschannel_t *listener = (named_statschannel_t *)arg; 3599 3600 REQUIRE(listener != NULL); 3601 REQUIRE(!ISC_LINK_LINKED(listener, link)); 3602 3603 /* We don't have to acquire the lock here since it's already unlinked */ 3604 dns_acl_detach(&listener->acl); 3605 3606 isc_mutex_destroy(&listener->lock); 3607 isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener)); 3608 } 3609 #endif 3610 3611 static isc_result_t 3612 add_listener(named_server_t *server, named_statschannel_t **listenerp, 3613 const cfg_obj_t *listen_params, const cfg_obj_t *config, 3614 isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, 3615 const char *socktext) { 3616 #if !defined(HAVE_LIBXML2) && !defined(HAVE_JSON_C) 3617 UNUSED(server); 3618 UNUSED(listenerp); 3619 UNUSED(listen_params); 3620 UNUSED(config); 3621 UNUSED(addr); 3622 UNUSED(aclconfctx); 3623 UNUSED(socktext); 3624 3625 return ISC_R_NOTIMPLEMENTED; 3626 #else 3627 isc_result_t result; 3628 named_statschannel_t *listener = NULL; 3629 const cfg_obj_t *allow = NULL; 3630 dns_acl_t *new_acl = NULL; 3631 int pf; 3632 3633 listener = isc_mem_get(server->mctx, sizeof(*listener)); 3634 *listener = (named_statschannel_t){ .address = *addr }; 3635 ISC_LINK_INIT(listener, link); 3636 isc_mutex_init(&listener->lock); 3637 isc_mem_attach(server->mctx, &listener->mctx); 3638 3639 allow = cfg_tuple_get(listen_params, "allow"); 3640 if (allow != NULL && cfg_obj_islist(allow)) { 3641 result = cfg_acl_fromconfig(allow, config, named_g_lctx, 3642 aclconfctx, listener->mctx, 0, 3643 &new_acl); 3644 } else { 3645 result = dns_acl_any(listener->mctx, &new_acl); 3646 } 3647 CHECK(result); 3648 3649 dns_acl_attach(new_acl, &listener->acl); 3650 dns_acl_detach(&new_acl); 3651 3652 pf = isc_sockaddr_pf(&listener->address); 3653 if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) || 3654 (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) 3655 { 3656 CHECK(ISC_R_FAMILYNOSUPPORT); 3657 } 3658 3659 CHECK(isc_httpdmgr_create(named_g_netmgr, server->mctx, addr, client_ok, 3660 destroy_listener, listener, 3661 &listener->httpdmgr)); 3662 3663 #ifdef HAVE_LIBXML2 3664 isc_httpdmgr_addurl(listener->httpdmgr, "/", false, render_xml_all, 3665 server); 3666 isc_httpdmgr_addurl(listener->httpdmgr, "/xml", false, render_xml_all, 3667 server); 3668 isc_httpdmgr_addurl(listener->httpdmgr, 3669 "/xml/v" STATS_XML_VERSION_MAJOR, false, 3670 render_xml_all, server); 3671 isc_httpdmgr_addurl(listener->httpdmgr, 3672 "/xml/v" STATS_XML_VERSION_MAJOR "/status", false, 3673 render_xml_status, server); 3674 isc_httpdmgr_addurl(listener->httpdmgr, 3675 "/xml/v" STATS_XML_VERSION_MAJOR "/server", false, 3676 render_xml_server, server); 3677 isc_httpdmgr_addurl(listener->httpdmgr, 3678 "/xml/v" STATS_XML_VERSION_MAJOR "/zones", false, 3679 render_xml_zones, server); 3680 isc_httpdmgr_addurl(listener->httpdmgr, 3681 "/xml/v" STATS_XML_VERSION_MAJOR "/xfrins", false, 3682 render_xml_xfrins, server); 3683 isc_httpdmgr_addurl(listener->httpdmgr, 3684 "/xml/v" STATS_XML_VERSION_MAJOR "/net", false, 3685 render_xml_net, server); 3686 isc_httpdmgr_addurl(listener->httpdmgr, 3687 "/xml/v" STATS_XML_VERSION_MAJOR "/mem", false, 3688 render_xml_mem, server); 3689 isc_httpdmgr_addurl(listener->httpdmgr, 3690 "/xml/v" STATS_XML_VERSION_MAJOR "/traffic", false, 3691 render_xml_traffic, server); 3692 isc_httpdmgr_addurl(listener->httpdmgr, "/bind9.xsl", true, render_xsl, 3693 server); 3694 #endif /* ifdef HAVE_LIBXML2 */ 3695 #ifdef HAVE_JSON_C 3696 isc_httpdmgr_addurl(listener->httpdmgr, "/json", false, render_json_all, 3697 server); 3698 isc_httpdmgr_addurl(listener->httpdmgr, 3699 "/json/v" STATS_JSON_VERSION_MAJOR, false, 3700 render_json_all, server); 3701 isc_httpdmgr_addurl(listener->httpdmgr, 3702 "/json/v" STATS_JSON_VERSION_MAJOR "/status", false, 3703 render_json_status, server); 3704 isc_httpdmgr_addurl(listener->httpdmgr, 3705 "/json/v" STATS_JSON_VERSION_MAJOR "/server", false, 3706 render_json_server, server); 3707 isc_httpdmgr_addurl(listener->httpdmgr, 3708 "/json/v" STATS_JSON_VERSION_MAJOR "/zones", false, 3709 render_json_zones, server); 3710 isc_httpdmgr_addurl(listener->httpdmgr, 3711 "/json/v" STATS_JSON_VERSION_MAJOR "/xfrins", false, 3712 render_json_xfrins, server); 3713 isc_httpdmgr_addurl(listener->httpdmgr, 3714 "/json/v" STATS_JSON_VERSION_MAJOR "/net", false, 3715 render_json_net, server); 3716 isc_httpdmgr_addurl(listener->httpdmgr, 3717 "/json/v" STATS_JSON_VERSION_MAJOR "/mem", false, 3718 render_json_mem, server); 3719 isc_httpdmgr_addurl(listener->httpdmgr, 3720 "/json/v" STATS_JSON_VERSION_MAJOR "/traffic", 3721 false, render_json_traffic, server); 3722 #endif /* ifdef HAVE_JSON_C */ 3723 3724 *listenerp = listener; 3725 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 3726 NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE, 3727 "statistics channel listening on %s", socktext); 3728 3729 return ISC_R_SUCCESS; 3730 3731 cleanup: 3732 if (listener->acl != NULL) { 3733 dns_acl_detach(&listener->acl); 3734 } 3735 isc_mutex_destroy(&listener->lock); 3736 isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener)); 3737 3738 return result; 3739 #endif 3740 } 3741 3742 static void 3743 update_listener(named_server_t *server, named_statschannel_t **listenerp, 3744 const cfg_obj_t *listen_params, const cfg_obj_t *config, 3745 isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, 3746 const char *socktext) { 3747 named_statschannel_t *listener; 3748 const cfg_obj_t *allow = NULL; 3749 dns_acl_t *new_acl = NULL; 3750 isc_result_t result = ISC_R_SUCCESS; 3751 3752 for (listener = ISC_LIST_HEAD(server->statschannels); listener != NULL; 3753 listener = ISC_LIST_NEXT(listener, link)) 3754 { 3755 if (isc_sockaddr_equal(addr, &listener->address)) { 3756 break; 3757 } 3758 } 3759 3760 if (listener == NULL) { 3761 *listenerp = NULL; 3762 return; 3763 } 3764 3765 /* 3766 * Now, keep the old access list unless a new one can be made. 3767 */ 3768 allow = cfg_tuple_get(listen_params, "allow"); 3769 if (allow != NULL && cfg_obj_islist(allow)) { 3770 result = cfg_acl_fromconfig(allow, config, named_g_lctx, 3771 aclconfctx, listener->mctx, 0, 3772 &new_acl); 3773 } else { 3774 result = dns_acl_any(listener->mctx, &new_acl); 3775 } 3776 3777 if (result == ISC_R_SUCCESS) { 3778 LOCK(&listener->lock); 3779 3780 dns_acl_detach(&listener->acl); 3781 dns_acl_attach(new_acl, &listener->acl); 3782 dns_acl_detach(&new_acl); 3783 3784 UNLOCK(&listener->lock); 3785 } else { 3786 cfg_obj_log(listen_params, named_g_lctx, ISC_LOG_WARNING, 3787 "couldn't install new acl for " 3788 "statistics channel %s: %s", 3789 socktext, isc_result_totext(result)); 3790 } 3791 3792 *listenerp = listener; 3793 } 3794 3795 isc_result_t 3796 named_statschannels_configure(named_server_t *server, const cfg_obj_t *config, 3797 cfg_aclconfctx_t *aclconfctx) { 3798 named_statschannel_t *listener, *listener_next; 3799 named_statschannellist_t new_listeners; 3800 const cfg_obj_t *statschannellist = NULL; 3801 const cfg_listelt_t *element, *element2; 3802 char socktext[ISC_SOCKADDR_FORMATSIZE]; 3803 3804 isc_once_do(&once, init_desc); 3805 3806 ISC_LIST_INIT(new_listeners); 3807 3808 /* 3809 * Get the list of named.conf 'statistics-channels' statements. 3810 */ 3811 (void)cfg_map_get(config, "statistics-channels", &statschannellist); 3812 3813 /* 3814 * Run through the new address/port list, noting sockets that are 3815 * already being listened on and moving them to the new list. 3816 * 3817 * Identifying duplicate addr/port combinations is left to either 3818 * the underlying config code, or to the bind attempt getting an 3819 * address-in-use error. 3820 */ 3821 if (statschannellist != NULL) { 3822 #ifndef EXTENDED_STATS 3823 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 3824 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, 3825 "statistics-channels specified but not effective " 3826 "due to missing XML and/or JSON library"); 3827 #else /* EXTENDED_STATS */ 3828 #ifndef HAVE_LIBXML2 3829 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 3830 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, 3831 "statistics-channels: XML library missing, " 3832 "only JSON stats will be available"); 3833 #endif /* !HAVE_LIBXML2 */ 3834 #ifndef HAVE_JSON_C 3835 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 3836 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, 3837 "statistics-channels: JSON library missing, " 3838 "only XML stats will be available"); 3839 #endif /* !HAVE_JSON_C */ 3840 #endif /* EXTENDED_STATS */ 3841 3842 for (element = cfg_list_first(statschannellist); 3843 element != NULL; element = cfg_list_next(element)) 3844 { 3845 const cfg_obj_t *statschannel; 3846 const cfg_obj_t *listenercfg = NULL; 3847 3848 statschannel = cfg_listelt_value(element); 3849 (void)cfg_map_get(statschannel, "inet", &listenercfg); 3850 if (listenercfg == NULL) { 3851 continue; 3852 } 3853 3854 for (element2 = cfg_list_first(listenercfg); 3855 element2 != NULL; 3856 element2 = cfg_list_next(element2)) 3857 { 3858 const cfg_obj_t *listen_params; 3859 const cfg_obj_t *obj; 3860 isc_sockaddr_t addr; 3861 3862 listen_params = cfg_listelt_value(element2); 3863 3864 obj = cfg_tuple_get(listen_params, "address"); 3865 addr = *cfg_obj_assockaddr(obj); 3866 if (isc_sockaddr_getport(&addr) == 0) { 3867 isc_sockaddr_setport( 3868 &addr, 3869 NAMED_STATSCHANNEL_HTTPPORT); 3870 } 3871 3872 isc_sockaddr_format(&addr, socktext, 3873 sizeof(socktext)); 3874 3875 isc_log_write(named_g_lctx, 3876 NAMED_LOGCATEGORY_GENERAL, 3877 NAMED_LOGMODULE_SERVER, 3878 ISC_LOG_DEBUG(9), 3879 "processing statistics " 3880 "channel %s", 3881 socktext); 3882 3883 update_listener(server, &listener, 3884 listen_params, config, &addr, 3885 aclconfctx, socktext); 3886 3887 if (listener != NULL) { 3888 /* 3889 * Remove the listener from the old 3890 * list, so it won't be shut down. 3891 */ 3892 ISC_LIST_UNLINK(server->statschannels, 3893 listener, link); 3894 } else { 3895 /* 3896 * This is a new listener. 3897 */ 3898 isc_result_t r; 3899 3900 r = add_listener(server, &listener, 3901 listen_params, config, 3902 &addr, aclconfctx, 3903 socktext); 3904 if (r != ISC_R_SUCCESS) { 3905 cfg_obj_log( 3906 listen_params, 3907 named_g_lctx, 3908 ISC_LOG_WARNING, 3909 "couldn't allocate " 3910 "statistics channel" 3911 " %s: %s", 3912 socktext, 3913 isc_result_totext(r)); 3914 } 3915 } 3916 3917 if (listener != NULL) { 3918 ISC_LIST_APPEND(new_listeners, listener, 3919 link); 3920 } 3921 } 3922 } 3923 } 3924 3925 for (listener = ISC_LIST_HEAD(server->statschannels); listener != NULL; 3926 listener = listener_next) 3927 { 3928 listener_next = ISC_LIST_NEXT(listener, link); 3929 ISC_LIST_UNLINK(server->statschannels, listener, link); 3930 shutdown_listener(listener); 3931 } 3932 3933 ISC_LIST_APPENDLIST(server->statschannels, new_listeners, link); 3934 return ISC_R_SUCCESS; 3935 } 3936 3937 void 3938 named_statschannels_shutdown(named_server_t *server) { 3939 named_statschannel_t *listener; 3940 3941 while ((listener = ISC_LIST_HEAD(server->statschannels)) != NULL) { 3942 ISC_LIST_UNLINK(server->statschannels, listener, link); 3943 shutdown_listener(listener); 3944 } 3945 } 3946 3947 isc_result_t 3948 named_stats_dump(named_server_t *server, FILE *fp) { 3949 isc_result_t result; 3950 dns_view_t *view; 3951 dns_zone_t *zone, *next; 3952 stats_dumparg_t dumparg; 3953 uint64_t nsstat_values[ns_statscounter_max]; 3954 uint64_t resstat_values[dns_resstatscounter_max]; 3955 uint64_t adbstat_values[dns_adbstats_max]; 3956 uint64_t zonestat_values[dns_zonestatscounter_max]; 3957 uint64_t sockstat_values[isc_sockstatscounter_max]; 3958 uint64_t gluecachestats_values[dns_gluecachestatscounter_max]; 3959 isc_stdtime_t now = isc_stdtime_now(); 3960 3961 isc_once_do(&once, init_desc); 3962 3963 /* Set common fields */ 3964 dumparg.type = isc_statsformat_file; 3965 dumparg.arg = fp; 3966 3967 fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now); 3968 3969 fprintf(fp, "++ Incoming Requests ++\n"); 3970 dns_opcodestats_dump(server->sctx->opcodestats, opcodestat_dump, 3971 &dumparg, 0); 3972 3973 fprintf(fp, "++ Incoming Queries ++\n"); 3974 dns_rdatatypestats_dump(server->sctx->rcvquerystats, rdtypestat_dump, 3975 &dumparg, 0); 3976 3977 fprintf(fp, "++ Outgoing Rcodes ++\n"); 3978 dns_rcodestats_dump(server->sctx->rcodestats, rcodestat_dump, &dumparg, 3979 0); 3980 3981 fprintf(fp, "++ Outgoing Queries ++\n"); 3982 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; 3983 view = ISC_LIST_NEXT(view, link)) 3984 { 3985 dns_stats_t *dstats = NULL; 3986 dns_resolver_getquerystats(view->resolver, &dstats); 3987 if (dstats == NULL) { 3988 continue; 3989 } 3990 if (strcmp(view->name, "_default") == 0) { 3991 fprintf(fp, "[View: default]\n"); 3992 } else { 3993 fprintf(fp, "[View: %s]\n", view->name); 3994 } 3995 dns_rdatatypestats_dump(dstats, rdtypestat_dump, &dumparg, 0); 3996 dns_stats_detach(&dstats); 3997 } 3998 3999 fprintf(fp, "++ Name Server Statistics ++\n"); 4000 (void)dump_stats(ns_stats_get(server->sctx->nsstats), 4001 isc_statsformat_file, fp, NULL, nsstats_desc, 4002 ns_statscounter_max, nsstats_index, nsstat_values, 0); 4003 4004 fprintf(fp, "++ Zone Maintenance Statistics ++\n"); 4005 (void)dump_stats(server->zonestats, isc_statsformat_file, fp, NULL, 4006 zonestats_desc, dns_zonestatscounter_max, 4007 zonestats_index, zonestat_values, 0); 4008 4009 fprintf(fp, "++ Resolver Statistics ++\n"); 4010 fprintf(fp, "[Common]\n"); 4011 (void)dump_stats(server->resolverstats, isc_statsformat_file, fp, NULL, 4012 resstats_desc, dns_resstatscounter_max, resstats_index, 4013 resstat_values, 0); 4014 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; 4015 view = ISC_LIST_NEXT(view, link)) 4016 { 4017 isc_stats_t *istats = NULL; 4018 dns_resolver_getstats(view->resolver, &istats); 4019 if (istats == NULL) { 4020 continue; 4021 } 4022 if (strcmp(view->name, "_default") == 0) { 4023 fprintf(fp, "[View: default]\n"); 4024 } else { 4025 fprintf(fp, "[View: %s]\n", view->name); 4026 } 4027 (void)dump_stats(istats, isc_statsformat_file, fp, NULL, 4028 resstats_desc, dns_resstatscounter_max, 4029 resstats_index, resstat_values, 0); 4030 isc_stats_detach(&istats); 4031 } 4032 4033 fprintf(fp, "++ Cache Statistics ++\n"); 4034 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; 4035 view = ISC_LIST_NEXT(view, link)) 4036 { 4037 if (strcmp(view->name, "_default") == 0) { 4038 fprintf(fp, "[View: default]\n"); 4039 } else { 4040 fprintf(fp, "[View: %s (Cache: %s)]\n", view->name, 4041 dns_cache_getname(view->cache)); 4042 } 4043 /* 4044 * Avoid dumping redundant statistics when the cache is shared. 4045 */ 4046 if (dns_view_iscacheshared(view)) { 4047 continue; 4048 } 4049 dns_cache_dumpstats(view->cache, fp); 4050 } 4051 4052 fprintf(fp, "++ Cache DB RRsets ++\n"); 4053 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; 4054 view = ISC_LIST_NEXT(view, link)) 4055 { 4056 dns_stats_t *cacherrstats; 4057 4058 cacherrstats = dns_db_getrrsetstats(view->cachedb); 4059 if (cacherrstats == NULL) { 4060 continue; 4061 } 4062 if (strcmp(view->name, "_default") == 0) { 4063 fprintf(fp, "[View: default]\n"); 4064 } else { 4065 fprintf(fp, "[View: %s (Cache: %s)]\n", view->name, 4066 dns_cache_getname(view->cache)); 4067 } 4068 if (dns_view_iscacheshared(view)) { 4069 /* 4070 * Avoid dumping redundant statistics when the cache is 4071 * shared. 4072 */ 4073 continue; 4074 } 4075 dns_rdatasetstats_dump(cacherrstats, rdatasetstats_dump, 4076 &dumparg, 0); 4077 } 4078 4079 fprintf(fp, "++ ADB stats ++\n"); 4080 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; 4081 view = ISC_LIST_NEXT(view, link)) 4082 { 4083 dns_adb_t *adb = NULL; 4084 isc_stats_t *adbstats = NULL; 4085 4086 dns_view_getadb(view, &adb); 4087 if (adb != NULL) { 4088 adbstats = dns_adb_getstats(adb); 4089 dns_adb_detach(&adb); 4090 } 4091 if (adbstats == NULL) { 4092 continue; 4093 } 4094 if (strcmp(view->name, "_default") == 0) { 4095 fprintf(fp, "[View: default]\n"); 4096 } else { 4097 fprintf(fp, "[View: %s]\n", view->name); 4098 } 4099 (void)dump_stats(adbstats, isc_statsformat_file, fp, NULL, 4100 adbstats_desc, dns_adbstats_max, 4101 adbstats_index, adbstat_values, 0); 4102 } 4103 4104 fprintf(fp, "++ Socket I/O Statistics ++\n"); 4105 (void)dump_stats(server->sockstats, isc_statsformat_file, fp, NULL, 4106 sockstats_desc, isc_sockstatscounter_max, 4107 sockstats_index, sockstat_values, 0); 4108 4109 fprintf(fp, "++ Per Zone Query Statistics ++\n"); 4110 zone = NULL; 4111 for (result = dns_zone_first(server->zonemgr, &zone); 4112 result == ISC_R_SUCCESS; 4113 next = NULL, result = dns_zone_next(zone, &next), zone = next) 4114 { 4115 isc_stats_t *zonestats = dns_zone_getrequeststats(zone); 4116 if (zonestats != NULL) { 4117 char zonename[DNS_NAME_FORMATSIZE]; 4118 4119 view = dns_zone_getview(zone); 4120 if (view == NULL) { 4121 continue; 4122 } 4123 4124 dns_name_format(dns_zone_getorigin(zone), zonename, 4125 sizeof(zonename)); 4126 fprintf(fp, "[%s", zonename); 4127 if (strcmp(view->name, "_default") != 0) { 4128 fprintf(fp, " (view: %s)", view->name); 4129 } 4130 fprintf(fp, "]\n"); 4131 4132 (void)dump_stats(zonestats, isc_statsformat_file, fp, 4133 NULL, nsstats_desc, 4134 ns_statscounter_max, nsstats_index, 4135 nsstat_values, 0); 4136 } 4137 } 4138 4139 fprintf(fp, "++ Per Zone Glue Cache Statistics ++\n"); 4140 zone = NULL; 4141 for (result = dns_zone_first(server->zonemgr, &zone); 4142 result == ISC_R_SUCCESS; 4143 next = NULL, result = dns_zone_next(zone, &next), zone = next) 4144 { 4145 isc_stats_t *gluecachestats = dns_zone_getgluecachestats(zone); 4146 if (gluecachestats != NULL) { 4147 char zonename[DNS_NAME_FORMATSIZE]; 4148 4149 view = dns_zone_getview(zone); 4150 if (view == NULL) { 4151 continue; 4152 } 4153 4154 dns_name_format(dns_zone_getorigin(zone), zonename, 4155 sizeof(zonename)); 4156 fprintf(fp, "[%s", zonename); 4157 if (strcmp(view->name, "_default") != 0) { 4158 fprintf(fp, " (view: %s)", view->name); 4159 } 4160 fprintf(fp, "]\n"); 4161 4162 (void)dump_stats(gluecachestats, isc_statsformat_file, 4163 fp, NULL, gluecachestats_desc, 4164 dns_gluecachestatscounter_max, 4165 gluecachestats_index, 4166 gluecachestats_values, 0); 4167 } 4168 } 4169 4170 fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now); 4171 4172 return ISC_R_SUCCESS; /* this function currently always succeeds */ 4173 } 4174