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