diff options
author | Doug Barton <dougb@FreeBSD.org> | 2009-05-31 05:42:58 +0000 |
---|---|---|
committer | Doug Barton <dougb@FreeBSD.org> | 2009-05-31 05:42:58 +0000 |
commit | 6318052d9e161cbc69e4085125ef824d94de16ef (patch) | |
tree | 21a5399cf53ce4f1ffedece1c1700a317f190f2e /contrib/bind9/bin/named/server.c | |
parent | b6d434fc28de9fa7b453178184bdcc767035f5af (diff) | |
parent | b0e69f719c1db2c19fcfba96f0dac9a5a2277350 (diff) |
Update BIND to version 9.6.1rc1. This version has better performance and
lots of new features compared to 9.4.x, including:
Full NSEC3 support
Automatic zone re-signing
New update-policy methods tcp-self and 6to4-self
DHCID support.
More detailed statistics counters including those supported in BIND 8.
Faster ACL processing.
Efficient LRU cache-cleaning mechanism.
NSID support.
Notes
Notes:
svn path=/head/; revision=193149
Diffstat (limited to 'contrib/bind9/bin/named/server.c')
-rw-r--r-- | contrib/bind9/bin/named/server.c | 905 |
1 files changed, 711 insertions, 194 deletions
diff --git a/contrib/bind9/bin/named/server.c b/contrib/bind9/bin/named/server.c index 784ff94d3414..e685e18dc336 100644 --- a/contrib/bind9/bin/named/server.c +++ b/contrib/bind9/bin/named/server.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.419.18.68 2008/09/04 23:46:08 tbox Exp $ */ +/* $Id: server.c,v 1.520.12.7 2009/01/30 03:53:38 marka Exp $ */ /*! \file */ @@ -30,17 +30,20 @@ #include <isc/entropy.h> #include <isc/file.h> #include <isc/hash.h> +#include <isc/httpd.h> #include <isc/lex.h> #include <isc/parseint.h> #include <isc/portset.h> #include <isc/print.h> #include <isc/resource.h> #include <isc/socket.h> +#include <isc/stats.h> #include <isc/stdio.h> #include <isc/string.h> #include <isc/task.h> #include <isc/timer.h> #include <isc/util.h> +#include <isc/xml.h> #include <isccfg/namedconf.h> @@ -63,6 +66,7 @@ #include <dns/order.h> #include <dns/peer.h> #include <dns/portlist.h> +#include <dns/rbt.h> #include <dns/rdataclass.h> #include <dns/rdataset.h> #include <dns/rdatastruct.h> @@ -71,6 +75,7 @@ #include <dns/secalg.h> #include <dns/stats.h> #include <dns/tkey.h> +#include <dns/tsig.h> #include <dns/view.h> #include <dns/zone.h> #include <dns/zt.h> @@ -88,6 +93,7 @@ #include <named/main.h> #include <named/os.h> #include <named/server.h> +#include <named/statschannel.h> #include <named/tkeyconf.h> #include <named/tsigconf.h> #include <named/zoneconf.h> @@ -101,12 +107,12 @@ * using it has a 'result' variable and a 'cleanup' label. */ #define CHECK(op) \ - do { result = (op); \ - if (result != ISC_R_SUCCESS) goto cleanup; \ + do { result = (op); \ + if (result != ISC_R_SUCCESS) goto cleanup; \ } while (0) #define CHECKM(op, msg) \ - do { result = (op); \ + do { result = (op); \ if (result != ISC_R_SUCCESS) { \ isc_log_write(ns_g_lctx, \ NS_LOGCATEGORY_GENERAL, \ @@ -119,7 +125,7 @@ } while (0) \ #define CHECKMF(op, msg, file) \ - do { result = (op); \ + do { result = (op); \ if (result != ISC_R_SUCCESS) { \ isc_log_write(ns_g_lctx, \ NS_LOGCATEGORY_GENERAL, \ @@ -132,7 +138,7 @@ } while (0) \ #define CHECKFATAL(op, msg) \ - do { result = (op); \ + do { result = (op); \ if (result != ISC_R_SUCCESS) \ fatal(msg, result); \ } while (0) \ @@ -209,7 +215,7 @@ static const struct { /* Local IPv6 Unicast Addresses */ { "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA", ISC_FALSE }, { "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA", ISC_FALSE }, - /* LOCALLY ASSIGNED LOCAL ADDRES S SCOPE */ + /* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */ { "D.F.IP6.ARPA", ISC_FALSE }, { "8.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ { "9.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ @@ -251,9 +257,8 @@ static void end_reserved_dispatches(ns_server_t *server, isc_boolean_t all); /*% - * Configure a single view ACL at '*aclp'. Get its configuration by - * calling 'getvcacl' (for per-view configuration) and maybe 'getscacl' - * (for a global default). + * Configure a single view ACL at '*aclp'. Get its configuration from + * 'vconfig' (for per-view configuration) and maybe from 'config' */ static isc_result_t configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config, @@ -280,12 +285,56 @@ configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config, (void)ns_config_get(maps, aclname, &aclobj); if (aclobj == NULL) /* - * No value available. *aclp == NULL. + * No value available. *aclp == NULL. */ return (ISC_R_SUCCESS); result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, - actx, mctx, aclp); + actx, mctx, 0, aclp); + + return (result); +} + + +/*% + * Configure a sortlist at '*aclp'. Essentially the same as + * configure_view_acl() except it calls cfg_acl_fromconfig with a + * nest_level value of 2. + */ +static isc_result_t +configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config, + cfg_aclconfctx_t *actx, isc_mem_t *mctx, + dns_acl_t **aclp) +{ + isc_result_t result; + const cfg_obj_t *maps[3]; + const cfg_obj_t *aclobj = NULL; + int i = 0; + + if (*aclp != NULL) + dns_acl_detach(aclp); + if (vconfig != NULL) + maps[i++] = cfg_tuple_get(vconfig, "options"); + if (config != NULL) { + const cfg_obj_t *options = NULL; + (void)cfg_map_get(config, "options", &options); + if (options != NULL) + maps[i++] = options; + } + maps[i] = NULL; + + (void)ns_config_get(maps, "sortlist", &aclobj); + if (aclobj == NULL) + return (ISC_R_SUCCESS); + + /* + * Use a nest level of 3 for the "top level" of the sortlist; + * this means each entry in the top three levels will be stored + * as lists of separate, nested ACLs, rather than merged together + * into IP tables as is usually done with ACLs. + */ + result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, + actx, mctx, 3, aclp); return (result); } @@ -398,7 +447,7 @@ configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key, * the security roots. * * The per-view configuration values and the server-global defaults are read - * from 'vconfig' and 'config'. The variable to be configured is '*target'. + * from 'vconfig' and 'config'. The variable to be configured is '*target'. */ static isc_result_t configure_view_dnsseckeys(const cfg_obj_t *vconfig, const cfg_obj_t *config, @@ -694,6 +743,11 @@ configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj))); obj = NULL; + (void)cfg_map_get(cpeer, "request-nsid", &obj); + if (obj != NULL) + CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj))); + + obj = NULL; (void)cfg_map_get(cpeer, "edns", &obj); if (obj != NULL) CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj))); @@ -901,6 +955,41 @@ check_dbtype(dns_zone_t **zonep, unsigned int dbtypec, const char **dbargv, isc_mem_free(mctx, argv); } +static isc_result_t +setquerystats(dns_zone_t *zone, isc_mem_t *mctx, isc_boolean_t on) { + isc_result_t result; + isc_stats_t *zoneqrystats; + + zoneqrystats = NULL; + if (on) { + result = isc_stats_create(mctx, &zoneqrystats, + dns_nsstatscounter_max); + if (result != ISC_R_SUCCESS) + return (result); + } + dns_zone_setrequeststats(zone, zoneqrystats); + if (zoneqrystats != NULL) + isc_stats_detach(&zoneqrystats); + + return (ISC_R_SUCCESS); +} + +static isc_boolean_t +cache_reusable(dns_view_t *originview, dns_view_t *view, + isc_boolean_t new_zero_no_soattl) +{ + if (originview->checknames != view->checknames || + dns_resolver_getzeronosoattl(originview->resolver) != + new_zero_no_soattl || + originview->acceptexpired != view->acceptexpired || + originview->enablevalidation != view->enablevalidation || + originview->maxcachettl != view->maxcachettl || + originview->maxncachettl != view->maxncachettl) { + return (ISC_FALSE); + } + + return (ISC_TRUE); +} /* * Configure 'view' according to 'vconfig', taking defaults from 'config' @@ -947,7 +1036,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, const char *str; dns_order_t *order = NULL; isc_uint32_t udpsize; - unsigned int check = 0; + unsigned int resopts = 0; dns_zone_t *zone = NULL; isc_uint32_t max_clients_per_query; const char *sep = ": view "; @@ -956,6 +1045,9 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, isc_boolean_t rfc1918; isc_boolean_t empty_zones_enable; const cfg_obj_t *disablelist = NULL; + isc_stats_t *resstats = NULL; + dns_stats_t *resquerystats = NULL; + isc_boolean_t zero_no_soattl; REQUIRE(DNS_VIEW_VALID(view)); @@ -1005,6 +1097,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, CHECK(isc_mem_create(0, 0, &cmctx)); CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr, ns_g_timermgr)); + isc_mem_setname(cmctx, "acache", NULL); isc_mem_detach(&cmctx); } if (view->acache != NULL) { @@ -1096,17 +1189,70 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, #endif /* + * Obtain configuration parameters that affect the decision of whether + * we can reuse/share an existing cache. + */ + /* Check-names. */ + obj = NULL; + result = ns_checknames_get(maps, "response", &obj); + INSIST(result == ISC_R_SUCCESS); + + str = cfg_obj_asstring(obj); + if (strcasecmp(str, "fail") == 0) { + resopts |= DNS_RESOLVER_CHECKNAMES | + DNS_RESOLVER_CHECKNAMESFAIL; + view->checknames = ISC_TRUE; + } else if (strcasecmp(str, "warn") == 0) { + resopts |= DNS_RESOLVER_CHECKNAMES; + view->checknames = ISC_FALSE; + } else if (strcasecmp(str, "ignore") == 0) { + view->checknames = ISC_FALSE; + } else + INSIST(0); + + obj = NULL; + result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj); + INSIST(result == ISC_R_SUCCESS); + zero_no_soattl = cfg_obj_asboolean(obj); + + obj = NULL; + result = ns_config_get(maps, "dnssec-accept-expired", &obj); + INSIST(result == ISC_R_SUCCESS); + view->acceptexpired = cfg_obj_asboolean(obj); + + obj = NULL; + result = ns_config_get(maps, "dnssec-validation", &obj); + INSIST(result == ISC_R_SUCCESS); + view->enablevalidation = cfg_obj_asboolean(obj); + + obj = NULL; + result = ns_config_get(maps, "max-cache-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + view->maxcachettl = cfg_obj_asuint32(obj); + + obj = NULL; + result = ns_config_get(maps, "max-ncache-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + view->maxncachettl = cfg_obj_asuint32(obj); + if (view->maxncachettl > 7 * 24 * 3600) + view->maxncachettl = 7 * 24 * 3600; + + /* * Configure the view's cache. Try to reuse an existing * cache if possible, otherwise create a new cache. * Note that the ADB is not preserved in either case. + * When a matching view is found, the associated statistics are + * also retrieved and reused. * - * XXX Determining when it is safe to reuse a cache is - * tricky. When the view's configuration changes, the cached - * data may become invalid because it reflects our old - * view of the world. As more view attributes become - * configurable, we will have to add code here to check - * whether they have changed in ways that could - * invalidate the cache. + * XXX Determining when it is safe to reuse a cache is tricky. + * When the view's configuration changes, the cached data may become + * invalid because it reflects our old view of the world. We check + * some of the configuration parameters that could invalidate the cache, + * but there are other configuration options that should be checked. + * For example, if a view uses a forwarder, changes in the forwarder + * configuration may invalidate the cache. At the moment, it's the + * administrator's responsibility to ensure these configuration options + * don't invalidate reusing. */ result = dns_viewlist_find(&ns_g_server->viewlist, view->name, view->rdclass, @@ -1114,17 +1260,29 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) goto cleanup; if (pview != NULL) { - INSIST(pview->cache != NULL); - isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, - NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(3), - "reusing existing cache"); - reused_cache = ISC_TRUE; - dns_cache_attach(pview->cache, &cache); + if (cache_reusable(pview, view, zero_no_soattl)) { + INSIST(pview->cache != NULL); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(3), + "reusing existing cache"); + reused_cache = ISC_TRUE; + dns_cache_attach(pview->cache, &cache); + } else { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), + "cache cannot be reused for view %s " + "due to configuration parameter mismatch", + view->name); + } + dns_view_getresstats(pview, &resstats); + dns_view_getresquerystats(pview, &resquerystats); dns_view_detach(&pview); - } else { + } + if (cache == NULL) { CHECK(isc_mem_create(0, 0, &cmctx)); CHECK(dns_cache_create(cmctx, ns_g_taskmgr, ns_g_timermgr, view->rdclass, "rbt", 0, NULL, &cache)); + isc_mem_setname(cmctx, "cache", NULL); } dns_view_setcache(view, cache); @@ -1170,27 +1328,6 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, dns_cache_detach(&cache); /* - * Check-names. - */ - obj = NULL; - result = ns_checknames_get(maps, "response", &obj); - INSIST(result == ISC_R_SUCCESS); - - str = cfg_obj_asstring(obj); - if (strcasecmp(str, "fail") == 0) { - check = DNS_RESOLVER_CHECKNAMES | - DNS_RESOLVER_CHECKNAMESFAIL; - view->checknames = ISC_TRUE; - } else if (strcasecmp(str, "warn") == 0) { - check = DNS_RESOLVER_CHECKNAMES; - view->checknames = ISC_FALSE; - } else if (strcasecmp(str, "ignore") == 0) { - check = 0; - view->checknames = ISC_FALSE; - } else - INSIST(0); - - /* * Resolver. * * XXXRTH Hardwired number of tasks. @@ -1210,9 +1347,18 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, } CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31, ns_g_socketmgr, ns_g_timermgr, - check, ns_g_dispatchmgr, + resopts, ns_g_dispatchmgr, dispatch4, dispatch6)); + if (resstats == NULL) { + CHECK(isc_stats_create(mctx, &resstats, + dns_resstatscounter_max)); + } + dns_view_setresstats(view, resstats); + if (resquerystats == NULL) + CHECK(dns_rdatatypestats_create(mctx, &resquerystats)); + dns_view_setresquerystats(view, resquerystats); + /* * Set the ADB cache size to 1/8th of the max-cache-size. */ @@ -1235,11 +1381,6 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, lame_ttl = 1800; dns_resolver_setlamettl(view->resolver, lame_ttl); - obj = NULL; - result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj); - INSIST(result == ISC_R_SUCCESS); - dns_resolver_setzeronosoattl(view->resolver, cfg_obj_asboolean(obj)); - /* * Set the resolver's EDNS UDP size. */ @@ -1460,28 +1601,26 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, } /* - * Set "allow-query-cache" and "allow-recursion" acls if + * Set "allow-query-cache", "allow-query-cache-on", + * "allow-recursion", and "allow-recursion-on" acls if * configured in named.conf. */ CHECK(configure_view_acl(vconfig, config, "allow-query-cache", actx, ns_g_mctx, &view->queryacl)); - - if (strcmp(view->name, "_bind") != 0) + CHECK(configure_view_acl(vconfig, config, "allow-query-cache-on", + actx, ns_g_mctx, &view->queryonacl)); + if (view->queryonacl == NULL) + CHECK(configure_view_acl(NULL, ns_g_config, + "allow-query-cache-on", actx, + ns_g_mctx, &view->queryonacl)); + if (strcmp(view->name, "_bind") != 0) { CHECK(configure_view_acl(vconfig, config, "allow-recursion", - actx, ns_g_mctx, &view->recursionacl)); - - /* - * Warning if both "recursion no;" and allow-recursion are active - * except for "allow-recursion { none; };". - */ - if (!view->recursion && view->recursionacl != NULL && - (view->recursionacl->length != 1 || - view->recursionacl->elements[0].type != dns_aclelementtype_any || - view->recursionacl->elements[0].negative != ISC_TRUE)) - isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, - NS_LOGMODULE_SERVER, ISC_LOG_WARNING, - "both \"recursion no;\" and \"allow-recursion\" " - "active%s%s", forview, viewname); + actx, ns_g_mctx, + &view->recursionacl)); + CHECK(configure_view_acl(vconfig, config, "allow-recursion-on", + actx, ns_g_mctx, + &view->recursiononacl)); + } /* * "allow-query-cache" inherits from "allow-recursion" if set, @@ -1491,25 +1630,66 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, */ if (view->queryacl == NULL && view->recursionacl != NULL) dns_acl_attach(view->recursionacl, &view->queryacl); - if (view->queryacl == NULL) + if (view->queryacl == NULL && view->recursion) CHECK(configure_view_acl(vconfig, config, "allow-query", actx, ns_g_mctx, &view->queryacl)); - if (view->recursionacl == NULL && view->queryacl != NULL) + if (view->recursion && + view->recursionacl == NULL && view->queryacl != NULL) dns_acl_attach(view->queryacl, &view->recursionacl); /* - * Set default "allow-recursion" and "allow-query-cache" acls. + * Set default "allow-recursion", "allow-recursion-on" and + * "allow-query-cache" acls. */ if (view->recursionacl == NULL && view->recursion) - CHECK(configure_view_acl(NULL, ns_g_config, "allow-recursion", - actx, ns_g_mctx, &view->recursionacl)); - if (view->queryacl == NULL) CHECK(configure_view_acl(NULL, ns_g_config, - "allow-query-cache", actx, - ns_g_mctx, &view->queryacl)); + "allow-recursion", + actx, ns_g_mctx, + &view->recursionacl)); + if (view->recursiononacl == NULL && view->recursion) + CHECK(configure_view_acl(NULL, ns_g_config, + "allow-recursion-on", + actx, ns_g_mctx, + &view->recursiononacl)); + if (view->queryacl == NULL) { + if (view->recursion) + CHECK(configure_view_acl(NULL, ns_g_config, + "allow-query-cache", actx, + ns_g_mctx, &view->queryacl)); + else { + if (view->queryacl != NULL) + dns_acl_detach(&view->queryacl); + CHECK(dns_acl_none(ns_g_mctx, &view->queryacl)); + } + } + + /* + * Configure sortlist, if set + */ + CHECK(configure_view_sortlist(vconfig, config, actx, ns_g_mctx, + &view->sortlist)); - CHECK(configure_view_acl(vconfig, config, "sortlist", - actx, ns_g_mctx, &view->sortlist)); + /* + * Configure default allow-transfer, allow-notify, allow-update + * and allow-update-forwarding ACLs, if set, so they can be + * inherited by zones. + */ + if (view->notifyacl == NULL) + CHECK(configure_view_acl(NULL, ns_g_config, + "allow-notify", actx, + ns_g_mctx, &view->notifyacl)); + if (view->transferacl == NULL) + CHECK(configure_view_acl(NULL, ns_g_config, + "allow-transfer", actx, + ns_g_mctx, &view->transferacl)); + if (view->updateacl == NULL) + CHECK(configure_view_acl(NULL, ns_g_config, + "allow-update", actx, + ns_g_mctx, &view->updateacl)); + if (view->upfwdacl == NULL) + CHECK(configure_view_acl(NULL, ns_g_config, + "allow-update-forwarding", actx, + ns_g_mctx, &view->upfwdacl)); obj = NULL; result = ns_config_get(maps, "request-ixfr", &obj); @@ -1522,6 +1702,11 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, view->provideixfr = cfg_obj_asboolean(obj); obj = NULL; + result = ns_config_get(maps, "request-nsid", &obj); + INSIST(result == ISC_R_SUCCESS); + view->requestnsid = cfg_obj_asboolean(obj); + + obj = NULL; result = ns_config_get(maps, "max-clients-per-query", &obj); INSIST(result == ISC_R_SUCCESS); max_clients_per_query = cfg_obj_asuint32(obj); @@ -1539,16 +1724,6 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, view->enablednssec = cfg_obj_asboolean(obj); obj = NULL; - result = ns_config_get(maps, "dnssec-accept-expired", &obj); - INSIST(result == ISC_R_SUCCESS); - view->acceptexpired = cfg_obj_asboolean(obj); - - obj = NULL; - result = ns_config_get(maps, "dnssec-validation", &obj); - INSIST(result == ISC_R_SUCCESS); - view->enablevalidation = cfg_obj_asboolean(obj); - - obj = NULL; result = ns_config_get(maps, "dnssec-lookaside", &obj); if (result == ISC_R_SUCCESS) { for (element = cfg_list_first(obj); @@ -1603,18 +1778,6 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, CHECK(mustbesecure(obj, view->resolver)); obj = NULL; - result = ns_config_get(maps, "max-cache-ttl", &obj); - INSIST(result == ISC_R_SUCCESS); - view->maxcachettl = cfg_obj_asuint32(obj); - - obj = NULL; - result = ns_config_get(maps, "max-ncache-ttl", &obj); - INSIST(result == ISC_R_SUCCESS); - view->maxncachettl = cfg_obj_asuint32(obj); - if (view->maxncachettl > 7 * 24 * 3600) - view->maxncachettl = 7 * 24 * 3600; - - obj = NULL; result = ns_config_get(maps, "preferred-glue", &obj); if (result == ISC_R_SUCCESS) { str = cfg_obj_asstring(obj); @@ -1690,6 +1853,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, const char *empty_dbtype[4] = { "_builtin", "empty", NULL, NULL }; int empty_dbtypec = 4; + isc_boolean_t zonestats_on; dns_fixedname_init(&fixed); name = dns_fixedname_name(&fixed); @@ -1724,6 +1888,11 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, } else empty_dbtype[3] = "."; + obj = NULL; + result = ns_config_get(maps, "zone-statistics", &obj); + INSIST(result == ISC_R_SUCCESS); + zonestats_on = cfg_obj_asboolean(obj); + logit = ISC_TRUE; for (empty = empty_zones[empty_zone].zone; empty != NULL; @@ -1748,6 +1917,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, */ (void)dns_view_findzone(view, name, &zone); if (zone != NULL) { + CHECK(setquerystats(zone, mctx, zonestats_on)); dns_zone_detach(&zone); continue; } @@ -1798,6 +1968,8 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, if (zone != NULL) { dns_zone_setview(zone, view); CHECK(dns_view_addzone(view, zone)); + CHECK(setquerystats(zone, mctx, + zonestats_on)); dns_zone_detach(&zone); continue; } @@ -1809,14 +1981,18 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); dns_zone_setclass(zone, view->rdclass); dns_zone_settype(zone, dns_zone_master); + dns_zone_setstats(zone, ns_g_server->zonestats); CHECK(dns_zone_setdbtype(zone, empty_dbtypec, empty_dbtype)); if (view->queryacl != NULL) dns_zone_setqueryacl(zone, view->queryacl); + if (view->queryonacl != NULL) + dns_zone_setqueryonacl(zone, view->queryonacl); dns_zone_setdialup(zone, dns_dialuptype_no); dns_zone_setnotifytype(zone, dns_notifytype_no); dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE); + CHECK(setquerystats(zone, mctx, zonestats_on)); CHECK(dns_view_addzone(view, zone)); isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_INFO, @@ -1835,6 +2011,10 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, dns_dispatch_detach(&dispatch4); if (dispatch6 != NULL) dns_dispatch_detach(&dispatch6); + if (resstats != NULL) + isc_stats_detach(&resstats); + if (resquerystats != NULL) + dns_stats_detach(&resquerystats); if (order != NULL) dns_order_detach(&order); if (cmctx != NULL) @@ -1959,6 +2139,8 @@ configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, isc_result_t result; in_port_t port; + ISC_LIST_INIT(addresses); + /* * Determine which port to send forwarded requests to. */ @@ -1984,8 +2166,6 @@ configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, if (forwarders != NULL) faddresses = cfg_tuple_get(forwarders, "addresses"); - ISC_LIST_INIT(addresses); - for (element = cfg_list_first(faddresses); element != NULL; element = cfg_list_next(element)) @@ -2283,6 +2463,7 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, if (view->acache != NULL) dns_zone_setacache(zone, view->acache); CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); + dns_zone_setstats(zone, ns_g_server->zonestats); } /* @@ -2398,25 +2579,23 @@ add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr, { ns_listenelt_t *lelt = NULL; dns_acl_t *src_acl = NULL; - dns_aclelement_t aelt; isc_result_t result; isc_sockaddr_t any_sa6; + isc_netaddr_t netaddr; REQUIRE(isc_sockaddr_pf(addr) == AF_INET6); isc_sockaddr_any6(&any_sa6); if (!isc_sockaddr_equal(&any_sa6, addr) && (wcardport_ok || isc_sockaddr_getport(addr) != 0)) { - aelt.type = dns_aclelementtype_ipprefix; - aelt.negative = ISC_FALSE; - aelt.u.ip_prefix.prefixlen = 128; - isc_netaddr_fromin6(&aelt.u.ip_prefix.address, - &addr->type.sin6.sin6_addr); + isc_netaddr_fromin6(&netaddr, &addr->type.sin6.sin6_addr); - result = dns_acl_create(mctx, 1, &src_acl); + result = dns_acl_create(mctx, 0, &src_acl); if (result != ISC_R_SUCCESS) return (result); - result = dns_acl_appendelement(src_acl, &aelt); + + result = dns_iptable_addprefix(src_acl->iptable, + &netaddr, 128, ISC_TRUE); if (result != ISC_R_SUCCESS) goto clean; @@ -2900,6 +3079,9 @@ load_configuration(const char *filename, ns_server_t *server, INSIST(result == ISC_R_SUCCESS); server->aclenv.match_mapped = cfg_obj_asboolean(obj); + CHECKM(ns_statschannels_configure(ns_g_server, config, &aclconfctx), + "configuring statistics server(s)"); + /* * Configure sets of UDP query source ports. */ @@ -3059,11 +3241,13 @@ load_configuration(const char *filename, ns_server_t *server, ns_g_mctx, &listenon); } else if (!ns_g_lwresdonly) { + isc_boolean_t enable; /* * Not specified, use default. */ + enable = ISC_TF(isc_net_probeipv4() != ISC_R_SUCCESS); CHECK(ns_listenlist_default(ns_g_mctx, listen_port, - ISC_FALSE, &listenon)); + enable, &listenon)); } if (listenon != NULL) { ns_interfacemgr_setlistenon6(server->interfacemgr, @@ -3370,8 +3554,17 @@ load_configuration(const char *filename, ns_server_t *server, obj = NULL; if (options != NULL && - cfg_map_get(options, "memstatistics-file", &obj) == ISC_R_SUCCESS) + cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS) + ns_g_memstatistics = cfg_obj_asboolean(obj); + else + ns_g_memstatistics = + ISC_TF((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0); + + obj = NULL; + if (ns_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS) ns_main_setmemstats(cfg_obj_asstring(obj)); + else if (ns_g_memstatistics) + ns_main_setmemstats("named.memstats"); else ns_main_setmemstats(NULL); @@ -3415,8 +3608,12 @@ load_configuration(const char *filename, ns_server_t *server, result = ns_config_get(maps, "server-id", &obj); server->server_usehostname = ISC_FALSE; if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) { - server->server_usehostname = ISC_TRUE; + /* The parser translates "hostname" to ISC_TRUE */ + server->server_usehostname = cfg_obj_asboolean(obj); + result = setstring(server, &server->server_id, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); } else if (result == ISC_R_SUCCESS) { + /* Found a quoted string */ CHECKM(setoptstring(server, &server->server_id, obj), "strdup"); } else { result = setstring(server, &server->server_id, NULL); @@ -3555,6 +3752,8 @@ run_server(isc_task_t *task, isc_event_t *event) { &ns_g_dispatchmgr), "creating dispatch manager"); + dns_dispatchmgr_setstats(ns_g_dispatchmgr, server->resolverstats); + CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_socketmgr, ns_g_dispatchmgr, &server->interfacemgr), @@ -3622,6 +3821,7 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { ISC_LOG_INFO, "shutting down%s", flush ? ": flushing changes" : ""); + ns_statschannels_shutdown(server); ns_controls_shutdown(server->controls); end_reserved_dispatches(server, ISC_TRUE); @@ -3742,7 +3942,16 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { server->statsfile = isc_mem_strdup(server->mctx, "named.stats"); CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, "isc_mem_strdup"); - server->querystats = NULL; + server->nsstats = NULL; + server->rcvquerystats = NULL; + server->opcodestats = NULL; + server->zonestats = NULL; + server->resolverstats = NULL; + server->sockstats = NULL; + CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats, + isc_sockstatscounter_max), + "isc_stats_create"); + isc_socketmgr_setstats(ns_g_socketmgr, server->sockstats); server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db"); CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, @@ -3759,8 +3968,24 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { server->server_usehostname = ISC_FALSE; server->server_id = NULL; - CHECKFATAL(dns_stats_alloccounters(ns_g_mctx, &server->querystats), - "dns_stats_alloccounters"); + CHECKFATAL(isc_stats_create(ns_g_mctx, &server->nsstats, + dns_nsstatscounter_max), + "dns_stats_create (server)"); + + CHECKFATAL(dns_rdatatypestats_create(ns_g_mctx, + &server->rcvquerystats), + "dns_stats_create (rcvquery)"); + + CHECKFATAL(dns_opcodestats_create(ns_g_mctx, &server->opcodestats), + "dns_stats_create (opcode)"); + + CHECKFATAL(isc_stats_create(ns_g_mctx, &server->zonestats, + dns_zonestatscounter_max), + "dns_stats_create (zone)"); + + CHECKFATAL(isc_stats_create(ns_g_mctx, &server->resolverstats, + dns_resstatscounter_max), + "dns_stats_create (resolver)"); server->flushonshutdown = ISC_FALSE; server->log_queries = ISC_FALSE; @@ -3771,6 +3996,8 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { server->dispatchgen = 0; ISC_LIST_INIT(server->dispatches); + ISC_LIST_INIT(server->statschannels); + server->magic = NS_SERVER_MAGIC; *serverp = server; } @@ -3782,7 +4009,12 @@ ns_server_destroy(ns_server_t **serverp) { ns_controls_destroy(&server->controls); - dns_stats_freecounters(server->mctx, &server->querystats); + isc_stats_detach(&server->nsstats); + dns_stats_detach(&server->rcvquerystats); + dns_stats_detach(&server->opcodestats); + isc_stats_detach(&server->zonestats); + isc_stats_detach(&server->resolverstats); + isc_stats_detach(&server->sockstats); isc_mem_free(server->mctx, server->statsfile); isc_mem_free(server->mctx, server->dumpfile); @@ -3936,13 +4168,17 @@ loadconfig(ns_server_t *server) { result = load_configuration(ns_g_lwresdonly ? lwresd_g_conffile : ns_g_conffile, server, ISC_FALSE); - if (result == ISC_R_SUCCESS) + if (result == ISC_R_SUCCESS) { end_reserved_dispatches(server, ISC_FALSE); - else + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "reloading configuration succeeded"); + } else { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR, "reloading configuration failed: %s", isc_result_totext(result)); + } return (result); } @@ -3952,12 +4188,16 @@ reload(ns_server_t *server) { CHECK(loadconfig(server)); result = load_zones(server, ISC_FALSE); - if (result != ISC_R_SUCCESS) { + if (result == ISC_R_SUCCESS) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "reloading zones succeeded"); + else isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR, "reloading zones failed: %s", isc_result_totext(result)); - } + cleanup: return (result); } @@ -3968,12 +4208,16 @@ reconfig(ns_server_t *server) { CHECK(loadconfig(server)); result = load_new_zones(server, ISC_FALSE); - if (result != ISC_R_SUCCESS) { + if (result == ISC_R_SUCCESS) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "any newly configured zones are now loaded"); + else isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR, "loading new zones failed: %s", isc_result_totext(result)); - } + cleanup: ; } @@ -3987,6 +4231,9 @@ ns_server_reload(isc_task_t *task, isc_event_t *event) { INSIST(task = server->task); UNUSED(task); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "received SIGHUP signal to reload zones"); (void)reload(server); LOCK(&server->reload_event_lock); @@ -4068,23 +4315,28 @@ zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep) { result = dns_rdataclass_fromtext(&rdclass, &r); if (result != ISC_R_SUCCESS) goto fail1; - } else { + } else rdclass = dns_rdataclass_in; - } - if (viewtxt == NULL) - viewtxt = "_default"; - result = dns_viewlist_find(&server->viewlist, viewtxt, - rdclass, &view); - if (result != ISC_R_SUCCESS) - goto fail1; + if (viewtxt == NULL) { + result = dns_viewlist_findzone(&server->viewlist, + dns_fixedname_name(&name), + ISC_TF(classtxt == NULL), + rdclass, zonep); + } else { + result = dns_viewlist_find(&server->viewlist, viewtxt, + rdclass, &view); + if (result != ISC_R_SUCCESS) + goto fail1; + + result = dns_zt_find(view->zonetable, dns_fixedname_name(&name), + 0, NULL, zonep); + dns_view_detach(&view); + } - result = dns_zt_find(view->zonetable, dns_fixedname_name(&name), - 0, NULL, zonep); /* Partial match? */ if (result != ISC_R_SUCCESS && *zonep != NULL) dns_zone_detach(zonep); - dns_view_detach(&view); fail1: return (result); } @@ -4313,7 +4565,8 @@ ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, return (result); result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"), - config, ns_g_lctx, actx, mctx, &delt->acl); + config, ns_g_lctx, actx, mctx, 0, + &delt->acl); if (result != ISC_R_SUCCESS) { ns_listenelt_destroy(delt); return (result); @@ -4325,61 +4578,26 @@ ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, isc_result_t ns_server_dumpstats(ns_server_t *server) { isc_result_t result; - dns_zone_t *zone, *next; - isc_stdtime_t now; FILE *fp = NULL; - int i; - int ncounters; - - isc_stdtime_get(&now); CHECKMF(isc_stdio_open(server->statsfile, "a", &fp), "could not open statistics dump file", server->statsfile); - ncounters = DNS_STATS_NCOUNTERS; - fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now); - - for (i = 0; i < ncounters; i++) - fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT "u\n", - dns_statscounter_names[i], - server->querystats[i]); - - zone = NULL; - for (result = dns_zone_first(server->zonemgr, &zone); - result == ISC_R_SUCCESS; - next = NULL, result = dns_zone_next(zone, &next), zone = next) - { - isc_uint64_t *zonestats = dns_zone_getstatscounters(zone); - if (zonestats != NULL) { - char zonename[DNS_NAME_FORMATSIZE]; - dns_view_t *view; - char *viewname; - - dns_name_format(dns_zone_getorigin(zone), - zonename, sizeof(zonename)); - view = dns_zone_getview(zone); - viewname = view->name; - for (i = 0; i < ncounters; i++) { - fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT - "u %s", - dns_statscounter_names[i], - zonestats[i], - zonename); - if (strcmp(viewname, "_default") != 0) - fprintf(fp, " %s", viewname); - fprintf(fp, "\n"); - } - } - } - if (result == ISC_R_NOMORE) - result = ISC_R_SUCCESS; + result = ns_stats_dump(server, fp); CHECK(result); - fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now); - cleanup: if (fp != NULL) (void)isc_stdio_close(fp); + if (result == ISC_R_SUCCESS) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "dumpstats complete"); + else + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "dumpstats failed: %s", + dns_result_totext(result)); return (result); } @@ -4564,7 +4782,7 @@ dumpdone(void *arg, isc_result_t result) { cleanup: if (result != ISC_R_SUCCESS) isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, - NS_LOGMODULE_SERVER, ISC_LOG_INFO, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, "dumpdb failed: %s", dns_result_totext(result)); dumpcontext_destroy(dctx); } @@ -4661,6 +4879,15 @@ ns_server_dumprecursing(ns_server_t *server) { cleanup: if (fp != NULL) result = isc_stdio_close(fp); + if (result == ISC_R_SUCCESS) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "dumprecursing complete"); + else + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "dumprecursing failed: %s", + dns_result_totext(result)); return (result); } @@ -4690,6 +4917,9 @@ ns_server_setdebuglevel(ns_server_t *server, char *args) { ns_g_debuglevel = (unsigned int)newlevel; } isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "debug level is now %d", ns_g_debuglevel); return (ISC_R_SUCCESS); } @@ -4774,15 +5004,33 @@ ns_server_flushcache(ns_server_t *server, char *args) { continue; found = ISC_TRUE; result = dns_view_flushcache(view); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { flushed = ISC_FALSE; + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "flushing cache in view '%s' failed: %s", + view->name, isc_result_totext(result)); + } } if (flushed && found) { + if (viewname != NULL) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "flushing cache in view '%s' succeeded", + viewname); + else + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "flushing caches in all views succeeded"); result = ISC_R_SUCCESS; } else { - if (!found) + if (!found) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "flushing cache in view '%s' failed: " + "view not found", viewname); result = ISC_R_NOTFOUND; - else + } else result = ISC_R_FAILURE; } isc_task_endexclusive(server->task); @@ -4833,15 +5081,36 @@ ns_server_flushname(ns_server_t *server, char *args) { continue; found = ISC_TRUE; result = dns_view_flushname(view, name); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { flushed = ISC_FALSE; + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "flushing name '%s' in cache view '%s' " + "failed: %s", target, view->name, + isc_result_totext(result)); + } } - if (flushed && found) + if (flushed && found) { + if (viewname != NULL) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "flushing name '%s' in cache view '%s' " + "succeeded", target, viewname); + else + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "flushing name '%s' in all cache views " + "succeeded", target); result = ISC_R_SUCCESS; - else if (!found) - result = ISC_R_NOTFOUND; - else + } else { + if (!found) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "flushing name '%s' in cache view '%s' " + "failed: view not found", target, + viewname); result = ISC_R_FAILURE; + } isc_task_endexclusive(server->task); return (result); } @@ -4850,7 +5119,16 @@ isc_result_t ns_server_status(ns_server_t *server, isc_buffer_t *text) { int zonecount, xferrunning, xferdeferred, soaqueries; unsigned int n; + const char *ob = "", *cb = "", *alt = ""; + if (ns_g_server->version_set) { + ob = " ("; + cb = ")"; + if (ns_g_server->version == NULL) + alt = "version.bind/txt/ch disabled"; + else + alt = ns_g_server->version; + } zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY); xferrunning = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_XFERRUNNING); @@ -4858,8 +5136,14 @@ ns_server_status(ns_server_t *server, isc_buffer_t *text) { DNS_ZONESTATE_XFERDEFERRED); soaqueries = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_SOAQUERY); + n = snprintf((char *)isc_buffer_used(text), isc_buffer_availablelength(text), + "version: %s%s%s%s\n" +#ifdef ISC_PLATFORM_USETHREADS + "CPUs found: %u\n" + "worker threads: %u\n" +#endif "number of zones: %u\n" "debug level: %d\n" "xfers running: %u\n" @@ -4869,6 +5153,10 @@ ns_server_status(ns_server_t *server, isc_buffer_t *text) { "recursive clients: %d/%d/%d\n" "tcp clients: %d/%d\n" "server is up and running", + ns_g_version, ob, alt, cb, +#ifdef ISC_PLATFORM_USETHREADS + ns_g_cpus_detected, ns_g_cpus, +#endif zonecount, ns_g_debuglevel, xferrunning, xferdeferred, soaqueries, server->log_queries ? "ON" : "OFF", server->recursionquota.used, server->recursionquota.soft, @@ -4880,6 +5168,235 @@ ns_server_status(ns_server_t *server, isc_buffer_t *text) { return (ISC_R_SUCCESS); } +static isc_result_t +delete_keynames(dns_tsig_keyring_t *ring, char *target, + unsigned int *foundkeys) +{ + char namestr[DNS_NAME_FORMATSIZE]; + isc_result_t result; + dns_rbtnodechain_t chain; + dns_name_t foundname; + dns_fixedname_t fixedorigin; + dns_name_t *origin; + dns_rbtnode_t *node; + dns_tsigkey_t *tkey; + + dns_name_init(&foundname, NULL); + dns_fixedname_init(&fixedorigin); + origin = dns_fixedname_name(&fixedorigin); + + again: + dns_rbtnodechain_init(&chain, ring->mctx); + result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, + origin); + if (result == ISC_R_NOTFOUND) { + dns_rbtnodechain_invalidate(&chain); + return (ISC_R_SUCCESS); + } + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + dns_rbtnodechain_invalidate(&chain); + return (result); + } + + for (;;) { + node = NULL; + dns_rbtnodechain_current(&chain, &foundname, origin, &node); + tkey = node->data; + + if (tkey != NULL) { + if (!tkey->generated) + goto nextkey; + + dns_name_format(&tkey->name, namestr, sizeof(namestr)); + if (strcmp(namestr, target) == 0) { + (*foundkeys)++; + dns_rbtnodechain_invalidate(&chain); + (void)dns_rbt_deletename(ring->keys, + &tkey->name, + ISC_FALSE); + goto again; + } + } + + nextkey: + result = dns_rbtnodechain_next(&chain, &foundname, origin); + if (result == ISC_R_NOMORE) + break; + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + dns_rbtnodechain_invalidate(&chain); + return (result); + } + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +ns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t *text) { + isc_result_t result; + unsigned int n; + dns_view_t *view; + unsigned int foundkeys = 0; + char *target; + char *viewname; + + (void)next_token(&command, " \t"); /* skip command name */ + target = next_token(&command, " \t"); + if (target == NULL) + return (ISC_R_UNEXPECTEDEND); + viewname = next_token(&command, " \t"); + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + if (viewname == NULL || strcmp(view->name, viewname) == 0) { + RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write); + result = delete_keynames(view->dynamickeys, target, + &foundkeys); + RWUNLOCK(&view->dynamickeys->lock, + isc_rwlocktype_write); + if (result != ISC_R_SUCCESS) { + isc_task_endexclusive(server->task); + return (result); + } + } + } + isc_task_endexclusive(server->task); + + n = snprintf((char *)isc_buffer_used(text), + isc_buffer_availablelength(text), + "%d tsig keys deleted.\n", foundkeys); + if (n >= isc_buffer_availablelength(text)) { + isc_task_endexclusive(server->task); + return (ISC_R_NOSPACE); + } + isc_buffer_add(text, n); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t *text, + unsigned int *foundkeys) +{ + char namestr[DNS_NAME_FORMATSIZE]; + char creatorstr[DNS_NAME_FORMATSIZE]; + isc_result_t result; + dns_rbtnodechain_t chain; + dns_name_t foundname; + dns_fixedname_t fixedorigin; + dns_name_t *origin; + dns_rbtnode_t *node; + dns_tsigkey_t *tkey; + unsigned int n; + const char *viewname; + + if (view != NULL) + viewname = view->name; + else + viewname = "(global)"; + + dns_name_init(&foundname, NULL); + dns_fixedname_init(&fixedorigin); + origin = dns_fixedname_name(&fixedorigin); + dns_rbtnodechain_init(&chain, ring->mctx); + result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, + origin); + if (result == ISC_R_NOTFOUND) { + dns_rbtnodechain_invalidate(&chain); + return (ISC_R_SUCCESS); + } + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + dns_rbtnodechain_invalidate(&chain); + return (result); + } + + for (;;) { + node = NULL; + dns_rbtnodechain_current(&chain, &foundname, origin, &node); + tkey = node->data; + + if (tkey != NULL) { + (*foundkeys)++; + dns_name_format(&tkey->name, namestr, sizeof(namestr)); + if (tkey->generated) { + dns_name_format(tkey->creator, creatorstr, + sizeof(creatorstr)); + n = snprintf((char *)isc_buffer_used(text), + isc_buffer_availablelength(text), + "view \"%s\"; type \"dynamic\"; key \"%s\"; creator \"%s\";\n", + viewname, namestr, creatorstr); + } else { + n = snprintf((char *)isc_buffer_used(text), + isc_buffer_availablelength(text), + "view \"%s\"; type \"static\"; key \"%s\";\n", + viewname, namestr); + } + if (n >= isc_buffer_availablelength(text)) { + dns_rbtnodechain_invalidate(&chain); + return (ISC_R_NOSPACE); + } + isc_buffer_add(text, n); + } + result = dns_rbtnodechain_next(&chain, &foundname, origin); + if (result == ISC_R_NOMORE) + break; + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + dns_rbtnodechain_invalidate(&chain); + return (result); + } + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) { + isc_result_t result; + unsigned int n; + dns_view_t *view; + unsigned int foundkeys = 0; + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + RWLOCK(&view->statickeys->lock, isc_rwlocktype_read); + result = list_keynames(view, view->statickeys, text, + &foundkeys); + RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read); + if (result != ISC_R_SUCCESS) { + isc_task_endexclusive(server->task); + return (result); + } + RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read); + result = list_keynames(view, view->dynamickeys, text, + &foundkeys); + RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read); + if (result != ISC_R_SUCCESS) { + isc_task_endexclusive(server->task); + return (result); + } + } + isc_task_endexclusive(server->task); + + if (foundkeys == 0) { + n = snprintf((char *)isc_buffer_used(text), + isc_buffer_availablelength(text), + "no tsig keys found.\n"); + if (n >= isc_buffer_availablelength(text)) { + isc_task_endexclusive(server->task); + return (ISC_R_NOSPACE); + } + isc_buffer_add(text, n); + } + + return (ISC_R_SUCCESS); +} + /* * Act on a "freeze" or "thaw" command from the command channel. */ |