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