Home | History | Annotate | Line # | Download | only in named
      1 /*	$NetBSD: server.c,v 1.28 2026/05/20 16:53:43 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 <ctype.h>
     19 #include <inttypes.h>
     20 #include <limits.h>
     21 #include <signal.h>
     22 #include <stdbool.h>
     23 #include <stdint.h>
     24 #include <stdlib.h>
     25 #include <sys/stat.h>
     26 #include <sys/types.h>
     27 #include <unistd.h>
     28 
     29 #include <dns/acl.h>
     30 
     31 #ifdef HAVE_DNSTAP
     32 #include <fstrm.h>
     33 #endif
     34 
     35 #include <isc/async.h>
     36 #include <isc/attributes.h>
     37 #include <isc/base64.h>
     38 #include <isc/commandline.h>
     39 #include <isc/dir.h>
     40 #include <isc/file.h>
     41 #include <isc/fips.h>
     42 #include <isc/hash.h>
     43 #include <isc/hex.h>
     44 #include <isc/hmac.h>
     45 #include <isc/httpd.h>
     46 #include <isc/job.h>
     47 #include <isc/lex.h>
     48 #include <isc/loop.h>
     49 #include <isc/meminfo.h>
     50 #include <isc/netmgr.h>
     51 #include <isc/nonce.h>
     52 #include <isc/parseint.h>
     53 #include <isc/portset.h>
     54 #include <isc/refcount.h>
     55 #include <isc/result.h>
     56 #include <isc/signal.h>
     57 #include <isc/siphash.h>
     58 #include <isc/stats.h>
     59 #include <isc/stdio.h>
     60 #include <isc/string.h>
     61 #include <isc/time.h>
     62 #include <isc/timer.h>
     63 #include <isc/util.h>
     64 
     65 #include <dns/adb.h>
     66 #include <dns/badcache.h>
     67 #include <dns/cache.h>
     68 #include <dns/catz.h>
     69 #include <dns/db.h>
     70 #include <dns/dispatch.h>
     71 #include <dns/dlz.h>
     72 #include <dns/dns64.h>
     73 #include <dns/dnsrps.h>
     74 #include <dns/dnssec.h>
     75 #include <dns/dyndb.h>
     76 #include <dns/fixedname.h>
     77 #include <dns/forward.h>
     78 #include <dns/geoip.h>
     79 #include <dns/journal.h>
     80 #include <dns/kasp.h>
     81 #include <dns/keymgr.h>
     82 #include <dns/keystore.h>
     83 #include <dns/keytable.h>
     84 #include <dns/keyvalues.h>
     85 #include <dns/master.h>
     86 #include <dns/masterdump.h>
     87 #include <dns/nametree.h>
     88 #include <dns/nsec3.h>
     89 #include <dns/nta.h>
     90 #include <dns/order.h>
     91 #include <dns/peer.h>
     92 #include <dns/private.h>
     93 #include <dns/rbt.h>
     94 #include <dns/rdataclass.h>
     95 #include <dns/rdatalist.h>
     96 #include <dns/rdataset.h>
     97 #include <dns/rdatastruct.h>
     98 #include <dns/resolver.h>
     99 #include <dns/rootns.h>
    100 #include <dns/rriterator.h>
    101 #include <dns/secalg.h>
    102 #include <dns/soa.h>
    103 #include <dns/stats.h>
    104 #include <dns/time.h>
    105 #include <dns/tkey.h>
    106 #include <dns/tsig.h>
    107 #include <dns/ttl.h>
    108 #include <dns/view.h>
    109 #include <dns/zone.h>
    110 #include <dns/zt.h>
    111 
    112 #include <dst/dst.h>
    113 
    114 #include <isccfg/check.h>
    115 #include <isccfg/grammar.h>
    116 #include <isccfg/kaspconf.h>
    117 #include <isccfg/namedconf.h>
    118 
    119 #include <ns/client.h>
    120 #include <ns/hooks.h>
    121 #include <ns/interfacemgr.h>
    122 #include <ns/listenlist.h>
    123 
    124 #include <named/config.h>
    125 #include <named/control.h>
    126 #if defined(HAVE_GEOIP2)
    127 #include <named/geoip.h>
    128 #endif /* HAVE_GEOIP2 */
    129 #include <named/log.h>
    130 #include <named/logconf.h>
    131 #include <named/main.h>
    132 #include <named/os.h>
    133 #include <named/server.h>
    134 #include <named/statschannel.h>
    135 #include <named/tkeyconf.h>
    136 #include <named/transportconf.h>
    137 #include <named/tsigconf.h>
    138 #include <named/zoneconf.h>
    139 #ifdef HAVE_LIBSCF
    140 #include <stdlib.h>
    141 
    142 #include <named/smf_globals.h>
    143 #endif /* ifdef HAVE_LIBSCF */
    144 
    145 /* On DragonFly BSD the header does not provide jemalloc API */
    146 #if defined(HAVE_MALLOC_NP_H) && !defined(__DragonFly__)
    147 #include <malloc_np.h>
    148 #define JEMALLOC_API_SUPPORTED 1
    149 #elif defined(HAVE_JEMALLOC)
    150 #include <jemalloc/jemalloc.h>
    151 #define JEMALLOC_API_SUPPORTED 1
    152 #endif
    153 
    154 #ifdef HAVE_LMDB
    155 #include <lmdb.h>
    156 #define configure_newzones configure_newzones_db
    157 #define dumpzone	   dumpzone_db
    158 #else /* HAVE_LMDB */
    159 #define configure_newzones configure_newzones_file
    160 #define dumpzone	   dumpzone_file
    161 #endif /* HAVE_LMDB */
    162 
    163 #ifndef SIZE_MAX
    164 #define SIZE_MAX ((size_t)-1)
    165 #endif /* ifndef SIZE_MAX */
    166 
    167 #ifndef SIZE_AS_PERCENT
    168 #define SIZE_AS_PERCENT ((size_t)-2)
    169 #endif /* ifndef SIZE_AS_PERCENT */
    170 
    171 /* RFC7828 defines timeout as 16-bit value specified in units of 100
    172  * milliseconds, so the maximum and minimum advertised and keepalive
    173  * timeouts are capped by the data type (it's ~109 minutes)
    174  */
    175 #define MIN_INITIAL_TIMEOUT    UINT32_C(2500)	/* 2.5 seconds */
    176 #define MAX_INITIAL_TIMEOUT    UINT32_C(120000) /* 2 minutes */
    177 #define MIN_IDLE_TIMEOUT       UINT32_C(100)	/* 0.1 seconds */
    178 #define MAX_IDLE_TIMEOUT       UINT32_C(120000) /* 2 minutes */
    179 #define MIN_KEEPALIVE_TIMEOUT  UINT32_C(100)	/* 0.1 seconds */
    180 #define MAX_KEEPALIVE_TIMEOUT  UINT32_C(UINT16_MAX * 100)
    181 #define MIN_ADVERTISED_TIMEOUT UINT32_C(0) /* No minimum */
    182 #define MAX_ADVERTISED_TIMEOUT UINT32_C(UINT16_MAX * 100)
    183 
    184 /*%
    185  * Check an operation for failure.  Assumes that the function
    186  * using it has a 'result' variable and a 'cleanup' label.
    187  */
    188 #define TCHECK(op)                               \
    189 	do {                                     \
    190 		tresult = (op);                  \
    191 		if (tresult != ISC_R_SUCCESS) {  \
    192 			isc_buffer_clear(*text); \
    193 			goto cleanup;            \
    194 		}                                \
    195 	} while (0)
    196 
    197 #define CHECKM(op, msg)                                                        \
    198 	do {                                                                   \
    199 		result = (op);                                                 \
    200 		if (result != ISC_R_SUCCESS) {                                 \
    201 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
    202 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,   \
    203 				      "%s: %s", msg,                           \
    204 				      isc_result_totext(result));              \
    205 			goto cleanup;                                          \
    206 		}                                                              \
    207 	} while (0)
    208 
    209 #define CHECKMF(op, msg, file)                                                 \
    210 	do {                                                                   \
    211 		result = (op);                                                 \
    212 		if (result != ISC_R_SUCCESS) {                                 \
    213 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
    214 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,   \
    215 				      "%s '%s': %s", msg, file,                \
    216 				      isc_result_totext(result));              \
    217 			goto cleanup;                                          \
    218 		}                                                              \
    219 	} while (0)
    220 
    221 #define CHECKFATAL(op, msg)                    \
    222 	{                                      \
    223 		result = (op);                 \
    224 		if (result != ISC_R_SUCCESS) { \
    225 			fatal(msg, result);    \
    226 		}                              \
    227 	}
    228 
    229 /*%
    230  * Maximum ADB size for views that share a cache.  Use this limit to suppress
    231  * the total of memory footprint, which should be the main reason for sharing
    232  * a cache.  Only effective when a finite max-cache-size is specified.
    233  * This is currently defined to be 8MB.
    234  */
    235 #define MAX_ADB_SIZE_FOR_CACHESHARE 8388608U
    236 
    237 struct named_dispatch {
    238 	isc_sockaddr_t addr;
    239 	unsigned int dispatchgen;
    240 	dns_dispatch_t *dispatch;
    241 	ISC_LINK(struct named_dispatch) link;
    242 };
    243 
    244 struct named_cache {
    245 	dns_cache_t *cache;
    246 	dns_view_t *primaryview;
    247 	bool needflush;
    248 	bool adbsizeadjusted;
    249 	dns_rdataclass_t rdclass;
    250 	ISC_LINK(named_cache_t) link;
    251 };
    252 
    253 struct dumpcontext {
    254 	isc_mem_t *mctx;
    255 	bool dumpcache;
    256 	bool dumpzones;
    257 	bool dumpadb;
    258 	bool dumpexpired;
    259 	bool dumpfail;
    260 	FILE *fp;
    261 	ISC_LIST(struct viewlistentry) viewlist;
    262 	struct viewlistentry *view;
    263 	struct zonelistentry *zone;
    264 	dns_dumpctx_t *mdctx;
    265 	dns_db_t *db;
    266 	dns_db_t *cache;
    267 	isc_loop_t *loop;
    268 	dns_dbversion_t *version;
    269 };
    270 
    271 struct viewlistentry {
    272 	dns_view_t *view;
    273 	ISC_LINK(struct viewlistentry) link;
    274 	ISC_LIST(struct zonelistentry) zonelist;
    275 };
    276 
    277 struct zonelistentry {
    278 	dns_zone_t *zone;
    279 	ISC_LINK(struct zonelistentry) link;
    280 };
    281 
    282 /*%
    283  * Message-to-view matching context to run message signature validation
    284  * asynchronously.
    285  */
    286 typedef struct matching_view_ctx {
    287 	isc_netaddr_t srcaddr;
    288 	isc_netaddr_t destaddr;
    289 	dns_message_t *message;
    290 	dns_aclenv_t *aclenv;
    291 	ns_server_t *sctx;
    292 	isc_loop_t *loop;
    293 	isc_job_cb cb;
    294 	void *cbarg;
    295 	isc_result_t *sigresult;
    296 	isc_result_t *viewmatchresult;
    297 	isc_result_t quota_result;
    298 	dns_view_t **viewp;
    299 	dns_view_t *view;
    300 } matching_view_ctx_t;
    301 
    302 /*%
    303  * Configuration context to retain for each view that allows
    304  * new zones to be added at runtime.
    305  */
    306 typedef struct ns_cfgctx {
    307 	isc_mem_t *mctx;
    308 	cfg_parser_t *conf_parser;
    309 	cfg_parser_t *add_parser;
    310 	cfg_obj_t *config;
    311 	cfg_obj_t *vconfig;
    312 	cfg_obj_t *nzf_config;
    313 	cfg_aclconfctx_t *actx;
    314 } ns_cfgctx_t;
    315 
    316 /*%
    317  * A function to write out added-zone configuration to the new_zone_file
    318  * specified in 'view'. Maybe called by delete_zoneconf().
    319  */
    320 typedef isc_result_t (*nzfwriter_t)(const cfg_obj_t *config, dns_view_t *view);
    321 
    322 /*%
    323  * Holds state information for the initial zone loading process.
    324  * Uses the isc_refcount structure to count the number of views
    325  * with pending zone loads, dereferencing as each view finishes.
    326  */
    327 typedef struct {
    328 	named_server_t *server;
    329 	bool reconfig;
    330 	isc_refcount_t refs;
    331 } ns_zoneload_t;
    332 
    333 typedef struct {
    334 	named_server_t *server;
    335 } catz_cb_data_t;
    336 
    337 typedef struct catz_chgzone {
    338 	isc_mem_t *mctx;
    339 	dns_catz_entry_t *entry;
    340 	dns_catz_zone_t *origin;
    341 	dns_view_t *view;
    342 	catz_cb_data_t *cbd;
    343 	bool mod;
    344 } catz_chgzone_t;
    345 
    346 typedef struct catz_reconfig_data {
    347 	dns_catz_zone_t *catz;
    348 	const cfg_obj_t *config;
    349 	catz_cb_data_t *cbd;
    350 } catz_reconfig_data_t;
    351 
    352 typedef enum {
    353 	CATZ_ADDZONE,
    354 	CATZ_MODZONE,
    355 	CATZ_DELZONE,
    356 } catz_type_t;
    357 
    358 typedef struct {
    359 	unsigned int magic;
    360 #define DZARG_MAGIC ISC_MAGIC('D', 'z', 'a', 'r')
    361 	isc_buffer_t **text;
    362 	isc_result_t result;
    363 } ns_dzarg_t;
    364 
    365 typedef enum {
    366 	MEMPROF_UNSUPPORTED = 0x00,
    367 	MEMPROF_INACTIVE = 0x01,
    368 	MEMPROF_FAILING = 0x02,
    369 	MEMPROF_OFF = 0x03,
    370 	MEMPROF_ON = 0x04,
    371 } memprof_status;
    372 
    373 static const char *memprof_status_text[] = {
    374 	[MEMPROF_UNSUPPORTED] = "UNSUPPORTED",
    375 	[MEMPROF_INACTIVE] = "INACTIVE",
    376 	[MEMPROF_FAILING] = "FAILING",
    377 	[MEMPROF_OFF] = "OFF",
    378 	[MEMPROF_ON] = "ON",
    379 };
    380 
    381 /*
    382  * These zones should not leak onto the Internet.
    383  */
    384 const char *empty_zones[] = {
    385 	/* RFC 1918 */
    386 	"10.IN-ADDR.ARPA", "16.172.IN-ADDR.ARPA", "17.172.IN-ADDR.ARPA",
    387 	"18.172.IN-ADDR.ARPA", "19.172.IN-ADDR.ARPA", "20.172.IN-ADDR.ARPA",
    388 	"21.172.IN-ADDR.ARPA", "22.172.IN-ADDR.ARPA", "23.172.IN-ADDR.ARPA",
    389 	"24.172.IN-ADDR.ARPA", "25.172.IN-ADDR.ARPA", "26.172.IN-ADDR.ARPA",
    390 	"27.172.IN-ADDR.ARPA", "28.172.IN-ADDR.ARPA", "29.172.IN-ADDR.ARPA",
    391 	"30.172.IN-ADDR.ARPA", "31.172.IN-ADDR.ARPA", "168.192.IN-ADDR.ARPA",
    392 
    393 	/* RFC 6598 */
    394 	"64.100.IN-ADDR.ARPA", "65.100.IN-ADDR.ARPA", "66.100.IN-ADDR.ARPA",
    395 	"67.100.IN-ADDR.ARPA", "68.100.IN-ADDR.ARPA", "69.100.IN-ADDR.ARPA",
    396 	"70.100.IN-ADDR.ARPA", "71.100.IN-ADDR.ARPA", "72.100.IN-ADDR.ARPA",
    397 	"73.100.IN-ADDR.ARPA", "74.100.IN-ADDR.ARPA", "75.100.IN-ADDR.ARPA",
    398 	"76.100.IN-ADDR.ARPA", "77.100.IN-ADDR.ARPA", "78.100.IN-ADDR.ARPA",
    399 	"79.100.IN-ADDR.ARPA", "80.100.IN-ADDR.ARPA", "81.100.IN-ADDR.ARPA",
    400 	"82.100.IN-ADDR.ARPA", "83.100.IN-ADDR.ARPA", "84.100.IN-ADDR.ARPA",
    401 	"85.100.IN-ADDR.ARPA", "86.100.IN-ADDR.ARPA", "87.100.IN-ADDR.ARPA",
    402 	"88.100.IN-ADDR.ARPA", "89.100.IN-ADDR.ARPA", "90.100.IN-ADDR.ARPA",
    403 	"91.100.IN-ADDR.ARPA", "92.100.IN-ADDR.ARPA", "93.100.IN-ADDR.ARPA",
    404 	"94.100.IN-ADDR.ARPA", "95.100.IN-ADDR.ARPA", "96.100.IN-ADDR.ARPA",
    405 	"97.100.IN-ADDR.ARPA", "98.100.IN-ADDR.ARPA", "99.100.IN-ADDR.ARPA",
    406 	"100.100.IN-ADDR.ARPA", "101.100.IN-ADDR.ARPA", "102.100.IN-ADDR.ARPA",
    407 	"103.100.IN-ADDR.ARPA", "104.100.IN-ADDR.ARPA", "105.100.IN-ADDR.ARPA",
    408 	"106.100.IN-ADDR.ARPA", "107.100.IN-ADDR.ARPA", "108.100.IN-ADDR.ARPA",
    409 	"109.100.IN-ADDR.ARPA", "110.100.IN-ADDR.ARPA", "111.100.IN-ADDR.ARPA",
    410 	"112.100.IN-ADDR.ARPA", "113.100.IN-ADDR.ARPA", "114.100.IN-ADDR.ARPA",
    411 	"115.100.IN-ADDR.ARPA", "116.100.IN-ADDR.ARPA", "117.100.IN-ADDR.ARPA",
    412 	"118.100.IN-ADDR.ARPA", "119.100.IN-ADDR.ARPA", "120.100.IN-ADDR.ARPA",
    413 	"121.100.IN-ADDR.ARPA", "122.100.IN-ADDR.ARPA", "123.100.IN-ADDR.ARPA",
    414 	"124.100.IN-ADDR.ARPA", "125.100.IN-ADDR.ARPA", "126.100.IN-ADDR.ARPA",
    415 	"127.100.IN-ADDR.ARPA",
    416 
    417 	/* RFC 5735 and RFC 5737 */
    418 	"0.IN-ADDR.ARPA",		/* THIS NETWORK */
    419 	"127.IN-ADDR.ARPA",		/* LOOPBACK */
    420 	"254.169.IN-ADDR.ARPA",		/* LINK LOCAL */
    421 	"2.0.192.IN-ADDR.ARPA",		/* TEST NET */
    422 	"100.51.198.IN-ADDR.ARPA",	/* TEST NET 2 */
    423 	"113.0.203.IN-ADDR.ARPA",	/* TEST NET 3 */
    424 	"255.255.255.255.IN-ADDR.ARPA", /* BROADCAST */
    425 
    426 	/* Local IPv6 Unicast Addresses */
    427 	/* clang-format off */
    428 	"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",
    429 	"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",
    430 	/* clang-format on */
    431 
    432 	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
    433 	"D.F.IP6.ARPA", "8.E.F.IP6.ARPA", /* LINK LOCAL */
    434 	"9.E.F.IP6.ARPA",		  /* LINK LOCAL */
    435 	"A.E.F.IP6.ARPA",		  /* LINK LOCAL */
    436 	"B.E.F.IP6.ARPA",		  /* LINK LOCAL */
    437 
    438 	/* Example Prefix, RFC 3849. */
    439 	"8.B.D.0.1.0.0.2.IP6.ARPA",
    440 
    441 	/* RFC 7534 */
    442 	"EMPTY.AS112.ARPA",
    443 
    444 	/* RFC 8375 */
    445 	"HOME.ARPA",
    446 
    447 	/* RFC 9462 */
    448 	"RESOLVER.ARPA",
    449 
    450 	NULL
    451 };
    452 
    453 noreturn static void
    454 fatal(const char *msg, isc_result_t result);
    455 
    456 static void
    457 named_server_reload(void *arg);
    458 
    459 #ifdef HAVE_LIBNGHTTP2
    460 static isc_result_t
    461 listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls,
    462 	       const ns_listen_tls_params_t *tls_params,
    463 	       isc_tlsctx_cache_t *tlsctx_cache, in_port_t port,
    464 	       isc_mem_t *mctx, isc_nm_proxy_type_t proxy,
    465 	       ns_listenelt_t **target);
    466 #endif
    467 
    468 static isc_result_t
    469 listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
    470 		     cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
    471 		     isc_tlsctx_cache_t *tlsctx_cache, ns_listenelt_t **target);
    472 
    473 static isc_result_t
    474 listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
    475 		      cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
    476 		      isc_tlsctx_cache_t *tlsctx_cache,
    477 		      ns_listenlist_t **target);
    478 
    479 static isc_result_t
    480 configure_forward(const cfg_obj_t *config, dns_view_t *view,
    481 		  const dns_name_t *origin, const cfg_obj_t *forwarders,
    482 		  const cfg_obj_t *forwardtype);
    483 
    484 static isc_result_t
    485 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
    486 		     const cfg_obj_t *alternates);
    487 
    488 static isc_result_t
    489 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
    490 	       const cfg_obj_t *vconfig, dns_view_t *view,
    491 	       dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
    492 	       dns_keystorelist_t *keystores, cfg_aclconfctx_t *aclconf,
    493 	       bool added, bool old_rpz_ok, bool is_catz_member, bool modify);
    494 
    495 static void
    496 configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
    497 			     dns_view_t *view);
    498 
    499 static isc_result_t
    500 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
    501 		   cfg_aclconfctx_t *actx);
    502 
    503 static const cfg_obj_t *
    504 find_maplist(const cfg_obj_t *config, const char *listname, const char *name);
    505 
    506 static isc_result_t
    507 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
    508 
    509 static void
    510 newzone_cfgctx_destroy(void **cfgp);
    511 
    512 static isc_result_t
    513 putstr(isc_buffer_t **b, const char *str);
    514 
    515 static isc_result_t
    516 putmem(isc_buffer_t **b, const char *str, size_t len);
    517 
    518 static isc_result_t
    519 putuint8(isc_buffer_t **b, uint8_t val);
    520 
    521 static isc_result_t
    522 putnull(isc_buffer_t **b);
    523 
    524 #ifdef HAVE_LMDB
    525 static isc_result_t
    526 nzd_writable(dns_view_t *view);
    527 
    528 static isc_result_t
    529 nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);
    530 
    531 static isc_result_t
    532 nzd_env_reopen(dns_view_t *view);
    533 
    534 static void
    535 nzd_env_close(dns_view_t *view);
    536 
    537 static isc_result_t
    538 nzd_close(MDB_txn **txnp, bool commit);
    539 #else  /* ifdef HAVE_LMDB */
    540 static isc_result_t
    541 nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
    542 #endif /* ifdef HAVE_LMDB */
    543 
    544 static isc_result_t
    545 load_nzf(dns_view_t *view, ns_cfgctx_t *nzcfg);
    546 
    547 /*%
    548  * Configure a single view ACL at '*aclp'.  Get its configuration from
    549  * 'vconfig' (for per-view configuration) and maybe from 'config'
    550  */
    551 static isc_result_t
    552 configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
    553 		   const cfg_obj_t *gconfig, const char *aclname,
    554 		   const char *acltuplename, cfg_aclconfctx_t *actx,
    555 		   isc_mem_t *mctx, dns_acl_t **aclp) {
    556 	isc_result_t result;
    557 	const cfg_obj_t *maps[4];
    558 	const cfg_obj_t *aclobj = NULL;
    559 	int i = 0;
    560 
    561 	if (*aclp != NULL) {
    562 		dns_acl_detach(aclp);
    563 	}
    564 	if (vconfig != NULL) {
    565 		maps[i++] = cfg_tuple_get(vconfig, "options");
    566 	}
    567 	if (config != NULL) {
    568 		const cfg_obj_t *options = NULL;
    569 		(void)cfg_map_get(config, "options", &options);
    570 		if (options != NULL) {
    571 			maps[i++] = options;
    572 		}
    573 	}
    574 	if (gconfig != NULL) {
    575 		const cfg_obj_t *options = NULL;
    576 		(void)cfg_map_get(gconfig, "options", &options);
    577 		if (options != NULL) {
    578 			maps[i++] = options;
    579 		}
    580 	}
    581 	maps[i] = NULL;
    582 
    583 	(void)named_config_get(maps, aclname, &aclobj);
    584 	if (aclobj == NULL) {
    585 		/*
    586 		 * No value available.	*aclp == NULL.
    587 		 */
    588 		return ISC_R_SUCCESS;
    589 	}
    590 
    591 	if (acltuplename != NULL) {
    592 		/*
    593 		 * If the ACL is given in an optional tuple, retrieve it.
    594 		 * The parser should have ensured that a valid object be
    595 		 * returned.
    596 		 */
    597 		aclobj = cfg_tuple_get(aclobj, acltuplename);
    598 	}
    599 
    600 	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 0,
    601 				    aclp);
    602 
    603 	return result;
    604 }
    605 
    606 /*%
    607  * Configure a sortlist at '*aclp'.  Essentially the same as
    608  * configure_view_acl() except it calls cfg_acl_fromconfig with a
    609  * nest_level value of 2.
    610  */
    611 static isc_result_t
    612 configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
    613 			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
    614 			dns_acl_t **aclp) {
    615 	isc_result_t result;
    616 	const cfg_obj_t *maps[3];
    617 	const cfg_obj_t *aclobj = NULL;
    618 	int i = 0;
    619 
    620 	if (*aclp != NULL) {
    621 		dns_acl_detach(aclp);
    622 	}
    623 	if (vconfig != NULL) {
    624 		maps[i++] = cfg_tuple_get(vconfig, "options");
    625 	}
    626 	if (config != NULL) {
    627 		const cfg_obj_t *options = NULL;
    628 		(void)cfg_map_get(config, "options", &options);
    629 		if (options != NULL) {
    630 			maps[i++] = options;
    631 		}
    632 	}
    633 	maps[i] = NULL;
    634 
    635 	(void)named_config_get(maps, "sortlist", &aclobj);
    636 	if (aclobj == NULL) {
    637 		return ISC_R_SUCCESS;
    638 	}
    639 
    640 	/*
    641 	 * Use a nest level of 3 for the "top level" of the sortlist;
    642 	 * this means each entry in the top three levels will be stored
    643 	 * as lists of separate, nested ACLs, rather than merged together
    644 	 * into IP tables as is usually done with ACLs.
    645 	 */
    646 	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 3,
    647 				    aclp);
    648 
    649 	return result;
    650 }
    651 
    652 static isc_result_t
    653 configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
    654 			 const char *confname, const char *conftuplename,
    655 			 isc_mem_t *mctx, dns_nametree_t **ntp) {
    656 	isc_result_t result = ISC_R_SUCCESS;
    657 	const cfg_obj_t *maps[3];
    658 	const cfg_obj_t *obj = NULL;
    659 	const cfg_listelt_t *element = NULL;
    660 	int i = 0;
    661 	dns_fixedname_t fixed;
    662 	dns_name_t *name = NULL;
    663 	isc_buffer_t b;
    664 	const char *str = NULL;
    665 	const cfg_obj_t *nameobj = NULL;
    666 
    667 	if (*ntp != NULL) {
    668 		dns_nametree_detach(ntp);
    669 	}
    670 	dns_nametree_create(mctx, DNS_NAMETREE_BOOL, confname, ntp);
    671 
    672 	if (vconfig != NULL) {
    673 		maps[i++] = cfg_tuple_get(vconfig, "options");
    674 	}
    675 	if (config != NULL) {
    676 		const cfg_obj_t *options = NULL;
    677 		(void)cfg_map_get(config, "options", &options);
    678 		if (options != NULL) {
    679 			maps[i++] = options;
    680 		}
    681 	}
    682 	maps[i] = NULL;
    683 
    684 	(void)named_config_get(maps, confname, &obj);
    685 	if (obj == NULL) {
    686 		/*
    687 		 * No value available.	*ntp == NULL.
    688 		 */
    689 		return ISC_R_SUCCESS;
    690 	}
    691 
    692 	if (conftuplename != NULL) {
    693 		obj = cfg_tuple_get(obj, conftuplename);
    694 		if (cfg_obj_isvoid(obj)) {
    695 			return ISC_R_SUCCESS;
    696 		}
    697 	}
    698 
    699 	name = dns_fixedname_initname(&fixed);
    700 	for (element = cfg_list_first(obj); element != NULL;
    701 	     element = cfg_list_next(element))
    702 	{
    703 		nameobj = cfg_listelt_value(element);
    704 		str = cfg_obj_asstring(nameobj);
    705 		isc_buffer_constinit(&b, str, strlen(str));
    706 		isc_buffer_add(&b, strlen(str));
    707 		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
    708 		result = dns_nametree_add(*ntp, name, true);
    709 		if (result != ISC_R_SUCCESS) {
    710 			cfg_obj_log(nameobj, named_g_lctx, ISC_LOG_ERROR,
    711 				    "failed to add %s for %s: %s", str,
    712 				    confname, isc_result_totext(result));
    713 			goto cleanup;
    714 		}
    715 	}
    716 
    717 	return ISC_R_SUCCESS;
    718 
    719 cleanup:
    720 	dns_nametree_detach(ntp);
    721 	return result;
    722 }
    723 
    724 static isc_result_t
    725 ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
    726 	      unsigned char *digest, dns_rdata_ds_t *ds) {
    727 	isc_result_t result;
    728 	dns_rdata_dnskey_t keystruct;
    729 	dns_rdata_t rdata = DNS_RDATA_INIT;
    730 	uint32_t rdata1, rdata2, rdata3;
    731 	const char *datastr = NULL, *namestr = NULL;
    732 	unsigned char data[4096];
    733 	isc_buffer_t databuf;
    734 	unsigned char rrdata[4096];
    735 	isc_buffer_t rrdatabuf;
    736 	isc_region_t r;
    737 	dns_fixedname_t fname;
    738 	dns_name_t *name = NULL;
    739 	isc_buffer_t namebuf;
    740 	const char *atstr = NULL;
    741 	enum {
    742 		INIT_DNSKEY,
    743 		STATIC_DNSKEY,
    744 		INIT_DS,
    745 		STATIC_DS,
    746 		TRUSTED
    747 	} anchortype;
    748 
    749 	REQUIRE(namestrp != NULL && *namestrp == NULL);
    750 	REQUIRE(ds != NULL);
    751 
    752 	/* if DNSKEY, flags; if DS, key tag */
    753 	rdata1 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata1"));
    754 
    755 	/* if DNSKEY, protocol; if DS, algorithm */
    756 	rdata2 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata2"));
    757 
    758 	/* if DNSKEY, algorithm; if DS, digest type */
    759 	rdata3 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata3"));
    760 
    761 	namestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
    762 	*namestrp = namestr;
    763 
    764 	name = dns_fixedname_initname(&fname);
    765 	isc_buffer_constinit(&namebuf, namestr, strlen(namestr));
    766 	isc_buffer_add(&namebuf, strlen(namestr));
    767 	CHECK(dns_name_fromtext(name, &namebuf, dns_rootname, 0, NULL));
    768 
    769 	if (*initialp) {
    770 		atstr = cfg_obj_asstring(cfg_tuple_get(key, "anchortype"));
    771 
    772 		if (strcasecmp(atstr, "static-key") == 0) {
    773 			*initialp = false;
    774 			anchortype = STATIC_DNSKEY;
    775 		} else if (strcasecmp(atstr, "static-ds") == 0) {
    776 			*initialp = false;
    777 			anchortype = STATIC_DS;
    778 		} else if (strcasecmp(atstr, "initial-key") == 0) {
    779 			anchortype = INIT_DNSKEY;
    780 		} else if (strcasecmp(atstr, "initial-ds") == 0) {
    781 			anchortype = INIT_DS;
    782 		} else {
    783 			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
    784 				    "key '%s': "
    785 				    "invalid initialization method '%s'",
    786 				    namestr, atstr);
    787 			result = ISC_R_FAILURE;
    788 			goto cleanup;
    789 		}
    790 	} else {
    791 		anchortype = TRUSTED;
    792 	}
    793 
    794 	isc_buffer_init(&databuf, data, sizeof(data));
    795 	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
    796 
    797 	*ds = (dns_rdata_ds_t){ .common.rdclass = dns_rdataclass_in,
    798 				.common.rdtype = dns_rdatatype_ds };
    799 
    800 	ISC_LINK_INIT(&ds->common, link);
    801 
    802 	switch (anchortype) {
    803 	case INIT_DNSKEY:
    804 	case STATIC_DNSKEY:
    805 	case TRUSTED:
    806 		/*
    807 		 * This function should never be reached for view
    808 		 * class other than IN
    809 		 */
    810 		keystruct.common.rdclass = dns_rdataclass_in;
    811 		keystruct.common.rdtype = dns_rdatatype_dnskey;
    812 
    813 		/*
    814 		 * The key data in keystruct is not dynamically allocated.
    815 		 */
    816 		keystruct.mctx = NULL;
    817 
    818 		ISC_LINK_INIT(&keystruct.common, link);
    819 
    820 		if (rdata1 > 0xffff) {
    821 			CHECKM(ISC_R_RANGE, "key flags");
    822 		}
    823 		if (rdata1 & DNS_KEYFLAG_REVOKE) {
    824 			CHECKM(DST_R_BADKEYTYPE, "key flags revoke bit set");
    825 		}
    826 		if (rdata2 > 0xff) {
    827 			CHECKM(ISC_R_RANGE, "key protocol");
    828 		}
    829 		if (rdata3 > 0xff) {
    830 			CHECKM(ISC_R_RANGE, "key algorithm");
    831 		}
    832 
    833 		keystruct.flags = (uint16_t)rdata1;
    834 		keystruct.protocol = (uint8_t)rdata2;
    835 		keystruct.algorithm = (uint8_t)rdata3;
    836 
    837 		if (!dst_algorithm_supported(keystruct.algorithm)) {
    838 			CHECK(DST_R_UNSUPPORTEDALG);
    839 		}
    840 
    841 		datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
    842 		CHECK(isc_base64_decodestring(datastr, &databuf));
    843 		isc_buffer_usedregion(&databuf, &r);
    844 		keystruct.datalen = r.length;
    845 		keystruct.data = r.base;
    846 
    847 		CHECK(dns_rdata_fromstruct(&rdata, keystruct.common.rdclass,
    848 					   keystruct.common.rdtype, &keystruct,
    849 					   &rrdatabuf));
    850 		CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
    851 					  digest, ds));
    852 		break;
    853 
    854 	case INIT_DS:
    855 	case STATIC_DS:
    856 		if (rdata1 > 0xffff) {
    857 			CHECKM(ISC_R_RANGE, "key tag");
    858 		}
    859 		if (rdata2 > 0xff) {
    860 			CHECKM(ISC_R_RANGE, "key algorithm");
    861 		}
    862 		if (rdata3 > 0xff) {
    863 			CHECKM(ISC_R_RANGE, "digest type");
    864 		}
    865 
    866 		ds->key_tag = (uint16_t)rdata1;
    867 		ds->algorithm = (uint8_t)rdata2;
    868 		ds->digest_type = (uint8_t)rdata3;
    869 
    870 		datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
    871 		CHECK(isc_hex_decodestring(datastr, &databuf));
    872 		isc_buffer_usedregion(&databuf, &r);
    873 
    874 		switch (ds->digest_type) {
    875 		case DNS_DSDIGEST_SHA1:
    876 			if (r.length != ISC_SHA1_DIGESTLENGTH) {
    877 				CHECK(ISC_R_UNEXPECTEDEND);
    878 			}
    879 			break;
    880 		case DNS_DSDIGEST_SHA256:
    881 			if (r.length != ISC_SHA256_DIGESTLENGTH) {
    882 				CHECK(ISC_R_UNEXPECTEDEND);
    883 			}
    884 			break;
    885 		case DNS_DSDIGEST_SHA384:
    886 			if (r.length != ISC_SHA384_DIGESTLENGTH) {
    887 				CHECK(ISC_R_UNEXPECTEDEND);
    888 			}
    889 			break;
    890 		default:
    891 			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
    892 				    "key '%s': "
    893 				    "unknown ds digest type %u",
    894 				    namestr, ds->digest_type);
    895 			result = ISC_R_FAILURE;
    896 			goto cleanup;
    897 			break;
    898 		}
    899 
    900 		ds->length = r.length;
    901 		ds->digest = digest;
    902 		memmove(ds->digest, r.base, r.length);
    903 
    904 		break;
    905 
    906 	default:
    907 		UNREACHABLE();
    908 	}
    909 
    910 	return ISC_R_SUCCESS;
    911 
    912 cleanup:
    913 	return result;
    914 }
    915 
    916 static void
    917 sfd_add(const dns_name_t *name, void *arg) {
    918 	if (arg != NULL) {
    919 		dns_view_sfd_add(arg, name);
    920 	}
    921 }
    922 
    923 /*%
    924  * Parse 'key' in the context of view configuration 'vconfig'.  If successful,
    925  * add the key to 'secroots' if both of the following conditions are true:
    926  *
    927  *   - 'keyname_match' is NULL or it matches the owner name of 'key',
    928  *   - support for the algorithm used by 'key' is not disabled by 'resolver'
    929  *     for the owner name of 'key'.
    930  *
    931  * 'managed' is true for managed keys and false for trusted keys.  'mctx' is
    932  * the memory context to use for allocating memory.
    933  */
    934 static isc_result_t
    935 process_key(const cfg_obj_t *key, dns_keytable_t *secroots,
    936 	    const dns_name_t *keyname_match, dns_view_t *view, bool managed) {
    937 	dns_fixedname_t fkeyname;
    938 	dns_name_t *keyname = NULL;
    939 	const char *namestr = NULL;
    940 	dns_rdata_ds_t ds;
    941 	isc_result_t result;
    942 	bool initializing = managed;
    943 	unsigned char digest[ISC_MAX_MD_SIZE];
    944 	isc_buffer_t b;
    945 
    946 	result = ta_fromconfig(key, &initializing, &namestr, digest, &ds);
    947 
    948 	switch (result) {
    949 	case ISC_R_SUCCESS:
    950 		/*
    951 		 * Trust anchor was parsed correctly.
    952 		 */
    953 		isc_buffer_constinit(&b, namestr, strlen(namestr));
    954 		isc_buffer_add(&b, strlen(namestr));
    955 		keyname = dns_fixedname_initname(&fkeyname);
    956 		result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
    957 		if (result != ISC_R_SUCCESS) {
    958 			return result;
    959 		}
    960 		break;
    961 	case DST_R_UNSUPPORTEDALG:
    962 	case DST_R_BADKEYTYPE:
    963 		/*
    964 		 * Key was parsed correctly, but it cannot be used; this is not
    965 		 * a fatal error - log a warning about this key being ignored,
    966 		 * but do not prevent any further ones from being processed.
    967 		 */
    968 		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
    969 			    "ignoring %s for '%s': %s",
    970 			    initializing ? "initial-key" : "static-key",
    971 			    namestr, isc_result_totext(result));
    972 		return ISC_R_SUCCESS;
    973 	case DST_R_NOCRYPTO:
    974 		/*
    975 		 * Crypto support is not available.
    976 		 */
    977 		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
    978 			    "ignoring %s for '%s': no crypto support",
    979 			    initializing ? "initial-key" : "static-key",
    980 			    namestr);
    981 		return result;
    982 	default:
    983 		/*
    984 		 * Something unexpected happened; we have no choice but to
    985 		 * indicate an error so that the configuration loading process
    986 		 * is interrupted.
    987 		 */
    988 		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
    989 			    "configuring %s for '%s': %s",
    990 			    initializing ? "initial-key" : "static-key",
    991 			    namestr, isc_result_totext(result));
    992 		return ISC_R_FAILURE;
    993 	}
    994 
    995 	/*
    996 	 * If the caller requested to only load keys for a specific name and
    997 	 * the owner name of this key does not match the requested name, do not
    998 	 * load it.
    999 	 */
   1000 	if (keyname_match != NULL && !dns_name_equal(keyname_match, keyname)) {
   1001 		goto done;
   1002 	}
   1003 
   1004 	/*
   1005 	 * Ensure that 'resolver' allows using the algorithm of this key for
   1006 	 * its owner name.  If it does not, do not load the key and log a
   1007 	 * warning, but do not prevent further keys from being processed.
   1008 	 */
   1009 	if (!dns_resolver_algorithm_supported(view->resolver, keyname,
   1010 					      ds.algorithm))
   1011 	{
   1012 		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
   1013 			    "ignoring %s for '%s': algorithm is disabled",
   1014 			    initializing ? "initial-key" : "static-key",
   1015 			    namestr);
   1016 		goto done;
   1017 	}
   1018 
   1019 	/*
   1020 	 * Add the key to 'secroots'.  Keys from a "trust-anchors" or
   1021 	 * "managed-keys" statement may be either static or initializing
   1022 	 * keys. If it's not initializing, we don't want to treat it as
   1023 	 * managed, so we use 'initializing' twice here, for both the
   1024 	 * 'managed' and 'initializing' arguments to dns_keytable_add().
   1025 	 */
   1026 	result = dns_keytable_add(secroots, initializing, initializing, keyname,
   1027 				  &ds, sfd_add, view);
   1028 
   1029 done:
   1030 	return result;
   1031 }
   1032 
   1033 /*
   1034  * Load keys from configuration into key table. If 'keyname' is specified,
   1035  * only load keys matching that name. If 'managed' is true, load the key as
   1036  * an initializing key.
   1037  */
   1038 static isc_result_t
   1039 load_view_keys(const cfg_obj_t *keys, dns_view_t *view, bool managed,
   1040 	       const dns_name_t *keyname) {
   1041 	const cfg_listelt_t *elt, *elt2;
   1042 	const cfg_obj_t *keylist;
   1043 	isc_result_t result;
   1044 	dns_keytable_t *secroots = NULL;
   1045 
   1046 	CHECK(dns_view_getsecroots(view, &secroots));
   1047 
   1048 	for (elt = cfg_list_first(keys); elt != NULL; elt = cfg_list_next(elt))
   1049 	{
   1050 		keylist = cfg_listelt_value(elt);
   1051 
   1052 		for (elt2 = cfg_list_first(keylist); elt2 != NULL;
   1053 		     elt2 = cfg_list_next(elt2))
   1054 		{
   1055 			CHECK(process_key(cfg_listelt_value(elt2), secroots,
   1056 					  keyname, view, managed));
   1057 		}
   1058 	}
   1059 
   1060 cleanup:
   1061 	if (secroots != NULL) {
   1062 		dns_keytable_detach(&secroots);
   1063 	}
   1064 	if (result == DST_R_NOCRYPTO) {
   1065 		result = ISC_R_SUCCESS;
   1066 	}
   1067 	return result;
   1068 }
   1069 
   1070 /*%
   1071  * Check whether a key has been successfully loaded.
   1072  */
   1073 static bool
   1074 keyloaded(dns_view_t *view, const dns_name_t *name) {
   1075 	isc_result_t result;
   1076 	dns_keytable_t *secroots = NULL;
   1077 	dns_keynode_t *keynode = NULL;
   1078 
   1079 	result = dns_view_getsecroots(view, &secroots);
   1080 	if (result != ISC_R_SUCCESS) {
   1081 		return false;
   1082 	}
   1083 
   1084 	result = dns_keytable_find(secroots, name, &keynode);
   1085 
   1086 	if (keynode != NULL) {
   1087 		dns_keynode_detach(&keynode);
   1088 	}
   1089 	if (secroots != NULL) {
   1090 		dns_keytable_detach(&secroots);
   1091 	}
   1092 
   1093 	return result == ISC_R_SUCCESS;
   1094 }
   1095 
   1096 /*%
   1097  * Configure DNSSEC keys for a view.
   1098  *
   1099  * The per-view configuration values and the server-global defaults are read
   1100  * from 'vconfig' and 'config'.
   1101  */
   1102 static isc_result_t
   1103 configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
   1104 			  const cfg_obj_t *config, const cfg_obj_t *bindkeys,
   1105 			  bool auto_root) {
   1106 	isc_result_t result = ISC_R_SUCCESS;
   1107 	const cfg_obj_t *view_keys = NULL;
   1108 	const cfg_obj_t *global_keys = NULL;
   1109 	const cfg_obj_t *view_managed_keys = NULL;
   1110 	const cfg_obj_t *view_trust_anchors = NULL;
   1111 	const cfg_obj_t *global_managed_keys = NULL;
   1112 	const cfg_obj_t *global_trust_anchors = NULL;
   1113 	const cfg_obj_t *maps[4];
   1114 	const cfg_obj_t *voptions = NULL;
   1115 	const cfg_obj_t *options = NULL;
   1116 	const cfg_obj_t *obj = NULL;
   1117 	const char *directory;
   1118 	int i = 0;
   1119 
   1120 	/* We don't need trust anchors for the _bind view */
   1121 	if (strcmp(view->name, "_bind") == 0 &&
   1122 	    view->rdclass == dns_rdataclass_chaos)
   1123 	{
   1124 		return ISC_R_SUCCESS;
   1125 	}
   1126 
   1127 	if (vconfig != NULL) {
   1128 		voptions = cfg_tuple_get(vconfig, "options");
   1129 		if (voptions != NULL) {
   1130 			(void)cfg_map_get(voptions, "trusted-keys", &view_keys);
   1131 
   1132 			/* managed-keys and trust-anchors are synonyms. */
   1133 			(void)cfg_map_get(voptions, "managed-keys",
   1134 					  &view_managed_keys);
   1135 			(void)cfg_map_get(voptions, "trust-anchors",
   1136 					  &view_trust_anchors);
   1137 
   1138 			maps[i++] = voptions;
   1139 		}
   1140 	}
   1141 
   1142 	if (config != NULL) {
   1143 		(void)cfg_map_get(config, "trusted-keys", &global_keys);
   1144 
   1145 		/* managed-keys and trust-anchors are synonyms. */
   1146 		(void)cfg_map_get(config, "managed-keys", &global_managed_keys);
   1147 		(void)cfg_map_get(config, "trust-anchors",
   1148 				  &global_trust_anchors);
   1149 
   1150 		(void)cfg_map_get(config, "options", &options);
   1151 		if (options != NULL) {
   1152 			maps[i++] = options;
   1153 		}
   1154 	}
   1155 
   1156 	maps[i++] = named_g_defaults;
   1157 	maps[i] = NULL;
   1158 
   1159 	dns_view_initsecroots(view);
   1160 	dns_view_initntatable(view, named_g_loopmgr);
   1161 
   1162 	if (auto_root && view->rdclass == dns_rdataclass_in) {
   1163 		const cfg_obj_t *builtin_keys = NULL;
   1164 
   1165 		/*
   1166 		 * If bind.keys exists and is populated, it overrides
   1167 		 * the trust-anchors clause hard-coded in named_g_config.
   1168 		 */
   1169 		if (bindkeys != NULL) {
   1170 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
   1171 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   1172 				      "obtaining root key for view %s "
   1173 				      "from '%s'",
   1174 				      view->name, named_g_server->bindkeysfile);
   1175 
   1176 			(void)cfg_map_get(bindkeys, "trust-anchors",
   1177 					  &builtin_keys);
   1178 
   1179 			if (builtin_keys == NULL) {
   1180 				isc_log_write(
   1181 					named_g_lctx, DNS_LOGCATEGORY_SECURITY,
   1182 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   1183 					"dnssec-validation auto: "
   1184 					"WARNING: root zone key "
   1185 					"not found");
   1186 			}
   1187 		}
   1188 
   1189 		if (builtin_keys == NULL) {
   1190 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
   1191 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   1192 				      "using built-in root key for view %s",
   1193 				      view->name);
   1194 
   1195 			(void)cfg_map_get(named_g_config, "trust-anchors",
   1196 					  &builtin_keys);
   1197 		}
   1198 
   1199 		if (builtin_keys != NULL) {
   1200 			CHECK(load_view_keys(builtin_keys, view, true,
   1201 					     dns_rootname));
   1202 		}
   1203 
   1204 		if (!keyloaded(view, dns_rootname)) {
   1205 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
   1206 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   1207 				      "root key not loaded");
   1208 			result = ISC_R_FAILURE;
   1209 			goto cleanup;
   1210 		}
   1211 	}
   1212 
   1213 	if (view->rdclass == dns_rdataclass_in) {
   1214 		CHECK(load_view_keys(view_keys, view, false, NULL));
   1215 		CHECK(load_view_keys(view_trust_anchors, view, true, NULL));
   1216 		CHECK(load_view_keys(view_managed_keys, view, true, NULL));
   1217 
   1218 		CHECK(load_view_keys(global_keys, view, false, NULL));
   1219 		CHECK(load_view_keys(global_trust_anchors, view, true, NULL));
   1220 		CHECK(load_view_keys(global_managed_keys, view, true, NULL));
   1221 	}
   1222 
   1223 	/*
   1224 	 * Add key zone for managed keys.
   1225 	 */
   1226 	obj = NULL;
   1227 	(void)named_config_get(maps, "managed-keys-directory", &obj);
   1228 	directory = (obj != NULL ? cfg_obj_asstring(obj) : NULL);
   1229 	if (directory != NULL) {
   1230 		result = isc_file_isdirectory(directory);
   1231 	}
   1232 	if (result != ISC_R_SUCCESS) {
   1233 		isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
   1234 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   1235 			      "invalid managed-keys-directory %s: %s",
   1236 			      directory, isc_result_totext(result));
   1237 		goto cleanup;
   1238 	} else if (directory != NULL) {
   1239 		if (!isc_file_isdirwritable(directory)) {
   1240 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   1241 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   1242 				      "managed-keys-directory '%s' "
   1243 				      "is not writable",
   1244 				      directory);
   1245 			result = ISC_R_NOPERM;
   1246 			goto cleanup;
   1247 		}
   1248 	}
   1249 
   1250 	if (auto_root) {
   1251 		CHECK(add_keydata_zone(view, directory, named_g_mctx));
   1252 	}
   1253 
   1254 cleanup:
   1255 	return result;
   1256 }
   1257 
   1258 static isc_result_t
   1259 mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
   1260 	const cfg_listelt_t *element;
   1261 	const cfg_obj_t *obj;
   1262 	const char *str;
   1263 	dns_fixedname_t fixed;
   1264 	dns_name_t *name;
   1265 	bool value;
   1266 	isc_result_t result;
   1267 	isc_buffer_t b;
   1268 
   1269 	name = dns_fixedname_initname(&fixed);
   1270 	for (element = cfg_list_first(mbs); element != NULL;
   1271 	     element = cfg_list_next(element))
   1272 	{
   1273 		obj = cfg_listelt_value(element);
   1274 		str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
   1275 		isc_buffer_constinit(&b, str, strlen(str));
   1276 		isc_buffer_add(&b, strlen(str));
   1277 		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
   1278 		value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
   1279 		CHECK(dns_resolver_setmustbesecure(resolver, name, value));
   1280 	}
   1281 
   1282 	result = ISC_R_SUCCESS;
   1283 
   1284 cleanup:
   1285 	return result;
   1286 }
   1287 
   1288 /*%
   1289  * Get a dispatch appropriate for the resolver of a given view.
   1290  */
   1291 static isc_result_t
   1292 get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
   1293 			      dns_dispatch_t **dispatchp, bool is_firstview) {
   1294 	isc_result_t result = ISC_R_FAILURE;
   1295 	dns_dispatch_t *disp = NULL;
   1296 	isc_sockaddr_t sa;
   1297 	const cfg_obj_t *obj = NULL;
   1298 
   1299 	switch (af) {
   1300 	case AF_INET:
   1301 		result = named_config_get(maps, "query-source", &obj);
   1302 		INSIST(result == ISC_R_SUCCESS);
   1303 		break;
   1304 	case AF_INET6:
   1305 		result = named_config_get(maps, "query-source-v6", &obj);
   1306 		INSIST(result == ISC_R_SUCCESS);
   1307 		break;
   1308 	default:
   1309 		UNREACHABLE();
   1310 	}
   1311 
   1312 	if (cfg_obj_isvoid(obj)) {
   1313 		/*
   1314 		 * We don't want to use this address family, let's
   1315 		 * bail now. The dispatch object for this family will
   1316 		 * be null then not used to run queries.
   1317 		 */
   1318 		return ISC_R_SUCCESS;
   1319 	} else {
   1320 		/*
   1321 		 * obj _has_ to be sockaddr here, cfg_obj_assockaddr()
   1322 		 * asserts this internally.
   1323 		 */
   1324 		sa = *(cfg_obj_assockaddr(obj));
   1325 		INSIST(isc_sockaddr_pf(&sa) == af);
   1326 	}
   1327 
   1328 	/*
   1329 	 * If we don't support this address family, we're done!
   1330 	 */
   1331 	switch (af) {
   1332 	case AF_INET:
   1333 		result = isc_net_probeipv4();
   1334 		break;
   1335 	case AF_INET6:
   1336 		result = isc_net_probeipv6();
   1337 		break;
   1338 	default:
   1339 		UNREACHABLE();
   1340 	}
   1341 	if (result != ISC_R_SUCCESS) {
   1342 		return ISC_R_SUCCESS;
   1343 	}
   1344 
   1345 	/*
   1346 	 * Try to find a dispatcher that we can share.
   1347 	 */
   1348 	if (isc_sockaddr_getport(&sa) != 0) {
   1349 		INSIST(obj != NULL);
   1350 		if (is_firstview) {
   1351 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
   1352 				    "using specific query-source port "
   1353 				    "suppresses port randomization and can be "
   1354 				    "insecure.");
   1355 		}
   1356 	}
   1357 
   1358 	result = dns_dispatch_createudp(named_g_dispatchmgr, &sa, &disp);
   1359 	if (result != ISC_R_SUCCESS) {
   1360 		isc_sockaddr_t any;
   1361 		char buf[ISC_SOCKADDR_FORMATSIZE];
   1362 
   1363 		switch (af) {
   1364 		case AF_INET:
   1365 			isc_sockaddr_any(&any);
   1366 			break;
   1367 		case AF_INET6:
   1368 			isc_sockaddr_any6(&any);
   1369 			break;
   1370 		}
   1371 		if (isc_sockaddr_equal(&sa, &any)) {
   1372 			return ISC_R_SUCCESS;
   1373 		}
   1374 		isc_sockaddr_format(&sa, buf, sizeof(buf));
   1375 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   1376 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   1377 			      "could not get query source dispatcher (%s): %s",
   1378 			      buf, isc_result_totext(result));
   1379 		return result;
   1380 	}
   1381 
   1382 	*dispatchp = disp;
   1383 
   1384 	return ISC_R_SUCCESS;
   1385 }
   1386 
   1387 static isc_result_t
   1388 configure_order(dns_order_t *order, const cfg_obj_t *ent) {
   1389 	dns_rdataclass_t rdclass;
   1390 	dns_rdatatype_t rdtype;
   1391 	const cfg_obj_t *obj;
   1392 	dns_fixedname_t fixed;
   1393 	unsigned int mode = 0;
   1394 	const char *str;
   1395 	isc_buffer_t b;
   1396 	isc_result_t result;
   1397 	bool addroot;
   1398 
   1399 	result = named_config_getclass(cfg_tuple_get(ent, "class"),
   1400 				       dns_rdataclass_any, &rdclass);
   1401 	if (result != ISC_R_SUCCESS) {
   1402 		return result;
   1403 	}
   1404 
   1405 	result = named_config_gettype(cfg_tuple_get(ent, "type"),
   1406 				      dns_rdatatype_any, &rdtype);
   1407 	if (result != ISC_R_SUCCESS) {
   1408 		return result;
   1409 	}
   1410 
   1411 	obj = cfg_tuple_get(ent, "name");
   1412 	if (cfg_obj_isstring(obj)) {
   1413 		str = cfg_obj_asstring(obj);
   1414 	} else {
   1415 		str = "*";
   1416 	}
   1417 	addroot = (strcmp(str, "*") == 0);
   1418 	isc_buffer_constinit(&b, str, strlen(str));
   1419 	isc_buffer_add(&b, strlen(str));
   1420 	dns_fixedname_init(&fixed);
   1421 	result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, dns_rootname,
   1422 				   0, NULL);
   1423 	if (result != ISC_R_SUCCESS) {
   1424 		return result;
   1425 	}
   1426 
   1427 	obj = cfg_tuple_get(ent, "ordering");
   1428 	INSIST(cfg_obj_isstring(obj));
   1429 	str = cfg_obj_asstring(obj);
   1430 	if (!strcasecmp(str, "fixed")) {
   1431 #if DNS_RDATASET_FIXED
   1432 		mode = DNS_RDATASETATTR_FIXEDORDER;
   1433 #else  /* if DNS_RDATASET_FIXED */
   1434 		mode = DNS_RDATASETATTR_CYCLIC;
   1435 #endif /* DNS_RDATASET_FIXED */
   1436 	} else if (!strcasecmp(str, "random")) {
   1437 		mode = DNS_RDATASETATTR_RANDOMIZE;
   1438 	} else if (!strcasecmp(str, "cyclic")) {
   1439 		mode = DNS_RDATASETATTR_CYCLIC;
   1440 	} else if (!strcasecmp(str, "none")) {
   1441 		mode = DNS_RDATASETATTR_NONE;
   1442 	} else {
   1443 		UNREACHABLE();
   1444 	}
   1445 
   1446 	/*
   1447 	 * "*" should match everything including the root (BIND 8 compat).
   1448 	 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
   1449 	 * explicit entry for "." when the name is "*".
   1450 	 */
   1451 	if (addroot) {
   1452 		result = dns_order_add(order, dns_rootname, rdtype, rdclass,
   1453 				       mode);
   1454 		if (result != ISC_R_SUCCESS) {
   1455 			return result;
   1456 		}
   1457 	}
   1458 
   1459 	return dns_order_add(order, dns_fixedname_name(&fixed), rdtype, rdclass,
   1460 			     mode);
   1461 }
   1462 
   1463 static isc_result_t
   1464 configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
   1465 	isc_netaddr_t na;
   1466 	dns_peer_t *peer;
   1467 	const cfg_obj_t *obj;
   1468 	const char *str;
   1469 	isc_result_t result;
   1470 	unsigned int prefixlen;
   1471 
   1472 	cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
   1473 
   1474 	peer = NULL;
   1475 	result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
   1476 	if (result != ISC_R_SUCCESS) {
   1477 		return result;
   1478 	}
   1479 
   1480 	obj = NULL;
   1481 	(void)cfg_map_get(cpeer, "bogus", &obj);
   1482 	if (obj != NULL) {
   1483 		CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
   1484 	}
   1485 
   1486 	obj = NULL;
   1487 	(void)cfg_map_get(cpeer, "provide-ixfr", &obj);
   1488 	if (obj != NULL) {
   1489 		CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
   1490 	}
   1491 
   1492 	obj = NULL;
   1493 	(void)cfg_map_get(cpeer, "request-expire", &obj);
   1494 	if (obj != NULL) {
   1495 		CHECK(dns_peer_setrequestexpire(peer, cfg_obj_asboolean(obj)));
   1496 	}
   1497 
   1498 	obj = NULL;
   1499 	(void)cfg_map_get(cpeer, "request-ixfr", &obj);
   1500 	if (obj != NULL) {
   1501 		CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
   1502 	}
   1503 
   1504 	obj = NULL;
   1505 	(void)cfg_map_get(cpeer, "request-nsid", &obj);
   1506 	if (obj != NULL) {
   1507 		CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
   1508 	}
   1509 
   1510 	obj = NULL;
   1511 	(void)cfg_map_get(cpeer, "send-cookie", &obj);
   1512 	if (obj != NULL) {
   1513 		CHECK(dns_peer_setsendcookie(peer, cfg_obj_asboolean(obj)));
   1514 	}
   1515 
   1516 	obj = NULL;
   1517 	(void)cfg_map_get(cpeer, "require-cookie", &obj);
   1518 	if (obj != NULL) {
   1519 		CHECK(dns_peer_setrequirecookie(peer, cfg_obj_asboolean(obj)));
   1520 	}
   1521 
   1522 	obj = NULL;
   1523 	(void)cfg_map_get(cpeer, "edns", &obj);
   1524 	if (obj != NULL) {
   1525 		CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
   1526 	}
   1527 
   1528 	obj = NULL;
   1529 	(void)cfg_map_get(cpeer, "edns-udp-size", &obj);
   1530 	if (obj != NULL) {
   1531 		uint32_t udpsize = cfg_obj_asuint32(obj);
   1532 		if (udpsize < 512U) {
   1533 			udpsize = 512U;
   1534 		}
   1535 		if (udpsize > 4096U) {
   1536 			udpsize = 4096U;
   1537 		}
   1538 		CHECK(dns_peer_setudpsize(peer, (uint16_t)udpsize));
   1539 	}
   1540 
   1541 	obj = NULL;
   1542 	(void)cfg_map_get(cpeer, "edns-version", &obj);
   1543 	if (obj != NULL) {
   1544 		uint32_t ednsversion = cfg_obj_asuint32(obj);
   1545 		if (ednsversion > 255U) {
   1546 			ednsversion = 255U;
   1547 		}
   1548 		CHECK(dns_peer_setednsversion(peer, (uint8_t)ednsversion));
   1549 	}
   1550 
   1551 	obj = NULL;
   1552 	(void)cfg_map_get(cpeer, "max-udp-size", &obj);
   1553 	if (obj != NULL) {
   1554 		uint32_t udpsize = cfg_obj_asuint32(obj);
   1555 		if (udpsize < 512U) {
   1556 			udpsize = 512U;
   1557 		}
   1558 		if (udpsize > 4096U) {
   1559 			udpsize = 4096U;
   1560 		}
   1561 		CHECK(dns_peer_setmaxudp(peer, (uint16_t)udpsize));
   1562 	}
   1563 
   1564 	obj = NULL;
   1565 	(void)cfg_map_get(cpeer, "padding", &obj);
   1566 	if (obj != NULL) {
   1567 		uint32_t padding = cfg_obj_asuint32(obj);
   1568 		if (padding > 512U) {
   1569 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   1570 				    "server padding value cannot "
   1571 				    "exceed 512: lowering");
   1572 			padding = 512U;
   1573 		}
   1574 		CHECK(dns_peer_setpadding(peer, (uint16_t)padding));
   1575 	}
   1576 
   1577 	obj = NULL;
   1578 	(void)cfg_map_get(cpeer, "tcp-only", &obj);
   1579 	if (obj != NULL) {
   1580 		CHECK(dns_peer_setforcetcp(peer, cfg_obj_asboolean(obj)));
   1581 	}
   1582 
   1583 	obj = NULL;
   1584 	(void)cfg_map_get(cpeer, "tcp-keepalive", &obj);
   1585 	if (obj != NULL) {
   1586 		CHECK(dns_peer_settcpkeepalive(peer, cfg_obj_asboolean(obj)));
   1587 	}
   1588 
   1589 	obj = NULL;
   1590 	(void)cfg_map_get(cpeer, "transfers", &obj);
   1591 	if (obj != NULL) {
   1592 		CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
   1593 	}
   1594 
   1595 	obj = NULL;
   1596 	(void)cfg_map_get(cpeer, "transfer-format", &obj);
   1597 	if (obj != NULL) {
   1598 		str = cfg_obj_asstring(obj);
   1599 		if (strcasecmp(str, "many-answers") == 0) {
   1600 			CHECK(dns_peer_settransferformat(peer,
   1601 							 dns_many_answers));
   1602 		} else if (strcasecmp(str, "one-answer") == 0) {
   1603 			CHECK(dns_peer_settransferformat(peer, dns_one_answer));
   1604 		} else {
   1605 			UNREACHABLE();
   1606 		}
   1607 	}
   1608 
   1609 	obj = NULL;
   1610 	(void)cfg_map_get(cpeer, "keys", &obj);
   1611 	if (obj != NULL) {
   1612 		result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
   1613 		if (result != ISC_R_SUCCESS) {
   1614 			goto cleanup;
   1615 		}
   1616 	}
   1617 
   1618 	obj = NULL;
   1619 	if (na.family == AF_INET) {
   1620 		(void)cfg_map_get(cpeer, "transfer-source", &obj);
   1621 	} else {
   1622 		(void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
   1623 	}
   1624 	if (obj != NULL) {
   1625 		result = dns_peer_settransfersource(peer,
   1626 						    cfg_obj_assockaddr(obj));
   1627 		if (result != ISC_R_SUCCESS) {
   1628 			goto cleanup;
   1629 		}
   1630 	}
   1631 
   1632 	obj = NULL;
   1633 	if (na.family == AF_INET) {
   1634 		(void)cfg_map_get(cpeer, "notify-source", &obj);
   1635 	} else {
   1636 		(void)cfg_map_get(cpeer, "notify-source-v6", &obj);
   1637 	}
   1638 	if (obj != NULL) {
   1639 		result = dns_peer_setnotifysource(peer,
   1640 						  cfg_obj_assockaddr(obj));
   1641 		if (result != ISC_R_SUCCESS) {
   1642 			goto cleanup;
   1643 		}
   1644 	}
   1645 
   1646 	obj = NULL;
   1647 	if (na.family == AF_INET) {
   1648 		(void)cfg_map_get(cpeer, "query-source", &obj);
   1649 	} else {
   1650 		(void)cfg_map_get(cpeer, "query-source-v6", &obj);
   1651 	}
   1652 	if (obj != NULL) {
   1653 		INSIST(cfg_obj_issockaddr(obj));
   1654 		result = dns_peer_setquerysource(peer, cfg_obj_assockaddr(obj));
   1655 		if (result != ISC_R_SUCCESS) {
   1656 			goto cleanup;
   1657 		}
   1658 	}
   1659 
   1660 	*peerp = peer;
   1661 	return ISC_R_SUCCESS;
   1662 
   1663 cleanup:
   1664 	dns_peer_detach(&peer);
   1665 	return result;
   1666 }
   1667 
   1668 static isc_result_t
   1669 configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx,
   1670 		const dns_dyndbctx_t *dctx) {
   1671 	isc_result_t result = ISC_R_SUCCESS;
   1672 	const cfg_obj_t *obj;
   1673 	const char *name, *library;
   1674 
   1675 	/* Get the name of the dyndb instance and the library path . */
   1676 	name = cfg_obj_asstring(cfg_tuple_get(dyndb, "name"));
   1677 	library = cfg_obj_asstring(cfg_tuple_get(dyndb, "library"));
   1678 
   1679 	obj = cfg_tuple_get(dyndb, "parameters");
   1680 	if (obj != NULL) {
   1681 		result = dns_dyndb_load(library, name, cfg_obj_asstring(obj),
   1682 					cfg_obj_file(obj), cfg_obj_line(obj),
   1683 					mctx, dctx);
   1684 	}
   1685 
   1686 	if (result != ISC_R_SUCCESS) {
   1687 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   1688 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   1689 			      "dynamic database '%s' configuration failed: %s",
   1690 			      name, isc_result_totext(result));
   1691 	}
   1692 	return result;
   1693 }
   1694 
   1695 static isc_result_t
   1696 disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
   1697 	isc_result_t result;
   1698 	const cfg_obj_t *algorithms;
   1699 	const cfg_listelt_t *element;
   1700 	const char *str;
   1701 	dns_fixedname_t fixed;
   1702 	dns_name_t *name;
   1703 	isc_buffer_t b;
   1704 
   1705 	name = dns_fixedname_initname(&fixed);
   1706 	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
   1707 	isc_buffer_constinit(&b, str, strlen(str));
   1708 	isc_buffer_add(&b, strlen(str));
   1709 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
   1710 
   1711 	algorithms = cfg_tuple_get(disabled, "algorithms");
   1712 	for (element = cfg_list_first(algorithms); element != NULL;
   1713 	     element = cfg_list_next(element))
   1714 	{
   1715 		isc_textregion_t r;
   1716 		dns_secalg_t alg;
   1717 
   1718 		r.base = UNCONST(cfg_obj_asstring(cfg_listelt_value(element)));
   1719 		r.length = strlen(r.base);
   1720 
   1721 		result = dns_secalg_fromtext(&alg, &r);
   1722 		if (result != ISC_R_SUCCESS) {
   1723 			uint8_t ui;
   1724 			result = isc_parse_uint8(&ui, r.base, 10);
   1725 			alg = ui;
   1726 		}
   1727 		if (result != ISC_R_SUCCESS) {
   1728 			cfg_obj_log(cfg_listelt_value(element), named_g_lctx,
   1729 				    ISC_LOG_ERROR, "invalid algorithm");
   1730 			CHECK(result);
   1731 		}
   1732 		CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
   1733 	}
   1734 cleanup:
   1735 	return result;
   1736 }
   1737 
   1738 static isc_result_t
   1739 disable_ds_digests(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
   1740 	isc_result_t result;
   1741 	const cfg_obj_t *digests;
   1742 	const cfg_listelt_t *element;
   1743 	const char *str;
   1744 	dns_fixedname_t fixed;
   1745 	dns_name_t *name;
   1746 	isc_buffer_t b;
   1747 
   1748 	name = dns_fixedname_initname(&fixed);
   1749 	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
   1750 	isc_buffer_constinit(&b, str, strlen(str));
   1751 	isc_buffer_add(&b, strlen(str));
   1752 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
   1753 
   1754 	digests = cfg_tuple_get(disabled, "digests");
   1755 	for (element = cfg_list_first(digests); element != NULL;
   1756 	     element = cfg_list_next(element))
   1757 	{
   1758 		isc_textregion_t r;
   1759 		dns_dsdigest_t digest;
   1760 
   1761 		r.base = UNCONST(cfg_obj_asstring(cfg_listelt_value(element)));
   1762 		r.length = strlen(r.base);
   1763 
   1764 		/* disable_ds_digests handles numeric values. */
   1765 		result = dns_dsdigest_fromtext(&digest, &r);
   1766 		if (result != ISC_R_SUCCESS) {
   1767 			cfg_obj_log(cfg_listelt_value(element), named_g_lctx,
   1768 				    ISC_LOG_ERROR, "invalid algorithm");
   1769 			CHECK(result);
   1770 		}
   1771 		CHECK(dns_resolver_disable_ds_digest(resolver, name, digest));
   1772 	}
   1773 cleanup:
   1774 	return result;
   1775 }
   1776 
   1777 static bool
   1778 on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
   1779 	const cfg_listelt_t *element;
   1780 	dns_fixedname_t fixed;
   1781 	dns_name_t *name;
   1782 	isc_result_t result;
   1783 	const cfg_obj_t *value;
   1784 	const char *str;
   1785 	isc_buffer_t b;
   1786 
   1787 	name = dns_fixedname_initname(&fixed);
   1788 
   1789 	for (element = cfg_list_first(disablelist); element != NULL;
   1790 	     element = cfg_list_next(element))
   1791 	{
   1792 		value = cfg_listelt_value(element);
   1793 		str = cfg_obj_asstring(value);
   1794 		isc_buffer_constinit(&b, str, strlen(str));
   1795 		isc_buffer_add(&b, strlen(str));
   1796 		result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
   1797 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1798 		if (dns_name_equal(name, zonename)) {
   1799 			return true;
   1800 		}
   1801 	}
   1802 	return false;
   1803 }
   1804 
   1805 static isc_result_t
   1806 check_dbtype(dns_zone_t *zone, unsigned int dbtypec, const char **dbargv,
   1807 	     isc_mem_t *mctx) {
   1808 	char **argv = NULL;
   1809 	unsigned int i;
   1810 	isc_result_t result = ISC_R_SUCCESS;
   1811 
   1812 	CHECK(dns_zone_getdbtype(zone, &argv, mctx));
   1813 
   1814 	/*
   1815 	 * Check that all the arguments match.
   1816 	 */
   1817 	for (i = 0; i < dbtypec; i++) {
   1818 		if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) {
   1819 			CHECK(ISC_R_FAILURE);
   1820 		}
   1821 	}
   1822 
   1823 	/*
   1824 	 * Check that there are not extra arguments.
   1825 	 */
   1826 	if (i == dbtypec && argv[i] != NULL) {
   1827 		result = ISC_R_FAILURE;
   1828 	}
   1829 
   1830 cleanup:
   1831 	isc_mem_free(mctx, argv);
   1832 	return result;
   1833 }
   1834 
   1835 static void
   1836 setquerystats(dns_zone_t *zone, isc_mem_t *mctx, dns_zonestat_level_t level) {
   1837 	isc_stats_t *zoneqrystats;
   1838 
   1839 	dns_zone_setstatlevel(zone, level);
   1840 
   1841 	zoneqrystats = NULL;
   1842 	if (level == dns_zonestat_full) {
   1843 		isc_stats_create(mctx, &zoneqrystats, ns_statscounter_max);
   1844 	}
   1845 	dns_zone_setrequeststats(zone, zoneqrystats);
   1846 	if (zoneqrystats != NULL) {
   1847 		isc_stats_detach(&zoneqrystats);
   1848 	}
   1849 }
   1850 
   1851 static named_cache_t *
   1852 cachelist_find(named_cachelist_t *cachelist, const char *cachename,
   1853 	       dns_rdataclass_t rdclass) {
   1854 	for (named_cache_t *nsc = ISC_LIST_HEAD(*cachelist); nsc != NULL;
   1855 	     nsc = ISC_LIST_NEXT(nsc, link))
   1856 	{
   1857 		if (nsc->rdclass == rdclass &&
   1858 		    strcmp(dns_cache_getname(nsc->cache), cachename) == 0)
   1859 		{
   1860 			return nsc;
   1861 		}
   1862 	}
   1863 
   1864 	return NULL;
   1865 }
   1866 
   1867 static bool
   1868 cache_reusable(dns_view_t *originview, dns_view_t *view,
   1869 	       bool new_zero_no_soattl) {
   1870 	if (originview->rdclass != view->rdclass ||
   1871 	    originview->checknames != view->checknames ||
   1872 	    originview->acceptexpired != view->acceptexpired ||
   1873 	    originview->enablevalidation != view->enablevalidation ||
   1874 	    originview->maxcachettl != view->maxcachettl ||
   1875 	    originview->maxncachettl != view->maxncachettl ||
   1876 	    originview->resolver == NULL ||
   1877 	    dns_resolver_getzeronosoattl(originview->resolver) !=
   1878 		    new_zero_no_soattl)
   1879 	{
   1880 		return false;
   1881 	}
   1882 
   1883 	return true;
   1884 }
   1885 
   1886 static bool
   1887 cache_sharable(dns_view_t *originview, dns_view_t *view,
   1888 	       bool new_zero_no_soattl, uint64_t new_max_cache_size,
   1889 	       uint32_t new_stale_ttl, uint32_t new_stale_refresh_time) {
   1890 	/*
   1891 	 * If the cache cannot even reused for the same view, it cannot be
   1892 	 * shared with other views.
   1893 	 */
   1894 	if (!cache_reusable(originview, view, new_zero_no_soattl)) {
   1895 		return false;
   1896 	}
   1897 
   1898 	/*
   1899 	 * Check other cache related parameters that must be consistent among
   1900 	 * the sharing views.
   1901 	 */
   1902 	if (dns_cache_getservestalettl(originview->cache) != new_stale_ttl ||
   1903 	    dns_cache_getservestalerefresh(originview->cache) !=
   1904 		    new_stale_refresh_time ||
   1905 	    dns_cache_getcachesize(originview->cache) != new_max_cache_size)
   1906 	{
   1907 		return false;
   1908 	}
   1909 
   1910 	return true;
   1911 }
   1912 
   1913 /*
   1914  * Callback from DLZ configure when the driver sets up a writeable zone
   1915  */
   1916 static isc_result_t
   1917 dlzconfigure_callback(dns_view_t *view, dns_dlzdb_t *dlzdb, dns_zone_t *zone) {
   1918 	dns_name_t *origin = dns_zone_getorigin(zone);
   1919 	dns_rdataclass_t zclass = view->rdclass;
   1920 	isc_result_t result;
   1921 
   1922 	dns_zone_setclass(zone, zclass);
   1923 	result = dns_zonemgr_managezone(named_g_server->zonemgr, zone);
   1924 	if (result != ISC_R_SUCCESS) {
   1925 		return result;
   1926 	}
   1927 
   1928 	dns_zone_setstats(zone, named_g_server->zonestats);
   1929 
   1930 	return named_zone_configure_writeable_dlz(dlzdb, zone, zclass, origin);
   1931 }
   1932 
   1933 static isc_result_t
   1934 dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na,
   1935 	      unsigned int prefixlen, const char *server, const char *contact) {
   1936 	char reverse[48 + sizeof("ip6.arpa.")] = { 0 };
   1937 	char buf[sizeof("x.x.")];
   1938 	const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." };
   1939 	const char *sep = ": view ";
   1940 	const char *viewname = view->name;
   1941 	const unsigned char *s6;
   1942 	dns_fixedname_t fixed;
   1943 	dns_name_t *name;
   1944 	dns_zone_t *zone = NULL;
   1945 	int dns64_dbtypec = 4;
   1946 	isc_buffer_t b;
   1947 	isc_result_t result;
   1948 
   1949 	REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
   1950 		prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
   1951 
   1952 	if (!strcmp(viewname, "_default")) {
   1953 		sep = "";
   1954 		viewname = "";
   1955 	}
   1956 
   1957 	/*
   1958 	 * Construct the reverse name of the zone.
   1959 	 */
   1960 	s6 = na->type.in6.s6_addr;
   1961 	while (prefixlen > 0) {
   1962 		prefixlen -= 8;
   1963 		snprintf(buf, sizeof(buf), "%x.%x.", s6[prefixlen / 8] & 0xf,
   1964 			 (s6[prefixlen / 8] >> 4) & 0xf);
   1965 		strlcat(reverse, buf, sizeof(reverse));
   1966 	}
   1967 	strlcat(reverse, "ip6.arpa.", sizeof(reverse));
   1968 
   1969 	/*
   1970 	 * Create the actual zone.
   1971 	 */
   1972 	if (server != NULL) {
   1973 		dns64_dbtype[2] = server;
   1974 	}
   1975 	if (contact != NULL) {
   1976 		dns64_dbtype[3] = contact;
   1977 	}
   1978 	name = dns_fixedname_initname(&fixed);
   1979 	isc_buffer_constinit(&b, reverse, strlen(reverse));
   1980 	isc_buffer_add(&b, strlen(reverse));
   1981 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
   1982 	dns_zone_create(&zone, mctx, 0);
   1983 	CHECK(dns_zone_setorigin(zone, name));
   1984 	dns_zone_setview(zone, view);
   1985 	CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
   1986 	dns_zone_setclass(zone, view->rdclass);
   1987 	dns_zone_settype(zone, dns_zone_primary);
   1988 	dns_zone_setstats(zone, named_g_server->zonestats);
   1989 	dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype);
   1990 	if (view->queryacl != NULL) {
   1991 		dns_zone_setqueryacl(zone, view->queryacl);
   1992 	}
   1993 	if (view->queryonacl != NULL) {
   1994 		dns_zone_setqueryonacl(zone, view->queryonacl);
   1995 	}
   1996 	dns_zone_setdialup(zone, dns_dialuptype_no);
   1997 	dns_zone_setcheckdstype(zone, dns_checkdstype_no);
   1998 	dns_zone_setnotifytype(zone, dns_notifytype_no);
   1999 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
   2000 	setquerystats(zone, mctx, dns_zonestat_none);
   2001 	CHECK(dns_view_addzone(view, zone));
   2002 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2003 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   2004 		      "dns64 reverse zone%s%s: %s", sep, viewname, reverse);
   2005 
   2006 cleanup:
   2007 	if (zone != NULL) {
   2008 		dns_zone_detach(&zone);
   2009 	}
   2010 	return result;
   2011 }
   2012 
   2013 #ifdef USE_DNSRPS
   2014 typedef struct conf_dnsrps_ctx conf_dnsrps_ctx_t;
   2015 struct conf_dnsrps_ctx {
   2016 	isc_result_t result;
   2017 	char *cstr;
   2018 	size_t cstr_size;
   2019 	isc_mem_t *mctx;
   2020 };
   2021 
   2022 /*
   2023  * Add to the DNSRPS configuration string.
   2024  */
   2025 static bool
   2026 conf_dnsrps_sadd(conf_dnsrps_ctx_t *ctx, const char *p, ...) {
   2027 	size_t new_len, cur_len, new_cstr_size;
   2028 	char *new_cstr;
   2029 	va_list args;
   2030 
   2031 	if (ctx->cstr == NULL) {
   2032 		ctx->cstr = isc_mem_get(ctx->mctx, 256);
   2033 		ctx->cstr[0] = '\0';
   2034 		ctx->cstr_size = 256;
   2035 	}
   2036 
   2037 	cur_len = strlen(ctx->cstr);
   2038 	va_start(args, p);
   2039 	new_len = vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p,
   2040 			    args) +
   2041 		  1;
   2042 	va_end(args);
   2043 
   2044 	if (cur_len + new_len <= ctx->cstr_size) {
   2045 		return true;
   2046 	}
   2047 
   2048 	new_cstr_size = ((cur_len + new_len) / 256 + 1) * 256;
   2049 	new_cstr = isc_mem_get(ctx->mctx, new_cstr_size);
   2050 
   2051 	memmove(new_cstr, ctx->cstr, cur_len);
   2052 	isc_mem_put(ctx->mctx, ctx->cstr, ctx->cstr_size);
   2053 	ctx->cstr_size = new_cstr_size;
   2054 	ctx->cstr = new_cstr;
   2055 
   2056 	/* cannot use args twice after a single va_start()on some systems */
   2057 	va_start(args, p);
   2058 	vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p, args);
   2059 	va_end(args);
   2060 	return true;
   2061 }
   2062 
   2063 /*
   2064  * Get a DNSRPS configuration value using the global and view options
   2065  * for the default.  Return false upon failure.
   2066  */
   2067 static bool
   2068 conf_dnsrps_get(const cfg_obj_t **sub_obj, const cfg_obj_t **maps,
   2069 		const cfg_obj_t *obj, const char *name,
   2070 		conf_dnsrps_ctx_t *ctx) {
   2071 	if (ctx != NULL && ctx->result != ISC_R_SUCCESS) {
   2072 		*sub_obj = NULL;
   2073 		return false;
   2074 	}
   2075 
   2076 	*sub_obj = cfg_tuple_get(obj, name);
   2077 	if (cfg_obj_isvoid(*sub_obj)) {
   2078 		*sub_obj = NULL;
   2079 		if (maps != NULL &&
   2080 		    ISC_R_SUCCESS != named_config_get(maps, name, sub_obj))
   2081 		{
   2082 			*sub_obj = NULL;
   2083 		}
   2084 	}
   2085 	return true;
   2086 }
   2087 
   2088 /*
   2089  * Handle a DNSRPS boolean configuration value with the global and view
   2090  * options providing the default.
   2091  */
   2092 static void
   2093 conf_dnsrps_yes_no(const cfg_obj_t *obj, const char *name,
   2094 		   conf_dnsrps_ctx_t *ctx) {
   2095 	const cfg_obj_t *sub_obj;
   2096 
   2097 	if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) {
   2098 		return;
   2099 	}
   2100 	if (sub_obj == NULL) {
   2101 		return;
   2102 	}
   2103 	if (ctx == NULL) {
   2104 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
   2105 			    "\"%s\" without \"dnsrps-enable yes\"", name);
   2106 		return;
   2107 	}
   2108 
   2109 	conf_dnsrps_sadd(ctx, " %s %s", name,
   2110 			 cfg_obj_asboolean(sub_obj) ? "yes" : "no");
   2111 }
   2112 
   2113 static void
   2114 conf_dnsrps_num(const cfg_obj_t *obj, const char *name,
   2115 		conf_dnsrps_ctx_t *ctx) {
   2116 	const cfg_obj_t *sub_obj;
   2117 
   2118 	if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) {
   2119 		return;
   2120 	}
   2121 	if (sub_obj == NULL) {
   2122 		return;
   2123 	}
   2124 	if (ctx == NULL) {
   2125 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
   2126 			    "\"%s\" without \"dnsrps-enable yes\"", name);
   2127 		return;
   2128 	}
   2129 
   2130 	if (cfg_obj_isduration(sub_obj)) {
   2131 		conf_dnsrps_sadd(ctx, " %s %d", name,
   2132 				 cfg_obj_asduration(sub_obj));
   2133 	} else {
   2134 		conf_dnsrps_sadd(ctx, " %s %d", name,
   2135 				 cfg_obj_asuint32(sub_obj));
   2136 	}
   2137 }
   2138 
   2139 /*
   2140  * Convert the parsed RPZ configuration statement to a string for
   2141  * dns_rpz_new_zones().
   2142  */
   2143 static isc_result_t
   2144 conf_dnsrps(dns_view_t *view, const cfg_obj_t **maps, bool nsip_enabled,
   2145 	    bool nsdname_enabled, dns_rpz_zbits_t *nsip_on,
   2146 	    dns_rpz_zbits_t *nsdname_on, char **rps_cstr, size_t *rps_cstr_size,
   2147 	    const cfg_obj_t *rpz_obj, const cfg_listelt_t *zone_element) {
   2148 	conf_dnsrps_ctx_t ctx;
   2149 	const cfg_obj_t *zone_obj, *obj;
   2150 	dns_rpz_num_t rpz_num;
   2151 	bool on;
   2152 	const char *s;
   2153 
   2154 	memset(&ctx, 0, sizeof(ctx));
   2155 	ctx.result = ISC_R_SUCCESS;
   2156 	ctx.mctx = view->mctx;
   2157 
   2158 	for (rpz_num = 0; zone_element != NULL && ctx.result == ISC_R_SUCCESS;
   2159 	     ++rpz_num)
   2160 	{
   2161 		zone_obj = cfg_listelt_value(zone_element);
   2162 
   2163 		s = cfg_obj_asstring(cfg_tuple_get(zone_obj, "zone name"));
   2164 		conf_dnsrps_sadd(&ctx, "zone \"%s\"", s);
   2165 
   2166 		obj = cfg_tuple_get(zone_obj, "policy");
   2167 		if (!cfg_obj_isvoid(obj)) {
   2168 			s = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
   2169 			conf_dnsrps_sadd(&ctx, " policy %s", s);
   2170 			if (strcasecmp(s, "cname") == 0) {
   2171 				s = cfg_obj_asstring(
   2172 					cfg_tuple_get(obj, "cname"));
   2173 				conf_dnsrps_sadd(&ctx, " %s", s);
   2174 			}
   2175 		}
   2176 
   2177 		conf_dnsrps_yes_no(zone_obj, "recursive-only", &ctx);
   2178 		conf_dnsrps_yes_no(zone_obj, "log", &ctx);
   2179 		conf_dnsrps_num(zone_obj, "max-policy-ttl", &ctx);
   2180 		obj = cfg_tuple_get(rpz_obj, "nsip-enable");
   2181 		if (!cfg_obj_isvoid(obj)) {
   2182 			if (cfg_obj_asboolean(obj)) {
   2183 				*nsip_on |= DNS_RPZ_ZBIT(rpz_num);
   2184 			} else {
   2185 				*nsip_on &= ~DNS_RPZ_ZBIT(rpz_num);
   2186 			}
   2187 		}
   2188 		on = ((*nsip_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
   2189 		if (nsip_enabled != on) {
   2190 			conf_dnsrps_sadd(&ctx, on ? " nsip-enable yes "
   2191 						  : " nsip-enable no ");
   2192 		}
   2193 		obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
   2194 		if (!cfg_obj_isvoid(obj)) {
   2195 			if (cfg_obj_asboolean(obj)) {
   2196 				*nsdname_on |= DNS_RPZ_ZBIT(rpz_num);
   2197 			} else {
   2198 				*nsdname_on &= ~DNS_RPZ_ZBIT(rpz_num);
   2199 			}
   2200 		}
   2201 		on = ((*nsdname_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
   2202 		if (nsdname_enabled != on) {
   2203 			conf_dnsrps_sadd(&ctx, on ? " nsdname-enable yes "
   2204 						  : " nsdname-enable no ");
   2205 		}
   2206 		conf_dnsrps_sadd(&ctx, ";\n");
   2207 		zone_element = cfg_list_next(zone_element);
   2208 	}
   2209 
   2210 	conf_dnsrps_yes_no(rpz_obj, "recursive-only", &ctx);
   2211 	conf_dnsrps_num(rpz_obj, "max-policy-ttl", &ctx);
   2212 	conf_dnsrps_num(rpz_obj, "min-ns-dots", &ctx);
   2213 	conf_dnsrps_yes_no(rpz_obj, "qname-wait-recurse", &ctx);
   2214 	conf_dnsrps_yes_no(rpz_obj, "break-dnssec", &ctx);
   2215 	if (!nsip_enabled) {
   2216 		conf_dnsrps_sadd(&ctx, " nsip-enable no ");
   2217 	}
   2218 	if (!nsdname_enabled) {
   2219 		conf_dnsrps_sadd(&ctx, " nsdname-enable no ");
   2220 	}
   2221 
   2222 	/*
   2223 	 * Get the general dnsrpzd parameters from the response-policy
   2224 	 * statement in the view and the general options.
   2225 	 */
   2226 	if (conf_dnsrps_get(&obj, maps, rpz_obj, "dnsrps-options", &ctx) &&
   2227 	    obj != NULL)
   2228 	{
   2229 		conf_dnsrps_sadd(&ctx, " %s\n", cfg_obj_asstring(obj));
   2230 	}
   2231 
   2232 	if (ctx.result == ISC_R_SUCCESS) {
   2233 		*rps_cstr = ctx.cstr;
   2234 		*rps_cstr_size = ctx.cstr_size;
   2235 	} else {
   2236 		if (ctx.cstr != NULL) {
   2237 			isc_mem_put(ctx.mctx, ctx.cstr, ctx.cstr_size);
   2238 		}
   2239 		*rps_cstr = NULL;
   2240 		*rps_cstr_size = 0;
   2241 	}
   2242 	return ctx.result;
   2243 }
   2244 #endif /* ifdef USE_DNSRPS */
   2245 
   2246 static isc_result_t
   2247 configure_rpz_name(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
   2248 		   const char *str, const char *msg) {
   2249 	isc_result_t result;
   2250 
   2251 	result = dns_name_fromstring(name, str, dns_rootname, DNS_NAME_DOWNCASE,
   2252 				     view->mctx);
   2253 	if (result != ISC_R_SUCCESS) {
   2254 		cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
   2255 			    "invalid %s '%s'", msg, str);
   2256 	}
   2257 	return result;
   2258 }
   2259 
   2260 static isc_result_t
   2261 configure_rpz_name2(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
   2262 		    const char *str, const dns_name_t *origin) {
   2263 	isc_result_t result;
   2264 
   2265 	result = dns_name_fromstring(name, str, origin, DNS_NAME_DOWNCASE,
   2266 				     view->mctx);
   2267 	if (result != ISC_R_SUCCESS) {
   2268 		cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
   2269 			    "invalid zone '%s'", str);
   2270 	}
   2271 	return result;
   2272 }
   2273 
   2274 static isc_result_t
   2275 configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element,
   2276 		   bool recursive_only_default, bool add_soa_default,
   2277 		   dns_ttl_t ttl_default, uint32_t minupdateinterval_default,
   2278 		   const dns_rpz_zone_t *old, bool *old_rpz_okp) {
   2279 	const cfg_obj_t *rpz_obj, *obj;
   2280 	const char *str;
   2281 	dns_rpz_zone_t *zone = NULL;
   2282 	isc_result_t result;
   2283 	dns_rpz_num_t rpz_num;
   2284 
   2285 	REQUIRE(old != NULL || !*old_rpz_okp);
   2286 
   2287 	rpz_obj = cfg_listelt_value(element);
   2288 
   2289 	if (view->rpzs->p.num_zones >= DNS_RPZ_MAX_ZONES) {
   2290 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
   2291 			    "limit of %d response policy zones exceeded",
   2292 			    DNS_RPZ_MAX_ZONES);
   2293 		return ISC_R_FAILURE;
   2294 	}
   2295 
   2296 	result = dns_rpz_new_zone(view->rpzs, &zone);
   2297 	if (result != ISC_R_SUCCESS) {
   2298 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
   2299 			    "Error creating new RPZ zone : %s",
   2300 			    isc_result_totext(result));
   2301 		return result;
   2302 	}
   2303 
   2304 	obj = cfg_tuple_get(rpz_obj, "recursive-only");
   2305 	if (cfg_obj_isvoid(obj) ? recursive_only_default
   2306 				: cfg_obj_asboolean(obj))
   2307 	{
   2308 		view->rpzs->p.no_rd_ok &= ~DNS_RPZ_ZBIT(zone->num);
   2309 	} else {
   2310 		view->rpzs->p.no_rd_ok |= DNS_RPZ_ZBIT(zone->num);
   2311 	}
   2312 
   2313 	obj = cfg_tuple_get(rpz_obj, "log");
   2314 	if (!cfg_obj_isvoid(obj) && !cfg_obj_asboolean(obj)) {
   2315 		view->rpzs->p.no_log |= DNS_RPZ_ZBIT(zone->num);
   2316 	} else {
   2317 		view->rpzs->p.no_log &= ~DNS_RPZ_ZBIT(zone->num);
   2318 	}
   2319 
   2320 	obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
   2321 	if (cfg_obj_isduration(obj)) {
   2322 		zone->max_policy_ttl = cfg_obj_asduration(obj);
   2323 	} else {
   2324 		zone->max_policy_ttl = ttl_default;
   2325 	}
   2326 	if (*old_rpz_okp && zone->max_policy_ttl != old->max_policy_ttl) {
   2327 		*old_rpz_okp = false;
   2328 	}
   2329 
   2330 	obj = cfg_tuple_get(rpz_obj, "min-update-interval");
   2331 	if (cfg_obj_isduration(obj)) {
   2332 		zone->min_update_interval = cfg_obj_asduration(obj);
   2333 	} else {
   2334 		zone->min_update_interval = minupdateinterval_default;
   2335 	}
   2336 	if (*old_rpz_okp &&
   2337 	    zone->min_update_interval != old->min_update_interval)
   2338 	{
   2339 		*old_rpz_okp = false;
   2340 	}
   2341 
   2342 	str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name"));
   2343 	result = configure_rpz_name(view, rpz_obj, &zone->origin, str, "zone");
   2344 	if (result != ISC_R_SUCCESS) {
   2345 		return result;
   2346 	}
   2347 	if (dns_name_equal(&zone->origin, dns_rootname)) {
   2348 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
   2349 			    "invalid zone name '%s'", str);
   2350 		return DNS_R_EMPTYLABEL;
   2351 	}
   2352 	if (!view->rpzs->p.dnsrps_enabled) {
   2353 		for (rpz_num = 0; rpz_num < view->rpzs->p.num_zones - 1;
   2354 		     ++rpz_num)
   2355 		{
   2356 			if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin,
   2357 					   &zone->origin))
   2358 			{
   2359 				cfg_obj_log(rpz_obj, named_g_lctx,
   2360 					    DNS_RPZ_ERROR_LEVEL,
   2361 					    "duplicate '%s'", str);
   2362 				result = DNS_R_DUPLICATE;
   2363 				return result;
   2364 			}
   2365 		}
   2366 	}
   2367 	if (*old_rpz_okp && !dns_name_equal(&old->origin, &zone->origin)) {
   2368 		*old_rpz_okp = false;
   2369 	}
   2370 
   2371 	result = configure_rpz_name2(view, rpz_obj, &zone->client_ip,
   2372 				     DNS_RPZ_CLIENT_IP_ZONE, &zone->origin);
   2373 	if (result != ISC_R_SUCCESS) {
   2374 		return result;
   2375 	}
   2376 
   2377 	result = configure_rpz_name2(view, rpz_obj, &zone->ip, DNS_RPZ_IP_ZONE,
   2378 				     &zone->origin);
   2379 	if (result != ISC_R_SUCCESS) {
   2380 		return result;
   2381 	}
   2382 
   2383 	result = configure_rpz_name2(view, rpz_obj, &zone->nsdname,
   2384 				     DNS_RPZ_NSDNAME_ZONE, &zone->origin);
   2385 	if (result != ISC_R_SUCCESS) {
   2386 		return result;
   2387 	}
   2388 
   2389 	result = configure_rpz_name2(view, rpz_obj, &zone->nsip,
   2390 				     DNS_RPZ_NSIP_ZONE, &zone->origin);
   2391 	if (result != ISC_R_SUCCESS) {
   2392 		return result;
   2393 	}
   2394 
   2395 	result = configure_rpz_name(view, rpz_obj, &zone->passthru,
   2396 				    DNS_RPZ_PASSTHRU_NAME, "name");
   2397 	if (result != ISC_R_SUCCESS) {
   2398 		return result;
   2399 	}
   2400 
   2401 	result = configure_rpz_name(view, rpz_obj, &zone->drop,
   2402 				    DNS_RPZ_DROP_NAME, "name");
   2403 	if (result != ISC_R_SUCCESS) {
   2404 		return result;
   2405 	}
   2406 
   2407 	result = configure_rpz_name(view, rpz_obj, &zone->tcp_only,
   2408 				    DNS_RPZ_TCP_ONLY_NAME, "name");
   2409 	if (result != ISC_R_SUCCESS) {
   2410 		return result;
   2411 	}
   2412 
   2413 	obj = cfg_tuple_get(rpz_obj, "policy");
   2414 	if (cfg_obj_isvoid(obj)) {
   2415 		zone->policy = DNS_RPZ_POLICY_GIVEN;
   2416 	} else {
   2417 		str = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
   2418 		zone->policy = dns_rpz_str2policy(str);
   2419 		INSIST(zone->policy != DNS_RPZ_POLICY_ERROR);
   2420 		if (zone->policy == DNS_RPZ_POLICY_CNAME) {
   2421 			str = cfg_obj_asstring(cfg_tuple_get(obj, "cname"));
   2422 			result = configure_rpz_name(view, rpz_obj, &zone->cname,
   2423 						    str, "cname");
   2424 			if (result != ISC_R_SUCCESS) {
   2425 				return result;
   2426 			}
   2427 		}
   2428 	}
   2429 	if (*old_rpz_okp && (zone->policy != old->policy ||
   2430 			     !dns_name_equal(&old->cname, &zone->cname)))
   2431 	{
   2432 		*old_rpz_okp = false;
   2433 	}
   2434 
   2435 	obj = cfg_tuple_get(rpz_obj, "ede");
   2436 	if (!cfg_obj_isstring(obj)) {
   2437 		zone->ede = 0;
   2438 	} else {
   2439 		str = cfg_obj_asstring(obj);
   2440 		zone->ede = dns_rpz_str2ede(str);
   2441 		INSIST(zone->ede != UINT16_MAX);
   2442 	}
   2443 	if (*old_rpz_okp && zone->ede != old->ede) {
   2444 		*old_rpz_okp = false;
   2445 	}
   2446 
   2447 	obj = cfg_tuple_get(rpz_obj, "add-soa");
   2448 	if (cfg_obj_isvoid(obj)) {
   2449 		zone->addsoa = add_soa_default;
   2450 	} else {
   2451 		zone->addsoa = cfg_obj_asboolean(obj);
   2452 	}
   2453 	if (*old_rpz_okp && zone->addsoa != old->addsoa) {
   2454 		*old_rpz_okp = false;
   2455 	}
   2456 
   2457 	return ISC_R_SUCCESS;
   2458 }
   2459 
   2460 static isc_result_t
   2461 configure_rpz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t **maps,
   2462 	      const cfg_obj_t *rpz_obj, bool *old_rpz_okp, bool first_time) {
   2463 	bool dnsrps_enabled;
   2464 	const cfg_listelt_t *zone_element;
   2465 	char *rps_cstr;
   2466 	size_t rps_cstr_size;
   2467 	const cfg_obj_t *sub_obj;
   2468 	bool recursive_only_default, add_soa_default;
   2469 	bool nsip_enabled, nsdname_enabled;
   2470 	dns_rpz_zbits_t nsip_on, nsdname_on;
   2471 	dns_ttl_t ttl_default;
   2472 	uint32_t minupdateinterval_default;
   2473 	dns_rpz_zones_t *zones;
   2474 	const dns_rpz_zones_t *old;
   2475 	bool pview_must_detach = false;
   2476 	const dns_rpz_zone_t *old_zone;
   2477 	isc_result_t result;
   2478 	int i;
   2479 
   2480 	*old_rpz_okp = false;
   2481 
   2482 	zone_element = cfg_list_first(cfg_tuple_get(rpz_obj, "zone list"));
   2483 	if (zone_element == NULL) {
   2484 		return ISC_R_SUCCESS;
   2485 	}
   2486 
   2487 	nsip_enabled = true;
   2488 	sub_obj = cfg_tuple_get(rpz_obj, "nsip-enable");
   2489 	if (!cfg_obj_isvoid(sub_obj)) {
   2490 		nsip_enabled = cfg_obj_asboolean(sub_obj);
   2491 	}
   2492 	nsip_on = nsip_enabled ? DNS_RPZ_ALL_ZBITS : 0;
   2493 
   2494 	nsdname_enabled = true;
   2495 	sub_obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
   2496 	if (!cfg_obj_isvoid(sub_obj)) {
   2497 		nsdname_enabled = cfg_obj_asboolean(sub_obj);
   2498 	}
   2499 	nsdname_on = nsdname_enabled ? DNS_RPZ_ALL_ZBITS : 0;
   2500 
   2501 	/*
   2502 	 * "dnsrps-enable yes|no" can be either a global or response-policy
   2503 	 * clause.
   2504 	 */
   2505 	dnsrps_enabled = false;
   2506 	rps_cstr = NULL;
   2507 	rps_cstr_size = 0;
   2508 	sub_obj = NULL;
   2509 	(void)named_config_get(maps, "dnsrps-enable", &sub_obj);
   2510 	if (sub_obj != NULL) {
   2511 		dnsrps_enabled = cfg_obj_asboolean(sub_obj);
   2512 	}
   2513 	sub_obj = cfg_tuple_get(rpz_obj, "dnsrps-enable");
   2514 	if (!cfg_obj_isvoid(sub_obj)) {
   2515 		dnsrps_enabled = cfg_obj_asboolean(sub_obj);
   2516 	}
   2517 #ifndef USE_DNSRPS
   2518 	if (dnsrps_enabled) {
   2519 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
   2520 			    "\"dnsrps-enable yes\" but"
   2521 			    " without `./configure --enable-dnsrps`");
   2522 		return ISC_R_FAILURE;
   2523 	}
   2524 #else  /* ifndef USE_DNSRPS */
   2525 	if (dnsrps_enabled) {
   2526 		if (librpz == NULL) {
   2527 			cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
   2528 				    "\"dnsrps-enable yes\" but %s",
   2529 				    librpz_lib_open_emsg.c);
   2530 			return ISC_R_FAILURE;
   2531 		}
   2532 
   2533 		/*
   2534 		 * Generate the DNS Response Policy Service
   2535 		 * configuration string.
   2536 		 */
   2537 		result = conf_dnsrps(view, maps, nsip_enabled, nsdname_enabled,
   2538 				     &nsip_on, &nsdname_on, &rps_cstr,
   2539 				     &rps_cstr_size, rpz_obj, zone_element);
   2540 		if (result != ISC_R_SUCCESS) {
   2541 			return result;
   2542 		}
   2543 	}
   2544 #endif /* ifndef USE_DNSRPS */
   2545 
   2546 	result = dns_rpz_new_zones(view, named_g_loopmgr, rps_cstr,
   2547 				   rps_cstr_size, &view->rpzs, first_time);
   2548 	if (result != ISC_R_SUCCESS) {
   2549 		return result;
   2550 	}
   2551 
   2552 	zones = view->rpzs;
   2553 
   2554 	zones->p.nsip_on = nsip_on;
   2555 	zones->p.nsdname_on = nsdname_on;
   2556 	zones->p.slow_mode = ns_server_getoption(named_g_server->sctx,
   2557 						 NS_SERVER_RPZSLOW);
   2558 
   2559 	sub_obj = cfg_tuple_get(rpz_obj, "recursive-only");
   2560 	if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
   2561 		recursive_only_default = false;
   2562 	} else {
   2563 		recursive_only_default = true;
   2564 	}
   2565 
   2566 	sub_obj = cfg_tuple_get(rpz_obj, "add-soa");
   2567 	if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
   2568 		add_soa_default = false;
   2569 	} else {
   2570 		add_soa_default = true;
   2571 	}
   2572 
   2573 	sub_obj = cfg_tuple_get(rpz_obj, "break-dnssec");
   2574 	if (!cfg_obj_isvoid(sub_obj) && cfg_obj_asboolean(sub_obj)) {
   2575 		zones->p.break_dnssec = true;
   2576 	} else {
   2577 		zones->p.break_dnssec = false;
   2578 	}
   2579 
   2580 	sub_obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
   2581 	if (cfg_obj_isduration(sub_obj)) {
   2582 		ttl_default = cfg_obj_asduration(sub_obj);
   2583 	} else {
   2584 		ttl_default = DNS_RPZ_MAX_TTL_DEFAULT;
   2585 	}
   2586 
   2587 	sub_obj = cfg_tuple_get(rpz_obj, "min-update-interval");
   2588 	if (cfg_obj_isduration(sub_obj)) {
   2589 		minupdateinterval_default = cfg_obj_asduration(sub_obj);
   2590 	} else {
   2591 		minupdateinterval_default = DNS_RPZ_MINUPDATEINTERVAL_DEFAULT;
   2592 	}
   2593 
   2594 	sub_obj = cfg_tuple_get(rpz_obj, "min-ns-dots");
   2595 	if (cfg_obj_isuint32(sub_obj)) {
   2596 		zones->p.min_ns_labels = cfg_obj_asuint32(sub_obj) + 1;
   2597 	} else {
   2598 		zones->p.min_ns_labels = 2;
   2599 	}
   2600 
   2601 	sub_obj = cfg_tuple_get(rpz_obj, "qname-wait-recurse");
   2602 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
   2603 		zones->p.qname_wait_recurse = true;
   2604 	} else {
   2605 		zones->p.qname_wait_recurse = false;
   2606 	}
   2607 
   2608 	sub_obj = cfg_tuple_get(rpz_obj, "nsdname-wait-recurse");
   2609 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
   2610 		zones->p.nsdname_wait_recurse = true;
   2611 	} else {
   2612 		zones->p.nsdname_wait_recurse = false;
   2613 	}
   2614 
   2615 	sub_obj = cfg_tuple_get(rpz_obj, "nsip-wait-recurse");
   2616 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
   2617 		zones->p.nsip_wait_recurse = true;
   2618 	} else {
   2619 		zones->p.nsip_wait_recurse = false;
   2620 	}
   2621 
   2622 	sub_obj = cfg_tuple_get(rpz_obj, "servfail-until-ready");
   2623 	if (!cfg_obj_isvoid(sub_obj) && cfg_obj_asboolean(sub_obj)) {
   2624 		zones->p.servfail_until_ready = true;
   2625 	} else {
   2626 		zones->p.servfail_until_ready = false;
   2627 	}
   2628 
   2629 	if (dnsrps_enabled && zones->p.servfail_until_ready) {
   2630 		zones->p.servfail_until_ready = false;
   2631 		cfg_obj_log(rpz_obj, named_g_lctx, ISC_LOG_WARNING,
   2632 			    "\"servfail-until-ready yes\" has no effect when "
   2633 			    "used with \"dnsrps-enable yes\"");
   2634 	}
   2635 
   2636 	if (pview != NULL) {
   2637 		old = pview->rpzs;
   2638 	} else {
   2639 		result = dns_viewlist_find(&named_g_server->viewlist,
   2640 					   view->name, view->rdclass, &pview);
   2641 		if (result == ISC_R_SUCCESS) {
   2642 			pview_must_detach = true;
   2643 			old = pview->rpzs;
   2644 		} else {
   2645 			old = NULL;
   2646 		}
   2647 	}
   2648 
   2649 	if (old == NULL) {
   2650 		*old_rpz_okp = false;
   2651 	} else {
   2652 		*old_rpz_okp = true;
   2653 	}
   2654 
   2655 	for (i = 0; zone_element != NULL;
   2656 	     ++i, zone_element = cfg_list_next(zone_element))
   2657 	{
   2658 		INSIST(!*old_rpz_okp || old != NULL);
   2659 		if (*old_rpz_okp && i < old->p.num_zones) {
   2660 			old_zone = old->zones[i];
   2661 		} else {
   2662 			*old_rpz_okp = false;
   2663 			old_zone = NULL;
   2664 		}
   2665 		result = configure_rpz_zone(
   2666 			view, zone_element, recursive_only_default,
   2667 			add_soa_default, ttl_default, minupdateinterval_default,
   2668 			old_zone, old_rpz_okp);
   2669 		if (result != ISC_R_SUCCESS) {
   2670 			if (pview_must_detach) {
   2671 				dns_view_detach(&pview);
   2672 			}
   2673 			return result;
   2674 		}
   2675 	}
   2676 
   2677 	/*
   2678 	 * If this is a reloading and the parameters and list of policy
   2679 	 * zones are unchanged, then use the same policy data.
   2680 	 * Data for individual zones that must be reloaded will be merged.
   2681 	 */
   2682 	if (*old_rpz_okp) {
   2683 		if (old != NULL &&
   2684 		    memcmp(&old->p, &zones->p, sizeof(zones->p)) != 0)
   2685 		{
   2686 			*old_rpz_okp = false;
   2687 		} else if ((old == NULL || old->rps_cstr == NULL) !=
   2688 			   (zones->rps_cstr == NULL))
   2689 		{
   2690 			*old_rpz_okp = false;
   2691 		} else if (old != NULL && zones->rps_cstr != NULL &&
   2692 			   strcmp(old->rps_cstr, zones->rps_cstr) != 0)
   2693 		{
   2694 			*old_rpz_okp = false;
   2695 		}
   2696 	}
   2697 
   2698 	if (*old_rpz_okp) {
   2699 		INSIST(pview->rpzs != NULL);
   2700 
   2701 		/* Discard the newly created rpzs. */
   2702 		dns_rpz_zones_shutdown(view->rpzs);
   2703 		dns_rpz_zones_detach(&view->rpzs);
   2704 
   2705 		/*
   2706 		 * We are reusing the old rpzs, so it can no longer be its
   2707 		 * first time.
   2708 		 */
   2709 		pview->rpzs->first_time = false;
   2710 
   2711 		/* Reuse rpzs from the old view. */
   2712 		dns_rpz_zones_attach(pview->rpzs, &view->rpzs);
   2713 		dns_rpz_zones_detach(&pview->rpzs);
   2714 	} else if (old != NULL && pview != NULL) {
   2715 		INSIST(pview->rpzs != NULL);
   2716 
   2717 		++pview->rpzs->rpz_ver;
   2718 		view->rpzs->rpz_ver = pview->rpzs->rpz_ver;
   2719 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_DEBUG_LEVEL1,
   2720 			    "updated RPZ policy: version %d",
   2721 			    view->rpzs->rpz_ver);
   2722 	}
   2723 
   2724 	if (pview_must_detach) {
   2725 		dns_view_detach(&pview);
   2726 	}
   2727 
   2728 	return ISC_R_SUCCESS;
   2729 }
   2730 
   2731 static void
   2732 catz_addmodzone_cb(void *arg) {
   2733 	catz_chgzone_t *cz = (catz_chgzone_t *)arg;
   2734 	isc_result_t result;
   2735 	dns_forwarders_t *dnsforwarders = NULL;
   2736 	dns_name_t *name = NULL;
   2737 	isc_buffer_t namebuf;
   2738 	isc_buffer_t *confbuf = NULL;
   2739 	char nameb[DNS_NAME_FORMATSIZE];
   2740 	const cfg_obj_t *zlist = NULL;
   2741 	cfg_obj_t *zoneconf = NULL;
   2742 	cfg_obj_t *zoneobj = NULL;
   2743 	ns_cfgctx_t *cfg = NULL;
   2744 	dns_zone_t *zone = NULL;
   2745 
   2746 	if (isc_loop_shuttingdown(isc_loop_get(named_g_loopmgr, isc_tid()))) {
   2747 		goto cleanup;
   2748 	}
   2749 
   2750 	/*
   2751 	 * A non-empty 'catalog-zones' statement implies that 'allow-new-zones'
   2752 	 * is true, so this is expected to be non-NULL.
   2753 	 */
   2754 	cfg = (ns_cfgctx_t *)cz->view->new_zone_config;
   2755 	if (cfg == NULL) {
   2756 		CHECK(ISC_R_FAILURE);
   2757 	}
   2758 
   2759 	name = dns_catz_entry_getname(cz->entry);
   2760 
   2761 	isc_buffer_init(&namebuf, nameb, DNS_NAME_FORMATSIZE);
   2762 	dns_name_totext(name, DNS_NAME_OMITFINALDOT, &namebuf);
   2763 	isc_buffer_putuint8(&namebuf, 0);
   2764 
   2765 	result = dns_fwdtable_find(cz->view->fwdtable, name, &dnsforwarders);
   2766 	if (result == ISC_R_SUCCESS &&
   2767 	    dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
   2768 	{
   2769 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2770 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2771 			      "catz: catz_addmodzone_cb: "
   2772 			      "zone '%s' will not be processed because of the "
   2773 			      "explicitly configured forwarding for that zone",
   2774 			      nameb);
   2775 		goto cleanup;
   2776 	}
   2777 
   2778 	result = dns_view_findzone(cz->view, name, DNS_ZTFIND_EXACT, &zone);
   2779 
   2780 	if (cz->mod) {
   2781 		dns_catz_zone_t *parentcatz;
   2782 
   2783 		if (result != ISC_R_SUCCESS) {
   2784 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2785 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2786 				      "catz: error \"%s\" while trying to "
   2787 				      "modify zone '%s'",
   2788 				      isc_result_totext(result), nameb);
   2789 			goto cleanup;
   2790 		}
   2791 
   2792 		if (!dns_zone_getadded(zone)) {
   2793 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2794 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2795 				      "catz: catz_addmodzone_cb: "
   2796 				      "zone '%s' is not a dynamically "
   2797 				      "added zone",
   2798 				      nameb);
   2799 			goto cleanup;
   2800 		}
   2801 
   2802 		parentcatz = dns_zone_get_parentcatz(zone);
   2803 
   2804 		if (parentcatz == NULL) {
   2805 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2806 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2807 				      "catz: catz_addmodzone_cb: "
   2808 				      "zone '%s' exists and is not added by "
   2809 				      "a catalog zone, so won't be modified",
   2810 				      nameb);
   2811 			goto cleanup;
   2812 		}
   2813 		if (parentcatz != cz->origin) {
   2814 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2815 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2816 				      "catz: catz_addmodzone_cb: "
   2817 				      "zone '%s' exists in multiple "
   2818 				      "catalog zones",
   2819 				      nameb);
   2820 			goto cleanup;
   2821 		}
   2822 
   2823 		dns_zone_detach(&zone);
   2824 	} else {
   2825 		/* Zone shouldn't already exist when adding */
   2826 		if (result == ISC_R_SUCCESS) {
   2827 			if (dns_zone_get_parentcatz(zone) == NULL) {
   2828 				isc_log_write(
   2829 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2830 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2831 					"catz: "
   2832 					"catz_addmodzone_cb: "
   2833 					"zone '%s' will not be added "
   2834 					"because it is an explicitly "
   2835 					"configured zone",
   2836 					nameb);
   2837 			} else {
   2838 				isc_log_write(
   2839 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2840 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2841 					"catz: "
   2842 					"catz_addmodzone_cb: "
   2843 					"zone '%s' will not be added "
   2844 					"because another catalog zone "
   2845 					"already contains an entry with "
   2846 					"that zone",
   2847 					nameb);
   2848 			}
   2849 			goto cleanup;
   2850 		} else {
   2851 			RUNTIME_CHECK(result == ISC_R_NOTFOUND);
   2852 		}
   2853 	}
   2854 	RUNTIME_CHECK(zone == NULL);
   2855 	/* Create a config for new zone */
   2856 	confbuf = NULL;
   2857 	result = dns_catz_generate_zonecfg(cz->origin, cz->entry, &confbuf);
   2858 	if (result == ISC_R_SUCCESS) {
   2859 		cfg_parser_reset(cfg->add_parser);
   2860 		result = cfg_parse_buffer(cfg->add_parser, confbuf, "catz", 0,
   2861 					  &cfg_type_addzoneconf, 0, &zoneconf);
   2862 	}
   2863 	/*
   2864 	 * Fail if either dns_catz_generate_zonecfg() or cfg_parse_buffer()
   2865 	 * failed.
   2866 	 */
   2867 	if (result != ISC_R_SUCCESS) {
   2868 		isc_log_write(
   2869 			named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2870 			NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   2871 			"catz: error \"%s\" while trying to generate "
   2872 			"config for zone '%s'%s%.*s%s",
   2873 			isc_result_totext(result), nameb,
   2874 			confbuf != NULL ? " buffer '" : "",
   2875 			confbuf != NULL ? (int)isc_buffer_usedlength(confbuf)
   2876 					: 0,
   2877 			confbuf != NULL ? (char *)isc_buffer_base(confbuf) : "",
   2878 			confbuf != NULL ? "'" : "");
   2879 		goto cleanup;
   2880 	}
   2881 	isc_buffer_free(&confbuf);
   2882 	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
   2883 	if (!cfg_obj_islist(zlist)) {
   2884 		CHECK(ISC_R_FAILURE);
   2885 	}
   2886 
   2887 	/* For now we only support adding one zone at a time */
   2888 	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
   2889 
   2890 	/* Mark view unfrozen so that zone can be added */
   2891 	isc_loopmgr_pause(named_g_loopmgr);
   2892 	dns_view_thaw(cz->view);
   2893 	result = configure_zone(cfg->config, zoneobj, cfg->vconfig, cz->view,
   2894 				&cz->cbd->server->viewlist,
   2895 				&cz->cbd->server->kasplist,
   2896 				&cz->cbd->server->keystorelist, cfg->actx, true,
   2897 				false, true, cz->mod);
   2898 	dns_view_freeze(cz->view);
   2899 	isc_loopmgr_resume(named_g_loopmgr);
   2900 
   2901 	if (result != ISC_R_SUCCESS) {
   2902 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2903 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2904 			      "catz: failed to configure zone '%s' - %d", nameb,
   2905 			      result);
   2906 		goto cleanup;
   2907 	}
   2908 
   2909 	/* Is it there yet? */
   2910 	CHECK(dns_view_findzone(cz->view, name, DNS_ZTFIND_EXACT, &zone));
   2911 
   2912 	/*
   2913 	 * Load the zone from the master file.	If this fails, we'll
   2914 	 * need to undo the configuration we've done already.
   2915 	 */
   2916 	result = dns_zone_load(zone, true);
   2917 	if (result != ISC_R_SUCCESS) {
   2918 		dns_db_t *dbp = NULL;
   2919 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2920 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   2921 			      "catz: dns_zone_load() failed "
   2922 			      "with %s; reverting.",
   2923 			      isc_result_totext(result));
   2924 
   2925 		/* If the zone loaded partially, unload it */
   2926 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
   2927 			dns_db_detach(&dbp);
   2928 			dns_zone_unload(zone);
   2929 		}
   2930 
   2931 		/* Remove the zone from the zone table */
   2932 		dns_view_delzone(cz->view, zone);
   2933 		goto cleanup;
   2934 	}
   2935 
   2936 	/* Flag the zone as having been added at runtime */
   2937 	dns_zone_setadded(zone, true);
   2938 	dns_zone_set_parentcatz(zone, cz->origin);
   2939 
   2940 cleanup:
   2941 	if (confbuf != NULL) {
   2942 		isc_buffer_free(&confbuf);
   2943 	}
   2944 	if (zone != NULL) {
   2945 		dns_zone_detach(&zone);
   2946 	}
   2947 	if (zoneconf != NULL) {
   2948 		cfg_obj_destroy(cfg->add_parser, &zoneconf);
   2949 	}
   2950 	if (dnsforwarders != NULL) {
   2951 		dns_forwarders_detach(&dnsforwarders);
   2952 	}
   2953 	dns_catz_entry_detach(cz->origin, &cz->entry);
   2954 	dns_catz_zone_detach(&cz->origin);
   2955 	dns_view_weakdetach(&cz->view);
   2956 	isc_mem_putanddetach(&cz->mctx, cz, sizeof(*cz));
   2957 }
   2958 
   2959 static void
   2960 catz_delzone_cb(void *arg) {
   2961 	catz_chgzone_t *cz = (catz_chgzone_t *)arg;
   2962 	isc_result_t result;
   2963 	dns_zone_t *zone = NULL;
   2964 	dns_db_t *dbp = NULL;
   2965 	char cname[DNS_NAME_FORMATSIZE];
   2966 	const char *file = NULL;
   2967 
   2968 	if (isc_loop_shuttingdown(isc_loop_get(named_g_loopmgr, isc_tid()))) {
   2969 		goto cleanup;
   2970 	}
   2971 
   2972 	isc_loopmgr_pause(named_g_loopmgr);
   2973 
   2974 	dns_name_format(dns_catz_entry_getname(cz->entry), cname,
   2975 			DNS_NAME_FORMATSIZE);
   2976 	result = dns_view_findzone(cz->view, dns_catz_entry_getname(cz->entry),
   2977 				   DNS_ZTFIND_EXACT, &zone);
   2978 	if (result != ISC_R_SUCCESS) {
   2979 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2980 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2981 			      "catz: catz_delzone_cb: "
   2982 			      "zone '%s' not found",
   2983 			      cname);
   2984 		goto resume;
   2985 	}
   2986 
   2987 	if (!dns_zone_getadded(zone)) {
   2988 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2989 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2990 			      "catz: catz_delzone_cb: "
   2991 			      "zone '%s' is not a dynamically added zone",
   2992 			      cname);
   2993 		goto resume;
   2994 	}
   2995 
   2996 	if (dns_zone_get_parentcatz(zone) != cz->origin) {
   2997 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2998 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2999 			      "catz: catz_delzone_cb: zone "
   3000 			      "'%s' exists in multiple catalog zones",
   3001 			      cname);
   3002 		goto resume;
   3003 	}
   3004 
   3005 	/* Stop answering for this zone */
   3006 	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
   3007 		dns_db_detach(&dbp);
   3008 		dns_zone_unload(zone);
   3009 	}
   3010 
   3011 	if (dns_view_delzone(cz->view, zone) != ISC_R_SUCCESS) {
   3012 		goto resume;
   3013 	}
   3014 	file = dns_zone_getfile(zone);
   3015 	if (file != NULL) {
   3016 		isc_file_remove(file);
   3017 		file = dns_zone_getjournal(zone);
   3018 		if (file != NULL) {
   3019 			isc_file_remove(file);
   3020 		}
   3021 	}
   3022 
   3023 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   3024 		      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   3025 		      "catz: catz_delzone_cb: "
   3026 		      "zone '%s' deleted",
   3027 		      cname);
   3028 resume:
   3029 	isc_loopmgr_resume(named_g_loopmgr);
   3030 cleanup:
   3031 	if (zone != NULL) {
   3032 		dns_zone_detach(&zone);
   3033 	}
   3034 	dns_catz_entry_detach(cz->origin, &cz->entry);
   3035 	dns_catz_zone_detach(&cz->origin);
   3036 	dns_view_weakdetach(&cz->view);
   3037 	isc_mem_putanddetach(&cz->mctx, cz, sizeof(*cz));
   3038 }
   3039 
   3040 static isc_result_t
   3041 catz_run(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
   3042 	 void *udata, catz_type_t type) {
   3043 	catz_chgzone_t *cz = NULL;
   3044 	isc_job_cb action = NULL;
   3045 
   3046 	switch (type) {
   3047 	case CATZ_ADDZONE:
   3048 	case CATZ_MODZONE:
   3049 		action = catz_addmodzone_cb;
   3050 		break;
   3051 	case CATZ_DELZONE:
   3052 		action = catz_delzone_cb;
   3053 		break;
   3054 	default:
   3055 		REQUIRE(0);
   3056 		UNREACHABLE();
   3057 	}
   3058 
   3059 	cz = isc_mem_get(view->mctx, sizeof(*cz));
   3060 	*cz = (catz_chgzone_t){
   3061 		.cbd = (catz_cb_data_t *)udata,
   3062 		.mod = (type == CATZ_MODZONE),
   3063 	};
   3064 	isc_mem_attach(view->mctx, &cz->mctx);
   3065 
   3066 	dns_catz_entry_attach(entry, &cz->entry);
   3067 	dns_catz_zone_attach(origin, &cz->origin);
   3068 	dns_view_weakattach(view, &cz->view);
   3069 
   3070 	isc_async_run(named_g_mainloop, action, cz);
   3071 
   3072 	return ISC_R_SUCCESS;
   3073 }
   3074 
   3075 static isc_result_t
   3076 catz_addzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
   3077 	     void *udata) {
   3078 	return catz_run(entry, origin, view, udata, CATZ_ADDZONE);
   3079 }
   3080 
   3081 static isc_result_t
   3082 catz_delzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
   3083 	     void *udata) {
   3084 	return catz_run(entry, origin, view, udata, CATZ_DELZONE);
   3085 }
   3086 
   3087 static isc_result_t
   3088 catz_modzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
   3089 	     void *udata) {
   3090 	return catz_run(entry, origin, view, udata, CATZ_MODZONE);
   3091 }
   3092 
   3093 static void
   3094 catz_changeview(dns_catz_entry_t *entry, void *arg1, void *arg2) {
   3095 	dns_view_t *pview = arg1;
   3096 	dns_view_t *view = arg2;
   3097 
   3098 	dns_zone_t *zone = NULL;
   3099 	isc_result_t result = dns_view_findzone(
   3100 		pview, dns_catz_entry_getname(entry), DNS_ZTFIND_EXACT, &zone);
   3101 
   3102 	if (result != ISC_R_SUCCESS) {
   3103 		return;
   3104 	}
   3105 
   3106 	dns_zone_setview(zone, view);
   3107 	dns_view_addzone(view, zone);
   3108 
   3109 	dns_zone_detach(&zone);
   3110 }
   3111 
   3112 static void
   3113 catz_reconfigure(dns_catz_entry_t *entry, void *arg1, void *arg2) {
   3114 	dns_view_t *view = arg1;
   3115 	catz_reconfig_data_t *data = arg2;
   3116 	isc_buffer_t namebuf;
   3117 	isc_buffer_t *confbuf = NULL;
   3118 	const cfg_obj_t *zlist = NULL;
   3119 	char nameb[DNS_NAME_FORMATSIZE];
   3120 	cfg_obj_t *zoneconf = NULL;
   3121 	cfg_obj_t *zoneobj = NULL;
   3122 	ns_cfgctx_t *cfg = NULL;
   3123 	dns_zone_t *zone = NULL;
   3124 	isc_result_t result;
   3125 
   3126 	isc_buffer_init(&namebuf, nameb, DNS_NAME_FORMATSIZE);
   3127 	dns_name_totext(dns_catz_entry_getname(entry), DNS_NAME_OMITFINALDOT,
   3128 			&namebuf);
   3129 	isc_buffer_putuint8(&namebuf, 0);
   3130 
   3131 	result = dns_view_findzone(view, dns_catz_entry_getname(entry),
   3132 				   DNS_ZTFIND_EXACT, &zone);
   3133 	if (result != ISC_R_SUCCESS) {
   3134 		return;
   3135 	}
   3136 
   3137 	/*
   3138 	 * A non-empty 'catalog-zones' statement implies that 'allow-new-zones'
   3139 	 * is true, so this is expected to be non-NULL.
   3140 	 */
   3141 	cfg = (ns_cfgctx_t *)view->new_zone_config;
   3142 	if (cfg == NULL) {
   3143 		CHECK(ISC_R_FAILURE);
   3144 	}
   3145 
   3146 	result = dns_catz_generate_zonecfg(data->catz, entry, &confbuf);
   3147 	if (result == ISC_R_SUCCESS) {
   3148 		cfg_parser_reset(cfg->add_parser);
   3149 		result = cfg_parse_buffer(cfg->add_parser, confbuf, "catz", 0,
   3150 					  &cfg_type_addzoneconf, 0, &zoneconf);
   3151 		isc_buffer_free(&confbuf);
   3152 	}
   3153 	/*
   3154 	 * Fail if either dns_catz_generate_zonecfg() or cfg_parse_buffer()
   3155 	 * failed.
   3156 	 */
   3157 	if (result != ISC_R_SUCCESS) {
   3158 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   3159 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   3160 			      "catz_reconfigure: error \"%s\" while trying to "
   3161 			      "generate config for member zone '%s'",
   3162 			      isc_result_totext(result), nameb);
   3163 		goto cleanup;
   3164 	}
   3165 
   3166 	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
   3167 	if (!cfg_obj_islist(zlist)) {
   3168 		CHECK(ISC_R_FAILURE);
   3169 	}
   3170 	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
   3171 
   3172 	result = configure_zone(data->config, zoneobj, cfg->vconfig, view,
   3173 				&data->cbd->server->viewlist,
   3174 				&data->cbd->server->kasplist,
   3175 				&data->cbd->server->keystorelist, cfg->actx,
   3176 				true, false, true, true);
   3177 	if (result != ISC_R_SUCCESS) {
   3178 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   3179 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   3180 			      "catz_reconfigure : error \"%s\" while trying to "
   3181 			      "reconfigure member zone '%s'",
   3182 			      isc_result_totext(result), nameb);
   3183 		goto cleanup;
   3184 	}
   3185 
   3186 cleanup:
   3187 	if (zoneconf != NULL) {
   3188 		cfg_obj_destroy(cfg->add_parser, &zoneconf);
   3189 	}
   3190 
   3191 	dns_zone_detach(&zone);
   3192 }
   3193 
   3194 static isc_result_t
   3195 configure_catz_zone(dns_view_t *view, dns_view_t *pview,
   3196 		    const cfg_obj_t *config, const cfg_listelt_t *element) {
   3197 	const cfg_obj_t *catz_obj, *obj;
   3198 	dns_catz_zone_t *zone = NULL;
   3199 	const char *str;
   3200 	isc_result_t result;
   3201 	dns_name_t origin;
   3202 	dns_ipkeylist_t ipkl;
   3203 	dns_catz_options_t *opts;
   3204 
   3205 	dns_name_init(&origin, NULL);
   3206 	dns_ipkeylist_init(&ipkl);
   3207 	catz_obj = cfg_listelt_value(element);
   3208 
   3209 	str = cfg_obj_asstring(cfg_tuple_get(catz_obj, "zone name"));
   3210 
   3211 	result = dns_name_fromstring(&origin, str, dns_rootname,
   3212 				     DNS_NAME_DOWNCASE, view->mctx);
   3213 	if (result == ISC_R_SUCCESS && dns_name_equal(&origin, dns_rootname)) {
   3214 		result = DNS_R_EMPTYLABEL;
   3215 	}
   3216 
   3217 	if (result != ISC_R_SUCCESS) {
   3218 		cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
   3219 			    "catz: invalid zone name '%s'", str);
   3220 		goto cleanup;
   3221 	}
   3222 
   3223 	obj = cfg_tuple_get(catz_obj, "default-masters");
   3224 	if (obj == NULL || !cfg_obj_istuple(obj)) {
   3225 		obj = cfg_tuple_get(catz_obj, "default-primaries");
   3226 	}
   3227 	if (obj != NULL && cfg_obj_istuple(obj)) {
   3228 		result = named_config_getipandkeylist(config, obj, view->mctx,
   3229 						      &ipkl);
   3230 		if (result != ISC_R_SUCCESS) {
   3231 			cfg_obj_log(catz_obj, named_g_lctx,
   3232 				    DNS_CATZ_ERROR_LEVEL,
   3233 				    "catz: default-primaries parse error: %s",
   3234 				    isc_result_totext(result));
   3235 			goto cleanup;
   3236 		}
   3237 	}
   3238 
   3239 	result = dns_catz_zone_add(view->catzs, &origin, &zone);
   3240 	if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
   3241 		cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
   3242 			    "catz: dns_catz_zone_add failed: %s",
   3243 			    isc_result_totext(result));
   3244 		goto cleanup;
   3245 	}
   3246 
   3247 	dns_catz_zone_prereconfig(zone);
   3248 
   3249 	if (result == ISC_R_EXISTS) {
   3250 		catz_reconfig_data_t data = {
   3251 			.catz = zone,
   3252 			.config = config,
   3253 			.cbd = (catz_cb_data_t *)dns_catz_zones_get_udata(
   3254 				view->catzs),
   3255 		};
   3256 
   3257 		/*
   3258 		 * We have to walk through all the member zones, re-attach
   3259 		 * them to the current view and reconfigure
   3260 		 */
   3261 		dns_catz_zone_for_each_entry2(zone, catz_changeview, pview,
   3262 					      view);
   3263 		dns_catz_zone_for_each_entry2(zone, catz_reconfigure, view,
   3264 					      &data);
   3265 
   3266 		result = ISC_R_SUCCESS;
   3267 	}
   3268 
   3269 	dns_catz_zone_resetdefoptions(zone);
   3270 	opts = dns_catz_zone_getdefoptions(zone);
   3271 	if (ipkl.count != 0) {
   3272 		/*
   3273 		 * Transfer the ownership of the pointers inside 'ipkl' and
   3274 		 * set its count to 0 in order to not cleanup it later below.
   3275 		 */
   3276 		opts->masters = ipkl;
   3277 		ipkl.count = 0;
   3278 	}
   3279 
   3280 	obj = cfg_tuple_get(catz_obj, "in-memory");
   3281 	if (obj != NULL && cfg_obj_isboolean(obj)) {
   3282 		opts->in_memory = cfg_obj_asboolean(obj);
   3283 	}
   3284 
   3285 	obj = cfg_tuple_get(catz_obj, "zone-directory");
   3286 	if (!opts->in_memory && obj != NULL && cfg_obj_isstring(obj)) {
   3287 		opts->zonedir = isc_mem_strdup(view->mctx,
   3288 					       cfg_obj_asstring(obj));
   3289 		if (isc_file_isdirectory(opts->zonedir) != ISC_R_SUCCESS) {
   3290 			cfg_obj_log(obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
   3291 				    "catz: zone-directory '%s' "
   3292 				    "not found; zone files will not be "
   3293 				    "saved",
   3294 				    opts->zonedir);
   3295 			opts->in_memory = true;
   3296 		}
   3297 	}
   3298 
   3299 	obj = cfg_tuple_get(catz_obj, "min-update-interval");
   3300 	if (obj != NULL && cfg_obj_isduration(obj)) {
   3301 		opts->min_update_interval = cfg_obj_asduration(obj);
   3302 	}
   3303 
   3304 	dns_catz_zone_postreconfig(zone);
   3305 
   3306 cleanup:
   3307 	dns_name_free(&origin, view->mctx);
   3308 	if (ipkl.count != 0) {
   3309 		dns_ipkeylist_clear(view->mctx, &ipkl);
   3310 	}
   3311 
   3312 	return result;
   3313 }
   3314 
   3315 static catz_cb_data_t ns_catz_cbdata;
   3316 static dns_catz_zonemodmethods_t ns_catz_zonemodmethods = {
   3317 	catz_addzone, catz_modzone, catz_delzone, &ns_catz_cbdata
   3318 };
   3319 
   3320 static isc_result_t
   3321 configure_catz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t *config,
   3322 	       const cfg_obj_t *catz_obj) {
   3323 	const cfg_listelt_t *zone_element = NULL;
   3324 	const dns_catz_zones_t *old = NULL;
   3325 	bool pview_must_detach = false;
   3326 	isc_result_t result;
   3327 
   3328 	/* xxxwpk TODO do it cleaner, once, somewhere */
   3329 	ns_catz_cbdata.server = named_g_server;
   3330 
   3331 	zone_element = cfg_list_first(cfg_tuple_get(catz_obj, "zone list"));
   3332 	if (zone_element == NULL) {
   3333 		return ISC_R_SUCCESS;
   3334 	}
   3335 
   3336 	if (pview != NULL) {
   3337 		old = pview->catzs;
   3338 	} else {
   3339 		result = dns_viewlist_find(&named_g_server->viewlist,
   3340 					   view->name, view->rdclass, &pview);
   3341 		if (result == ISC_R_SUCCESS) {
   3342 			pview_must_detach = true;
   3343 			old = pview->catzs;
   3344 		}
   3345 	}
   3346 
   3347 	if (old != NULL) {
   3348 		dns_catz_zones_attach(pview->catzs, &view->catzs);
   3349 		dns_catz_zones_detach(&pview->catzs);
   3350 		dns_catz_prereconfig(view->catzs);
   3351 	} else {
   3352 		view->catzs = dns_catz_zones_new(view->mctx, named_g_loopmgr,
   3353 						 &ns_catz_zonemodmethods);
   3354 	}
   3355 
   3356 	while (zone_element != NULL) {
   3357 		CHECK(configure_catz_zone(view, pview, config, zone_element));
   3358 		zone_element = cfg_list_next(zone_element);
   3359 	}
   3360 
   3361 	if (old != NULL) {
   3362 		dns_catz_postreconfig(view->catzs);
   3363 	}
   3364 
   3365 	result = ISC_R_SUCCESS;
   3366 
   3367 cleanup:
   3368 	if (pview_must_detach) {
   3369 		dns_view_detach(&pview);
   3370 	}
   3371 
   3372 	return result;
   3373 }
   3374 
   3375 #define CHECK_RRL(cond, pat, val1, val2)                                   \
   3376 	do {                                                               \
   3377 		if (!(cond)) {                                             \
   3378 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, pat, \
   3379 				    val1, val2);                           \
   3380 			result = ISC_R_RANGE;                              \
   3381 			goto cleanup;                                      \
   3382 		}                                                          \
   3383 	} while (0)
   3384 
   3385 #define CHECK_RRL_RATE(rate, def, max_rate, name)                           \
   3386 	do {                                                                \
   3387 		obj = NULL;                                                 \
   3388 		rrl->rate.str = name;                                       \
   3389 		result = cfg_map_get(map, name, &obj);                      \
   3390 		if (result == ISC_R_SUCCESS) {                              \
   3391 			rrl->rate.r = cfg_obj_asuint32(obj);                \
   3392 			CHECK_RRL(rrl->rate.r <= max_rate, name " %d > %d", \
   3393 				  rrl->rate.r, max_rate);                   \
   3394 		} else {                                                    \
   3395 			rrl->rate.r = def;                                  \
   3396 		}                                                           \
   3397 		rrl->rate.scaled = rrl->rate.r;                             \
   3398 	} while (0)
   3399 
   3400 static isc_result_t
   3401 configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
   3402 	const cfg_obj_t *obj;
   3403 	dns_rrl_t *rrl;
   3404 	isc_result_t result;
   3405 	int min_entries, i, j;
   3406 
   3407 	/*
   3408 	 * Most DNS servers have few clients, but intentinally open
   3409 	 * recursive and authoritative servers often have many.
   3410 	 * So start with a small number of entries unless told otherwise
   3411 	 * to reduce cold-start costs.
   3412 	 */
   3413 	min_entries = 500;
   3414 	obj = NULL;
   3415 	result = cfg_map_get(map, "min-table-size", &obj);
   3416 	if (result == ISC_R_SUCCESS) {
   3417 		min_entries = cfg_obj_asuint32(obj);
   3418 		if (min_entries < 1) {
   3419 			min_entries = 1;
   3420 		}
   3421 	}
   3422 	result = dns_rrl_init(&rrl, view, min_entries);
   3423 	if (result != ISC_R_SUCCESS) {
   3424 		return result;
   3425 	}
   3426 
   3427 	i = ISC_MAX(20000, min_entries);
   3428 	obj = NULL;
   3429 	result = cfg_map_get(map, "max-table-size", &obj);
   3430 	if (result == ISC_R_SUCCESS) {
   3431 		i = cfg_obj_asuint32(obj);
   3432 		CHECK_RRL(i >= min_entries,
   3433 			  "max-table-size %d < min-table-size %d", i,
   3434 			  min_entries);
   3435 	}
   3436 	rrl->max_entries = i;
   3437 
   3438 	CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE,
   3439 		       "responses-per-second");
   3440 	CHECK_RRL_RATE(referrals_per_second, rrl->responses_per_second.r,
   3441 		       DNS_RRL_MAX_RATE, "referrals-per-second");
   3442 	CHECK_RRL_RATE(nodata_per_second, rrl->responses_per_second.r,
   3443 		       DNS_RRL_MAX_RATE, "nodata-per-second");
   3444 	CHECK_RRL_RATE(nxdomains_per_second, rrl->responses_per_second.r,
   3445 		       DNS_RRL_MAX_RATE, "nxdomains-per-second");
   3446 	CHECK_RRL_RATE(errors_per_second, rrl->responses_per_second.r,
   3447 		       DNS_RRL_MAX_RATE, "errors-per-second");
   3448 
   3449 	CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE, "all-per-second");
   3450 
   3451 	CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP, "slip");
   3452 
   3453 	i = 15;
   3454 	obj = NULL;
   3455 	result = cfg_map_get(map, "window", &obj);
   3456 	if (result == ISC_R_SUCCESS) {
   3457 		i = cfg_obj_asuint32(obj);
   3458 		CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW,
   3459 			  "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW);
   3460 	}
   3461 	rrl->window = i;
   3462 
   3463 	i = 0;
   3464 	obj = NULL;
   3465 	result = cfg_map_get(map, "qps-scale", &obj);
   3466 	if (result == ISC_R_SUCCESS) {
   3467 		i = cfg_obj_asuint32(obj);
   3468 		CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, "");
   3469 	}
   3470 	rrl->qps_scale = i;
   3471 	rrl->qps = 1.0;
   3472 
   3473 	i = 24;
   3474 	obj = NULL;
   3475 	result = cfg_map_get(map, "ipv4-prefix-length", &obj);
   3476 	if (result == ISC_R_SUCCESS) {
   3477 		i = cfg_obj_asuint32(obj);
   3478 		CHECK_RRL(i >= 8 && i <= 32,
   3479 			  "invalid 'ipv4-prefix-length %d'%s", i, "");
   3480 	}
   3481 	rrl->ipv4_prefixlen = i;
   3482 	if (i == 32) {
   3483 		rrl->ipv4_mask = 0xffffffff;
   3484 	} else {
   3485 		rrl->ipv4_mask = htonl(0xffffffff << (32 - i));
   3486 	}
   3487 
   3488 	i = 56;
   3489 	obj = NULL;
   3490 	result = cfg_map_get(map, "ipv6-prefix-length", &obj);
   3491 	if (result == ISC_R_SUCCESS) {
   3492 		i = cfg_obj_asuint32(obj);
   3493 		CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX,
   3494 			  "ipv6-prefix-length %d < 16 or > %d", i,
   3495 			  DNS_RRL_MAX_PREFIX);
   3496 	}
   3497 	rrl->ipv6_prefixlen = i;
   3498 	for (j = 0; j < 4; ++j) {
   3499 		if (i <= 0) {
   3500 			rrl->ipv6_mask[j] = 0;
   3501 		} else if (i < 32) {
   3502 			rrl->ipv6_mask[j] = htonl(0xffffffff << (32 - i));
   3503 		} else {
   3504 			rrl->ipv6_mask[j] = 0xffffffff;
   3505 		}
   3506 		i -= 32;
   3507 	}
   3508 
   3509 	obj = NULL;
   3510 	result = cfg_map_get(map, "exempt-clients", &obj);
   3511 	if (result == ISC_R_SUCCESS) {
   3512 		result = cfg_acl_fromconfig(obj, config, named_g_lctx,
   3513 					    named_g_aclconfctx, named_g_mctx, 0,
   3514 					    &rrl->exempt);
   3515 		CHECK_RRL(result == ISC_R_SUCCESS, "invalid %s%s",
   3516 			  "address match list", "");
   3517 	}
   3518 
   3519 	obj = NULL;
   3520 	result = cfg_map_get(map, "log-only", &obj);
   3521 	if (result == ISC_R_SUCCESS && cfg_obj_asboolean(obj)) {
   3522 		rrl->log_only = true;
   3523 	} else {
   3524 		rrl->log_only = false;
   3525 	}
   3526 
   3527 	return ISC_R_SUCCESS;
   3528 
   3529 cleanup:
   3530 	dns_rrl_view_destroy(view);
   3531 	return result;
   3532 }
   3533 
   3534 static isc_result_t
   3535 add_soa(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
   3536 	const dns_name_t *origin, const dns_name_t *contact) {
   3537 	dns_dbnode_t *node = NULL;
   3538 	dns_rdata_t rdata = DNS_RDATA_INIT;
   3539 	dns_rdatalist_t rdatalist;
   3540 	dns_rdataset_t rdataset;
   3541 	isc_result_t result;
   3542 	unsigned char buf[DNS_SOA_BUFFERSIZE];
   3543 
   3544 	CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db), 0, 28800,
   3545 				 7200, 604800, 86400, buf, &rdata));
   3546 
   3547 	dns_rdatalist_init(&rdatalist);
   3548 	rdatalist.type = rdata.type;
   3549 	rdatalist.rdclass = rdata.rdclass;
   3550 	rdatalist.ttl = 86400;
   3551 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
   3552 
   3553 	dns_rdataset_init(&rdataset);
   3554 	dns_rdatalist_tordataset(&rdatalist, &rdataset);
   3555 	CHECK(dns_db_findnode(db, name, true, &node));
   3556 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
   3557 
   3558 cleanup:
   3559 	if (node != NULL) {
   3560 		dns_db_detachnode(db, &node);
   3561 	}
   3562 	return result;
   3563 }
   3564 
   3565 static isc_result_t
   3566 add_ns(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
   3567        const dns_name_t *nsname) {
   3568 	dns_dbnode_t *node = NULL;
   3569 	dns_rdata_ns_t ns;
   3570 	dns_rdata_t rdata = DNS_RDATA_INIT;
   3571 	dns_rdatalist_t rdatalist;
   3572 	dns_rdataset_t rdataset;
   3573 	isc_result_t result;
   3574 	isc_buffer_t b;
   3575 	unsigned char buf[DNS_NAME_MAXWIRE];
   3576 
   3577 	isc_buffer_init(&b, buf, sizeof(buf));
   3578 
   3579 	ns.common.rdtype = dns_rdatatype_ns;
   3580 	ns.common.rdclass = dns_db_class(db);
   3581 	ns.mctx = NULL;
   3582 	dns_name_init(&ns.name, NULL);
   3583 	dns_name_clone(nsname, &ns.name);
   3584 	CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns,
   3585 				   &ns, &b));
   3586 
   3587 	dns_rdatalist_init(&rdatalist);
   3588 	rdatalist.type = rdata.type;
   3589 	rdatalist.rdclass = rdata.rdclass;
   3590 	rdatalist.ttl = 86400;
   3591 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
   3592 
   3593 	dns_rdataset_init(&rdataset);
   3594 	dns_rdatalist_tordataset(&rdatalist, &rdataset);
   3595 	CHECK(dns_db_findnode(db, name, true, &node));
   3596 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
   3597 
   3598 cleanup:
   3599 	if (node != NULL) {
   3600 		dns_db_detachnode(db, &node);
   3601 	}
   3602 	return result;
   3603 }
   3604 
   3605 static isc_result_t
   3606 create_empty_zone(dns_zone_t *pzone, dns_name_t *name, dns_view_t *view,
   3607 		  const cfg_obj_t *zonelist, const char **empty_dbtype,
   3608 		  int empty_dbtypec, dns_zonestat_level_t statlevel) {
   3609 	char namebuf[DNS_NAME_FORMATSIZE];
   3610 	const cfg_listelt_t *element;
   3611 	const cfg_obj_t *obj;
   3612 	const cfg_obj_t *zconfig;
   3613 	const cfg_obj_t *zoptions;
   3614 	const char *default_dbtype[4] = { ZONEDB_DEFAULT };
   3615 	const char *sep = ": view ";
   3616 	const char *str;
   3617 	const char *viewname = view->name;
   3618 	dns_db_t *db = NULL;
   3619 	dns_dbversion_t *version = NULL;
   3620 	dns_fixedname_t cfixed;
   3621 	dns_fixedname_t fixed;
   3622 	dns_fixedname_t nsfixed;
   3623 	dns_name_t *contact;
   3624 	dns_name_t *ns;
   3625 	dns_name_t *zname;
   3626 	dns_zone_t *zone = NULL;
   3627 	int default_dbtypec = 1;
   3628 	isc_result_t result;
   3629 	dns_namereln_t namereln;
   3630 	int order;
   3631 	unsigned int nlabels;
   3632 
   3633 	zname = dns_fixedname_initname(&fixed);
   3634 	ns = dns_fixedname_initname(&nsfixed);
   3635 	contact = dns_fixedname_initname(&cfixed);
   3636 
   3637 	/*
   3638 	 * Look for forward "zones" beneath this empty zone and if so
   3639 	 * create a custom db for the empty zone.
   3640 	 */
   3641 	for (element = cfg_list_first(zonelist); element != NULL;
   3642 	     element = cfg_list_next(element))
   3643 	{
   3644 		zconfig = cfg_listelt_value(element);
   3645 		str = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
   3646 		CHECK(dns_name_fromstring(zname, str, dns_rootname, 0, NULL));
   3647 		namereln = dns_name_fullcompare(zname, name, &order, &nlabels);
   3648 		if (namereln != dns_namereln_subdomain) {
   3649 			continue;
   3650 		}
   3651 
   3652 		zoptions = cfg_tuple_get(zconfig, "options");
   3653 
   3654 		obj = NULL;
   3655 		(void)cfg_map_get(zoptions, "type", &obj);
   3656 		if (obj != NULL &&
   3657 		    strcasecmp(cfg_obj_asstring(obj), "forward") == 0)
   3658 		{
   3659 			obj = NULL;
   3660 			(void)cfg_map_get(zoptions, "forward", &obj);
   3661 			if (obj == NULL) {
   3662 				continue;
   3663 			}
   3664 			if (strcasecmp(cfg_obj_asstring(obj), "only") != 0) {
   3665 				continue;
   3666 			}
   3667 		}
   3668 		if (db == NULL) {
   3669 			CHECK(dns_db_create(view->mctx, ZONEDB_DEFAULT, name,
   3670 					    dns_dbtype_zone, view->rdclass, 0,
   3671 					    NULL, &db));
   3672 			CHECK(dns_db_newversion(db, &version));
   3673 			if (strcmp(empty_dbtype[2], "@") == 0) {
   3674 				dns_name_clone(name, ns);
   3675 			} else {
   3676 				CHECK(dns_name_fromstring(ns, empty_dbtype[2],
   3677 							  dns_rootname, 0,
   3678 							  NULL));
   3679 			}
   3680 			CHECK(dns_name_fromstring(contact, empty_dbtype[3],
   3681 						  dns_rootname, 0, NULL));
   3682 			CHECK(add_soa(db, version, name, ns, contact));
   3683 			CHECK(add_ns(db, version, name, ns));
   3684 		}
   3685 		CHECK(add_ns(db, version, zname, dns_rootname));
   3686 	}
   3687 
   3688 	/*
   3689 	 * Is the existing zone ok to use?
   3690 	 */
   3691 	if (pzone != NULL) {
   3692 		unsigned int typec;
   3693 		const char **dbargv = NULL;
   3694 
   3695 		if (db != NULL) {
   3696 			typec = default_dbtypec;
   3697 			dbargv = default_dbtype;
   3698 		} else {
   3699 			typec = empty_dbtypec;
   3700 			dbargv = empty_dbtype;
   3701 		}
   3702 
   3703 		result = check_dbtype(pzone, typec, dbargv, view->mctx);
   3704 		if (result != ISC_R_SUCCESS) {
   3705 			pzone = NULL;
   3706 		}
   3707 
   3708 		if (pzone != NULL &&
   3709 		    dns_zone_gettype(pzone) != dns_zone_primary)
   3710 		{
   3711 			pzone = NULL;
   3712 		}
   3713 		if (pzone != NULL && dns_zone_getfile(pzone) != NULL) {
   3714 			pzone = NULL;
   3715 		}
   3716 		if (pzone != NULL) {
   3717 			dns_zone_getraw(pzone, &zone);
   3718 			if (zone != NULL) {
   3719 				dns_zone_detach(&zone);
   3720 				pzone = NULL;
   3721 			}
   3722 		}
   3723 	}
   3724 
   3725 	if (pzone == NULL) {
   3726 		CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
   3727 		CHECK(dns_zone_setorigin(zone, name));
   3728 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
   3729 		if (db == NULL) {
   3730 			dns_zone_setdbtype(zone, empty_dbtypec, empty_dbtype);
   3731 		}
   3732 		dns_zone_setclass(zone, view->rdclass);
   3733 		dns_zone_settype(zone, dns_zone_primary);
   3734 		dns_zone_setstats(zone, named_g_server->zonestats);
   3735 	} else {
   3736 		dns_zone_attach(pzone, &zone);
   3737 	}
   3738 
   3739 	dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, false);
   3740 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
   3741 	dns_zone_setcheckdstype(zone, dns_checkdstype_no);
   3742 	dns_zone_setnotifytype(zone, dns_notifytype_no);
   3743 	dns_zone_setdialup(zone, dns_dialuptype_no);
   3744 	dns_zone_setautomatic(zone, true);
   3745 	if (view->queryacl != NULL) {
   3746 		dns_zone_setqueryacl(zone, view->queryacl);
   3747 	} else {
   3748 		dns_zone_clearqueryacl(zone);
   3749 	}
   3750 	if (view->queryonacl != NULL) {
   3751 		dns_zone_setqueryonacl(zone, view->queryonacl);
   3752 	} else {
   3753 		dns_zone_clearqueryonacl(zone);
   3754 	}
   3755 	dns_zone_clearupdateacl(zone);
   3756 	if (view->transferacl != NULL) {
   3757 		dns_zone_setxfracl(zone, view->transferacl);
   3758 	} else {
   3759 		dns_zone_clearxfracl(zone);
   3760 	}
   3761 
   3762 	setquerystats(zone, view->mctx, statlevel);
   3763 	if (db != NULL) {
   3764 		dns_db_closeversion(db, &version, true);
   3765 		CHECK(dns_zone_replacedb(zone, db, false));
   3766 	}
   3767 	dns_zone_setoption(zone, DNS_ZONEOPT_AUTOEMPTY, true);
   3768 	dns_zone_setview(zone, view);
   3769 	CHECK(dns_view_addzone(view, zone));
   3770 
   3771 	if (!strcmp(viewname, "_default")) {
   3772 		sep = "";
   3773 		viewname = "";
   3774 	}
   3775 	dns_name_format(name, namebuf, sizeof(namebuf));
   3776 	isc_log_write(named_g_lctx, DNS_LOGCATEGORY_ZONELOAD,
   3777 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   3778 		      "automatic empty zone%s%s: %s", sep, viewname, namebuf);
   3779 
   3780 cleanup:
   3781 	if (zone != NULL) {
   3782 		dns_zone_detach(&zone);
   3783 	}
   3784 	if (version != NULL) {
   3785 		dns_db_closeversion(db, &version, false);
   3786 	}
   3787 	if (db != NULL) {
   3788 		dns_db_detach(&db);
   3789 	}
   3790 
   3791 	INSIST(version == NULL);
   3792 
   3793 	return result;
   3794 }
   3795 
   3796 static isc_result_t
   3797 create_ipv4only_zone(dns_zone_t *pzone, dns_view_t *view,
   3798 		     const dns_name_t *name, const char *type, isc_mem_t *mctx,
   3799 		     const char *server, const char *contact) {
   3800 	char namebuf[DNS_NAME_FORMATSIZE];
   3801 	const char *dbtype[4] = { "_builtin", NULL, "@", "." };
   3802 	const char *sep = ": view ";
   3803 	const char *viewname = view->name;
   3804 	dns_zone_t *zone = NULL;
   3805 	int dbtypec = 4;
   3806 	isc_result_t result;
   3807 
   3808 	REQUIRE(type != NULL);
   3809 
   3810 	if (!strcmp(viewname, "_default")) {
   3811 		sep = "";
   3812 		viewname = "";
   3813 	}
   3814 
   3815 	dbtype[1] = type;
   3816 	if (server != NULL) {
   3817 		dbtype[2] = server;
   3818 	}
   3819 	if (contact != NULL) {
   3820 		dbtype[3] = contact;
   3821 	}
   3822 
   3823 	if (pzone != NULL) {
   3824 		result = check_dbtype(pzone, dbtypec, dbtype, view->mctx);
   3825 		if (result != ISC_R_SUCCESS) {
   3826 			pzone = NULL;
   3827 		}
   3828 	}
   3829 
   3830 	if (pzone == NULL) {
   3831 		/*
   3832 		 * Create the actual zone.
   3833 		 */
   3834 		dns_zone_create(&zone, mctx, 0);
   3835 		CHECK(dns_zone_setorigin(zone, name));
   3836 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
   3837 		dns_zone_setclass(zone, view->rdclass);
   3838 		dns_zone_settype(zone, dns_zone_primary);
   3839 		dns_zone_setstats(zone, named_g_server->zonestats);
   3840 		dns_zone_setdbtype(zone, dbtypec, dbtype);
   3841 		dns_zone_setdialup(zone, dns_dialuptype_no);
   3842 		dns_zone_setcheckdstype(zone, dns_checkdstype_no);
   3843 		dns_zone_setnotifytype(zone, dns_notifytype_no);
   3844 		dns_zone_setautomatic(zone, true);
   3845 		dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
   3846 	} else {
   3847 		dns_zone_attach(pzone, &zone);
   3848 	}
   3849 	if (view->queryacl != NULL) {
   3850 		dns_zone_setqueryacl(zone, view->queryacl);
   3851 	} else {
   3852 		dns_zone_clearqueryacl(zone);
   3853 	}
   3854 	if (view->queryonacl != NULL) {
   3855 		dns_zone_setqueryonacl(zone, view->queryonacl);
   3856 	} else {
   3857 		dns_zone_clearqueryonacl(zone);
   3858 	}
   3859 	dns_zone_setview(zone, view);
   3860 	CHECK(dns_view_addzone(view, zone));
   3861 
   3862 	dns_name_format(name, namebuf, sizeof(namebuf));
   3863 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   3864 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   3865 		      "automatic ipv4only zone%s%s: %s", sep, viewname,
   3866 		      namebuf);
   3867 
   3868 cleanup:
   3869 	if (zone != NULL) {
   3870 		dns_zone_detach(&zone);
   3871 	}
   3872 	return result;
   3873 }
   3874 
   3875 #ifdef HAVE_DNSTAP
   3876 static isc_result_t
   3877 configure_dnstap(const cfg_obj_t **maps, dns_view_t *view) {
   3878 	isc_result_t result;
   3879 	const cfg_obj_t *obj, *obj2;
   3880 	const cfg_listelt_t *element;
   3881 	const char *dpath;
   3882 	const cfg_obj_t *dlist = NULL;
   3883 	dns_dtmsgtype_t dttypes = 0;
   3884 	unsigned int i;
   3885 	struct fstrm_iothr_options *fopt = NULL;
   3886 
   3887 	result = named_config_get(maps, "dnstap", &dlist);
   3888 	if (result != ISC_R_SUCCESS) {
   3889 		return ISC_R_SUCCESS;
   3890 	}
   3891 
   3892 	for (element = cfg_list_first(dlist); element != NULL;
   3893 	     element = cfg_list_next(element))
   3894 	{
   3895 		const char *str;
   3896 		dns_dtmsgtype_t dt = 0;
   3897 
   3898 		obj = cfg_listelt_value(element);
   3899 		obj2 = cfg_tuple_get(obj, "type");
   3900 		str = cfg_obj_asstring(obj2);
   3901 		if (strcasecmp(str, "client") == 0) {
   3902 			dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR;
   3903 		} else if (strcasecmp(str, "auth") == 0) {
   3904 			dt |= DNS_DTTYPE_AQ | DNS_DTTYPE_AR;
   3905 		} else if (strcasecmp(str, "resolver") == 0) {
   3906 			dt |= DNS_DTTYPE_RQ | DNS_DTTYPE_RR;
   3907 		} else if (strcasecmp(str, "forwarder") == 0) {
   3908 			dt |= DNS_DTTYPE_FQ | DNS_DTTYPE_FR;
   3909 		} else if (strcasecmp(str, "update") == 0) {
   3910 			dt |= DNS_DTTYPE_UQ | DNS_DTTYPE_UR;
   3911 		} else if (strcasecmp(str, "all") == 0) {
   3912 			dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR | DNS_DTTYPE_AQ |
   3913 			      DNS_DTTYPE_AR | DNS_DTTYPE_RQ | DNS_DTTYPE_RR |
   3914 			      DNS_DTTYPE_FQ | DNS_DTTYPE_FR | DNS_DTTYPE_UQ |
   3915 			      DNS_DTTYPE_UR;
   3916 		}
   3917 
   3918 		obj2 = cfg_tuple_get(obj, "mode");
   3919 		if (obj2 == NULL || cfg_obj_isvoid(obj2)) {
   3920 			dttypes |= dt;
   3921 			continue;
   3922 		}
   3923 
   3924 		str = cfg_obj_asstring(obj2);
   3925 		if (strcasecmp(str, "query") == 0) {
   3926 			dt &= ~DNS_DTTYPE_RESPONSE;
   3927 		} else if (strcasecmp(str, "response") == 0) {
   3928 			dt &= ~DNS_DTTYPE_QUERY;
   3929 		}
   3930 
   3931 		dttypes |= dt;
   3932 	}
   3933 
   3934 	if (named_g_server->dtenv == NULL && dttypes != 0) {
   3935 		dns_dtmode_t dmode;
   3936 		uint64_t max_size = 0;
   3937 		uint32_t rolls = 0;
   3938 		isc_log_rollsuffix_t suffix = isc_log_rollsuffix_increment;
   3939 
   3940 		obj = NULL;
   3941 		CHECKM(named_config_get(maps, "dnstap-output", &obj),
   3942 		       "'dnstap-output' must be set if 'dnstap' is set");
   3943 
   3944 		obj2 = cfg_tuple_get(obj, "mode");
   3945 		if (obj2 == NULL) {
   3946 			CHECKM(ISC_R_FAILURE, "dnstap-output mode not found");
   3947 		}
   3948 		if (strcasecmp(cfg_obj_asstring(obj2), "file") == 0) {
   3949 			dmode = dns_dtmode_file;
   3950 		} else {
   3951 			dmode = dns_dtmode_unix;
   3952 		}
   3953 
   3954 		obj2 = cfg_tuple_get(obj, "path");
   3955 		if (obj2 == NULL) {
   3956 			CHECKM(ISC_R_FAILURE, "dnstap-output path not found");
   3957 		}
   3958 
   3959 		dpath = cfg_obj_asstring(obj2);
   3960 
   3961 		obj2 = cfg_tuple_get(obj, "size");
   3962 		if (obj2 != NULL && cfg_obj_isuint64(obj2)) {
   3963 			max_size = cfg_obj_asuint64(obj2);
   3964 			if (max_size > SIZE_MAX) {
   3965 				cfg_obj_log(obj2, named_g_lctx, ISC_LOG_WARNING,
   3966 					    "'dnstap-output size "
   3967 					    "%" PRIu64 "' "
   3968 					    "is too large for this "
   3969 					    "system; reducing to %lu",
   3970 					    max_size, (unsigned long)SIZE_MAX);
   3971 				max_size = SIZE_MAX;
   3972 			}
   3973 		}
   3974 
   3975 		obj2 = cfg_tuple_get(obj, "versions");
   3976 		if (obj2 != NULL && cfg_obj_isuint32(obj2)) {
   3977 			rolls = cfg_obj_asuint32(obj2);
   3978 		} else {
   3979 			rolls = ISC_LOG_ROLLINFINITE;
   3980 		}
   3981 
   3982 		obj2 = cfg_tuple_get(obj, "suffix");
   3983 		if (obj2 != NULL && cfg_obj_isstring(obj2) &&
   3984 		    strcasecmp(cfg_obj_asstring(obj2), "timestamp") == 0)
   3985 		{
   3986 			suffix = isc_log_rollsuffix_timestamp;
   3987 		}
   3988 
   3989 		fopt = fstrm_iothr_options_init();
   3990 		/*
   3991 		 * Both network threads and worker threads may log dnstap data.
   3992 		 */
   3993 		fstrm_iothr_options_set_num_input_queues(fopt,
   3994 							 2 * named_g_cpus);
   3995 		fstrm_iothr_options_set_queue_model(
   3996 			fopt, FSTRM_IOTHR_QUEUE_MODEL_MPSC);
   3997 
   3998 		obj = NULL;
   3999 		result = named_config_get(maps, "fstrm-set-buffer-hint", &obj);
   4000 		if (result == ISC_R_SUCCESS) {
   4001 			i = cfg_obj_asuint32(obj);
   4002 			fstrm_iothr_options_set_buffer_hint(fopt, i);
   4003 		}
   4004 
   4005 		obj = NULL;
   4006 		result = named_config_get(maps, "fstrm-set-flush-timeout",
   4007 					  &obj);
   4008 		if (result == ISC_R_SUCCESS) {
   4009 			i = cfg_obj_asuint32(obj);
   4010 			fstrm_iothr_options_set_flush_timeout(fopt, i);
   4011 		}
   4012 
   4013 		obj = NULL;
   4014 		result = named_config_get(maps, "fstrm-set-input-queue-size",
   4015 					  &obj);
   4016 		if (result == ISC_R_SUCCESS) {
   4017 			i = cfg_obj_asuint32(obj);
   4018 			fstrm_iothr_options_set_input_queue_size(fopt, i);
   4019 		}
   4020 
   4021 		obj = NULL;
   4022 		result = named_config_get(
   4023 			maps, "fstrm-set-output-notify-threshold", &obj);
   4024 		if (result == ISC_R_SUCCESS) {
   4025 			i = cfg_obj_asuint32(obj);
   4026 			fstrm_iothr_options_set_queue_notify_threshold(fopt, i);
   4027 		}
   4028 
   4029 		obj = NULL;
   4030 		result = named_config_get(maps, "fstrm-set-output-queue-model",
   4031 					  &obj);
   4032 		if (result == ISC_R_SUCCESS) {
   4033 			if (strcasecmp(cfg_obj_asstring(obj), "spsc") == 0) {
   4034 				i = FSTRM_IOTHR_QUEUE_MODEL_SPSC;
   4035 			} else {
   4036 				i = FSTRM_IOTHR_QUEUE_MODEL_MPSC;
   4037 			}
   4038 			fstrm_iothr_options_set_queue_model(fopt, i);
   4039 		}
   4040 
   4041 		obj = NULL;
   4042 		result = named_config_get(maps, "fstrm-set-output-queue-size",
   4043 					  &obj);
   4044 		if (result == ISC_R_SUCCESS) {
   4045 			i = cfg_obj_asuint32(obj);
   4046 			fstrm_iothr_options_set_output_queue_size(fopt, i);
   4047 		}
   4048 
   4049 		obj = NULL;
   4050 		result = named_config_get(maps, "fstrm-set-reopen-interval",
   4051 					  &obj);
   4052 		if (result == ISC_R_SUCCESS) {
   4053 			i = cfg_obj_asduration(obj);
   4054 			fstrm_iothr_options_set_reopen_interval(fopt, i);
   4055 		}
   4056 
   4057 		CHECKM(dns_dt_create(named_g_mctx, dmode, dpath, &fopt,
   4058 				     named_g_mainloop, &named_g_server->dtenv),
   4059 		       "unable to create dnstap environment");
   4060 
   4061 		CHECKM(dns_dt_setupfile(named_g_server->dtenv, max_size, rolls,
   4062 					suffix),
   4063 		       "unable to set up dnstap logfile");
   4064 	}
   4065 
   4066 	if (named_g_server->dtenv == NULL) {
   4067 		return ISC_R_SUCCESS;
   4068 	}
   4069 
   4070 	obj = NULL;
   4071 	result = named_config_get(maps, "dnstap-version", &obj);
   4072 	if (result != ISC_R_SUCCESS) {
   4073 		/* not specified; use the product and version */
   4074 		dns_dt_setversion(named_g_server->dtenv, PACKAGE_STRING);
   4075 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
   4076 		/* Quoted string */
   4077 		dns_dt_setversion(named_g_server->dtenv, cfg_obj_asstring(obj));
   4078 	}
   4079 
   4080 	obj = NULL;
   4081 	result = named_config_get(maps, "dnstap-identity", &obj);
   4082 	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
   4083 		/* "hostname" is interpreted as boolean true */
   4084 		char buf[256];
   4085 		if (gethostname(buf, sizeof(buf)) == 0) {
   4086 			dns_dt_setidentity(named_g_server->dtenv, buf);
   4087 		}
   4088 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
   4089 		/* Quoted string */
   4090 		dns_dt_setidentity(named_g_server->dtenv,
   4091 				   cfg_obj_asstring(obj));
   4092 	}
   4093 
   4094 	dns_dtenv_attach(named_g_server->dtenv, &view->dtenv);
   4095 	view->dttypes = dttypes;
   4096 
   4097 	result = ISC_R_SUCCESS;
   4098 
   4099 cleanup:
   4100 	if (fopt != NULL) {
   4101 		fstrm_iothr_options_destroy(&fopt);
   4102 	}
   4103 
   4104 	return result;
   4105 }
   4106 #endif /* HAVE_DNSTAP */
   4107 
   4108 static isc_result_t
   4109 create_mapped_acl(void) {
   4110 	isc_result_t result;
   4111 	dns_acl_t *acl = NULL;
   4112 	struct in6_addr in6 = IN6ADDR_V4MAPPED_INIT;
   4113 	isc_netaddr_t addr;
   4114 
   4115 	isc_netaddr_fromin6(&addr, &in6);
   4116 
   4117 	dns_acl_create(named_g_mctx, 1, &acl);
   4118 
   4119 	result = dns_iptable_addprefix(acl->iptable, &addr, 96, true);
   4120 	if (result == ISC_R_SUCCESS) {
   4121 		dns_acl_attach(acl, &named_g_mapped);
   4122 	}
   4123 	dns_acl_detach(&acl);
   4124 	return result;
   4125 }
   4126 
   4127 /*%
   4128  * A callback for the cfg_pluginlist_foreach() call in configure_view() below.
   4129  * If registering any plugin fails, registering subsequent ones is not
   4130  * attempted.
   4131  */
   4132 static isc_result_t
   4133 register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj,
   4134 		    const char *plugin_path, const char *parameters,
   4135 		    void *callback_data) {
   4136 	dns_view_t *view = callback_data;
   4137 	char full_path[PATH_MAX];
   4138 	isc_result_t result;
   4139 
   4140 	result = ns_plugin_expandpath(plugin_path, full_path,
   4141 				      sizeof(full_path));
   4142 	if (result != ISC_R_SUCCESS) {
   4143 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   4144 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   4145 			      "%s: plugin configuration failed: "
   4146 			      "unable to get full plugin path: %s",
   4147 			      plugin_path, isc_result_totext(result));
   4148 		return result;
   4149 	}
   4150 
   4151 	result = ns_plugin_register(full_path, parameters, config,
   4152 				    cfg_obj_file(obj), cfg_obj_line(obj),
   4153 				    named_g_mctx, named_g_lctx,
   4154 				    named_g_aclconfctx, view);
   4155 	if (result != ISC_R_SUCCESS) {
   4156 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   4157 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   4158 			      "%s: plugin configuration failed: %s", full_path,
   4159 			      isc_result_totext(result));
   4160 	}
   4161 
   4162 	return result;
   4163 }
   4164 
   4165 static const char *const response_synonyms[] = { "response", NULL };
   4166 
   4167 /*
   4168  * Configure 'view' according to 'vconfig', taking defaults from
   4169  * 'config' where values are missing in 'vconfig'.
   4170  *
   4171  * When configuring the default view, 'vconfig' will be NULL and the
   4172  * global defaults in 'config' used exclusively.
   4173  */
   4174 static isc_result_t
   4175 configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
   4176 	       cfg_obj_t *vconfig, named_cachelist_t *cachelist,
   4177 	       named_cachelist_t *oldcachelist, dns_kasplist_t *kasplist,
   4178 	       dns_keystorelist_t *keystores, const cfg_obj_t *bindkeys,
   4179 	       isc_mem_t *mctx, cfg_aclconfctx_t *actx, bool need_hints,
   4180 	       bool first_time) {
   4181 	const cfg_obj_t *maps[4] = { 0 };
   4182 	const cfg_obj_t *cfgmaps[3] = { 0 };
   4183 	const cfg_obj_t *options = NULL;
   4184 	const cfg_obj_t *voptions = NULL;
   4185 	const cfg_obj_t *forwardtype;
   4186 	const cfg_obj_t *forwarders;
   4187 	const cfg_obj_t *alternates;
   4188 	const cfg_obj_t *zonelist;
   4189 	const cfg_obj_t *dlzlist;
   4190 	const cfg_obj_t *dlz;
   4191 	const cfg_obj_t *prefetch_trigger;
   4192 	const cfg_obj_t *prefetch_eligible;
   4193 	unsigned int dlzargc;
   4194 	char **dlzargv;
   4195 	const cfg_obj_t *dyndb_list, *plugin_list;
   4196 	const cfg_obj_t *disabled;
   4197 	const cfg_obj_t *obj, *obj2;
   4198 	const cfg_listelt_t *element = NULL;
   4199 	const cfg_listelt_t *zone_element_latest = NULL;
   4200 	in_port_t port;
   4201 	dns_cache_t *cache = NULL;
   4202 	isc_result_t result;
   4203 	size_t max_cache_size;
   4204 	uint32_t max_cache_size_percent = 0;
   4205 	size_t max_adb_size;
   4206 	uint32_t lame_ttl, fail_ttl;
   4207 	uint32_t max_stale_ttl = 0;
   4208 	uint32_t stale_refresh_time = 0;
   4209 	dns_tsigkeyring_t *ring = NULL;
   4210 	dns_transport_list_t *transports = NULL;
   4211 	dns_view_t *pview = NULL; /* Production view */
   4212 	dns_dispatch_t *dispatch4 = NULL;
   4213 	dns_dispatch_t *dispatch6 = NULL;
   4214 	bool rpz_configured = false;
   4215 	bool catz_configured = false;
   4216 	bool shared_cache = false;
   4217 	int i = 0, j = 0;
   4218 	const char *str = NULL;
   4219 	const char *cachename = NULL;
   4220 	dns_order_t *order = NULL;
   4221 	uint32_t udpsize;
   4222 	uint32_t maxbits;
   4223 	unsigned int resopts = 0;
   4224 	dns_zone_t *zone = NULL;
   4225 	uint32_t clients_per_query, max_clients_per_query;
   4226 	bool empty_zones_enable;
   4227 	const cfg_obj_t *disablelist = NULL;
   4228 	isc_stats_t *resstats = NULL;
   4229 	dns_stats_t *resquerystats = NULL;
   4230 	bool auto_root = false;
   4231 	named_cache_t *nsc = NULL;
   4232 	bool zero_no_soattl;
   4233 	dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
   4234 	unsigned int query_timeout;
   4235 	bool old_rpz_ok = false;
   4236 	dns_dyndbctx_t *dctx = NULL;
   4237 	dns_ntatable_t *ntatable = NULL;
   4238 	const char *qminmode = NULL;
   4239 	dns_adb_t *adb = NULL;
   4240 	bool oldcache = false;
   4241 	uint32_t padding;
   4242 
   4243 	REQUIRE(DNS_VIEW_VALID(view));
   4244 
   4245 	if (config != NULL) {
   4246 		(void)cfg_map_get(config, "options", &options);
   4247 	}
   4248 
   4249 	/*
   4250 	 * maps: view options, options, defaults
   4251 	 * cfgmaps: view options, top-level config
   4252 	 */
   4253 	if (vconfig != NULL) {
   4254 		voptions = cfg_tuple_get(vconfig, "options");
   4255 		maps[i++] = voptions;
   4256 		cfgmaps[j++] = voptions;
   4257 	}
   4258 	if (options != NULL) {
   4259 		maps[i++] = options;
   4260 	}
   4261 	maps[i++] = named_g_defaults;
   4262 
   4263 	if (config != NULL) {
   4264 		cfgmaps[j++] = config;
   4265 	}
   4266 
   4267 	/*
   4268 	 * Set the view's port number for outgoing queries.
   4269 	 */
   4270 	CHECKM(named_config_getport(config, "port", &port), "port");
   4271 	dns_view_setdstport(view, port);
   4272 
   4273 	/*
   4274 	 * Make the list of response policy zone names for a view that
   4275 	 * is used for real lookups and so cares about hints.
   4276 	 */
   4277 	obj = NULL;
   4278 	if (view->rdclass == dns_rdataclass_in && need_hints &&
   4279 	    named_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS)
   4280 	{
   4281 		CHECK(configure_rpz(view, NULL, maps, obj, &old_rpz_ok,
   4282 				    first_time));
   4283 		rpz_configured = true;
   4284 	}
   4285 
   4286 	obj = NULL;
   4287 	if (view->rdclass != dns_rdataclass_in && need_hints &&
   4288 	    named_config_get(maps, "catalog-zones", &obj) == ISC_R_SUCCESS)
   4289 	{
   4290 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   4291 			    "'catalog-zones' option is only supported "
   4292 			    "for views with class IN");
   4293 	}
   4294 
   4295 	obj = NULL;
   4296 	if (view->rdclass == dns_rdataclass_in && need_hints &&
   4297 	    named_config_get(maps, "catalog-zones", &obj) == ISC_R_SUCCESS)
   4298 	{
   4299 		CHECK(configure_catz(view, NULL, config, obj));
   4300 		catz_configured = true;
   4301 	}
   4302 
   4303 	/*
   4304 	 * Configure the zones.
   4305 	 */
   4306 	zonelist = NULL;
   4307 	if (voptions != NULL) {
   4308 		(void)cfg_map_get(voptions, "zone", &zonelist);
   4309 	} else {
   4310 		(void)cfg_map_get(config, "zone", &zonelist);
   4311 	}
   4312 
   4313 	/*
   4314 	 * Load zone configuration
   4315 	 */
   4316 	for (element = cfg_list_first(zonelist); element != NULL;
   4317 	     element = cfg_list_next(element))
   4318 	{
   4319 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
   4320 		CHECK(configure_zone(config, zconfig, vconfig, view, viewlist,
   4321 				     kasplist, keystores, actx, false,
   4322 				     old_rpz_ok, false, false));
   4323 		zone_element_latest = element;
   4324 	}
   4325 
   4326 	/*
   4327 	 * Check that a primary or secondary zone was found for each
   4328 	 * zone named in the response policy statement, unless we are
   4329 	 * using RPZ service interface.
   4330 	 */
   4331 	if (view->rpzs != NULL && !view->rpzs->p.dnsrps_enabled) {
   4332 		dns_rpz_num_t n;
   4333 
   4334 		for (n = 0; n < view->rpzs->p.num_zones; ++n) {
   4335 			if ((view->rpzs->defined & DNS_RPZ_ZBIT(n)) == 0) {
   4336 				char namebuf[DNS_NAME_FORMATSIZE];
   4337 
   4338 				dns_name_format(&view->rpzs->zones[n]->origin,
   4339 						namebuf, sizeof(namebuf));
   4340 				isc_log_write(named_g_lctx,
   4341 					      NAMED_LOGCATEGORY_GENERAL,
   4342 					      NAMED_LOGMODULE_SERVER,
   4343 					      DNS_RPZ_ERROR_LEVEL,
   4344 					      "rpz '%s' is not a primary or a "
   4345 					      "secondary zone",
   4346 					      namebuf);
   4347 				result = ISC_R_NOTFOUND;
   4348 				goto cleanup;
   4349 			}
   4350 		}
   4351 	}
   4352 
   4353 	/*
   4354 	 * If we're allowing added zones, then load zone configuration
   4355 	 * from the newzone file for zones that were added during previous
   4356 	 * runs.
   4357 	 */
   4358 	CHECK(configure_newzones(view, config, vconfig, actx));
   4359 
   4360 	/*
   4361 	 * Create Dynamically Loadable Zone driver.
   4362 	 */
   4363 	dlzlist = NULL;
   4364 	if (voptions != NULL) {
   4365 		(void)cfg_map_get(voptions, "dlz", &dlzlist);
   4366 	} else {
   4367 		(void)cfg_map_get(config, "dlz", &dlzlist);
   4368 	}
   4369 
   4370 	for (element = cfg_list_first(dlzlist); element != NULL;
   4371 	     element = cfg_list_next(element))
   4372 	{
   4373 		dlz = cfg_listelt_value(element);
   4374 
   4375 		obj = NULL;
   4376 		(void)cfg_map_get(dlz, "database", &obj);
   4377 		if (obj != NULL) {
   4378 			dns_dlzdb_t *dlzdb = NULL;
   4379 			const cfg_obj_t *name, *search = NULL;
   4380 			char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
   4381 
   4382 			if (s == NULL) {
   4383 				result = ISC_R_NOMEMORY;
   4384 				goto cleanup;
   4385 			}
   4386 
   4387 			result = isc_commandline_strtoargv(mctx, s, &dlzargc,
   4388 							   &dlzargv, 0);
   4389 			if (result != ISC_R_SUCCESS) {
   4390 				isc_mem_free(mctx, s);
   4391 				goto cleanup;
   4392 			}
   4393 
   4394 			name = cfg_map_getname(dlz);
   4395 			result = dns_dlzcreate(mctx, cfg_obj_asstring(name),
   4396 					       dlzargv[0], dlzargc, dlzargv,
   4397 					       &dlzdb);
   4398 			isc_mem_free(mctx, s);
   4399 			isc_mem_cput(mctx, dlzargv, dlzargc, sizeof(*dlzargv));
   4400 			if (result != ISC_R_SUCCESS) {
   4401 				goto cleanup;
   4402 			}
   4403 
   4404 			/*
   4405 			 * If the DLZ backend supports configuration,
   4406 			 * and is searchable, then call its configure
   4407 			 * method now.  If not searchable, we'll take
   4408 			 * care of it when we process the zone statement.
   4409 			 */
   4410 			(void)cfg_map_get(dlz, "search", &search);
   4411 			if (search == NULL || cfg_obj_asboolean(search)) {
   4412 				dlzdb->search = true;
   4413 				result = dns_dlzconfigure(
   4414 					view, dlzdb, dlzconfigure_callback);
   4415 				if (result != ISC_R_SUCCESS) {
   4416 					goto cleanup;
   4417 				}
   4418 				ISC_LIST_APPEND(view->dlz_searched, dlzdb,
   4419 						link);
   4420 			} else {
   4421 				dlzdb->search = false;
   4422 				ISC_LIST_APPEND(view->dlz_unsearched, dlzdb,
   4423 						link);
   4424 			}
   4425 		}
   4426 	}
   4427 
   4428 	/*
   4429 	 * Obtain configuration parameters that affect the decision of whether
   4430 	 * we can reuse/share an existing cache.
   4431 	 */
   4432 	obj = NULL;
   4433 	result = named_config_get(maps, "recursion", &obj);
   4434 	INSIST(result == ISC_R_SUCCESS);
   4435 	view->recursion = (view->rdclass == dns_rdataclass_in &&
   4436 			   cfg_obj_asboolean(obj));
   4437 
   4438 	if (named_g_maxcachesize != 0) {
   4439 		/*
   4440 		 * If "-T maxcachesize=..." is in effect, it overrides any
   4441 		 * other "max-cache-size" setting found in configuration,
   4442 		 * either implicit or explicit.  For simplicity, the value
   4443 		 * passed to that command line option is always treated as
   4444 		 * the number of bytes to set "max-cache-size" to.
   4445 		 */
   4446 		max_cache_size = named_g_maxcachesize;
   4447 	} else {
   4448 		obj = NULL;
   4449 		result = named_config_get(maps, "max-cache-size", &obj);
   4450 		INSIST(result == ISC_R_SUCCESS);
   4451 		if (cfg_obj_isstring(obj) &&
   4452 		    strcasecmp(cfg_obj_asstring(obj), "default") == 0)
   4453 		{
   4454 			/*
   4455 			 * The default for a view with recursion
   4456 			 * is 90% of memory. With no recursion,
   4457 			 * it's the minimum cache size allowed by
   4458 			 * dns_cache_setcachesize().
   4459 			 */
   4460 			if (view->recursion) {
   4461 				max_cache_size = SIZE_AS_PERCENT;
   4462 				max_cache_size_percent = 90;
   4463 			} else {
   4464 				max_cache_size = 1;
   4465 			}
   4466 		} else if (cfg_obj_isstring(obj)) {
   4467 			str = cfg_obj_asstring(obj);
   4468 			INSIST(strcasecmp(str, "unlimited") == 0);
   4469 			max_cache_size = 0;
   4470 		} else if (cfg_obj_ispercentage(obj)) {
   4471 			max_cache_size = SIZE_AS_PERCENT;
   4472 			max_cache_size_percent = cfg_obj_aspercentage(obj);
   4473 		} else if (cfg_obj_isuint64(obj)) {
   4474 			uint64_t value = cfg_obj_asuint64(obj);
   4475 			if (value > SIZE_MAX) {
   4476 				cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   4477 					    "'max-cache-size "
   4478 					    "%" PRIu64 "' "
   4479 					    "is too large for this "
   4480 					    "system; reducing to %lu",
   4481 					    value, (unsigned long)SIZE_MAX);
   4482 				value = SIZE_MAX;
   4483 			}
   4484 			max_cache_size = (size_t)value;
   4485 		} else {
   4486 			UNREACHABLE();
   4487 		}
   4488 	}
   4489 
   4490 	if (max_cache_size == SIZE_AS_PERCENT) {
   4491 		uint64_t totalphys = isc_meminfo_totalphys();
   4492 
   4493 		max_cache_size =
   4494 			(size_t)(totalphys * max_cache_size_percent / 100);
   4495 		if (totalphys == 0) {
   4496 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   4497 				    "Unable to determine amount of physical "
   4498 				    "memory, setting 'max-cache-size' to "
   4499 				    "unlimited");
   4500 		} else {
   4501 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
   4502 				    "'max-cache-size %d%%' "
   4503 				    "- setting to %" PRIu64 "MB "
   4504 				    "(out of %" PRIu64 "MB)",
   4505 				    max_cache_size_percent,
   4506 				    (uint64_t)(max_cache_size / (1024 * 1024)),
   4507 				    totalphys / (1024 * 1024));
   4508 		}
   4509 	}
   4510 
   4511 	/* Check-names. */
   4512 	obj = NULL;
   4513 	result = named_checknames_get(maps, response_synonyms, &obj);
   4514 	INSIST(result == ISC_R_SUCCESS);
   4515 
   4516 	str = cfg_obj_asstring(obj);
   4517 	if (strcasecmp(str, "fail") == 0) {
   4518 		resopts |= DNS_RESOLVER_CHECKNAMES |
   4519 			   DNS_RESOLVER_CHECKNAMESFAIL;
   4520 		view->checknames = true;
   4521 	} else if (strcasecmp(str, "warn") == 0) {
   4522 		resopts |= DNS_RESOLVER_CHECKNAMES;
   4523 		view->checknames = false;
   4524 	} else if (strcasecmp(str, "ignore") == 0) {
   4525 		view->checknames = false;
   4526 	} else {
   4527 		UNREACHABLE();
   4528 	}
   4529 
   4530 	obj = NULL;
   4531 	result = named_config_get(maps, "zero-no-soa-ttl-cache", &obj);
   4532 	INSIST(result == ISC_R_SUCCESS);
   4533 	zero_no_soattl = cfg_obj_asboolean(obj);
   4534 
   4535 	obj = NULL;
   4536 	result = named_config_get(maps, "resolver-use-dns64", &obj);
   4537 	INSIST(result == ISC_R_SUCCESS);
   4538 	view->usedns64 = cfg_obj_asboolean(obj);
   4539 
   4540 	obj = NULL;
   4541 	result = named_config_get(maps, "dns64", &obj);
   4542 	if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") &&
   4543 	    strcmp(view->name, "_meta"))
   4544 	{
   4545 		isc_netaddr_t na, suffix, *sp;
   4546 		unsigned int prefixlen;
   4547 		const char *server, *contact;
   4548 		const cfg_obj_t *myobj;
   4549 
   4550 		myobj = NULL;
   4551 		result = named_config_get(maps, "dns64-server", &myobj);
   4552 		if (result == ISC_R_SUCCESS) {
   4553 			server = cfg_obj_asstring(myobj);
   4554 		} else {
   4555 			server = NULL;
   4556 		}
   4557 
   4558 		myobj = NULL;
   4559 		result = named_config_get(maps, "dns64-contact", &myobj);
   4560 		if (result == ISC_R_SUCCESS) {
   4561 			contact = cfg_obj_asstring(myobj);
   4562 		} else {
   4563 			contact = NULL;
   4564 		}
   4565 
   4566 		for (element = cfg_list_first(obj); element != NULL;
   4567 		     element = cfg_list_next(element))
   4568 		{
   4569 			const cfg_obj_t *map = cfg_listelt_value(element);
   4570 			dns_dns64_t *dns64 = NULL;
   4571 			unsigned int dns64options = 0;
   4572 
   4573 			cfg_obj_asnetprefix(cfg_map_getname(map), &na,
   4574 					    &prefixlen);
   4575 
   4576 			obj = NULL;
   4577 			(void)cfg_map_get(map, "suffix", &obj);
   4578 			if (obj != NULL) {
   4579 				sp = &suffix;
   4580 				isc_netaddr_fromsockaddr(
   4581 					sp, cfg_obj_assockaddr(obj));
   4582 			} else {
   4583 				sp = NULL;
   4584 			}
   4585 
   4586 			clients = mapped = excluded = NULL;
   4587 			obj = NULL;
   4588 			(void)cfg_map_get(map, "clients", &obj);
   4589 			if (obj != NULL) {
   4590 				result = cfg_acl_fromconfig(obj, config,
   4591 							    named_g_lctx, actx,
   4592 							    mctx, 0, &clients);
   4593 				if (result != ISC_R_SUCCESS) {
   4594 					goto cleanup;
   4595 				}
   4596 			}
   4597 			obj = NULL;
   4598 			(void)cfg_map_get(map, "mapped", &obj);
   4599 			if (obj != NULL) {
   4600 				result = cfg_acl_fromconfig(obj, config,
   4601 							    named_g_lctx, actx,
   4602 							    mctx, 0, &mapped);
   4603 				if (result != ISC_R_SUCCESS) {
   4604 					goto cleanup;
   4605 				}
   4606 			}
   4607 			obj = NULL;
   4608 			(void)cfg_map_get(map, "exclude", &obj);
   4609 			if (obj != NULL) {
   4610 				result = cfg_acl_fromconfig(obj, config,
   4611 							    named_g_lctx, actx,
   4612 							    mctx, 0, &excluded);
   4613 				if (result != ISC_R_SUCCESS) {
   4614 					goto cleanup;
   4615 				}
   4616 			} else {
   4617 				if (named_g_mapped == NULL) {
   4618 					result = create_mapped_acl();
   4619 					if (result != ISC_R_SUCCESS) {
   4620 						goto cleanup;
   4621 					}
   4622 				}
   4623 				dns_acl_attach(named_g_mapped, &excluded);
   4624 			}
   4625 
   4626 			obj = NULL;
   4627 			(void)cfg_map_get(map, "recursive-only", &obj);
   4628 			if (obj != NULL && cfg_obj_asboolean(obj)) {
   4629 				dns64options |= DNS_DNS64_RECURSIVE_ONLY;
   4630 			}
   4631 
   4632 			obj = NULL;
   4633 			(void)cfg_map_get(map, "break-dnssec", &obj);
   4634 			if (obj != NULL && cfg_obj_asboolean(obj)) {
   4635 				dns64options |= DNS_DNS64_BREAK_DNSSEC;
   4636 			}
   4637 
   4638 			result = dns_dns64_create(mctx, &na, prefixlen, sp,
   4639 						  clients, mapped, excluded,
   4640 						  dns64options, &dns64);
   4641 			if (result != ISC_R_SUCCESS) {
   4642 				goto cleanup;
   4643 			}
   4644 			dns_dns64_append(&view->dns64, dns64);
   4645 			view->dns64cnt++;
   4646 			result = dns64_reverse(view, mctx, &na, prefixlen,
   4647 					       server, contact);
   4648 			if (result != ISC_R_SUCCESS) {
   4649 				goto cleanup;
   4650 			}
   4651 			if (clients != NULL) {
   4652 				dns_acl_detach(&clients);
   4653 			}
   4654 			if (mapped != NULL) {
   4655 				dns_acl_detach(&mapped);
   4656 			}
   4657 			if (excluded != NULL) {
   4658 				dns_acl_detach(&excluded);
   4659 			}
   4660 		}
   4661 	}
   4662 
   4663 	obj = NULL;
   4664 	result = named_config_get(maps, "dnssec-accept-expired", &obj);
   4665 	INSIST(result == ISC_R_SUCCESS);
   4666 	view->acceptexpired = cfg_obj_asboolean(obj);
   4667 
   4668 	obj = NULL;
   4669 	result = named_config_get(maps, "dnssec-validation", &obj);
   4670 	INSIST(result == ISC_R_SUCCESS);
   4671 	if (cfg_obj_isboolean(obj)) {
   4672 		view->enablevalidation = cfg_obj_asboolean(obj);
   4673 	} else {
   4674 		/*
   4675 		 * If dnssec-validation is set but not boolean,
   4676 		 * then it must be "auto"
   4677 		 */
   4678 		view->enablevalidation = true;
   4679 		auto_root = true;
   4680 	}
   4681 
   4682 	obj = NULL;
   4683 	result = named_config_get(maps, "max-cache-ttl", &obj);
   4684 	INSIST(result == ISC_R_SUCCESS);
   4685 	view->maxcachettl = cfg_obj_asduration(obj);
   4686 
   4687 	obj = NULL;
   4688 	result = named_config_get(maps, "max-ncache-ttl", &obj);
   4689 	INSIST(result == ISC_R_SUCCESS);
   4690 	view->maxncachettl = cfg_obj_asduration(obj);
   4691 
   4692 	obj = NULL;
   4693 	result = named_config_get(maps, "min-cache-ttl", &obj);
   4694 	INSIST(result == ISC_R_SUCCESS);
   4695 	view->mincachettl = cfg_obj_asduration(obj);
   4696 
   4697 	obj = NULL;
   4698 	result = named_config_get(maps, "min-ncache-ttl", &obj);
   4699 	INSIST(result == ISC_R_SUCCESS);
   4700 	view->minncachettl = cfg_obj_asduration(obj);
   4701 
   4702 	obj = NULL;
   4703 	result = named_config_get(maps, "synth-from-dnssec", &obj);
   4704 	INSIST(result == ISC_R_SUCCESS);
   4705 	view->synthfromdnssec = cfg_obj_asboolean(obj);
   4706 
   4707 	obj = NULL;
   4708 	result = named_config_get(maps, "stale-cache-enable", &obj);
   4709 	INSIST(result == ISC_R_SUCCESS);
   4710 	if (cfg_obj_asboolean(obj)) {
   4711 		obj = NULL;
   4712 		result = named_config_get(maps, "max-stale-ttl", &obj);
   4713 		INSIST(result == ISC_R_SUCCESS);
   4714 		max_stale_ttl = ISC_MAX(cfg_obj_asduration(obj), 1);
   4715 	}
   4716 	/*
   4717 	 * If 'stale-cache-enable' is false, max_stale_ttl is set to 0,
   4718 	 * meaning keeping stale RRsets in cache is disabled.
   4719 	 */
   4720 
   4721 	obj = NULL;
   4722 	result = named_config_get(maps, "stale-answer-enable", &obj);
   4723 	INSIST(result == ISC_R_SUCCESS);
   4724 	view->staleanswersenable = cfg_obj_asboolean(obj);
   4725 
   4726 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
   4727 				   view->rdclass, &pview);
   4728 	if (result == ISC_R_SUCCESS) {
   4729 		view->staleanswersok = pview->staleanswersok;
   4730 		dns_view_detach(&pview);
   4731 	} else {
   4732 		view->staleanswersok = dns_stale_answer_conf;
   4733 	}
   4734 
   4735 	obj = NULL;
   4736 	result = named_config_get(maps, "stale-answer-client-timeout", &obj);
   4737 	INSIST(result == ISC_R_SUCCESS);
   4738 	if (cfg_obj_isstring(obj)) {
   4739 		/*
   4740 		 * The only string values available for this option
   4741 		 * are "disabled" and "off".
   4742 		 * We use (uint32_t) -1 to represent disabled since
   4743 		 * a value of zero means that stale data can be used
   4744 		 * to promptly answer the query, while an attempt to
   4745 		 * refresh the RRset will still be made in background.
   4746 		 */
   4747 		view->staleanswerclienttimeout = (uint32_t)-1;
   4748 	} else {
   4749 		view->staleanswerclienttimeout = cfg_obj_asuint32(obj);
   4750 
   4751 		/*
   4752 		 * BIND 9 no longer supports non-zero values of
   4753 		 * stale-answer-client-timeout.
   4754 		 */
   4755 		if (view->staleanswerclienttimeout != 0) {
   4756 			view->staleanswerclienttimeout = 0;
   4757 			isc_log_write(
   4758 				named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   4759 				NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   4760 				"BIND 9 no longer supports non-zero values of "
   4761 				"stale-answer-client-timeout, adjusted to 0");
   4762 		}
   4763 	}
   4764 
   4765 	obj = NULL;
   4766 	result = named_config_get(maps, "stale-refresh-time", &obj);
   4767 	INSIST(result == ISC_R_SUCCESS);
   4768 	stale_refresh_time = cfg_obj_asduration(obj);
   4769 
   4770 	/*
   4771 	 * Configure the view's cache.
   4772 	 *
   4773 	 * First, check to see if there are any attach-cache options.  If yes,
   4774 	 * attempt to lookup an existing cache at attach it to the view.  If
   4775 	 * there is not one, then try to reuse an existing cache if possible;
   4776 	 * otherwise create a new cache.
   4777 	 *
   4778 	 * Note that the ADB is not preserved or shared in either case.
   4779 	 *
   4780 	 * When a matching view is found, the associated statistics are also
   4781 	 * retrieved and reused.
   4782 	 *
   4783 	 * XXX Determining when it is safe to reuse or share a cache is tricky.
   4784 	 * When the view's configuration changes, the cached data may become
   4785 	 * invalid because it reflects our old view of the world.  We check
   4786 	 * some of the configuration parameters that could invalidate the cache
   4787 	 * or otherwise make it unshareable, but there are other configuration
   4788 	 * options that should be checked.  For example, if a view uses a
   4789 	 * forwarder, changes in the forwarder configuration may invalidate
   4790 	 * the cache.  At the moment, it's the administrator's responsibility to
   4791 	 * ensure these configuration options don't invalidate reusing/sharing.
   4792 	 */
   4793 	obj = NULL;
   4794 	result = named_config_get(maps, "attach-cache", &obj);
   4795 	if (result == ISC_R_SUCCESS) {
   4796 		cachename = cfg_obj_asstring(obj);
   4797 	} else {
   4798 		cachename = view->name;
   4799 	}
   4800 
   4801 	nsc = cachelist_find(cachelist, cachename, view->rdclass);
   4802 	if (result == ISC_R_SUCCESS && nsc == NULL) {
   4803 		/*
   4804 		 * If we're using 'attach-cache' but didn't find the
   4805 		 * specified cache in the cache list already, check
   4806 		 * the old list.
   4807 		 */
   4808 		nsc = cachelist_find(oldcachelist, cachename, view->rdclass);
   4809 		oldcache = true;
   4810 	}
   4811 	if (nsc != NULL) {
   4812 		if (!cache_sharable(nsc->primaryview, view, zero_no_soattl,
   4813 				    max_cache_size, max_stale_ttl,
   4814 				    stale_refresh_time))
   4815 		{
   4816 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   4817 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   4818 				      "view %s can't use existing cache %s due "
   4819 				      "to configuration parameter mismatch",
   4820 				      view->name,
   4821 				      dns_cache_getname(nsc->cache));
   4822 			nsc = NULL;
   4823 		} else {
   4824 			shared_cache = true;
   4825 			dns_cache_attach(nsc->cache, &cache);
   4826 			if (oldcache) {
   4827 				/*
   4828 				 * We need to re-use the cache, but we don't
   4829 				 * want to mutate the old production list.
   4830 				 */
   4831 				nsc = NULL;
   4832 			}
   4833 		}
   4834 	} else if (strcmp(cachename, view->name) == 0) {
   4835 		result = dns_viewlist_find(&named_g_server->viewlist, cachename,
   4836 					   view->rdclass, &pview);
   4837 		if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
   4838 			goto cleanup;
   4839 		}
   4840 		if (pview != NULL) {
   4841 			if (!cache_reusable(pview, view, zero_no_soattl)) {
   4842 				isc_log_write(named_g_lctx,
   4843 					      NAMED_LOGCATEGORY_GENERAL,
   4844 					      NAMED_LOGMODULE_SERVER,
   4845 					      ISC_LOG_DEBUG(1),
   4846 					      "cache cannot be reused "
   4847 					      "for view %s due to "
   4848 					      "configuration parameter "
   4849 					      "mismatch",
   4850 					      view->name);
   4851 			} else {
   4852 				INSIST(pview->cache != NULL);
   4853 				isc_log_write(named_g_lctx,
   4854 					      NAMED_LOGCATEGORY_GENERAL,
   4855 					      NAMED_LOGMODULE_SERVER,
   4856 					      ISC_LOG_DEBUG(3),
   4857 					      "reusing existing cache");
   4858 				dns_cache_attach(pview->cache, &cache);
   4859 			}
   4860 			dns_resolver_getstats(pview->resolver, &resstats);
   4861 			dns_resolver_getquerystats(pview->resolver,
   4862 						   &resquerystats);
   4863 			dns_view_detach(&pview);
   4864 		}
   4865 	}
   4866 
   4867 	if (nsc == NULL) {
   4868 		/*
   4869 		 * Create a cache with the desired name.  This normally
   4870 		 * equals the view name, but may also be a forward
   4871 		 * reference to a view that share the cache with this
   4872 		 * view but is not yet configured.  If it is not the
   4873 		 * view name but not a forward reference either, then it
   4874 		 * is simply a named cache that is not shared.
   4875 		 */
   4876 		if (cache == NULL) {
   4877 			CHECK(dns_cache_create(named_g_loopmgr, view->rdclass,
   4878 					       cachename, mctx, &cache));
   4879 		}
   4880 
   4881 		nsc = isc_mem_get(mctx, sizeof(*nsc));
   4882 		*nsc = (named_cache_t){
   4883 			.primaryview = view,
   4884 			.rdclass = view->rdclass,
   4885 			.link = ISC_LINK_INITIALIZER,
   4886 		};
   4887 
   4888 		dns_cache_attach(cache, &nsc->cache);
   4889 		ISC_LIST_APPEND(*cachelist, nsc, link);
   4890 	}
   4891 
   4892 	dns_view_setcache(view, cache, shared_cache);
   4893 
   4894 	dns_cache_setcachesize(cache, max_cache_size);
   4895 	dns_cache_setservestalettl(cache, max_stale_ttl);
   4896 	dns_cache_setservestalerefresh(cache, stale_refresh_time);
   4897 
   4898 	dns_cache_detach(&cache);
   4899 
   4900 	obj = NULL;
   4901 	result = named_config_get(maps, "stale-answer-ttl", &obj);
   4902 	INSIST(result == ISC_R_SUCCESS);
   4903 	view->staleanswerttl = ISC_MAX(cfg_obj_asduration(obj), 1);
   4904 
   4905 	/*
   4906 	 * Resolver.
   4907 	 */
   4908 	CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4,
   4909 					    ISC_LIST_PREV(view, link) == NULL));
   4910 	CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6,
   4911 					    ISC_LIST_PREV(view, link) == NULL));
   4912 	if (dispatch4 == NULL && dispatch6 == NULL) {
   4913 		UNEXPECTED_ERROR("unable to obtain either an IPv4 or"
   4914 				 " an IPv6 dispatch");
   4915 		result = ISC_R_UNEXPECTED;
   4916 		goto cleanup;
   4917 	}
   4918 
   4919 	CHECK(dns_view_createresolver(view, named_g_netmgr, resopts,
   4920 				      named_g_server->tlsctx_client_cache,
   4921 				      dispatch4, dispatch6));
   4922 
   4923 	if (resstats == NULL) {
   4924 		isc_stats_create(mctx, &resstats, dns_resstatscounter_max);
   4925 	}
   4926 	dns_resolver_setstats(view->resolver, resstats);
   4927 	if (resquerystats == NULL) {
   4928 		dns_rdatatypestats_create(mctx, &resquerystats);
   4929 	}
   4930 	dns_resolver_setquerystats(view->resolver, resquerystats);
   4931 
   4932 	/*
   4933 	 * Set the ADB cache size to 1/8th of the max-cache-size or
   4934 	 * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
   4935 	 */
   4936 	max_adb_size = 0;
   4937 	if (max_cache_size != 0U) {
   4938 		max_adb_size = max_cache_size / 8;
   4939 		if (max_adb_size == 0U) {
   4940 			max_adb_size = 1; /* Force minimum. */
   4941 		}
   4942 		if (view != nsc->primaryview &&
   4943 		    max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE)
   4944 		{
   4945 			max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE;
   4946 			if (!nsc->adbsizeadjusted) {
   4947 				dns_view_getadb(nsc->primaryview, &adb);
   4948 				if (adb != NULL) {
   4949 					dns_adb_setadbsize(
   4950 						adb,
   4951 						MAX_ADB_SIZE_FOR_CACHESHARE);
   4952 					nsc->adbsizeadjusted = true;
   4953 					dns_adb_detach(&adb);
   4954 				}
   4955 			}
   4956 		}
   4957 	}
   4958 	dns_view_getadb(view, &adb);
   4959 	if (adb != NULL) {
   4960 		dns_adb_setadbsize(adb, max_adb_size);
   4961 		dns_adb_detach(&adb);
   4962 	}
   4963 
   4964 	/*
   4965 	 * Set up ADB quotas
   4966 	 */
   4967 	{
   4968 		uint32_t fps, freq;
   4969 		double low, high, discount;
   4970 
   4971 		obj = NULL;
   4972 		result = named_config_get(maps, "fetches-per-server", &obj);
   4973 		INSIST(result == ISC_R_SUCCESS);
   4974 		obj2 = cfg_tuple_get(obj, "fetches");
   4975 		fps = cfg_obj_asuint32(obj2);
   4976 		obj2 = cfg_tuple_get(obj, "response");
   4977 		if (!cfg_obj_isvoid(obj2)) {
   4978 			const char *resp = cfg_obj_asstring(obj2);
   4979 			isc_result_t r = DNS_R_SERVFAIL;
   4980 
   4981 			if (strcasecmp(resp, "drop") == 0) {
   4982 				r = DNS_R_DROP;
   4983 			} else if (strcasecmp(resp, "fail") == 0) {
   4984 				r = DNS_R_SERVFAIL;
   4985 			} else {
   4986 				UNREACHABLE();
   4987 			}
   4988 
   4989 			dns_resolver_setquotaresponse(view->resolver,
   4990 						      dns_quotatype_server, r);
   4991 		}
   4992 
   4993 		obj = NULL;
   4994 		result = named_config_get(maps, "fetch-quota-params", &obj);
   4995 		INSIST(result == ISC_R_SUCCESS);
   4996 
   4997 		obj2 = cfg_tuple_get(obj, "frequency");
   4998 		freq = cfg_obj_asuint32(obj2);
   4999 
   5000 		obj2 = cfg_tuple_get(obj, "low");
   5001 		low = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
   5002 
   5003 		obj2 = cfg_tuple_get(obj, "high");
   5004 		high = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
   5005 
   5006 		obj2 = cfg_tuple_get(obj, "discount");
   5007 		discount = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
   5008 
   5009 		dns_view_getadb(view, &adb);
   5010 		if (adb != NULL) {
   5011 			dns_adb_setquota(adb, fps, freq, low, high, discount);
   5012 			dns_adb_detach(&adb);
   5013 		}
   5014 	}
   5015 
   5016 	/*
   5017 	 * Set resolver's lame-ttl.
   5018 	 */
   5019 	obj = NULL;
   5020 	result = named_config_get(maps, "lame-ttl", &obj);
   5021 	INSIST(result == ISC_R_SUCCESS);
   5022 	lame_ttl = cfg_obj_asduration(obj);
   5023 	if (lame_ttl > 0) {
   5024 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   5025 			    "disabling lame cache despite lame-ttl > 0 as it "
   5026 			    "may cause performance issues");
   5027 	}
   5028 
   5029 	/*
   5030 	 * Set the resolver's query timeout.
   5031 	 */
   5032 	obj = NULL;
   5033 	result = named_config_get(maps, "resolver-query-timeout", &obj);
   5034 	INSIST(result == ISC_R_SUCCESS);
   5035 	query_timeout = cfg_obj_asuint32(obj);
   5036 	dns_resolver_settimeout(view->resolver, query_timeout);
   5037 
   5038 	/* Specify whether to use 0-TTL for negative response for SOA query */
   5039 	dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl);
   5040 
   5041 	/*
   5042 	 * Set the resolver's EDNS UDP size.
   5043 	 */
   5044 	obj = NULL;
   5045 	result = named_config_get(maps, "edns-udp-size", &obj);
   5046 	INSIST(result == ISC_R_SUCCESS);
   5047 	udpsize = cfg_obj_asuint32(obj);
   5048 	if (udpsize < 512) {
   5049 		udpsize = 512;
   5050 	}
   5051 	if (udpsize > 4096) {
   5052 		udpsize = 4096;
   5053 	}
   5054 	dns_view_setudpsize(view, (uint16_t)udpsize);
   5055 
   5056 	/*
   5057 	 * Set the maximum UDP response size.
   5058 	 */
   5059 	obj = NULL;
   5060 	result = named_config_get(maps, "max-udp-size", &obj);
   5061 	INSIST(result == ISC_R_SUCCESS);
   5062 	udpsize = cfg_obj_asuint32(obj);
   5063 	if (udpsize < 512) {
   5064 		udpsize = 512;
   5065 	}
   5066 	if (udpsize > 4096) {
   5067 		udpsize = 4096;
   5068 	}
   5069 	view->maxudp = udpsize;
   5070 
   5071 	/*
   5072 	 * Set the maximum UDP when a COOKIE is not provided.
   5073 	 */
   5074 	obj = NULL;
   5075 	result = named_config_get(maps, "nocookie-udp-size", &obj);
   5076 	INSIST(result == ISC_R_SUCCESS);
   5077 	udpsize = cfg_obj_asuint32(obj);
   5078 	if (udpsize < 128) {
   5079 		udpsize = 128;
   5080 	}
   5081 	if (udpsize > view->maxudp) {
   5082 		udpsize = view->maxudp;
   5083 	}
   5084 	view->nocookieudp = udpsize;
   5085 
   5086 	/*
   5087 	 * Set the maximum rsa exponent bits.
   5088 	 */
   5089 	obj = NULL;
   5090 	result = named_config_get(maps, "max-rsa-exponent-size", &obj);
   5091 	INSIST(result == ISC_R_SUCCESS);
   5092 	maxbits = cfg_obj_asuint32(obj);
   5093 	if (maxbits != 0 && maxbits < 35) {
   5094 		maxbits = 35;
   5095 	}
   5096 	if (maxbits > 4096) {
   5097 		maxbits = 4096;
   5098 	}
   5099 	view->maxbits = maxbits;
   5100 
   5101 	/*
   5102 	 * Set supported DNSSEC algorithms.
   5103 	 */
   5104 	disabled = NULL;
   5105 	(void)named_config_get(maps, "disable-algorithms", &disabled);
   5106 	if (disabled != NULL) {
   5107 		for (element = cfg_list_first(disabled); element != NULL;
   5108 		     element = cfg_list_next(element))
   5109 		{
   5110 			CHECK(disable_algorithms(cfg_listelt_value(element),
   5111 						 view->resolver));
   5112 		}
   5113 	}
   5114 
   5115 	/*
   5116 	 * Set supported DS digest types.
   5117 	 */
   5118 	disabled = NULL;
   5119 	(void)named_config_get(maps, "disable-ds-digests", &disabled);
   5120 	if (disabled != NULL) {
   5121 		for (element = cfg_list_first(disabled); element != NULL;
   5122 		     element = cfg_list_next(element))
   5123 		{
   5124 			CHECK(disable_ds_digests(cfg_listelt_value(element),
   5125 						 view->resolver));
   5126 		}
   5127 	}
   5128 
   5129 	/*
   5130 	 * A global or view "forwarders" option, if present,
   5131 	 * creates an entry for "." in the forwarding table.
   5132 	 */
   5133 	forwardtype = NULL;
   5134 	forwarders = NULL;
   5135 	(void)named_config_get(maps, "forward", &forwardtype);
   5136 	(void)named_config_get(maps, "forwarders", &forwarders);
   5137 	if (forwarders != NULL) {
   5138 		CHECK(configure_forward(config, view, dns_rootname, forwarders,
   5139 					forwardtype));
   5140 	}
   5141 
   5142 	/*
   5143 	 * Dual Stack Servers.
   5144 	 */
   5145 	alternates = NULL;
   5146 	(void)named_config_get(maps, "dual-stack-servers", &alternates);
   5147 	if (alternates != NULL) {
   5148 		CHECK(configure_alternates(config, view, alternates));
   5149 	}
   5150 
   5151 	/*
   5152 	 * We have default root hints for class IN if we need them.
   5153 	 * Each view gets its own rootdb so a priming response only
   5154 	 * writes into that view's copy.  Other classes don't support
   5155 	 * recursion and don't need hints.
   5156 	 */
   5157 	if (view->rdclass == dns_rdataclass_in && view->hints == NULL) {
   5158 		dns_view_sethints(view, named_g_server->in_roothints);
   5159 	}
   5160 
   5161 	/*
   5162 	 * Configure the view's transports (DoT/DoH)
   5163 	 */
   5164 	CHECK(named_transports_fromconfig(config, vconfig, view->mctx,
   5165 					  &transports));
   5166 	dns_view_settransports(view, transports);
   5167 	dns_transport_list_detach(&transports);
   5168 
   5169 	/*
   5170 	 * Configure SIG(0) check limits when matching a DNS message to a view.
   5171 	 */
   5172 	obj = NULL;
   5173 	result = named_config_get(maps, "sig0key-checks-limit", &obj);
   5174 	INSIST(result == ISC_R_SUCCESS);
   5175 	view->sig0key_checks_limit = cfg_obj_asuint32(obj);
   5176 
   5177 	obj = NULL;
   5178 	result = named_config_get(maps, "sig0message-checks-limit", &obj);
   5179 	INSIST(result == ISC_R_SUCCESS);
   5180 	view->sig0message_checks_limit = cfg_obj_asuint32(obj);
   5181 
   5182 	/*
   5183 	 * Configure the view's TSIG keys.
   5184 	 */
   5185 	CHECK(named_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
   5186 	if (named_g_server->sessionkey != NULL) {
   5187 		dns_tsigkey_t *tsigkey = NULL;
   5188 		result = dns_tsigkey_createfromkey(
   5189 			named_g_server->session_keyname,
   5190 			named_g_server->session_keyalg,
   5191 			named_g_server->sessionkey, false, false, NULL, 0, 0,
   5192 			mctx, &tsigkey);
   5193 		if (result == ISC_R_SUCCESS) {
   5194 			result = dns_tsigkeyring_add(ring, tsigkey);
   5195 			dns_tsigkey_detach(&tsigkey);
   5196 		}
   5197 		CHECK(result);
   5198 	}
   5199 	dns_view_setkeyring(view, ring);
   5200 	dns_tsigkeyring_detach(&ring);
   5201 
   5202 	/*
   5203 	 * See if we can re-use a dynamic key ring.
   5204 	 */
   5205 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
   5206 				   view->rdclass, &pview);
   5207 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
   5208 		goto cleanup;
   5209 	}
   5210 	if (pview != NULL) {
   5211 		dns_view_getdynamickeyring(pview, &ring);
   5212 		if (ring != NULL) {
   5213 			dns_view_setdynamickeyring(view, ring);
   5214 		}
   5215 		dns_tsigkeyring_detach(&ring);
   5216 		dns_view_detach(&pview);
   5217 	} else {
   5218 		dns_view_restorekeyring(view);
   5219 	}
   5220 
   5221 	/*
   5222 	 * Configure the view's peer list.
   5223 	 */
   5224 	{
   5225 		const cfg_obj_t *peers = NULL;
   5226 		dns_peerlist_t *newpeers = NULL;
   5227 
   5228 		(void)named_config_get(cfgmaps, "server", &peers);
   5229 		CHECK(dns_peerlist_new(mctx, &newpeers));
   5230 		for (element = cfg_list_first(peers); element != NULL;
   5231 		     element = cfg_list_next(element))
   5232 		{
   5233 			const cfg_obj_t *cpeer = cfg_listelt_value(element);
   5234 			dns_peer_t *peer;
   5235 
   5236 			CHECK(configure_peer(cpeer, mctx, &peer));
   5237 			dns_peerlist_addpeer(newpeers, peer);
   5238 			dns_peer_detach(&peer);
   5239 		}
   5240 		dns_peerlist_detach(&view->peers);
   5241 		view->peers = newpeers; /* Transfer ownership. */
   5242 	}
   5243 
   5244 	/*
   5245 	 *	Configure the views rrset-order.
   5246 	 */
   5247 	{
   5248 		const cfg_obj_t *rrsetorder = NULL;
   5249 
   5250 		(void)named_config_get(maps, "rrset-order", &rrsetorder);
   5251 		CHECK(dns_order_create(mctx, &order));
   5252 		for (element = cfg_list_first(rrsetorder); element != NULL;
   5253 		     element = cfg_list_next(element))
   5254 		{
   5255 			const cfg_obj_t *ent = cfg_listelt_value(element);
   5256 
   5257 			CHECK(configure_order(order, ent));
   5258 		}
   5259 		if (view->order != NULL) {
   5260 			dns_order_detach(&view->order);
   5261 		}
   5262 		dns_order_attach(order, &view->order);
   5263 		dns_order_detach(&order);
   5264 	}
   5265 	/*
   5266 	 * Copy the aclenv object.
   5267 	 */
   5268 	dns_aclenv_copy(view->aclenv, ns_interfacemgr_getaclenv(
   5269 					      named_g_server->interfacemgr));
   5270 
   5271 	/*
   5272 	 * Configure the "match-clients" and "match-destinations" ACL.
   5273 	 * (These are only meaningful at the view level, but 'config'
   5274 	 * must be passed so that named ACLs defined at the global level
   5275 	 * can be retrieved.)
   5276 	 */
   5277 	CHECK(configure_view_acl(vconfig, config, NULL, "match-clients", NULL,
   5278 				 actx, named_g_mctx, &view->matchclients));
   5279 	CHECK(configure_view_acl(vconfig, config, NULL, "match-destinations",
   5280 				 NULL, actx, named_g_mctx,
   5281 				 &view->matchdestinations));
   5282 
   5283 	/*
   5284 	 * Configure the "match-recursive-only" option.
   5285 	 */
   5286 	obj = NULL;
   5287 	(void)named_config_get(maps, "match-recursive-only", &obj);
   5288 	if (obj != NULL && cfg_obj_asboolean(obj)) {
   5289 		view->matchrecursiveonly = true;
   5290 	} else {
   5291 		view->matchrecursiveonly = false;
   5292 	}
   5293 
   5294 	/*
   5295 	 * Configure other configurable data.
   5296 	 */
   5297 	obj = NULL;
   5298 	result = named_config_get(maps, "qname-minimization", &obj);
   5299 	INSIST(result == ISC_R_SUCCESS);
   5300 	qminmode = cfg_obj_asstring(obj);
   5301 	INSIST(qminmode != NULL);
   5302 	if (!strcmp(qminmode, "strict")) {
   5303 		view->qminimization = true;
   5304 		view->qmin_strict = true;
   5305 	} else if (!strcmp(qminmode, "relaxed")) {
   5306 		view->qminimization = true;
   5307 		view->qmin_strict = false;
   5308 	} else { /* "disabled" or "off" */
   5309 		view->qminimization = false;
   5310 		view->qmin_strict = false;
   5311 	}
   5312 
   5313 	obj = NULL;
   5314 	result = named_config_get(maps, "auth-nxdomain", &obj);
   5315 	INSIST(result == ISC_R_SUCCESS);
   5316 	view->auth_nxdomain = cfg_obj_asboolean(obj);
   5317 
   5318 	obj = NULL;
   5319 	result = named_config_get(maps, "minimal-any", &obj);
   5320 	INSIST(result == ISC_R_SUCCESS);
   5321 	view->minimal_any = cfg_obj_asboolean(obj);
   5322 
   5323 	obj = NULL;
   5324 	result = named_config_get(maps, "minimal-responses", &obj);
   5325 	INSIST(result == ISC_R_SUCCESS);
   5326 	if (cfg_obj_isboolean(obj)) {
   5327 		if (cfg_obj_asboolean(obj)) {
   5328 			view->minimalresponses = dns_minimal_yes;
   5329 		} else {
   5330 			view->minimalresponses = dns_minimal_no;
   5331 		}
   5332 	} else {
   5333 		str = cfg_obj_asstring(obj);
   5334 		if (strcasecmp(str, "no-auth") == 0) {
   5335 			view->minimalresponses = dns_minimal_noauth;
   5336 		} else if (strcasecmp(str, "no-auth-recursive") == 0) {
   5337 			view->minimalresponses = dns_minimal_noauthrec;
   5338 		} else {
   5339 			UNREACHABLE();
   5340 		}
   5341 	}
   5342 
   5343 	obj = NULL;
   5344 	result = named_config_get(maps, "transfer-format", &obj);
   5345 	INSIST(result == ISC_R_SUCCESS);
   5346 	str = cfg_obj_asstring(obj);
   5347 	if (strcasecmp(str, "many-answers") == 0) {
   5348 		view->transfer_format = dns_many_answers;
   5349 	} else if (strcasecmp(str, "one-answer") == 0) {
   5350 		view->transfer_format = dns_one_answer;
   5351 	} else {
   5352 		UNREACHABLE();
   5353 	}
   5354 
   5355 	obj = NULL;
   5356 	result = named_config_get(maps, "trust-anchor-telemetry", &obj);
   5357 	INSIST(result == ISC_R_SUCCESS);
   5358 	view->trust_anchor_telemetry = cfg_obj_asboolean(obj);
   5359 
   5360 	obj = NULL;
   5361 	result = named_config_get(maps, "root-key-sentinel", &obj);
   5362 	INSIST(result == ISC_R_SUCCESS);
   5363 	view->root_key_sentinel = cfg_obj_asboolean(obj);
   5364 
   5365 	/*
   5366 	 * Set the "allow-query", "allow-query-cache", "allow-recursion",
   5367 	 * "allow-recursion-on" and "allow-query-cache-on" ACLs if
   5368 	 * configured in named.conf, but NOT from the global defaults.
   5369 	 * This is done by leaving the third argument to configure_view_acl()
   5370 	 * NULL.
   5371 	 *
   5372 	 * We ignore the global defaults here because these ACLs
   5373 	 * can inherit from each other.  If any are still unset after
   5374 	 * applying the inheritance rules, we'll look up the defaults at
   5375 	 * that time.
   5376 	 */
   5377 
   5378 	/* named.conf only */
   5379 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query", NULL,
   5380 				 actx, named_g_mctx, &view->queryacl));
   5381 
   5382 	/* named.conf only */
   5383 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache",
   5384 				 NULL, actx, named_g_mctx, &view->cacheacl));
   5385 	/* named.conf only */
   5386 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache-on",
   5387 				 NULL, actx, named_g_mctx, &view->cacheonacl));
   5388 
   5389 	CHECK(configure_view_acl(vconfig, config, named_g_config, "allow-proxy",
   5390 				 NULL, actx, named_g_mctx, &view->proxyacl));
   5391 
   5392 	CHECK(configure_view_acl(vconfig, config, named_g_config,
   5393 				 "allow-proxy-on", NULL, actx, named_g_mctx,
   5394 				 &view->proxyonacl));
   5395 
   5396 	if (view->rdclass != dns_rdataclass_in) {
   5397 		dns_acl_none(named_g_mctx, &view->recursionacl);
   5398 		dns_acl_none(named_g_mctx, &view->recursiononacl);
   5399 	} else {
   5400 		CHECK(configure_view_acl(vconfig, config, NULL,
   5401 					 "allow-recursion", NULL, actx,
   5402 					 named_g_mctx, &view->recursionacl));
   5403 		CHECK(configure_view_acl(vconfig, config, NULL,
   5404 					 "allow-recursion-on", NULL, actx,
   5405 					 named_g_mctx, &view->recursiononacl));
   5406 	}
   5407 
   5408 	if (view->recursion) {
   5409 		/*
   5410 		 * "allow-query-cache" inherits from "allow-recursion" if set,
   5411 		 * otherwise from "allow-query" if set.
   5412 		 */
   5413 		if (view->cacheacl == NULL) {
   5414 			if (view->recursionacl != NULL) {
   5415 				dns_acl_attach(view->recursionacl,
   5416 					       &view->cacheacl);
   5417 			} else if (view->queryacl != NULL) {
   5418 				dns_acl_attach(view->queryacl, &view->cacheacl);
   5419 			}
   5420 		}
   5421 
   5422 		/*
   5423 		 * "allow-recursion" inherits from "allow-query-cache" if set,
   5424 		 * otherwise from "allow-query" if set.
   5425 		 */
   5426 		if (view->recursionacl == NULL) {
   5427 			if (view->cacheacl != NULL) {
   5428 				dns_acl_attach(view->cacheacl,
   5429 					       &view->recursionacl);
   5430 			} else if (view->queryacl != NULL) {
   5431 				dns_acl_attach(view->queryacl,
   5432 					       &view->recursionacl);
   5433 			}
   5434 		}
   5435 
   5436 		/*
   5437 		 * "allow-query-cache-on" inherits from "allow-recursion-on"
   5438 		 * if set.
   5439 		 */
   5440 		if (view->cacheonacl == NULL) {
   5441 			if (view->recursiononacl != NULL) {
   5442 				dns_acl_attach(view->recursiononacl,
   5443 					       &view->cacheonacl);
   5444 			}
   5445 		}
   5446 
   5447 		/*
   5448 		 * "allow-recursion-on" inherits from "allow-query-cache-on"
   5449 		 * if set.
   5450 		 */
   5451 		if (view->recursiononacl == NULL) {
   5452 			if (view->cacheonacl != NULL) {
   5453 				dns_acl_attach(view->cacheonacl,
   5454 					       &view->recursiononacl);
   5455 			}
   5456 		}
   5457 
   5458 		/*
   5459 		 * If any are still unset at this point, we now get default
   5460 		 * values for from the global config.
   5461 		 */
   5462 
   5463 		if (view->recursionacl == NULL) {
   5464 			/* global default only */
   5465 			CHECK(configure_view_acl(
   5466 				NULL, NULL, named_g_config, "allow-recursion",
   5467 				NULL, actx, named_g_mctx, &view->recursionacl));
   5468 		}
   5469 		if (view->recursiononacl == NULL) {
   5470 			/* global default only */
   5471 			CHECK(configure_view_acl(NULL, NULL, named_g_config,
   5472 						 "allow-recursion-on", NULL,
   5473 						 actx, named_g_mctx,
   5474 						 &view->recursiononacl));
   5475 		}
   5476 		if (view->cacheacl == NULL) {
   5477 			/* global default only */
   5478 			CHECK(configure_view_acl(
   5479 				NULL, NULL, named_g_config, "allow-query-cache",
   5480 				NULL, actx, named_g_mctx, &view->cacheacl));
   5481 		}
   5482 		if (view->cacheonacl == NULL) {
   5483 			/* global default only */
   5484 			CHECK(configure_view_acl(NULL, NULL, named_g_config,
   5485 						 "allow-query-cache-on", NULL,
   5486 						 actx, named_g_mctx,
   5487 						 &view->cacheonacl));
   5488 		}
   5489 	} else {
   5490 		/*
   5491 		 * We're not recursive; if the query-cache ACLs haven't
   5492 		 * been set at the options/view level, set them to none.
   5493 		 */
   5494 		if (view->cacheacl == NULL) {
   5495 			CHECK(dns_acl_none(mctx, &view->cacheacl));
   5496 		}
   5497 		if (view->cacheonacl == NULL) {
   5498 			CHECK(dns_acl_none(mctx, &view->cacheonacl));
   5499 		}
   5500 	}
   5501 
   5502 	/*
   5503 	 * Finished setting recursion and query-cache ACLs, so now we
   5504 	 * can get the allow-query default if it wasn't set in named.conf
   5505 	 */
   5506 	if (view->queryacl == NULL) {
   5507 		/* global default only */
   5508 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
   5509 					 "allow-query", NULL, actx,
   5510 					 named_g_mctx, &view->queryacl));
   5511 	}
   5512 
   5513 	/*
   5514 	 * Ignore case when compressing responses to the specified
   5515 	 * clients. This causes case not always to be preserved,
   5516 	 * and is needed by some broken clients.
   5517 	 */
   5518 	CHECK(configure_view_acl(vconfig, config, named_g_config,
   5519 				 "no-case-compress", NULL, actx, named_g_mctx,
   5520 				 &view->nocasecompress));
   5521 
   5522 	/*
   5523 	 * Disable name compression completely, this is a tradeoff
   5524 	 * between CPU and network usage.
   5525 	 */
   5526 	obj = NULL;
   5527 	result = named_config_get(maps, "message-compression", &obj);
   5528 	INSIST(result == ISC_R_SUCCESS);
   5529 	view->msgcompression = cfg_obj_asboolean(obj);
   5530 
   5531 	/*
   5532 	 * Filter setting on addresses in the answer section.
   5533 	 */
   5534 	CHECK(configure_view_acl(vconfig, config, named_g_config,
   5535 				 "deny-answer-addresses", "acl", actx,
   5536 				 named_g_mctx, &view->denyansweracl));
   5537 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses",
   5538 				       "except-from", named_g_mctx,
   5539 				       &view->answeracl_exclude));
   5540 
   5541 	/*
   5542 	 * Filter setting on names (CNAME/DNAME targets) in the answer section.
   5543 	 */
   5544 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
   5545 				       "name", named_g_mctx,
   5546 				       &view->denyanswernames));
   5547 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
   5548 				       "except-from", named_g_mctx,
   5549 				       &view->answernames_exclude));
   5550 
   5551 	/*
   5552 	 * Configure sortlist, if set
   5553 	 */
   5554 	CHECK(configure_view_sortlist(vconfig, config, actx, named_g_mctx,
   5555 				      &view->sortlist));
   5556 
   5557 	/*
   5558 	 * Configure default allow-update and allow-update-forwarding ACLs,
   5559 	 * so they can be inherited by zones. (XXX: These are not
   5560 	 * read from the options/view level here. However, they may be
   5561 	 * read from there in zoneconf.c:configure_zone_acl() later.)
   5562 	 */
   5563 	if (view->updateacl == NULL) {
   5564 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
   5565 					 "allow-update", NULL, actx,
   5566 					 named_g_mctx, &view->updateacl));
   5567 	}
   5568 	if (view->upfwdacl == NULL) {
   5569 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
   5570 					 "allow-update-forwarding", NULL, actx,
   5571 					 named_g_mctx, &view->upfwdacl));
   5572 	}
   5573 
   5574 	/*
   5575 	 * Configure default allow-transfer and allow-notify ACLs so they
   5576 	 * can be inherited by zones.
   5577 	 */
   5578 	if (view->transferacl == NULL) {
   5579 		CHECK(configure_view_acl(vconfig, config, named_g_config,
   5580 					 "allow-transfer", NULL, actx,
   5581 					 named_g_mctx, &view->transferacl));
   5582 	}
   5583 	if (view->notifyacl == NULL) {
   5584 		CHECK(configure_view_acl(vconfig, config, named_g_config,
   5585 					 "allow-notify", NULL, actx,
   5586 					 named_g_mctx, &view->notifyacl));
   5587 	}
   5588 
   5589 	obj = NULL;
   5590 	result = named_config_get(maps, "provide-ixfr", &obj);
   5591 	INSIST(result == ISC_R_SUCCESS);
   5592 	view->provideixfr = cfg_obj_asboolean(obj);
   5593 
   5594 	obj = NULL;
   5595 	result = named_config_get(maps, "request-nsid", &obj);
   5596 	INSIST(result == ISC_R_SUCCESS);
   5597 	view->requestnsid = cfg_obj_asboolean(obj);
   5598 
   5599 	obj = NULL;
   5600 	result = named_config_get(maps, "send-cookie", &obj);
   5601 	INSIST(result == ISC_R_SUCCESS);
   5602 	view->sendcookie = cfg_obj_asboolean(obj);
   5603 
   5604 	obj = NULL;
   5605 	if (view->pad_acl != NULL) {
   5606 		dns_acl_detach(&view->pad_acl);
   5607 	}
   5608 	result = named_config_get(maps, "response-padding", &obj);
   5609 	INSIST(result == ISC_R_SUCCESS);
   5610 	padding = cfg_obj_asuint32(cfg_tuple_get(obj, "block-size"));
   5611 	if (padding > 512U) {
   5612 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   5613 			    "response-padding block-size cannot "
   5614 			    "exceed 512: lowering");
   5615 		padding = 512U;
   5616 	}
   5617 	view->padding = (uint16_t)padding;
   5618 	CHECK(cfg_acl_fromconfig(cfg_tuple_get(obj, "acl"), config,
   5619 				 named_g_lctx, actx, named_g_mctx, 0,
   5620 				 &view->pad_acl));
   5621 
   5622 	obj = NULL;
   5623 	result = named_config_get(maps, "require-server-cookie", &obj);
   5624 	INSIST(result == ISC_R_SUCCESS);
   5625 	view->requireservercookie = cfg_obj_asboolean(obj);
   5626 
   5627 	obj = NULL;
   5628 	result = named_config_get(maps, "v6-bias", &obj);
   5629 	INSIST(result == ISC_R_SUCCESS);
   5630 	view->v6bias = cfg_obj_asuint32(obj) * 1000;
   5631 
   5632 	obj = NULL;
   5633 	result = named_config_get(maps, "clients-per-query", &obj);
   5634 	INSIST(result == ISC_R_SUCCESS);
   5635 	clients_per_query = cfg_obj_asuint32(obj);
   5636 
   5637 	obj = NULL;
   5638 	result = named_config_get(maps, "max-clients-per-query", &obj);
   5639 	INSIST(result == ISC_R_SUCCESS);
   5640 	max_clients_per_query = cfg_obj_asuint32(obj);
   5641 
   5642 	if (max_clients_per_query < clients_per_query) {
   5643 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   5644 			    "configured clients-per-query (%u) exceeds "
   5645 			    "max-clients-per-query (%u); automatically "
   5646 			    "adjusting max-clients-per-query to (%u)",
   5647 			    clients_per_query, max_clients_per_query,
   5648 			    clients_per_query);
   5649 		max_clients_per_query = clients_per_query;
   5650 	}
   5651 	dns_resolver_setclientsperquery(view->resolver, clients_per_query,
   5652 					max_clients_per_query);
   5653 
   5654 	/*
   5655 	 * This is used for the cache and also as a default value
   5656 	 * for zone databases.
   5657 	 */
   5658 	obj = NULL;
   5659 	result = named_config_get(maps, "max-records-per-type", &obj);
   5660 	INSIST(result == ISC_R_SUCCESS);
   5661 	dns_view_setmaxrrperset(view, cfg_obj_asuint32(obj));
   5662 
   5663 	/*
   5664 	 * This is used for the cache and also as a default value
   5665 	 * for zone databases.
   5666 	 */
   5667 	obj = NULL;
   5668 	result = named_config_get(maps, "max-types-per-name", &obj);
   5669 	INSIST(result == ISC_R_SUCCESS);
   5670 	dns_view_setmaxtypepername(view, cfg_obj_asuint32(obj));
   5671 
   5672 	obj = NULL;
   5673 	result = named_config_get(maps, "max-recursion-depth", &obj);
   5674 	INSIST(result == ISC_R_SUCCESS);
   5675 	dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj));
   5676 
   5677 	obj = NULL;
   5678 	result = named_config_get(maps, "max-recursion-queries", &obj);
   5679 	INSIST(result == ISC_R_SUCCESS);
   5680 	dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
   5681 
   5682 	obj = NULL;
   5683 	result = named_config_get(maps, "max-query-restarts", &obj);
   5684 	INSIST(result == ISC_R_SUCCESS);
   5685 	dns_view_setmaxrestarts(view, cfg_obj_asuint32(obj));
   5686 
   5687 	obj = NULL;
   5688 	result = named_config_get(maps, "max-query-count", &obj);
   5689 	INSIST(result == ISC_R_SUCCESS);
   5690 	dns_view_setmaxqueries(view, cfg_obj_asuint32(obj));
   5691 
   5692 	obj = NULL;
   5693 	result = named_config_get(maps, "max-validations-per-fetch", &obj);
   5694 	if (result == ISC_R_SUCCESS) {
   5695 		dns_resolver_setmaxvalidations(view->resolver,
   5696 					       cfg_obj_asuint32(obj));
   5697 	}
   5698 
   5699 	obj = NULL;
   5700 	result = named_config_get(maps, "max-validation-failures-per-fetch",
   5701 				  &obj);
   5702 	if (result == ISC_R_SUCCESS) {
   5703 		dns_resolver_setmaxvalidationfails(view->resolver,
   5704 						   cfg_obj_asuint32(obj));
   5705 	}
   5706 
   5707 	obj = NULL;
   5708 	result = named_config_get(maps, "fetches-per-zone", &obj);
   5709 	INSIST(result == ISC_R_SUCCESS);
   5710 	obj2 = cfg_tuple_get(obj, "fetches");
   5711 	dns_resolver_setfetchesperzone(view->resolver, cfg_obj_asuint32(obj2));
   5712 	obj2 = cfg_tuple_get(obj, "response");
   5713 	if (!cfg_obj_isvoid(obj2)) {
   5714 		const char *resp = cfg_obj_asstring(obj2);
   5715 		isc_result_t r = DNS_R_SERVFAIL;
   5716 
   5717 		if (strcasecmp(resp, "drop") == 0) {
   5718 			r = DNS_R_DROP;
   5719 		} else if (strcasecmp(resp, "fail") == 0) {
   5720 			r = DNS_R_SERVFAIL;
   5721 		} else {
   5722 			UNREACHABLE();
   5723 		}
   5724 
   5725 		dns_resolver_setquotaresponse(view->resolver,
   5726 					      dns_quotatype_zone, r);
   5727 	}
   5728 
   5729 	obj = NULL;
   5730 	result = named_config_get(maps, "prefetch", &obj);
   5731 	INSIST(result == ISC_R_SUCCESS);
   5732 	prefetch_trigger = cfg_tuple_get(obj, "trigger");
   5733 	view->prefetch_trigger = cfg_obj_asuint32(prefetch_trigger);
   5734 	if (view->prefetch_trigger > 10) {
   5735 		view->prefetch_trigger = 10;
   5736 	}
   5737 	prefetch_eligible = cfg_tuple_get(obj, "eligible");
   5738 	if (cfg_obj_isvoid(prefetch_eligible)) {
   5739 		int m;
   5740 		for (m = 1; maps[m] != NULL; m++) {
   5741 			obj = NULL;
   5742 			result = named_config_get(&maps[m], "prefetch", &obj);
   5743 			INSIST(result == ISC_R_SUCCESS);
   5744 			prefetch_eligible = cfg_tuple_get(obj, "eligible");
   5745 			if (cfg_obj_isuint32(prefetch_eligible)) {
   5746 				break;
   5747 			}
   5748 		}
   5749 		INSIST(cfg_obj_isuint32(prefetch_eligible));
   5750 	}
   5751 	view->prefetch_eligible = cfg_obj_asuint32(prefetch_eligible);
   5752 	if (view->prefetch_eligible < view->prefetch_trigger + 6) {
   5753 		view->prefetch_eligible = view->prefetch_trigger + 6;
   5754 	}
   5755 
   5756 	/*
   5757 	 * For now, there is only one kind of trusted keys, the
   5758 	 * "security roots".
   5759 	 */
   5760 	CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys,
   5761 					auto_root));
   5762 
   5763 	obj = NULL;
   5764 	result = named_config_get(maps, "dnssec-must-be-secure", &obj);
   5765 	if (result == ISC_R_SUCCESS) {
   5766 		CHECK(mustbesecure(obj, view->resolver));
   5767 	}
   5768 
   5769 	obj = NULL;
   5770 	result = named_config_get(maps, "nta-recheck", &obj);
   5771 	INSIST(result == ISC_R_SUCCESS);
   5772 	view->nta_recheck = cfg_obj_asduration(obj);
   5773 
   5774 	obj = NULL;
   5775 	result = named_config_get(maps, "nta-lifetime", &obj);
   5776 	INSIST(result == ISC_R_SUCCESS);
   5777 	view->nta_lifetime = cfg_obj_asduration(obj);
   5778 
   5779 	obj = NULL;
   5780 	result = named_config_get(maps, "preferred-glue", &obj);
   5781 	if (result == ISC_R_SUCCESS) {
   5782 		str = cfg_obj_asstring(obj);
   5783 		if (strcasecmp(str, "a") == 0) {
   5784 			view->preferred_glue = dns_rdatatype_a;
   5785 		} else if (strcasecmp(str, "aaaa") == 0) {
   5786 			view->preferred_glue = dns_rdatatype_aaaa;
   5787 		} else {
   5788 			view->preferred_glue = 0;
   5789 		}
   5790 	} else {
   5791 		view->preferred_glue = 0;
   5792 	}
   5793 
   5794 	/*
   5795 	 * Load DynDB modules.
   5796 	 */
   5797 	dyndb_list = NULL;
   5798 	if (voptions != NULL) {
   5799 		(void)cfg_map_get(voptions, "dyndb", &dyndb_list);
   5800 	} else {
   5801 		(void)cfg_map_get(config, "dyndb", &dyndb_list);
   5802 	}
   5803 
   5804 	for (element = cfg_list_first(dyndb_list); element != NULL;
   5805 	     element = cfg_list_next(element))
   5806 	{
   5807 		const cfg_obj_t *dyndb = cfg_listelt_value(element);
   5808 
   5809 		if (dctx == NULL) {
   5810 			const void *hashinit = isc_hash_get_initializer();
   5811 			CHECK(dns_dyndb_createctx(mctx, hashinit, named_g_lctx,
   5812 						  view, named_g_server->zonemgr,
   5813 						  named_g_loopmgr, &dctx));
   5814 		}
   5815 
   5816 		CHECK(configure_dyndb(dyndb, mctx, dctx));
   5817 	}
   5818 
   5819 	/*
   5820 	 * Load plugins.
   5821 	 */
   5822 	plugin_list = NULL;
   5823 	if (voptions != NULL) {
   5824 		(void)cfg_map_get(voptions, "plugin", &plugin_list);
   5825 	} else {
   5826 		(void)cfg_map_get(config, "plugin", &plugin_list);
   5827 	}
   5828 
   5829 	if (plugin_list != NULL) {
   5830 		INSIST(view->hooktable == NULL);
   5831 		CHECK(ns_hooktable_create(view->mctx,
   5832 					  (ns_hooktable_t **)&view->hooktable));
   5833 		view->hooktable_free = ns_hooktable_free;
   5834 
   5835 		ns_plugins_create(view->mctx, (ns_plugins_t **)&view->plugins);
   5836 		view->plugins_free = ns_plugins_free;
   5837 
   5838 		CHECK(cfg_pluginlist_foreach(config, plugin_list, named_g_lctx,
   5839 					     register_one_plugin, view));
   5840 	}
   5841 
   5842 	/*
   5843 	 * Setup automatic empty zones.  If recursion is off then
   5844 	 * they are disabled by default.
   5845 	 */
   5846 	obj = NULL;
   5847 	(void)named_config_get(maps, "empty-zones-enable", &obj);
   5848 	(void)named_config_get(maps, "disable-empty-zone", &disablelist);
   5849 	if (obj == NULL && disablelist == NULL &&
   5850 	    view->rdclass == dns_rdataclass_in)
   5851 	{
   5852 		empty_zones_enable = view->recursion;
   5853 	} else if (view->rdclass == dns_rdataclass_in) {
   5854 		if (obj != NULL) {
   5855 			empty_zones_enable = cfg_obj_asboolean(obj);
   5856 		} else {
   5857 			empty_zones_enable = view->recursion;
   5858 		}
   5859 	} else {
   5860 		empty_zones_enable = false;
   5861 	}
   5862 
   5863 	if (empty_zones_enable) {
   5864 		const char *empty;
   5865 		int empty_zone = 0;
   5866 		dns_fixedname_t fixed;
   5867 		dns_name_t *name;
   5868 		isc_buffer_t buffer;
   5869 		char server[DNS_NAME_FORMATSIZE + 1];
   5870 		char contact[DNS_NAME_FORMATSIZE + 1];
   5871 		const char *empty_dbtype[4] = { "_builtin", "empty", NULL,
   5872 						NULL };
   5873 		int empty_dbtypec = 4;
   5874 		dns_zonestat_level_t statlevel = dns_zonestat_none;
   5875 
   5876 		name = dns_fixedname_initname(&fixed);
   5877 
   5878 		obj = NULL;
   5879 		result = named_config_get(maps, "empty-server", &obj);
   5880 		if (result == ISC_R_SUCCESS) {
   5881 			CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
   5882 						  dns_rootname, 0, NULL));
   5883 			isc_buffer_init(&buffer, server, sizeof(server) - 1);
   5884 			CHECK(dns_name_totext(name, 0, &buffer));
   5885 			server[isc_buffer_usedlength(&buffer)] = 0;
   5886 			empty_dbtype[2] = server;
   5887 		} else {
   5888 			empty_dbtype[2] = "@";
   5889 		}
   5890 
   5891 		obj = NULL;
   5892 		result = named_config_get(maps, "empty-contact", &obj);
   5893 		if (result == ISC_R_SUCCESS) {
   5894 			CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
   5895 						  dns_rootname, 0, NULL));
   5896 			isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
   5897 			CHECK(dns_name_totext(name, 0, &buffer));
   5898 			contact[isc_buffer_usedlength(&buffer)] = 0;
   5899 			empty_dbtype[3] = contact;
   5900 		} else {
   5901 			empty_dbtype[3] = ".";
   5902 		}
   5903 
   5904 		obj = NULL;
   5905 		result = named_config_get(maps, "zone-statistics", &obj);
   5906 		INSIST(result == ISC_R_SUCCESS);
   5907 		if (cfg_obj_isboolean(obj)) {
   5908 			if (cfg_obj_asboolean(obj)) {
   5909 				statlevel = dns_zonestat_full;
   5910 			} else {
   5911 				statlevel = dns_zonestat_none;
   5912 			}
   5913 		} else {
   5914 			const char *levelstr = cfg_obj_asstring(obj);
   5915 			if (strcasecmp(levelstr, "full") == 0) {
   5916 				statlevel = dns_zonestat_full;
   5917 			} else if (strcasecmp(levelstr, "terse") == 0) {
   5918 				statlevel = dns_zonestat_terse;
   5919 			} else if (strcasecmp(levelstr, "none") == 0) {
   5920 				statlevel = dns_zonestat_none;
   5921 			} else {
   5922 				UNREACHABLE();
   5923 			}
   5924 		}
   5925 
   5926 		for (empty = empty_zones[empty_zone]; empty != NULL;
   5927 		     empty = empty_zones[++empty_zone])
   5928 		{
   5929 			dns_forwarders_t *dnsforwarders = NULL;
   5930 			dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
   5931 
   5932 			/*
   5933 			 * Look for zone on drop list.
   5934 			 */
   5935 			CHECK(dns_name_fromstring(name, empty, dns_rootname, 0,
   5936 						  NULL));
   5937 			if (disablelist != NULL &&
   5938 			    on_disable_list(disablelist, name))
   5939 			{
   5940 				continue;
   5941 			}
   5942 
   5943 			/*
   5944 			 * This zone already exists.
   5945 			 */
   5946 			(void)dns_view_findzone(view, name, DNS_ZTFIND_EXACT,
   5947 						&zone);
   5948 			if (zone != NULL) {
   5949 				dns_zone_detach(&zone);
   5950 				continue;
   5951 			}
   5952 
   5953 			/*
   5954 			 * If we would forward this name don't add a
   5955 			 * empty zone for it.
   5956 			 */
   5957 			result = dns_fwdtable_find(view->fwdtable, name,
   5958 						   &dnsforwarders);
   5959 			if (result == ISC_R_SUCCESS ||
   5960 			    result == DNS_R_PARTIALMATCH)
   5961 			{
   5962 				fwdpolicy = dnsforwarders->fwdpolicy;
   5963 				dns_forwarders_detach(&dnsforwarders);
   5964 			}
   5965 			if (fwdpolicy == dns_fwdpolicy_only) {
   5966 				continue;
   5967 			}
   5968 
   5969 			/*
   5970 			 * See if we can re-use a existing zone.
   5971 			 */
   5972 			result = dns_viewlist_find(&named_g_server->viewlist,
   5973 						   view->name, view->rdclass,
   5974 						   &pview);
   5975 			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
   5976 			{
   5977 				goto cleanup;
   5978 			}
   5979 
   5980 			if (pview != NULL) {
   5981 				(void)dns_view_findzone(
   5982 					pview, name, DNS_ZTFIND_EXACT, &zone);
   5983 				dns_view_detach(&pview);
   5984 			}
   5985 
   5986 			CHECK(create_empty_zone(zone, name, view, zonelist,
   5987 						empty_dbtype, empty_dbtypec,
   5988 						statlevel));
   5989 			if (zone != NULL) {
   5990 				dns_zone_detach(&zone);
   5991 			}
   5992 		}
   5993 	}
   5994 
   5995 	obj = NULL;
   5996 	if (view->rdclass == dns_rdataclass_in) {
   5997 		(void)named_config_get(maps, "ipv4only-enable", &obj);
   5998 	}
   5999 	if (view->rdclass == dns_rdataclass_in && (obj != NULL)
   6000 		    ? cfg_obj_asboolean(obj)
   6001 		    : !ISC_LIST_EMPTY(view->dns64))
   6002 	{
   6003 		const char *server, *contact;
   6004 		dns_fixedname_t fixed;
   6005 		dns_name_t *name;
   6006 		struct {
   6007 			const char *name;
   6008 			const char *type;
   6009 		} zones[] = {
   6010 			{ "ipv4only.arpa", "ipv4only" },
   6011 			{ "170.0.0.192.in-addr.arpa", "ipv4reverse" },
   6012 			{ "171.0.0.192.in-addr.arpa", "ipv4reverse" },
   6013 		};
   6014 		size_t ipv4only_zone;
   6015 
   6016 		obj = NULL;
   6017 		result = named_config_get(maps, "ipv4only-server", &obj);
   6018 		if (result == ISC_R_SUCCESS) {
   6019 			server = cfg_obj_asstring(obj);
   6020 		} else {
   6021 			server = NULL;
   6022 		}
   6023 
   6024 		obj = NULL;
   6025 		result = named_config_get(maps, "ipv4only-contact", &obj);
   6026 		if (result == ISC_R_SUCCESS) {
   6027 			contact = cfg_obj_asstring(obj);
   6028 		} else {
   6029 			contact = NULL;
   6030 		}
   6031 
   6032 		name = dns_fixedname_initname(&fixed);
   6033 		for (ipv4only_zone = 0; ipv4only_zone < ARRAY_SIZE(zones);
   6034 		     ipv4only_zone++)
   6035 		{
   6036 			dns_forwarders_t *dnsforwarders = NULL;
   6037 			dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
   6038 
   6039 			CHECK(dns_name_fromstring(name,
   6040 						  zones[ipv4only_zone].name,
   6041 						  dns_rootname, 0, NULL));
   6042 
   6043 			(void)dns_view_findzone(view, name, DNS_ZTFIND_EXACT,
   6044 						&zone);
   6045 			if (zone != NULL) {
   6046 				dns_zone_detach(&zone);
   6047 				continue;
   6048 			}
   6049 
   6050 			/*
   6051 			 * If we would forward this name don't add it.
   6052 			 */
   6053 			result = dns_fwdtable_find(view->fwdtable, name,
   6054 						   &dnsforwarders);
   6055 			if (result == ISC_R_SUCCESS ||
   6056 			    result == DNS_R_PARTIALMATCH)
   6057 			{
   6058 				fwdpolicy = dnsforwarders->fwdpolicy;
   6059 				dns_forwarders_detach(&dnsforwarders);
   6060 			}
   6061 			if (fwdpolicy == dns_fwdpolicy_only) {
   6062 				continue;
   6063 			}
   6064 
   6065 			/*
   6066 			 * See if we can re-use a existing zone.
   6067 			 */
   6068 			result = dns_viewlist_find(&named_g_server->viewlist,
   6069 						   view->name, view->rdclass,
   6070 						   &pview);
   6071 			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
   6072 			{
   6073 				goto cleanup;
   6074 			}
   6075 
   6076 			if (pview != NULL) {
   6077 				(void)dns_view_findzone(
   6078 					pview, name, DNS_ZTFIND_EXACT, &zone);
   6079 				dns_view_detach(&pview);
   6080 			}
   6081 
   6082 			CHECK(create_ipv4only_zone(zone, view, name,
   6083 						   zones[ipv4only_zone].type,
   6084 						   mctx, server, contact));
   6085 			if (zone != NULL) {
   6086 				dns_zone_detach(&zone);
   6087 			}
   6088 		}
   6089 	}
   6090 
   6091 	obj = NULL;
   6092 	result = named_config_get(maps, "rate-limit", &obj);
   6093 	if (result == ISC_R_SUCCESS) {
   6094 		result = configure_rrl(view, config, obj);
   6095 		if (result != ISC_R_SUCCESS) {
   6096 			goto cleanup;
   6097 		}
   6098 	}
   6099 
   6100 	/*
   6101 	 * Set the servfail-ttl.
   6102 	 */
   6103 	obj = NULL;
   6104 	result = named_config_get(maps, "servfail-ttl", &obj);
   6105 	INSIST(result == ISC_R_SUCCESS);
   6106 	fail_ttl = cfg_obj_asduration(obj);
   6107 	if (fail_ttl > 30) {
   6108 		fail_ttl = 30;
   6109 	}
   6110 	dns_view_setfailttl(view, fail_ttl);
   6111 
   6112 	/*
   6113 	 * Name space to look up redirect information in.
   6114 	 */
   6115 	obj = NULL;
   6116 	result = named_config_get(maps, "nxdomain-redirect", &obj);
   6117 	if (result == ISC_R_SUCCESS) {
   6118 		dns_name_t *name = dns_fixedname_name(&view->redirectfixed);
   6119 		CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
   6120 					  dns_rootname, 0, NULL));
   6121 		view->redirectzone = name;
   6122 	} else {
   6123 		view->redirectzone = NULL;
   6124 	}
   6125 
   6126 	/*
   6127 	 * Exceptions to DNSSEC validation.
   6128 	 */
   6129 	obj = NULL;
   6130 	result = named_config_get(maps, "validate-except", &obj);
   6131 	if (result == ISC_R_SUCCESS) {
   6132 		result = dns_view_getntatable(view, &ntatable);
   6133 	}
   6134 	if (result == ISC_R_SUCCESS) {
   6135 		for (element = cfg_list_first(obj); element != NULL;
   6136 		     element = cfg_list_next(element))
   6137 		{
   6138 			dns_fixedname_t fntaname;
   6139 			dns_name_t *ntaname;
   6140 
   6141 			ntaname = dns_fixedname_initname(&fntaname);
   6142 			obj = cfg_listelt_value(element);
   6143 			CHECK(dns_name_fromstring(ntaname,
   6144 						  cfg_obj_asstring(obj),
   6145 						  dns_rootname, 0, NULL));
   6146 			CHECK(dns_ntatable_add(ntatable, ntaname, true, 0,
   6147 					       0xffffffffU));
   6148 		}
   6149 	}
   6150 
   6151 #ifdef HAVE_DNSTAP
   6152 	/*
   6153 	 * Set up the dnstap environment and configure message
   6154 	 * types to log.
   6155 	 */
   6156 	CHECK(configure_dnstap(maps, view));
   6157 #endif /* HAVE_DNSTAP */
   6158 
   6159 	result = ISC_R_SUCCESS;
   6160 
   6161 cleanup:
   6162 	/*
   6163 	 * Revert to the old view if there was an error.
   6164 	 */
   6165 	if (result != ISC_R_SUCCESS) {
   6166 		isc_result_t result2;
   6167 
   6168 		result2 = dns_viewlist_find(&named_g_server->viewlist,
   6169 					    view->name, view->rdclass, &pview);
   6170 		if (result2 == ISC_R_SUCCESS) {
   6171 			dns_view_thaw(pview);
   6172 
   6173 			obj = NULL;
   6174 			if (rpz_configured &&
   6175 			    pview->rdclass == dns_rdataclass_in && need_hints &&
   6176 			    named_config_get(maps, "response-policy", &obj) ==
   6177 				    ISC_R_SUCCESS)
   6178 			{
   6179 				/*
   6180 				 * We are swapping the places of the `view` and
   6181 				 * `pview` in the function's parameters list
   6182 				 * because we are reverting the same operation
   6183 				 * done previously in the "correct" order.
   6184 				 */
   6185 				result2 = configure_rpz(pview, view, maps, obj,
   6186 							&old_rpz_ok,
   6187 							first_time);
   6188 				if (result2 != ISC_R_SUCCESS) {
   6189 					isc_log_write(named_g_lctx,
   6190 						      NAMED_LOGCATEGORY_GENERAL,
   6191 						      NAMED_LOGMODULE_SERVER,
   6192 						      ISC_LOG_ERROR,
   6193 						      "rpz configuration "
   6194 						      "revert failed for view "
   6195 						      "'%s'",
   6196 						      pview->name);
   6197 				}
   6198 			}
   6199 
   6200 			obj = NULL;
   6201 			if (catz_configured &&
   6202 			    pview->rdclass == dns_rdataclass_in && need_hints &&
   6203 			    named_config_get(maps, "catalog-zones", &obj) ==
   6204 				    ISC_R_SUCCESS)
   6205 			{
   6206 				/*
   6207 				 * We are swapping the places of the `view` and
   6208 				 * `pview` in the function's parameters list
   6209 				 * because we are reverting the same operation
   6210 				 * done previously in the "correct" order.
   6211 				 */
   6212 				result2 = configure_catz(pview, view, config,
   6213 							 obj);
   6214 				if (result2 != ISC_R_SUCCESS) {
   6215 					isc_log_write(named_g_lctx,
   6216 						      NAMED_LOGCATEGORY_GENERAL,
   6217 						      NAMED_LOGMODULE_SERVER,
   6218 						      ISC_LOG_ERROR,
   6219 						      "catz configuration "
   6220 						      "revert failed for view "
   6221 						      "'%s'",
   6222 						      pview->name);
   6223 				}
   6224 			}
   6225 
   6226 			dns_view_freeze(pview);
   6227 		}
   6228 
   6229 		if (pview != NULL) {
   6230 			dns_view_detach(&pview);
   6231 		}
   6232 
   6233 		if (zone_element_latest != NULL) {
   6234 			for (element = cfg_list_first(zonelist);
   6235 			     element != NULL; element = cfg_list_next(element))
   6236 			{
   6237 				const cfg_obj_t *zconfig =
   6238 					cfg_listelt_value(element);
   6239 				configure_zone_setviewcommit(result, zconfig,
   6240 							     view);
   6241 				if (element == zone_element_latest) {
   6242 					/*
   6243 					 * This was the latest element that was
   6244 					 * successfully configured earlier.
   6245 					 */
   6246 					break;
   6247 				}
   6248 			}
   6249 		}
   6250 	}
   6251 
   6252 	if (ntatable != NULL) {
   6253 		dns_ntatable_detach(&ntatable);
   6254 	}
   6255 	if (clients != NULL) {
   6256 		dns_acl_detach(&clients);
   6257 	}
   6258 	if (mapped != NULL) {
   6259 		dns_acl_detach(&mapped);
   6260 	}
   6261 	if (excluded != NULL) {
   6262 		dns_acl_detach(&excluded);
   6263 	}
   6264 	if (ring != NULL) {
   6265 		dns_tsigkeyring_detach(&ring);
   6266 	}
   6267 	if (zone != NULL) {
   6268 		dns_zone_detach(&zone);
   6269 	}
   6270 	if (dispatch4 != NULL) {
   6271 		dns_dispatch_detach(&dispatch4);
   6272 	}
   6273 	if (dispatch6 != NULL) {
   6274 		dns_dispatch_detach(&dispatch6);
   6275 	}
   6276 	if (resstats != NULL) {
   6277 		isc_stats_detach(&resstats);
   6278 	}
   6279 	if (resquerystats != NULL) {
   6280 		dns_stats_detach(&resquerystats);
   6281 	}
   6282 	if (order != NULL) {
   6283 		dns_order_detach(&order);
   6284 	}
   6285 	if (cache != NULL) {
   6286 		dns_cache_detach(&cache);
   6287 	}
   6288 	if (dctx != NULL) {
   6289 		dns_dyndb_destroyctx(&dctx);
   6290 	}
   6291 
   6292 	return result;
   6293 }
   6294 
   6295 static isc_result_t
   6296 configure_hints(dns_view_t *view, const char *filename) {
   6297 	isc_result_t result;
   6298 	dns_db_t *db;
   6299 
   6300 	db = NULL;
   6301 	result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
   6302 	if (result == ISC_R_SUCCESS) {
   6303 		dns_view_sethints(view, db);
   6304 		dns_db_detach(&db);
   6305 	}
   6306 
   6307 	return result;
   6308 }
   6309 
   6310 static isc_result_t
   6311 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
   6312 		     const cfg_obj_t *alternates) {
   6313 	const cfg_obj_t *portobj;
   6314 	const cfg_obj_t *addresses;
   6315 	const cfg_listelt_t *element;
   6316 	isc_result_t result = ISC_R_SUCCESS;
   6317 	in_port_t port;
   6318 
   6319 	/*
   6320 	 * Determine which port to send requests to.
   6321 	 */
   6322 	CHECKM(named_config_getport(config, "port", &port), "port");
   6323 
   6324 	if (alternates != NULL) {
   6325 		portobj = cfg_tuple_get(alternates, "port");
   6326 		if (cfg_obj_isuint32(portobj)) {
   6327 			uint32_t val = cfg_obj_asuint32(portobj);
   6328 			if (val > UINT16_MAX) {
   6329 				cfg_obj_log(portobj, named_g_lctx,
   6330 					    ISC_LOG_ERROR,
   6331 					    "port '%u' out of range", val);
   6332 				return ISC_R_RANGE;
   6333 			}
   6334 			port = (in_port_t)val;
   6335 		}
   6336 	}
   6337 
   6338 	addresses = NULL;
   6339 	if (alternates != NULL) {
   6340 		addresses = cfg_tuple_get(alternates, "addresses");
   6341 	}
   6342 
   6343 	for (element = cfg_list_first(addresses); element != NULL;
   6344 	     element = cfg_list_next(element))
   6345 	{
   6346 		const cfg_obj_t *alternate = cfg_listelt_value(element);
   6347 		isc_sockaddr_t sa;
   6348 
   6349 		if (!cfg_obj_issockaddr(alternate)) {
   6350 			dns_fixedname_t fixed;
   6351 			dns_name_t *name;
   6352 			const char *str = cfg_obj_asstring(
   6353 				cfg_tuple_get(alternate, "name"));
   6354 			isc_buffer_t buffer;
   6355 			in_port_t myport = port;
   6356 
   6357 			isc_buffer_constinit(&buffer, str, strlen(str));
   6358 			isc_buffer_add(&buffer, strlen(str));
   6359 			name = dns_fixedname_initname(&fixed);
   6360 			CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
   6361 						NULL));
   6362 
   6363 			portobj = cfg_tuple_get(alternate, "port");
   6364 			if (cfg_obj_isuint32(portobj)) {
   6365 				uint32_t val = cfg_obj_asuint32(portobj);
   6366 				if (val > UINT16_MAX) {
   6367 					cfg_obj_log(portobj, named_g_lctx,
   6368 						    ISC_LOG_ERROR,
   6369 						    "port '%u' out of range",
   6370 						    val);
   6371 					return ISC_R_RANGE;
   6372 				}
   6373 				myport = (in_port_t)val;
   6374 			}
   6375 			dns_resolver_addalternate(view->resolver, NULL, name,
   6376 						  myport);
   6377 			continue;
   6378 		}
   6379 
   6380 		sa = *cfg_obj_assockaddr(alternate);
   6381 		if (isc_sockaddr_getport(&sa) == 0) {
   6382 			isc_sockaddr_setport(&sa, port);
   6383 		}
   6384 		dns_resolver_addalternate(view->resolver, &sa, NULL, 0);
   6385 	}
   6386 
   6387 cleanup:
   6388 	return result;
   6389 }
   6390 
   6391 static isc_result_t
   6392 validate_tls(const cfg_obj_t *config, dns_view_t *view, const cfg_obj_t *obj,
   6393 	     isc_log_t *logctx, const char *str, dns_name_t **name) {
   6394 	dns_fixedname_t fname;
   6395 	dns_name_t *nm = dns_fixedname_initname(&fname);
   6396 	isc_result_t result = dns_name_fromstring(nm, str, dns_rootname, 0,
   6397 						  NULL);
   6398 
   6399 	if (result != ISC_R_SUCCESS) {
   6400 		cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
   6401 			    "'%s' is not a valid name", str);
   6402 		return result;
   6403 	}
   6404 
   6405 	if (strcasecmp(str, "ephemeral") != 0) {
   6406 		const cfg_obj_t *tlsmap = find_maplist(config, "tls", str);
   6407 
   6408 		if (tlsmap == NULL) {
   6409 			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
   6410 				    "tls '%s' is not defined", str);
   6411 			return ISC_R_FAILURE;
   6412 		}
   6413 	}
   6414 
   6415 	if (name != NULL && *name == NULL) {
   6416 		*name = isc_mem_get(view->mctx, sizeof(dns_name_t));
   6417 		dns_name_init(*name, NULL);
   6418 		dns_name_dup(nm, view->mctx, *name);
   6419 	}
   6420 
   6421 	return ISC_R_SUCCESS;
   6422 }
   6423 
   6424 static isc_result_t
   6425 configure_forward(const cfg_obj_t *config, dns_view_t *view,
   6426 		  const dns_name_t *origin, const cfg_obj_t *forwarders,
   6427 		  const cfg_obj_t *forwardtype) {
   6428 	const cfg_obj_t *portobj = NULL;
   6429 	const cfg_obj_t *tlspobj = NULL;
   6430 	const cfg_obj_t *faddresses = NULL;
   6431 	const cfg_listelt_t *element = NULL;
   6432 	dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
   6433 	dns_forwarderlist_t fwdlist;
   6434 	dns_forwarder_t *fwd = NULL;
   6435 	isc_result_t result;
   6436 	in_port_t port;
   6437 	in_port_t tls_port;
   6438 	const char *tls = NULL;
   6439 
   6440 	ISC_LIST_INIT(fwdlist);
   6441 
   6442 	/*
   6443 	 * Determine which port to send forwarded requests to.
   6444 	 */
   6445 	CHECKM(named_config_getport(config, "port", &port), "port");
   6446 	CHECKM(named_config_getport(config, "tls-port", &tls_port), "tls-port");
   6447 
   6448 	if (forwarders != NULL) {
   6449 		portobj = cfg_tuple_get(forwarders, "port");
   6450 		if (cfg_obj_isuint32(portobj)) {
   6451 			uint32_t val = cfg_obj_asuint32(portobj);
   6452 			if (val > UINT16_MAX) {
   6453 				cfg_obj_log(portobj, named_g_lctx,
   6454 					    ISC_LOG_ERROR,
   6455 					    "port '%u' out of range", val);
   6456 				return ISC_R_RANGE;
   6457 			}
   6458 			port = tls_port = (in_port_t)val;
   6459 		}
   6460 	}
   6461 
   6462 	/*
   6463 	 * TLS value for forwarded requests.
   6464 	 */
   6465 	if (forwarders != NULL) {
   6466 		tlspobj = cfg_tuple_get(forwarders, "tls");
   6467 		if (cfg_obj_isstring(tlspobj)) {
   6468 			tls = cfg_obj_asstring(tlspobj);
   6469 			if (tls != NULL) {
   6470 				result = validate_tls(config, view, tlspobj,
   6471 						      named_g_lctx, tls, NULL);
   6472 				if (result != ISC_R_SUCCESS) {
   6473 					return result;
   6474 				}
   6475 			}
   6476 		}
   6477 	}
   6478 
   6479 	faddresses = NULL;
   6480 	if (forwarders != NULL) {
   6481 		faddresses = cfg_tuple_get(forwarders, "addresses");
   6482 	}
   6483 
   6484 	for (element = cfg_list_first(faddresses); element != NULL;
   6485 	     element = cfg_list_next(element))
   6486 	{
   6487 		const cfg_obj_t *forwarder = cfg_listelt_value(element);
   6488 		const char *cur_tls = NULL;
   6489 
   6490 		fwd = isc_mem_get(view->mctx, sizeof(dns_forwarder_t));
   6491 		fwd->tlsname = NULL;
   6492 		cur_tls = cfg_obj_getsockaddrtls(forwarder);
   6493 		if (cur_tls == NULL) {
   6494 			cur_tls = tls;
   6495 		}
   6496 		if (cur_tls != NULL) {
   6497 			result = validate_tls(config, view, faddresses,
   6498 					      named_g_lctx, cur_tls,
   6499 					      &fwd->tlsname);
   6500 			if (result != ISC_R_SUCCESS) {
   6501 				isc_mem_put(view->mctx, fwd,
   6502 					    sizeof(dns_forwarder_t));
   6503 				goto cleanup;
   6504 			}
   6505 		}
   6506 		fwd->addr = *cfg_obj_assockaddr(forwarder);
   6507 		if (isc_sockaddr_getport(&fwd->addr) == 0) {
   6508 			isc_sockaddr_setport(&fwd->addr,
   6509 					     cur_tls != NULL ? tls_port : port);
   6510 		}
   6511 		ISC_LINK_INIT(fwd, link);
   6512 		ISC_LIST_APPEND(fwdlist, fwd, link);
   6513 	}
   6514 
   6515 	if (ISC_LIST_EMPTY(fwdlist)) {
   6516 		if (forwardtype != NULL) {
   6517 			cfg_obj_log(forwardtype, named_g_lctx, ISC_LOG_WARNING,
   6518 				    "no forwarders seen; disabling "
   6519 				    "forwarding");
   6520 		}
   6521 		fwdpolicy = dns_fwdpolicy_none;
   6522 	} else {
   6523 		if (forwardtype == NULL) {
   6524 			fwdpolicy = dns_fwdpolicy_first;
   6525 		} else {
   6526 			const char *forwardstr = cfg_obj_asstring(forwardtype);
   6527 			if (strcasecmp(forwardstr, "first") == 0) {
   6528 				fwdpolicy = dns_fwdpolicy_first;
   6529 			} else if (strcasecmp(forwardstr, "only") == 0) {
   6530 				fwdpolicy = dns_fwdpolicy_only;
   6531 			} else {
   6532 				UNREACHABLE();
   6533 			}
   6534 		}
   6535 	}
   6536 
   6537 	result = dns_fwdtable_addfwd(view->fwdtable, origin, &fwdlist,
   6538 				     fwdpolicy);
   6539 	if (result != ISC_R_SUCCESS) {
   6540 		char namebuf[DNS_NAME_FORMATSIZE];
   6541 		dns_name_format(origin, namebuf, sizeof(namebuf));
   6542 		cfg_obj_log(forwarders, named_g_lctx, ISC_LOG_WARNING,
   6543 			    "could not set up forwarding for domain '%s': %s",
   6544 			    namebuf, isc_result_totext(result));
   6545 		goto cleanup;
   6546 	}
   6547 
   6548 	if (fwdpolicy == dns_fwdpolicy_only) {
   6549 		dns_view_sfd_add(view, origin);
   6550 	}
   6551 
   6552 	result = ISC_R_SUCCESS;
   6553 
   6554 cleanup:
   6555 
   6556 	while (!ISC_LIST_EMPTY(fwdlist)) {
   6557 		fwd = ISC_LIST_HEAD(fwdlist);
   6558 		ISC_LIST_UNLINK(fwdlist, fwd, link);
   6559 		if (fwd->tlsname != NULL) {
   6560 			dns_name_free(fwd->tlsname, view->mctx);
   6561 			isc_mem_put(view->mctx, fwd->tlsname,
   6562 				    sizeof(dns_name_t));
   6563 		}
   6564 		isc_mem_put(view->mctx, fwd, sizeof(dns_forwarder_t));
   6565 	}
   6566 
   6567 	return result;
   6568 }
   6569 
   6570 static isc_result_t
   6571 get_viewinfo(const cfg_obj_t *vconfig, const char **namep,
   6572 	     dns_rdataclass_t *classp) {
   6573 	isc_result_t result = ISC_R_SUCCESS;
   6574 	const char *viewname;
   6575 	dns_rdataclass_t viewclass;
   6576 
   6577 	REQUIRE(namep != NULL && *namep == NULL);
   6578 	REQUIRE(classp != NULL);
   6579 
   6580 	if (vconfig != NULL) {
   6581 		const cfg_obj_t *classobj = NULL;
   6582 
   6583 		viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
   6584 		classobj = cfg_tuple_get(vconfig, "class");
   6585 		CHECK(named_config_getclass(classobj, dns_rdataclass_in,
   6586 					    &viewclass));
   6587 		if (dns_rdataclass_ismeta(viewclass)) {
   6588 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   6589 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   6590 				      "view '%s': class must not be meta",
   6591 				      viewname);
   6592 			CHECK(ISC_R_FAILURE);
   6593 		}
   6594 	} else {
   6595 		viewname = "_default";
   6596 		viewclass = dns_rdataclass_in;
   6597 	}
   6598 
   6599 	*namep = viewname;
   6600 	*classp = viewclass;
   6601 
   6602 cleanup:
   6603 	return result;
   6604 }
   6605 
   6606 /*
   6607  * Find a view based on its configuration info and attach to it.
   6608  *
   6609  * If 'vconfig' is NULL, attach to the default view.
   6610  */
   6611 static isc_result_t
   6612 find_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
   6613 	  dns_view_t **viewp) {
   6614 	isc_result_t result;
   6615 	const char *viewname = NULL;
   6616 	dns_rdataclass_t viewclass;
   6617 	dns_view_t *view = NULL;
   6618 
   6619 	result = get_viewinfo(vconfig, &viewname, &viewclass);
   6620 	if (result != ISC_R_SUCCESS) {
   6621 		return result;
   6622 	}
   6623 
   6624 	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
   6625 	if (result != ISC_R_SUCCESS) {
   6626 		return result;
   6627 	}
   6628 
   6629 	*viewp = view;
   6630 	return ISC_R_SUCCESS;
   6631 }
   6632 
   6633 /*
   6634  * Create a new view and add it to the list.
   6635  *
   6636  * If 'vconfig' is NULL, create the default view.
   6637  *
   6638  * The view created is attached to '*viewp'.
   6639  */
   6640 static isc_result_t
   6641 create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
   6642 	    dns_view_t **viewp) {
   6643 	isc_result_t result;
   6644 	const char *viewname = NULL;
   6645 	dns_rdataclass_t viewclass;
   6646 	dns_view_t *view = NULL;
   6647 
   6648 	result = get_viewinfo(vconfig, &viewname, &viewclass);
   6649 	if (result != ISC_R_SUCCESS) {
   6650 		return result;
   6651 	}
   6652 
   6653 	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
   6654 	if (result == ISC_R_SUCCESS) {
   6655 		return ISC_R_EXISTS;
   6656 	}
   6657 	if (result != ISC_R_NOTFOUND) {
   6658 		return result;
   6659 	}
   6660 	INSIST(view == NULL);
   6661 
   6662 	result = dns_view_create(named_g_mctx, named_g_loopmgr,
   6663 				 named_g_dispatchmgr, viewclass, viewname,
   6664 				 &view);
   6665 	if (result != ISC_R_SUCCESS) {
   6666 		return result;
   6667 	}
   6668 
   6669 	isc_nonce_buf(view->secret, sizeof(view->secret));
   6670 
   6671 	ISC_LIST_APPEND(*viewlist, view, link);
   6672 	dns_view_attach(view, viewp);
   6673 	return ISC_R_SUCCESS;
   6674 }
   6675 
   6676 /*
   6677  * Configure or reconfigure a zone.
   6678  */
   6679 static isc_result_t
   6680 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
   6681 	       const cfg_obj_t *vconfig, dns_view_t *view,
   6682 	       dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
   6683 	       dns_keystorelist_t *keystores, cfg_aclconfctx_t *aclconf,
   6684 	       bool added, bool old_rpz_ok, bool is_catz_member, bool modify) {
   6685 	dns_view_t *pview = NULL; /* Production view */
   6686 	dns_zone_t *zone = NULL;  /* New or reused zone */
   6687 	dns_zone_t *raw = NULL;	  /* New or reused raw zone */
   6688 	dns_zone_t *dupzone = NULL;
   6689 	const cfg_obj_t *options = NULL;
   6690 	const cfg_obj_t *zoptions = NULL;
   6691 	const cfg_obj_t *typeobj = NULL;
   6692 	const cfg_obj_t *forwarders = NULL;
   6693 	const cfg_obj_t *forwardtype = NULL;
   6694 	const cfg_obj_t *ixfrfromdiffs = NULL;
   6695 	const cfg_obj_t *viewobj = NULL;
   6696 	isc_result_t result = ISC_R_SUCCESS;
   6697 	isc_result_t tresult;
   6698 	isc_buffer_t buffer;
   6699 	dns_fixedname_t fixorigin;
   6700 	dns_name_t *origin;
   6701 	const char *zname;
   6702 	dns_rdataclass_t zclass;
   6703 	const char *ztypestr;
   6704 	dns_rpz_num_t rpz_num;
   6705 	bool zone_is_catz = false;
   6706 	bool zone_maybe_inline = false;
   6707 	bool inline_signing = false;
   6708 	bool fullsign = false;
   6709 
   6710 	options = NULL;
   6711 	(void)cfg_map_get(config, "options", &options);
   6712 
   6713 	zoptions = cfg_tuple_get(zconfig, "options");
   6714 
   6715 	/*
   6716 	 * Get the zone origin as a dns_name_t.
   6717 	 */
   6718 	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
   6719 	isc_buffer_constinit(&buffer, zname, strlen(zname));
   6720 	isc_buffer_add(&buffer, strlen(zname));
   6721 	dns_fixedname_init(&fixorigin);
   6722 	CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), &buffer,
   6723 				dns_rootname, 0, NULL));
   6724 	origin = dns_fixedname_name(&fixorigin);
   6725 
   6726 	CHECK(named_config_getclass(cfg_tuple_get(zconfig, "class"),
   6727 				    view->rdclass, &zclass));
   6728 	if (zclass != view->rdclass) {
   6729 		const char *vname = NULL;
   6730 		if (vconfig != NULL) {
   6731 			vname = cfg_obj_asstring(
   6732 				cfg_tuple_get(vconfig, "name"));
   6733 		} else {
   6734 			vname = "<default view>";
   6735 		}
   6736 
   6737 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   6738 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   6739 			      "zone '%s': wrong class for view '%s'", zname,
   6740 			      vname);
   6741 		result = ISC_R_FAILURE;
   6742 		goto cleanup;
   6743 	}
   6744 
   6745 	(void)cfg_map_get(zoptions, "in-view", &viewobj);
   6746 	if (viewobj != NULL) {
   6747 		const char *inview = cfg_obj_asstring(viewobj);
   6748 		dns_view_t *otherview = NULL;
   6749 
   6750 		if (viewlist == NULL) {
   6751 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
   6752 				    "'in-view' option is not permitted in "
   6753 				    "dynamically added zones");
   6754 			result = ISC_R_FAILURE;
   6755 			goto cleanup;
   6756 		}
   6757 
   6758 		result = dns_viewlist_find(viewlist, inview, view->rdclass,
   6759 					   &otherview);
   6760 		if (result != ISC_R_SUCCESS) {
   6761 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
   6762 				    "view '%s' is not yet defined.", inview);
   6763 			result = ISC_R_FAILURE;
   6764 			goto cleanup;
   6765 		}
   6766 
   6767 		result = dns_view_findzone(otherview, origin, DNS_ZTFIND_EXACT,
   6768 					   &zone);
   6769 		dns_view_detach(&otherview);
   6770 		if (result != ISC_R_SUCCESS) {
   6771 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
   6772 				    "zone '%s' not defined in view '%s'", zname,
   6773 				    inview);
   6774 			result = ISC_R_FAILURE;
   6775 			goto cleanup;
   6776 		}
   6777 
   6778 		CHECK(dns_view_addzone(view, zone));
   6779 		dns_zone_detach(&zone);
   6780 
   6781 		/*
   6782 		 * If the zone contains a 'forwarders' statement, configure
   6783 		 * selective forwarding.  Note: this is not inherited from the
   6784 		 * other view.
   6785 		 */
   6786 		forwarders = NULL;
   6787 		result = cfg_map_get(zoptions, "forwarders", &forwarders);
   6788 		if (result == ISC_R_SUCCESS) {
   6789 			forwardtype = NULL;
   6790 			(void)cfg_map_get(zoptions, "forward", &forwardtype);
   6791 			CHECK(configure_forward(config, view, origin,
   6792 						forwarders, forwardtype));
   6793 		}
   6794 		result = ISC_R_SUCCESS;
   6795 		goto cleanup;
   6796 	}
   6797 
   6798 	(void)cfg_map_get(zoptions, "type", &typeobj);
   6799 	if (typeobj == NULL) {
   6800 		cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
   6801 			    "zone '%s' 'type' not specified", zname);
   6802 		result = ISC_R_FAILURE;
   6803 		goto cleanup;
   6804 	}
   6805 	ztypestr = cfg_obj_asstring(typeobj);
   6806 
   6807 	/*
   6808 	 * "hints zones" aren't zones.	If we've got one,
   6809 	 * configure it and return.
   6810 	 */
   6811 	if (strcasecmp(ztypestr, "hint") == 0) {
   6812 		const cfg_obj_t *fileobj = NULL;
   6813 		if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
   6814 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   6815 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   6816 				      "zone '%s': 'file' not specified", zname);
   6817 			result = ISC_R_FAILURE;
   6818 			goto cleanup;
   6819 		}
   6820 		if (dns_name_equal(origin, dns_rootname)) {
   6821 			const char *hintsfile = cfg_obj_asstring(fileobj);
   6822 
   6823 			CHECK(configure_hints(view, hintsfile));
   6824 		} else {
   6825 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   6826 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   6827 				      "ignoring non-root hint zone '%s'",
   6828 				      zname);
   6829 			result = ISC_R_SUCCESS;
   6830 		}
   6831 		/* Skip ordinary zone processing. */
   6832 		goto cleanup;
   6833 	}
   6834 
   6835 	/*
   6836 	 * "forward zones" aren't zones either.  Translate this syntax into
   6837 	 * the appropriate selective forwarding configuration and return.
   6838 	 */
   6839 	if (strcasecmp(ztypestr, "forward") == 0) {
   6840 		forwardtype = NULL;
   6841 		forwarders = NULL;
   6842 
   6843 		(void)cfg_map_get(zoptions, "forward", &forwardtype);
   6844 		(void)cfg_map_get(zoptions, "forwarders", &forwarders);
   6845 		CHECK(configure_forward(config, view, origin, forwarders,
   6846 					forwardtype));
   6847 		goto cleanup;
   6848 	}
   6849 
   6850 	/*
   6851 	 * Redirect zones only require minimal configuration.
   6852 	 */
   6853 	if (strcasecmp(ztypestr, "redirect") == 0) {
   6854 		if (view->redirect != NULL) {
   6855 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
   6856 				    "redirect zone already exists");
   6857 			result = ISC_R_EXISTS;
   6858 			goto cleanup;
   6859 		}
   6860 		result = dns_viewlist_find(viewlist, view->name, view->rdclass,
   6861 					   &pview);
   6862 		if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
   6863 			goto cleanup;
   6864 		}
   6865 		if (pview != NULL && pview->redirect != NULL) {
   6866 			dns_zone_attach(pview->redirect, &zone);
   6867 			dns_zone_setview(zone, view);
   6868 		} else {
   6869 			CHECK(dns_zonemgr_createzone(named_g_server->zonemgr,
   6870 						     &zone));
   6871 			CHECK(dns_zone_setorigin(zone, origin));
   6872 			dns_zone_setview(zone, view);
   6873 			CHECK(dns_zonemgr_managezone(named_g_server->zonemgr,
   6874 						     zone));
   6875 			dns_zone_setstats(zone, named_g_server->zonestats);
   6876 		}
   6877 		CHECK(named_zone_configure(config, vconfig, zconfig, aclconf,
   6878 					   kasplist, keystores, zone, NULL));
   6879 		dns_zone_attach(zone, &view->redirect);
   6880 		goto cleanup;
   6881 	}
   6882 
   6883 	if (!modify) {
   6884 		/*
   6885 		 * Check for duplicates in the new zone table.
   6886 		 */
   6887 		result = dns_view_findzone(view, origin, DNS_ZTFIND_EXACT,
   6888 					   &dupzone);
   6889 		if (result == ISC_R_SUCCESS) {
   6890 			/*
   6891 			 * We already have this zone!
   6892 			 */
   6893 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
   6894 				    "zone '%s' already exists", zname);
   6895 			dns_zone_detach(&dupzone);
   6896 			result = ISC_R_EXISTS;
   6897 			goto cleanup;
   6898 		}
   6899 		INSIST(dupzone == NULL);
   6900 	}
   6901 
   6902 	/*
   6903 	 * Note whether this is a response policy zone and which one if so,
   6904 	 * unless we are using RPZ service interface.  In that case, the
   6905 	 * BIND zone database has nothing to do with rpz and so we don't care.
   6906 	 */
   6907 	for (rpz_num = 0;; ++rpz_num) {
   6908 		if (view->rpzs == NULL || rpz_num >= view->rpzs->p.num_zones ||
   6909 		    view->rpzs->p.dnsrps_enabled)
   6910 		{
   6911 			rpz_num = DNS_RPZ_INVALID_NUM;
   6912 			break;
   6913 		}
   6914 		if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin, origin))
   6915 		{
   6916 			break;
   6917 		}
   6918 	}
   6919 
   6920 	if (!is_catz_member && view->catzs != NULL &&
   6921 	    dns_catz_zone_get(view->catzs, origin) != NULL)
   6922 	{
   6923 		zone_is_catz = true;
   6924 	}
   6925 
   6926 	/*
   6927 	 * See if we can reuse an existing zone.  This is
   6928 	 * only possible if all of these are true:
   6929 	 *   - The zone's view exists
   6930 	 *   - A zone with the right name exists in the view
   6931 	 *   - The zone is compatible with the config
   6932 	 *     options (e.g., an existing primary zone cannot
   6933 	 *     be reused if the options specify a secondary zone)
   6934 	 *   - The zone was not and is still not a response policy zone
   6935 	 *     or the zone is a policy zone with an unchanged number
   6936 	 *     and we are using the old policy zone summary data.
   6937 	 */
   6938 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
   6939 				   view->rdclass, &pview);
   6940 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
   6941 		goto cleanup;
   6942 	}
   6943 	if (pview != NULL) {
   6944 		result = dns_view_findzone(pview, origin, DNS_ZTFIND_EXACT,
   6945 					   &zone);
   6946 	}
   6947 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
   6948 		goto cleanup;
   6949 	}
   6950 
   6951 	if (zone != NULL &&
   6952 	    !named_zone_reusable(zone, zconfig, vconfig, config, kasplist))
   6953 	{
   6954 		dns_zone_detach(&zone);
   6955 		fullsign = true;
   6956 	}
   6957 
   6958 	if (zone != NULL && (rpz_num != dns_zone_get_rpz_num(zone) ||
   6959 			     (rpz_num != DNS_RPZ_INVALID_NUM && !old_rpz_ok)))
   6960 	{
   6961 		dns_zone_detach(&zone);
   6962 	}
   6963 
   6964 	if (zone != NULL) {
   6965 		/*
   6966 		 * We found a reusable zone.  Make it use the
   6967 		 * new view.
   6968 		 */
   6969 		dns_zone_setview(zone, view);
   6970 	} else {
   6971 		/*
   6972 		 * We cannot reuse an existing zone, we have
   6973 		 * to create a new one.
   6974 		 */
   6975 		CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
   6976 		CHECK(dns_zone_setorigin(zone, origin));
   6977 		dns_zone_setview(zone, view);
   6978 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
   6979 		dns_zone_setstats(zone, named_g_server->zonestats);
   6980 	}
   6981 	if (rpz_num != DNS_RPZ_INVALID_NUM) {
   6982 		result = dns_zone_rpz_enable(zone, view->rpzs, rpz_num);
   6983 		if (result != ISC_R_SUCCESS) {
   6984 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   6985 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   6986 				      "zone '%s': incompatible"
   6987 				      " masterfile-format or database"
   6988 				      " for a response policy zone",
   6989 				      zname);
   6990 			goto cleanup;
   6991 		}
   6992 	}
   6993 
   6994 	if (zone_is_catz) {
   6995 		dns_zone_catz_enable(zone, view->catzs);
   6996 	} else if (dns_zone_catz_is_enabled(zone)) {
   6997 		dns_zone_catz_disable(zone);
   6998 	}
   6999 
   7000 	/*
   7001 	 * If the zone contains a 'forwarders' statement, configure
   7002 	 * selective forwarding.
   7003 	 */
   7004 	forwarders = NULL;
   7005 	if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) {
   7006 		forwardtype = NULL;
   7007 		(void)cfg_map_get(zoptions, "forward", &forwardtype);
   7008 		CHECK(configure_forward(config, view, origin, forwarders,
   7009 					forwardtype));
   7010 	}
   7011 
   7012 	/*
   7013 	 * Mark whether the zone was originally added at runtime or not
   7014 	 */
   7015 	if (!modify) {
   7016 		dns_zone_setadded(zone, added);
   7017 	}
   7018 
   7019 	/*
   7020 	 * Determine if we need to set up inline signing.
   7021 	 */
   7022 	zone_maybe_inline = (strcasecmp(ztypestr, "primary") == 0 ||
   7023 			     strcasecmp(ztypestr, "master") == 0 ||
   7024 			     strcasecmp(ztypestr, "secondary") == 0 ||
   7025 			     strcasecmp(ztypestr, "slave") == 0);
   7026 
   7027 	if (zone_maybe_inline) {
   7028 		inline_signing = named_zone_inlinesigning(zconfig, vconfig,
   7029 							  config, kasplist);
   7030 	}
   7031 	if (inline_signing) {
   7032 		dns_zone_getraw(zone, &raw);
   7033 		if (raw == NULL) {
   7034 			dns_zone_create(&raw, dns_zone_getmem(zone),
   7035 					dns_zone_gettid(zone));
   7036 			CHECK(dns_zone_setorigin(raw, origin));
   7037 			dns_zone_setview(raw, view);
   7038 			dns_zone_setstats(raw, named_g_server->zonestats);
   7039 			CHECK(dns_zone_link(zone, raw));
   7040 		}
   7041 		if (cfg_map_get(zoptions, "ixfr-from-differences",
   7042 				&ixfrfromdiffs) == ISC_R_SUCCESS)
   7043 		{
   7044 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7045 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   7046 				      "zone '%s': 'ixfr-from-differences' is "
   7047 				      "ignored for inline-signed zones",
   7048 				      zname);
   7049 		}
   7050 	}
   7051 
   7052 	/*
   7053 	 * Configure the zone.
   7054 	 */
   7055 	CHECK(named_zone_configure(config, vconfig, zconfig, aclconf, kasplist,
   7056 				   keystores, zone, raw));
   7057 
   7058 	/*
   7059 	 * Add the zone to its view in the new view list.
   7060 	 */
   7061 	if (!modify) {
   7062 		CHECK(dns_view_addzone(view, zone));
   7063 	}
   7064 
   7065 	if (zone_is_catz) {
   7066 		/*
   7067 		 * force catz reload if the zone is loaded;
   7068 		 * if it's not it'll get reloaded on zone load
   7069 		 */
   7070 		dns_db_t *db = NULL;
   7071 
   7072 		tresult = dns_zone_getdb(zone, &db);
   7073 		if (tresult == ISC_R_SUCCESS) {
   7074 			dns_catz_dbupdate_callback(db, view->catzs);
   7075 			dns_db_detach(&db);
   7076 		}
   7077 	}
   7078 
   7079 	/*
   7080 	 * Ensure that zone keys are reloaded on reconfig
   7081 	 */
   7082 	if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0) {
   7083 		dns_zone_rekey(zone, fullsign, false);
   7084 	}
   7085 
   7086 cleanup:
   7087 	if (zone != NULL) {
   7088 		dns_zone_detach(&zone);
   7089 	}
   7090 	if (raw != NULL) {
   7091 		dns_zone_detach(&raw);
   7092 	}
   7093 	if (pview != NULL) {
   7094 		dns_view_detach(&pview);
   7095 	}
   7096 
   7097 	return result;
   7098 }
   7099 
   7100 /*
   7101  * Configure built-in zone for storing managed-key data.
   7102  */
   7103 static isc_result_t
   7104 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
   7105 	isc_result_t result;
   7106 	dns_view_t *pview = NULL;
   7107 	dns_zone_t *zone = NULL;
   7108 	dns_acl_t *none = NULL;
   7109 	char filename[PATH_MAX];
   7110 	bool defaultview;
   7111 
   7112 	REQUIRE(view != NULL);
   7113 
   7114 	/* See if we can re-use an existing keydata zone. */
   7115 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
   7116 				   view->rdclass, &pview);
   7117 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
   7118 		return result;
   7119 	}
   7120 
   7121 	if (pview != NULL) {
   7122 		if (pview->managed_keys != NULL) {
   7123 			dns_zone_attach(pview->managed_keys,
   7124 					&view->managed_keys);
   7125 			dns_zone_setview(pview->managed_keys, view);
   7126 			dns_zone_setviewcommit(pview->managed_keys);
   7127 			dns_view_detach(&pview);
   7128 			dns_zone_synckeyzone(view->managed_keys);
   7129 			return ISC_R_SUCCESS;
   7130 		}
   7131 
   7132 		dns_view_detach(&pview);
   7133 	}
   7134 
   7135 	/* No existing keydata zone was found; create one */
   7136 	CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
   7137 	CHECK(dns_zone_setorigin(zone, dns_rootname));
   7138 
   7139 	defaultview = (strcmp(view->name, "_default") == 0);
   7140 	CHECK(isc_file_sanitize(
   7141 		directory, defaultview ? "managed-keys" : view->name,
   7142 		defaultview ? "bind" : "mkeys", filename, sizeof(filename)));
   7143 	CHECK(dns_zone_setfile(zone, filename, dns_masterformat_text,
   7144 			       &dns_master_style_default));
   7145 
   7146 	dns_zone_setview(zone, view);
   7147 	dns_zone_settype(zone, dns_zone_key);
   7148 	dns_zone_setclass(zone, view->rdclass);
   7149 
   7150 	CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
   7151 
   7152 	CHECK(dns_acl_none(mctx, &none));
   7153 	dns_zone_setqueryacl(zone, none);
   7154 	dns_zone_setqueryonacl(zone, none);
   7155 	dns_acl_detach(&none);
   7156 
   7157 	dns_zone_setdialup(zone, dns_dialuptype_no);
   7158 	dns_zone_setcheckdstype(zone, dns_checkdstype_no);
   7159 	dns_zone_setnotifytype(zone, dns_notifytype_no);
   7160 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
   7161 	dns_zone_setjournalsize(zone, 0);
   7162 
   7163 	dns_zone_setstats(zone, named_g_server->zonestats);
   7164 	setquerystats(zone, mctx, dns_zonestat_none);
   7165 
   7166 	if (view->managed_keys != NULL) {
   7167 		dns_zone_detach(&view->managed_keys);
   7168 	}
   7169 	dns_zone_attach(zone, &view->managed_keys);
   7170 
   7171 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7172 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   7173 		      "set up managed keys zone for view %s, file '%s'",
   7174 		      view->name, filename);
   7175 
   7176 cleanup:
   7177 	if (zone != NULL) {
   7178 		dns_zone_detach(&zone);
   7179 	}
   7180 	if (none != NULL) {
   7181 		dns_acl_detach(&none);
   7182 	}
   7183 
   7184 	return result;
   7185 }
   7186 
   7187 /*
   7188  * Configure a single server quota.
   7189  */
   7190 static void
   7191 configure_server_quota(const cfg_obj_t **maps, const char *name,
   7192 		       isc_quota_t *quota) {
   7193 	const cfg_obj_t *obj = NULL;
   7194 	isc_result_t result;
   7195 
   7196 	result = named_config_get(maps, name, &obj);
   7197 	INSIST(result == ISC_R_SUCCESS);
   7198 	isc_quota_max(quota, cfg_obj_asuint32(obj));
   7199 }
   7200 
   7201 /*
   7202  * This function is called as soon as the 'directory' statement has been
   7203  * parsed.  This can be extended to support other options if necessary.
   7204  */
   7205 static isc_result_t
   7206 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
   7207 	isc_result_t result;
   7208 	const char *directory;
   7209 
   7210 	REQUIRE(strcasecmp("directory", clausename) == 0);
   7211 
   7212 	UNUSED(arg);
   7213 	UNUSED(clausename);
   7214 
   7215 	/*
   7216 	 * Change directory.
   7217 	 */
   7218 	directory = cfg_obj_asstring(obj);
   7219 
   7220 	if (!isc_file_ischdiridempotent(directory)) {
   7221 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   7222 			    "option 'directory' contains relative path '%s'",
   7223 			    directory);
   7224 	}
   7225 
   7226 	if (!isc_file_isdirwritable(directory)) {
   7227 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7228 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   7229 			      "directory '%s' is not writable", directory);
   7230 		return ISC_R_NOPERM;
   7231 	}
   7232 
   7233 	result = isc_dir_chdir(directory);
   7234 	if (result != ISC_R_SUCCESS) {
   7235 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
   7236 			    "change directory to '%s' failed: %s", directory,
   7237 			    isc_result_totext(result));
   7238 		return result;
   7239 	}
   7240 
   7241 	char cwd[PATH_MAX];
   7242 	if (getcwd(cwd, sizeof(cwd)) == cwd) {
   7243 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7244 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   7245 			      "the working directory is now '%s'", cwd);
   7246 	}
   7247 
   7248 	return ISC_R_SUCCESS;
   7249 }
   7250 
   7251 /*
   7252  * This event callback is invoked to do periodic network interface
   7253  * scanning.
   7254  */
   7255 
   7256 static void
   7257 interface_timer_tick(void *arg) {
   7258 	named_server_t *server = (named_server_t *)arg;
   7259 
   7260 	(void)ns_interfacemgr_scan(server->interfacemgr, false, false);
   7261 }
   7262 
   7263 static void
   7264 heartbeat_timer_tick(void *arg) {
   7265 	named_server_t *server = (named_server_t *)arg;
   7266 	dns_view_t *view = NULL;
   7267 
   7268 	view = ISC_LIST_HEAD(server->viewlist);
   7269 	while (view != NULL) {
   7270 		dns_view_dialup(view);
   7271 		view = ISC_LIST_NEXT(view, link);
   7272 	}
   7273 }
   7274 
   7275 typedef struct {
   7276 	isc_mem_t *mctx;
   7277 	isc_loop_t *loop;
   7278 	dns_fetch_t *fetch;
   7279 	dns_view_t *view;
   7280 	dns_fixedname_t tatname;
   7281 	dns_fixedname_t keyname;
   7282 	dns_rdataset_t rdataset;
   7283 	dns_rdataset_t sigrdataset;
   7284 } ns_tat_t;
   7285 
   7286 static int
   7287 cid(const void *a, const void *b) {
   7288 	const uint16_t ida = *(const uint16_t *)a;
   7289 	const uint16_t idb = *(const uint16_t *)b;
   7290 	if (ida < idb) {
   7291 		return -1;
   7292 	} else if (ida > idb) {
   7293 		return 1;
   7294 	} else {
   7295 		return 0;
   7296 	}
   7297 }
   7298 
   7299 static void
   7300 tat_done(void *arg) {
   7301 	dns_fetchresponse_t *resp = (dns_fetchresponse_t *)arg;
   7302 	ns_tat_t *tat = NULL;
   7303 
   7304 	INSIST(resp != NULL);
   7305 
   7306 	tat = resp->arg;
   7307 
   7308 	INSIST(tat != NULL);
   7309 
   7310 	/* Free resources which are not of interest */
   7311 	if (resp->node != NULL) {
   7312 		dns_db_detachnode(resp->db, &resp->node);
   7313 	}
   7314 	if (resp->db != NULL) {
   7315 		dns_db_detach(&resp->db);
   7316 	}
   7317 
   7318 	dns_resolver_freefresp(&resp);
   7319 	dns_resolver_destroyfetch(&tat->fetch);
   7320 	if (dns_rdataset_isassociated(&tat->rdataset)) {
   7321 		dns_rdataset_disassociate(&tat->rdataset);
   7322 	}
   7323 	if (dns_rdataset_isassociated(&tat->sigrdataset)) {
   7324 		dns_rdataset_disassociate(&tat->sigrdataset);
   7325 	}
   7326 	dns_view_detach(&tat->view);
   7327 	isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
   7328 }
   7329 
   7330 struct dotat_arg {
   7331 	dns_view_t *view;
   7332 	isc_loop_t *loop;
   7333 };
   7334 
   7335 /*%
   7336  * Prepare the QNAME for the TAT query to be sent by processing the trust
   7337  * anchors present at 'keynode' of 'keytable'.  Store the result in 'dst' and
   7338  * the domain name which 'keynode' is associated with in 'origin'.
   7339  *
   7340  * A maximum of 12 key IDs can be reported in a single TAT query due to the
   7341  * 63-octet length limit for any single label in a domain name.  If there are
   7342  * more than 12 keys configured at 'keynode', only the first 12 will be
   7343  * reported in the TAT query.
   7344  */
   7345 static isc_result_t
   7346 get_tat_qname(dns_name_t *target, dns_name_t *keyname, dns_keynode_t *keynode) {
   7347 	dns_rdataset_t dsset;
   7348 	unsigned int i, n = 0;
   7349 	uint16_t ids[12];
   7350 	isc_textregion_t r;
   7351 	char label[64];
   7352 	int m;
   7353 
   7354 	dns_rdataset_init(&dsset);
   7355 	if (dns_keynode_dsset(keynode, &dsset)) {
   7356 		isc_result_t result;
   7357 
   7358 		for (result = dns_rdataset_first(&dsset);
   7359 		     result == ISC_R_SUCCESS;
   7360 		     result = dns_rdataset_next(&dsset))
   7361 		{
   7362 			dns_rdata_t rdata = DNS_RDATA_INIT;
   7363 			dns_rdata_ds_t ds;
   7364 
   7365 			dns_rdata_reset(&rdata);
   7366 			dns_rdataset_current(&dsset, &rdata);
   7367 			result = dns_rdata_tostruct(&rdata, &ds, NULL);
   7368 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7369 			if (n < (sizeof(ids) / sizeof(ids[0]))) {
   7370 				ids[n] = ds.key_tag;
   7371 				n++;
   7372 			}
   7373 		}
   7374 		dns_rdataset_disassociate(&dsset);
   7375 	}
   7376 
   7377 	if (n == 0) {
   7378 		return DNS_R_EMPTYNAME;
   7379 	}
   7380 
   7381 	if (n > 1) {
   7382 		qsort(ids, n, sizeof(ids[0]), cid);
   7383 	}
   7384 
   7385 	/*
   7386 	 * Encoded as "_ta-xxxx\(-xxxx\)*" where xxxx is the hex version of
   7387 	 * of the keyid.
   7388 	 */
   7389 	label[0] = 0;
   7390 	r.base = label;
   7391 	r.length = sizeof(label);
   7392 	m = snprintf(r.base, r.length, "_ta");
   7393 	if (m < 0 || (unsigned int)m > r.length) {
   7394 		return ISC_R_FAILURE;
   7395 	}
   7396 	isc_textregion_consume(&r, m);
   7397 	for (i = 0; i < n; i++) {
   7398 		m = snprintf(r.base, r.length, "-%04x", ids[i]);
   7399 		if (m < 0 || (unsigned int)m > r.length) {
   7400 			return ISC_R_FAILURE;
   7401 		}
   7402 		isc_textregion_consume(&r, m);
   7403 	}
   7404 
   7405 	return dns_name_fromstring(target, label, keyname, 0, NULL);
   7406 }
   7407 
   7408 static void
   7409 tat_send(void *arg) {
   7410 	ns_tat_t *tat = (ns_tat_t *)arg;
   7411 	char namebuf[DNS_NAME_FORMATSIZE];
   7412 	dns_fixedname_t fdomain;
   7413 	dns_name_t *domain = NULL;
   7414 	dns_rdataset_t nameservers;
   7415 	isc_result_t result;
   7416 	dns_name_t *keyname = NULL;
   7417 	dns_name_t *tatname = NULL;
   7418 
   7419 	keyname = dns_fixedname_name(&tat->keyname);
   7420 	tatname = dns_fixedname_name(&tat->tatname);
   7421 
   7422 	dns_name_format(tatname, namebuf, sizeof(namebuf));
   7423 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7424 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   7425 		      "%s: sending trust-anchor-telemetry query '%s/NULL'",
   7426 		      tat->view->name, namebuf);
   7427 
   7428 	/*
   7429 	 * TAT queries should be sent to the authoritative servers for a given
   7430 	 * zone.  If this function is called for a keytable node corresponding
   7431 	 * to a locally served zone, calling dns_resolver_createfetch() with
   7432 	 * NULL 'domain' and 'nameservers' arguments will cause 'tatname' to be
   7433 	 * resolved locally, without sending any TAT queries upstream.
   7434 	 *
   7435 	 * Work around this issue by calling dns_view_findzonecut() first.  If
   7436 	 * the zone is served locally, the NS RRset for the given domain name
   7437 	 * will be retrieved from local data; if it is not, the deepest zone
   7438 	 * cut we have for it will be retrieved from cache.  In either case,
   7439 	 * passing the results to dns_resolver_createfetch() will prevent it
   7440 	 * from returning NXDOMAIN for 'tatname' while still allowing it to
   7441 	 * chase down any potential delegations returned by upstream servers in
   7442 	 * order to eventually find the destination host to send the TAT query
   7443 	 * to.
   7444 	 *
   7445 	 * After the dns_view_findzonecut() call, 'domain' will hold the
   7446 	 * deepest zone cut we can find for 'keyname' while 'nameservers' will
   7447 	 * hold the NS RRset at that zone cut.
   7448 	 */
   7449 	domain = dns_fixedname_initname(&fdomain);
   7450 	dns_rdataset_init(&nameservers);
   7451 	result = dns_view_findzonecut(tat->view, keyname, domain, NULL, 0, 0,
   7452 				      true, true, &nameservers, NULL);
   7453 	if (result == ISC_R_SUCCESS) {
   7454 		result = dns_resolver_createfetch(
   7455 			tat->view->resolver, tatname, dns_rdatatype_null,
   7456 			domain, &nameservers, NULL, NULL, 0, 0, 0, NULL, NULL,
   7457 			NULL, tat->loop, tat_done, tat, NULL, &tat->rdataset,
   7458 			&tat->sigrdataset, &tat->fetch);
   7459 	}
   7460 
   7461 	/*
   7462 	 * 'domain' holds the dns_name_t pointer inside a dst_key_t structure.
   7463 	 * dns_resolver_createfetch() creates its own copy of 'domain' if it
   7464 	 * succeeds.  Thus, 'domain' is not freed here.
   7465 	 *
   7466 	 * Even if dns_view_findzonecut() returned something else than
   7467 	 * ISC_R_SUCCESS, it still could have associated 'nameservers'.
   7468 	 * dns_resolver_createfetch() creates its own copy of 'nameservers' if
   7469 	 * it succeeds.  Thus, we need to check whether 'nameservers' is
   7470 	 * associated and release it if it is.
   7471 	 */
   7472 	if (dns_rdataset_isassociated(&nameservers)) {
   7473 		dns_rdataset_disassociate(&nameservers);
   7474 	}
   7475 
   7476 	if (result != ISC_R_SUCCESS) {
   7477 		dns_view_detach(&tat->view);
   7478 		isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
   7479 	}
   7480 }
   7481 
   7482 static void
   7483 dotat(dns_keytable_t *keytable, dns_keynode_t *keynode, dns_name_t *keyname,
   7484       void *arg) {
   7485 	struct dotat_arg *dotat_arg = (struct dotat_arg *)arg;
   7486 	isc_result_t result;
   7487 	dns_view_t *view = NULL;
   7488 	ns_tat_t *tat = NULL;
   7489 
   7490 	REQUIRE(keytable != NULL);
   7491 	REQUIRE(keynode != NULL);
   7492 	REQUIRE(dotat_arg != NULL);
   7493 
   7494 	view = dotat_arg->view;
   7495 
   7496 	tat = isc_mem_get(view->mctx, sizeof(*tat));
   7497 	*tat = (ns_tat_t){ 0 };
   7498 
   7499 	dns_rdataset_init(&tat->rdataset);
   7500 	dns_rdataset_init(&tat->sigrdataset);
   7501 	dns_name_copy(keyname, dns_fixedname_initname(&tat->keyname));
   7502 	result = get_tat_qname(dns_fixedname_initname(&tat->tatname), keyname,
   7503 			       keynode);
   7504 	if (result != ISC_R_SUCCESS) {
   7505 		isc_mem_put(view->mctx, tat, sizeof(*tat));
   7506 		return;
   7507 	}
   7508 	isc_mem_attach(view->mctx, &tat->mctx);
   7509 	tat->loop = dotat_arg->loop;
   7510 	dns_view_attach(view, &tat->view);
   7511 
   7512 	/*
   7513 	 * We don't want to be holding the keytable lock when calling
   7514 	 * dns_view_findzonecut() as it creates a lock order loop so
   7515 	 * call dns_view_findzonecut() in a event handler.
   7516 	 *
   7517 	 * zone->lock (dns_zone_setviewcommit) while holding view->lock
   7518 	 * (dns_view_setviewcommit)
   7519 	 *
   7520 	 * keytable->lock (dns_keytable_find) while holding zone->lock
   7521 	 * (zone_asyncload)
   7522 	 *
   7523 	 * view->lock (dns_view_findzonecut) while holding keytable->lock
   7524 	 * (dns_keytable_forall)
   7525 	 */
   7526 	isc_async_run(named_g_mainloop, tat_send, tat);
   7527 }
   7528 
   7529 static void
   7530 tat_timer_tick(void *arg) {
   7531 	isc_result_t result;
   7532 	named_server_t *server = (named_server_t *)arg;
   7533 	struct dotat_arg dotat_arg = { 0 };
   7534 	dns_view_t *view = NULL;
   7535 	dns_keytable_t *secroots = NULL;
   7536 
   7537 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   7538 	     view = ISC_LIST_NEXT(view, link))
   7539 	{
   7540 		if (!view->trust_anchor_telemetry || !view->enablevalidation) {
   7541 			continue;
   7542 		}
   7543 
   7544 		result = dns_view_getsecroots(view, &secroots);
   7545 		if (result != ISC_R_SUCCESS) {
   7546 			continue;
   7547 		}
   7548 
   7549 		dotat_arg.view = view;
   7550 		dotat_arg.loop = named_g_mainloop;
   7551 		dns_keytable_forall(secroots, dotat, &dotat_arg);
   7552 		dns_keytable_detach(&secroots);
   7553 	}
   7554 }
   7555 
   7556 static void
   7557 pps_timer_tick(void *arg) {
   7558 	static unsigned int oldrequests = 0;
   7559 	unsigned int requests = atomic_load_relaxed(&ns_client_requests);
   7560 
   7561 	UNUSED(arg);
   7562 
   7563 	/*
   7564 	 * Don't worry about wrapping as the overflow result will be right.
   7565 	 */
   7566 	dns_pps = (requests - oldrequests) / 1200;
   7567 	oldrequests = requests;
   7568 }
   7569 
   7570 /*
   7571  * Replace the current value of '*field', a dynamically allocated
   7572  * string or NULL, with a dynamically allocated copy of the
   7573  * null-terminated string pointed to by 'value', or NULL.
   7574  */
   7575 static void
   7576 setstring(named_server_t *server, char **field, const char *value) {
   7577 	char *copy;
   7578 
   7579 	if (value != NULL) {
   7580 		copy = isc_mem_strdup(server->mctx, value);
   7581 	} else {
   7582 		copy = NULL;
   7583 	}
   7584 
   7585 	if (*field != NULL) {
   7586 		isc_mem_free(server->mctx, *field);
   7587 	}
   7588 
   7589 	*field = copy;
   7590 }
   7591 
   7592 /*
   7593  * Replace the current value of '*field', a dynamically allocated
   7594  * string or NULL, with another dynamically allocated string
   7595  * or NULL if whether 'obj' is a string or void value, respectively.
   7596  */
   7597 static void
   7598 setoptstring(named_server_t *server, char **field, const cfg_obj_t *obj) {
   7599 	if (cfg_obj_isvoid(obj)) {
   7600 		setstring(server, field, NULL);
   7601 	} else {
   7602 		setstring(server, field, cfg_obj_asstring(obj));
   7603 	}
   7604 }
   7605 
   7606 static void
   7607 portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
   7608 		 bool positive) {
   7609 	const cfg_listelt_t *element;
   7610 
   7611 	for (element = cfg_list_first(ports); element != NULL;
   7612 	     element = cfg_list_next(element))
   7613 	{
   7614 		const cfg_obj_t *obj = cfg_listelt_value(element);
   7615 
   7616 		if (cfg_obj_isuint32(obj)) {
   7617 			in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
   7618 
   7619 			if (positive) {
   7620 				isc_portset_add(portset, port);
   7621 			} else {
   7622 				isc_portset_remove(portset, port);
   7623 			}
   7624 		} else {
   7625 			const cfg_obj_t *obj_loport, *obj_hiport;
   7626 			in_port_t loport, hiport;
   7627 
   7628 			obj_loport = cfg_tuple_get(obj, "loport");
   7629 			loport = (in_port_t)cfg_obj_asuint32(obj_loport);
   7630 			obj_hiport = cfg_tuple_get(obj, "hiport");
   7631 			hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
   7632 
   7633 			if (positive) {
   7634 				isc_portset_addrange(portset, loport, hiport);
   7635 			} else {
   7636 				isc_portset_removerange(portset, loport,
   7637 							hiport);
   7638 			}
   7639 		}
   7640 	}
   7641 }
   7642 
   7643 static isc_result_t
   7644 removed(dns_zone_t *zone, void *uap) {
   7645 	if (dns_zone_getview(zone) != uap) {
   7646 		return ISC_R_SUCCESS;
   7647 	}
   7648 
   7649 	dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed",
   7650 		     dns_zonetype_name(dns_zone_gettype(zone)));
   7651 	return ISC_R_SUCCESS;
   7652 }
   7653 
   7654 static void
   7655 cleanup_session_key(named_server_t *server, isc_mem_t *mctx) {
   7656 	if (server->session_keyfile != NULL) {
   7657 		isc_file_remove(server->session_keyfile);
   7658 		isc_mem_free(mctx, server->session_keyfile);
   7659 		server->session_keyfile = NULL;
   7660 	}
   7661 
   7662 	if (server->session_keyname != NULL) {
   7663 		if (dns_name_dynamic(server->session_keyname)) {
   7664 			dns_name_free(server->session_keyname, mctx);
   7665 		}
   7666 		isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t));
   7667 		server->session_keyname = NULL;
   7668 	}
   7669 
   7670 	if (server->sessionkey != NULL) {
   7671 		dst_key_free(&server->sessionkey);
   7672 	}
   7673 
   7674 	server->session_keyalg = DST_ALG_UNKNOWN;
   7675 	server->session_keybits = 0;
   7676 }
   7677 
   7678 static isc_result_t
   7679 generate_session_key(const char *filename, const char *keynamestr,
   7680 		     const dns_name_t *keyname, dst_algorithm_t alg,
   7681 		     uint16_t bits, isc_mem_t *mctx, bool first_time,
   7682 		     dst_key_t **keyp) {
   7683 	isc_result_t result = ISC_R_SUCCESS;
   7684 	dst_key_t *key = NULL;
   7685 	isc_buffer_t key_txtbuffer;
   7686 	isc_buffer_t key_rawbuffer;
   7687 	char key_txtsecret[256];
   7688 	char key_rawsecret[64];
   7689 	isc_region_t key_rawregion;
   7690 	FILE *fp = NULL;
   7691 
   7692 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7693 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   7694 		      "generating session key for dynamic DNS");
   7695 
   7696 	/* generate key */
   7697 	result = dst_key_generate(keyname, alg, bits, 1, 0, DNS_KEYPROTO_ANY,
   7698 				  dns_rdataclass_in, NULL, mctx, &key, NULL);
   7699 	if (result != ISC_R_SUCCESS) {
   7700 		return result;
   7701 	}
   7702 
   7703 	/*
   7704 	 * Dump the key to the buffer for later use.
   7705 	 */
   7706 	isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
   7707 	CHECK(dst_key_tobuffer(key, &key_rawbuffer));
   7708 
   7709 	isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
   7710 	isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
   7711 	CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer));
   7712 
   7713 	/* Dump the key to the key file. */
   7714 	fp = named_os_openfile(filename, S_IRUSR | S_IWUSR, first_time);
   7715 	if (fp == NULL) {
   7716 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7717 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   7718 			      "could not create %s", filename);
   7719 		result = ISC_R_NOPERM;
   7720 		goto cleanup;
   7721 	}
   7722 
   7723 	fprintf(fp,
   7724 		"key \"%s\" {\n"
   7725 		"\talgorithm %s;\n"
   7726 		"\tsecret \"%.*s\";\n};\n",
   7727 		keynamestr, dst_hmac_algorithm_totext(alg),
   7728 		(int)isc_buffer_usedlength(&key_txtbuffer),
   7729 		(char *)isc_buffer_base(&key_txtbuffer));
   7730 
   7731 	CHECK(isc_stdio_flush(fp));
   7732 	result = isc_stdio_close(fp);
   7733 	if (result != ISC_R_SUCCESS) {
   7734 		goto cleanup;
   7735 	}
   7736 
   7737 	*keyp = key;
   7738 	return ISC_R_SUCCESS;
   7739 
   7740 cleanup:
   7741 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7742 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   7743 		      "failed to generate session key "
   7744 		      "for dynamic DNS: %s",
   7745 		      isc_result_totext(result));
   7746 	if (fp != NULL) {
   7747 		(void)isc_stdio_close(fp);
   7748 		(void)isc_file_remove(filename);
   7749 	}
   7750 	if (key != NULL) {
   7751 		dst_key_free(&key);
   7752 	}
   7753 
   7754 	return result;
   7755 }
   7756 
   7757 static isc_result_t
   7758 configure_session_key(const cfg_obj_t **maps, named_server_t *server,
   7759 		      isc_mem_t *mctx, bool first_time) {
   7760 	const char *keyfile = NULL, *keynamestr = NULL, *algstr = NULL;
   7761 	unsigned int algtype;
   7762 	dns_fixedname_t fname;
   7763 	dns_name_t *keyname = NULL;
   7764 	isc_buffer_t buffer;
   7765 	uint16_t bits;
   7766 	const cfg_obj_t *obj = NULL;
   7767 	bool need_deleteold = false;
   7768 	bool need_createnew = false;
   7769 	isc_result_t result;
   7770 
   7771 	obj = NULL;
   7772 	result = named_config_get(maps, "session-keyfile", &obj);
   7773 	if (result == ISC_R_SUCCESS) {
   7774 		if (cfg_obj_isvoid(obj)) {
   7775 			keyfile = NULL; /* disable it */
   7776 		} else {
   7777 			keyfile = cfg_obj_asstring(obj);
   7778 		}
   7779 	} else {
   7780 		keyfile = named_g_defaultsessionkeyfile;
   7781 	}
   7782 
   7783 	obj = NULL;
   7784 	result = named_config_get(maps, "session-keyname", &obj);
   7785 	INSIST(result == ISC_R_SUCCESS);
   7786 	keynamestr = cfg_obj_asstring(obj);
   7787 	isc_buffer_constinit(&buffer, keynamestr, strlen(keynamestr));
   7788 	isc_buffer_add(&buffer, strlen(keynamestr));
   7789 	keyname = dns_fixedname_initname(&fname);
   7790 	result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL);
   7791 	if (result != ISC_R_SUCCESS) {
   7792 		return result;
   7793 	}
   7794 
   7795 	obj = NULL;
   7796 	result = named_config_get(maps, "session-keyalg", &obj);
   7797 	INSIST(result == ISC_R_SUCCESS);
   7798 	algstr = cfg_obj_asstring(obj);
   7799 	result = named_config_getkeyalgorithm(algstr, &algtype, &bits);
   7800 	if (result != ISC_R_SUCCESS) {
   7801 		const char *s = " (keeping current key)";
   7802 
   7803 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
   7804 			    "session-keyalg: "
   7805 			    "unsupported or unknown algorithm '%s'%s",
   7806 			    algstr, server->session_keyfile != NULL ? s : "");
   7807 		return result;
   7808 	}
   7809 
   7810 	/* See if we need to (re)generate a new key. */
   7811 	if (keyfile == NULL) {
   7812 		if (server->session_keyfile != NULL) {
   7813 			need_deleteold = true;
   7814 		}
   7815 	} else if (server->session_keyfile == NULL) {
   7816 		need_createnew = true;
   7817 	} else if (strcmp(keyfile, server->session_keyfile) != 0 ||
   7818 		   !dns_name_equal(server->session_keyname, keyname) ||
   7819 		   server->session_keyalg != algtype ||
   7820 		   server->session_keybits != bits)
   7821 	{
   7822 		need_deleteold = true;
   7823 		need_createnew = true;
   7824 	}
   7825 
   7826 	if (need_deleteold) {
   7827 		INSIST(server->session_keyfile != NULL);
   7828 		INSIST(server->session_keyname != NULL);
   7829 		INSIST(server->sessionkey != NULL);
   7830 
   7831 		cleanup_session_key(server, mctx);
   7832 	}
   7833 
   7834 	if (need_createnew) {
   7835 		INSIST(server->sessionkey == NULL);
   7836 		INSIST(server->session_keyfile == NULL);
   7837 		INSIST(server->session_keyname == NULL);
   7838 		INSIST(server->session_keyalg == DST_ALG_UNKNOWN);
   7839 		INSIST(server->session_keybits == 0);
   7840 
   7841 		server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t));
   7842 		dns_name_init(server->session_keyname, NULL);
   7843 		dns_name_dup(keyname, mctx, server->session_keyname);
   7844 
   7845 		server->session_keyfile = isc_mem_strdup(mctx, keyfile);
   7846 
   7847 		server->session_keyalg = algtype;
   7848 		server->session_keybits = bits;
   7849 
   7850 		CHECK(generate_session_key(keyfile, keynamestr, keyname,
   7851 					   algtype, bits, mctx, first_time,
   7852 					   &server->sessionkey));
   7853 	}
   7854 
   7855 	return result;
   7856 
   7857 cleanup:
   7858 	cleanup_session_key(server, mctx);
   7859 	return result;
   7860 }
   7861 
   7862 static isc_result_t
   7863 setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
   7864 	       cfg_parser_t *conf_parser, cfg_aclconfctx_t *actx) {
   7865 	isc_result_t result = ISC_R_SUCCESS;
   7866 	bool allow = false;
   7867 	ns_cfgctx_t *nzcfg = NULL;
   7868 	const cfg_obj_t *maps[4];
   7869 	const cfg_obj_t *options = NULL, *voptions = NULL;
   7870 	const cfg_obj_t *nz = NULL;
   7871 	const cfg_obj_t *nzdir = NULL;
   7872 	const char *dir = NULL;
   7873 	const cfg_obj_t *obj = NULL;
   7874 	int i = 0;
   7875 	uint64_t mapsize = 0ULL;
   7876 
   7877 	REQUIRE(config != NULL);
   7878 
   7879 	if (vconfig != NULL) {
   7880 		voptions = cfg_tuple_get(vconfig, "options");
   7881 	}
   7882 	if (voptions != NULL) {
   7883 		maps[i++] = voptions;
   7884 	}
   7885 	result = cfg_map_get(config, "options", &options);
   7886 	if (result == ISC_R_SUCCESS) {
   7887 		maps[i++] = options;
   7888 	}
   7889 	maps[i++] = named_g_defaults;
   7890 	maps[i] = NULL;
   7891 
   7892 	result = named_config_get(maps, "allow-new-zones", &nz);
   7893 	if (result == ISC_R_SUCCESS) {
   7894 		allow = cfg_obj_asboolean(nz);
   7895 	}
   7896 	result = named_config_get(maps, "new-zones-directory", &nzdir);
   7897 	if (result == ISC_R_SUCCESS) {
   7898 		dir = cfg_obj_asstring(nzdir);
   7899 		result = isc_file_isdirectory(dir);
   7900 		if (result != ISC_R_SUCCESS) {
   7901 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
   7902 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   7903 				      "invalid new-zones-directory %s: %s", dir,
   7904 				      isc_result_totext(result));
   7905 			return result;
   7906 		}
   7907 		if (!isc_file_isdirwritable(dir)) {
   7908 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7909 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   7910 				      "new-zones-directory '%s' "
   7911 				      "is not writable",
   7912 				      dir);
   7913 			return ISC_R_NOPERM;
   7914 		}
   7915 
   7916 		dns_view_setnewzonedir(view, dir);
   7917 	}
   7918 
   7919 #ifdef HAVE_LMDB
   7920 	result = named_config_get(maps, "lmdb-mapsize", &obj);
   7921 	if (result == ISC_R_SUCCESS && obj != NULL) {
   7922 		mapsize = cfg_obj_asuint64(obj);
   7923 		if (mapsize < (1ULL << 20)) { /* 1 megabyte */
   7924 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
   7925 				    "'lmdb-mapsize "
   7926 				    "%" PRId64 "' "
   7927 				    "is too small",
   7928 				    mapsize);
   7929 			return ISC_R_FAILURE;
   7930 		} else if (mapsize > (1ULL << 40)) { /* 1 terabyte */
   7931 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
   7932 				    "'lmdb-mapsize "
   7933 				    "%" PRId64 "' "
   7934 				    "is too large",
   7935 				    mapsize);
   7936 			return ISC_R_FAILURE;
   7937 		}
   7938 	}
   7939 #else  /* ifdef HAVE_LMDB */
   7940 	UNUSED(obj);
   7941 #endif /* HAVE_LMDB */
   7942 
   7943 	/*
   7944 	 * A non-empty catalog-zones statement implies allow-new-zones
   7945 	 */
   7946 	if (!allow) {
   7947 		const cfg_obj_t *cz = NULL;
   7948 		result = named_config_get(maps, "catalog-zones", &cz);
   7949 		if (result == ISC_R_SUCCESS) {
   7950 			const cfg_listelt_t *e =
   7951 				cfg_list_first(cfg_tuple_get(cz, "zone list"));
   7952 			if (e != NULL) {
   7953 				allow = true;
   7954 			}
   7955 		}
   7956 	}
   7957 
   7958 	if (!allow) {
   7959 		dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
   7960 		return ISC_R_SUCCESS;
   7961 	}
   7962 
   7963 	nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg));
   7964 	*nzcfg = (ns_cfgctx_t){ 0 };
   7965 
   7966 	/*
   7967 	 * We attach the parser that was used for config as well
   7968 	 * as the one that will be used for added zones, to avoid
   7969 	 * a shutdown race later.
   7970 	 */
   7971 	isc_mem_attach(view->mctx, &nzcfg->mctx);
   7972 	cfg_parser_attach(conf_parser, &nzcfg->conf_parser);
   7973 	cfg_parser_attach(named_g_addparser, &nzcfg->add_parser);
   7974 	cfg_aclconfctx_attach(actx, &nzcfg->actx);
   7975 
   7976 	result = dns_view_setnewzones(view, true, nzcfg, newzone_cfgctx_destroy,
   7977 				      mapsize);
   7978 	if (result != ISC_R_SUCCESS) {
   7979 		cfg_aclconfctx_detach(&nzcfg->actx);
   7980 		cfg_parser_destroy(&nzcfg->add_parser);
   7981 		cfg_parser_destroy(&nzcfg->conf_parser);
   7982 		isc_mem_putanddetach(&nzcfg->mctx, nzcfg, sizeof(*nzcfg));
   7983 		dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
   7984 		return result;
   7985 	}
   7986 
   7987 	cfg_obj_attach(config, &nzcfg->config);
   7988 	if (vconfig != NULL) {
   7989 		cfg_obj_attach(vconfig, &nzcfg->vconfig);
   7990 	}
   7991 
   7992 	result = load_nzf(view, nzcfg);
   7993 	return result;
   7994 }
   7995 
   7996 static void
   7997 configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
   7998 			     dns_view_t *view) {
   7999 	const char *zname;
   8000 	dns_fixedname_t fixorigin;
   8001 	dns_name_t *origin;
   8002 	isc_result_t result2;
   8003 	dns_view_t *pview = NULL;
   8004 	dns_zone_t *zone = NULL;
   8005 
   8006 	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
   8007 	origin = dns_fixedname_initname(&fixorigin);
   8008 
   8009 	result2 = dns_name_fromstring(origin, zname, dns_rootname, 0, NULL);
   8010 	if (result2 != ISC_R_SUCCESS) {
   8011 		return;
   8012 	}
   8013 
   8014 	result2 = dns_viewlist_find(&named_g_server->viewlist, view->name,
   8015 				    view->rdclass, &pview);
   8016 	if (result2 != ISC_R_SUCCESS) {
   8017 		return;
   8018 	}
   8019 
   8020 	result2 = dns_view_findzone(pview, origin, DNS_ZTFIND_EXACT, &zone);
   8021 	if (result2 != ISC_R_SUCCESS) {
   8022 		dns_view_detach(&pview);
   8023 		return;
   8024 	}
   8025 
   8026 	if (result == ISC_R_SUCCESS) {
   8027 		dns_zone_setviewcommit(zone);
   8028 	} else {
   8029 		dns_zone_setviewrevert(zone);
   8030 	}
   8031 
   8032 	dns_zone_detach(&zone);
   8033 	dns_view_detach(&pview);
   8034 }
   8035 
   8036 #ifndef HAVE_LMDB
   8037 
   8038 static isc_result_t
   8039 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
   8040 		   cfg_aclconfctx_t *actx) {
   8041 	isc_result_t result;
   8042 	ns_cfgctx_t *nzctx;
   8043 	const cfg_obj_t *zonelist;
   8044 	const cfg_listelt_t *element;
   8045 
   8046 	nzctx = view->new_zone_config;
   8047 	if (nzctx == NULL || nzctx->nzf_config == NULL) {
   8048 		return ISC_R_SUCCESS;
   8049 	}
   8050 
   8051 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8052 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8053 		      "loading additional zones for view '%s'", view->name);
   8054 
   8055 	zonelist = NULL;
   8056 	cfg_map_get(nzctx->nzf_config, "zone", &zonelist);
   8057 
   8058 	for (element = cfg_list_first(zonelist); element != NULL;
   8059 	     element = cfg_list_next(element))
   8060 	{
   8061 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
   8062 		CHECK(configure_zone(config, zconfig, vconfig, view,
   8063 				     &named_g_server->viewlist,
   8064 				     &named_g_server->kasplist,
   8065 				     &named_g_server->keystorelist, actx, true,
   8066 				     false, false, false));
   8067 	}
   8068 
   8069 	result = ISC_R_SUCCESS;
   8070 
   8071 cleanup:
   8072 	for (element = cfg_list_first(zonelist); element != NULL;
   8073 	     element = cfg_list_next(element))
   8074 	{
   8075 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
   8076 		configure_zone_setviewcommit(result, zconfig, view);
   8077 	}
   8078 
   8079 	return result;
   8080 }
   8081 
   8082 #else /* HAVE_LMDB */
   8083 
   8084 static isc_result_t
   8085 data_to_cfg(dns_view_t *view, MDB_val *key, MDB_val *data, isc_buffer_t **text,
   8086 	    cfg_obj_t **zoneconfig) {
   8087 	isc_result_t result;
   8088 	const char *zone_name;
   8089 	size_t zone_name_len;
   8090 	const char *zone_config;
   8091 	size_t zone_config_len;
   8092 	cfg_obj_t *zoneconf = NULL;
   8093 	char bufname[DNS_NAME_FORMATSIZE];
   8094 
   8095 	REQUIRE(view != NULL);
   8096 	REQUIRE(key != NULL);
   8097 	REQUIRE(data != NULL);
   8098 	REQUIRE(text != NULL);
   8099 	REQUIRE(zoneconfig != NULL && *zoneconfig == NULL);
   8100 
   8101 	if (*text == NULL) {
   8102 		isc_buffer_allocate(view->mctx, text, 256);
   8103 	} else {
   8104 		isc_buffer_clear(*text);
   8105 	}
   8106 
   8107 	zone_name = (const char *)key->mv_data;
   8108 	zone_name_len = key->mv_size;
   8109 	INSIST(zone_name != NULL && zone_name_len > 0);
   8110 
   8111 	zone_config = (const char *)data->mv_data;
   8112 	zone_config_len = data->mv_size;
   8113 	INSIST(zone_config != NULL && zone_config_len > 0);
   8114 
   8115 	/* zone zonename { config; }; */
   8116 	result = isc_buffer_reserve(*text, 6 + zone_name_len + 2 +
   8117 						   zone_config_len + 2);
   8118 	if (result != ISC_R_SUCCESS) {
   8119 		goto cleanup;
   8120 	}
   8121 
   8122 	CHECK(putstr(text, "zone \""));
   8123 	CHECK(putmem(text, (const void *)zone_name, zone_name_len));
   8124 	CHECK(putstr(text, "\" "));
   8125 	CHECK(putmem(text, (const void *)zone_config, zone_config_len));
   8126 	CHECK(putstr(text, ";\n"));
   8127 
   8128 	snprintf(bufname, sizeof(bufname), "%.*s", (int)zone_name_len,
   8129 		 zone_name);
   8130 
   8131 	cfg_parser_reset(named_g_addparser);
   8132 	result = cfg_parse_buffer(named_g_addparser, *text, bufname, 0,
   8133 				  &cfg_type_addzoneconf, 0, &zoneconf);
   8134 	if (result != ISC_R_SUCCESS) {
   8135 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8136 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   8137 			      "parsing config for zone '%.*s' in "
   8138 			      "NZD database '%s' failed",
   8139 			      (int)zone_name_len, zone_name, view->new_zone_db);
   8140 		goto cleanup;
   8141 	}
   8142 
   8143 	*zoneconfig = zoneconf;
   8144 	zoneconf = NULL;
   8145 	result = ISC_R_SUCCESS;
   8146 
   8147 cleanup:
   8148 	if (zoneconf != NULL) {
   8149 		cfg_obj_destroy(named_g_addparser, &zoneconf);
   8150 	}
   8151 
   8152 	return result;
   8153 }
   8154 
   8155 /*%
   8156  * Prototype for a callback which can be used with for_all_newzone_cfgs().
   8157  */
   8158 typedef isc_result_t (*newzone_cfg_cb_t)(const cfg_obj_t *zconfig,
   8159 					 cfg_obj_t *config, cfg_obj_t *vconfig,
   8160 					 dns_view_t *view,
   8161 					 cfg_aclconfctx_t *actx);
   8162 
   8163 /*%
   8164  * For each zone found in a NZD opened by the caller, create an object
   8165  * representing its configuration and invoke "callback" with the created
   8166  * object, "config", "vconfig", "mctx", "view" and "actx" as arguments (all
   8167  * these are non-global variables required to invoke configure_zone()).
   8168  * Immediately interrupt processing if an error is encountered while
   8169  * transforming NZD data into a zone configuration object or if "callback"
   8170  * returns an error.
   8171  *
   8172  * Caller must hold 'view->new_zone_lock'.
   8173  */
   8174 static isc_result_t
   8175 for_all_newzone_cfgs(newzone_cfg_cb_t callback, cfg_obj_t *config,
   8176 		     cfg_obj_t *vconfig, dns_view_t *view,
   8177 		     cfg_aclconfctx_t *actx, MDB_txn *txn, MDB_dbi dbi) {
   8178 	const cfg_obj_t *zconfig, *zlist;
   8179 	isc_result_t result = ISC_R_SUCCESS;
   8180 	cfg_obj_t *zconfigobj = NULL;
   8181 	isc_buffer_t *text = NULL;
   8182 	MDB_cursor *cursor = NULL;
   8183 	MDB_val data, key;
   8184 	int status;
   8185 
   8186 	status = mdb_cursor_open(txn, dbi, &cursor);
   8187 	if (status != MDB_SUCCESS) {
   8188 		return ISC_R_FAILURE;
   8189 	}
   8190 
   8191 	for (status = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
   8192 	     status == MDB_SUCCESS;
   8193 	     status = mdb_cursor_get(cursor, &key, &data, MDB_NEXT))
   8194 	{
   8195 		/*
   8196 		 * Create a configuration object from data fetched from NZD.
   8197 		 */
   8198 		result = data_to_cfg(view, &key, &data, &text, &zconfigobj);
   8199 		if (result != ISC_R_SUCCESS) {
   8200 			break;
   8201 		}
   8202 
   8203 		/*
   8204 		 * Extract zone configuration from configuration object.
   8205 		 */
   8206 		zlist = NULL;
   8207 		result = cfg_map_get(zconfigobj, "zone", &zlist);
   8208 		if (result != ISC_R_SUCCESS) {
   8209 			break;
   8210 		} else if (!cfg_obj_islist(zlist)) {
   8211 			result = ISC_R_FAILURE;
   8212 			break;
   8213 		}
   8214 		zconfig = cfg_listelt_value(cfg_list_first(zlist));
   8215 
   8216 		/*
   8217 		 * Invoke callback.
   8218 		 */
   8219 		result = callback(zconfig, config, vconfig, view, actx);
   8220 		if (result != ISC_R_SUCCESS) {
   8221 			break;
   8222 		}
   8223 
   8224 		/*
   8225 		 * Destroy the configuration object created in this iteration.
   8226 		 */
   8227 		cfg_obj_destroy(named_g_addparser, &zconfigobj);
   8228 	}
   8229 
   8230 	if (text != NULL) {
   8231 		isc_buffer_free(&text);
   8232 	}
   8233 	if (zconfigobj != NULL) {
   8234 		cfg_obj_destroy(named_g_addparser, &zconfigobj);
   8235 	}
   8236 	mdb_cursor_close(cursor);
   8237 
   8238 	return result;
   8239 }
   8240 
   8241 /*%
   8242  * Attempt to configure a zone found in NZD and return the result.
   8243  */
   8244 static isc_result_t
   8245 configure_newzone(const cfg_obj_t *zconfig, cfg_obj_t *config,
   8246 		  cfg_obj_t *vconfig, dns_view_t *view,
   8247 		  cfg_aclconfctx_t *actx) {
   8248 	return configure_zone(
   8249 		config, zconfig, vconfig, view, &named_g_server->viewlist,
   8250 		&named_g_server->kasplist, &named_g_server->keystorelist, actx,
   8251 		true, false, false, false);
   8252 }
   8253 
   8254 /*%
   8255  * Revert new view assignment for a zone found in NZD.
   8256  */
   8257 static isc_result_t
   8258 configure_newzone_revert(const cfg_obj_t *zconfig, cfg_obj_t *config,
   8259 			 cfg_obj_t *vconfig, dns_view_t *view,
   8260 			 cfg_aclconfctx_t *actx) {
   8261 	UNUSED(config);
   8262 	UNUSED(vconfig);
   8263 	UNUSED(actx);
   8264 
   8265 	configure_zone_setviewcommit(ISC_R_FAILURE, zconfig, view);
   8266 
   8267 	return ISC_R_SUCCESS;
   8268 }
   8269 
   8270 static isc_result_t
   8271 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
   8272 		   cfg_aclconfctx_t *actx) {
   8273 	isc_result_t result;
   8274 	MDB_txn *txn = NULL;
   8275 	MDB_dbi dbi;
   8276 
   8277 	if (view->new_zone_config == NULL) {
   8278 		return ISC_R_SUCCESS;
   8279 	}
   8280 
   8281 	LOCK(&view->new_zone_lock);
   8282 
   8283 	result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
   8284 	if (result != ISC_R_SUCCESS) {
   8285 		UNLOCK(&view->new_zone_lock);
   8286 		return ISC_R_SUCCESS;
   8287 	}
   8288 
   8289 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8290 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8291 		      "loading NZD configs from '%s' "
   8292 		      "for view '%s'",
   8293 		      view->new_zone_db, view->name);
   8294 
   8295 	result = for_all_newzone_cfgs(configure_newzone, config, vconfig, view,
   8296 				      actx, txn, dbi);
   8297 	if (result != ISC_R_SUCCESS) {
   8298 		/*
   8299 		 * An error was encountered while attempting to configure zones
   8300 		 * found in NZD.  As this error may have been caused by a
   8301 		 * configure_zone() failure, try restoring a sane configuration
   8302 		 * by reattaching all zones found in NZD to the old view.  If
   8303 		 * this also fails, too bad, there is nothing more we can do in
   8304 		 * terms of trying to make things right.
   8305 		 */
   8306 		(void)for_all_newzone_cfgs(configure_newzone_revert, config,
   8307 					   vconfig, view, actx, txn, dbi);
   8308 	}
   8309 
   8310 	(void)nzd_close(&txn, false);
   8311 
   8312 	UNLOCK(&view->new_zone_lock);
   8313 
   8314 	return result;
   8315 }
   8316 
   8317 static isc_result_t
   8318 get_newzone_config(dns_view_t *view, const char *zonename,
   8319 		   cfg_obj_t **zoneconfig) {
   8320 	isc_result_t result;
   8321 	int status;
   8322 	cfg_obj_t *zoneconf = NULL;
   8323 	isc_buffer_t *text = NULL;
   8324 	MDB_txn *txn = NULL;
   8325 	MDB_dbi dbi;
   8326 	MDB_val key, data;
   8327 	char zname[DNS_NAME_FORMATSIZE];
   8328 	dns_fixedname_t fname;
   8329 	dns_name_t *name;
   8330 	isc_buffer_t b;
   8331 
   8332 	INSIST(zoneconfig != NULL && *zoneconfig == NULL);
   8333 
   8334 	LOCK(&view->new_zone_lock);
   8335 
   8336 	CHECK(nzd_open(view, MDB_RDONLY, &txn, &dbi));
   8337 
   8338 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8339 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8340 		      "loading NZD config from '%s' "
   8341 		      "for zone '%s'",
   8342 		      view->new_zone_db, zonename);
   8343 
   8344 	/* Normalize zone name */
   8345 	isc_buffer_constinit(&b, zonename, strlen(zonename));
   8346 	isc_buffer_add(&b, strlen(zonename));
   8347 	name = dns_fixedname_initname(&fname);
   8348 	CHECK(dns_name_fromtext(name, &b, dns_rootname, DNS_NAME_DOWNCASE,
   8349 				NULL));
   8350 	dns_name_format(name, zname, sizeof(zname));
   8351 
   8352 	key.mv_data = zname;
   8353 	key.mv_size = strlen(zname);
   8354 
   8355 	status = mdb_get(txn, dbi, &key, &data);
   8356 	if (status != MDB_SUCCESS) {
   8357 		CHECK(ISC_R_FAILURE);
   8358 	}
   8359 
   8360 	CHECK(data_to_cfg(view, &key, &data, &text, &zoneconf));
   8361 
   8362 	*zoneconfig = zoneconf;
   8363 	zoneconf = NULL;
   8364 	result = ISC_R_SUCCESS;
   8365 
   8366 cleanup:
   8367 	(void)nzd_close(&txn, false);
   8368 
   8369 	UNLOCK(&view->new_zone_lock);
   8370 
   8371 	if (zoneconf != NULL) {
   8372 		cfg_obj_destroy(named_g_addparser, &zoneconf);
   8373 	}
   8374 	if (text != NULL) {
   8375 		isc_buffer_free(&text);
   8376 	}
   8377 
   8378 	return result;
   8379 }
   8380 
   8381 #endif /* HAVE_LMDB */
   8382 
   8383 static isc_result_t
   8384 load_configuration(const char *filename, named_server_t *server,
   8385 		   bool first_time) {
   8386 	cfg_obj_t *config = NULL, *bindkeys = NULL;
   8387 	cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL;
   8388 	const cfg_listelt_t *element;
   8389 	const cfg_obj_t *builtin_views;
   8390 	const cfg_obj_t *maps[3];
   8391 	const cfg_obj_t *obj;
   8392 	const cfg_obj_t *options;
   8393 	const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
   8394 	const cfg_obj_t *kasps;
   8395 	const cfg_obj_t *keystores;
   8396 	dns_kasp_t *kasp = NULL;
   8397 	dns_kasp_t *kasp_next = NULL;
   8398 	dns_kasp_t *default_kasp = NULL;
   8399 	dns_kasplist_t tmpkasplist, kasplist;
   8400 	unsigned int kaspopts = (ISCCFG_KASPCONF_CHECK_ALGORITHMS |
   8401 				 ISCCFG_KASPCONF_CHECK_KEYLIST |
   8402 				 ISCCFG_KASPCONF_LOG_ERRORS);
   8403 	dns_keystore_t *keystore = NULL;
   8404 	dns_keystore_t *keystore_next = NULL;
   8405 	dns_keystorelist_t tmpkeystorelist, keystorelist;
   8406 	const cfg_obj_t *views = NULL;
   8407 	dns_view_t *view_next = NULL;
   8408 	dns_viewlist_t tmpviewlist;
   8409 	dns_viewlist_t viewlist, builtin_viewlist;
   8410 	in_port_t listen_port, port_low, port_high;
   8411 	int i, backlog;
   8412 	isc_interval_t interval;
   8413 	isc_logconfig_t *logc = NULL;
   8414 	isc_portset_t *v4portset = NULL;
   8415 	isc_portset_t *v6portset = NULL;
   8416 	isc_result_t result;
   8417 	uint32_t heartbeat_interval;
   8418 	uint32_t interface_interval;
   8419 	uint32_t udpsize;
   8420 	uint32_t transfer_message_size;
   8421 	uint32_t recv_tcp_buffer_size;
   8422 	uint32_t send_tcp_buffer_size;
   8423 	uint32_t recv_udp_buffer_size;
   8424 	uint32_t send_udp_buffer_size;
   8425 	named_cache_t *nsc = NULL;
   8426 	named_cachelist_t cachelist, tmpcachelist;
   8427 	ns_altsecret_t *altsecret;
   8428 	ns_altsecretlist_t altsecrets, tmpaltsecrets;
   8429 	uint32_t softquota = 0;
   8430 	uint32_t max;
   8431 	uint64_t initial, idle, keepalive, advertised;
   8432 	bool loadbalancesockets;
   8433 	bool exclusive = true;
   8434 	dns_aclenv_t *env =
   8435 		ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
   8436 
   8437 	/*
   8438 	 * Require the reconfiguration to happen always on the main loop
   8439 	 */
   8440 	REQUIRE(isc_loop() == named_g_mainloop);
   8441 
   8442 	ISC_LIST_INIT(kasplist);
   8443 	ISC_LIST_INIT(keystorelist);
   8444 	ISC_LIST_INIT(viewlist);
   8445 	ISC_LIST_INIT(builtin_viewlist);
   8446 	ISC_LIST_INIT(cachelist);
   8447 	ISC_LIST_INIT(altsecrets);
   8448 
   8449 	/* Ensure exclusive access to configuration data. */
   8450 	isc_loopmgr_pause(named_g_loopmgr);
   8451 
   8452 	/* Create the ACL configuration context */
   8453 	if (named_g_aclconfctx != NULL) {
   8454 		cfg_aclconfctx_detach(&named_g_aclconfctx);
   8455 	}
   8456 	result = cfg_aclconfctx_create(named_g_mctx, &named_g_aclconfctx);
   8457 	if (result != ISC_R_SUCCESS) {
   8458 		goto cleanup_exclusive;
   8459 	}
   8460 
   8461 	/*
   8462 	 * Shut down all dyndb instances.
   8463 	 */
   8464 	dns_dyndb_cleanup(false);
   8465 
   8466 	/*
   8467 	 * Parse the global default pseudo-config file.
   8468 	 */
   8469 	if (first_time) {
   8470 		result = named_config_parsedefaults(named_g_parser,
   8471 						    &named_g_config);
   8472 		if (result != ISC_R_SUCCESS) {
   8473 			named_main_earlyfatal("unable to load "
   8474 					      "internal defaults: %s",
   8475 					      isc_result_totext(result));
   8476 		}
   8477 		RUNTIME_CHECK(cfg_map_get(named_g_config, "options",
   8478 					  &named_g_defaults) == ISC_R_SUCCESS);
   8479 	}
   8480 
   8481 	/*
   8482 	 * Log the current working directory.
   8483 	 */
   8484 	if (first_time) {
   8485 		char cwd[PATH_MAX];
   8486 		if (getcwd(cwd, sizeof(cwd)) == cwd) {
   8487 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8488 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8489 				      "the initial working directory is '%s'",
   8490 				      cwd);
   8491 		}
   8492 	}
   8493 
   8494 	/*
   8495 	 * Parse the configuration file using the new config code.
   8496 	 */
   8497 	config = NULL;
   8498 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8499 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8500 		      "loading configuration from '%s'", filename);
   8501 	result = cfg_parser_create(named_g_mctx, named_g_lctx, &conf_parser);
   8502 	if (result != ISC_R_SUCCESS) {
   8503 		goto cleanup_exclusive;
   8504 	}
   8505 
   8506 	cfg_parser_setcallback(conf_parser, directory_callback, NULL);
   8507 	result = cfg_parse_file(conf_parser, filename, &cfg_type_namedconf,
   8508 				&config);
   8509 	if (result != ISC_R_SUCCESS) {
   8510 		goto cleanup_conf_parser;
   8511 	}
   8512 
   8513 	/*
   8514 	 * Check the validity of the configuration.
   8515 	 *
   8516 	 * (Ignore plugin parameters for now; they will be
   8517 	 * checked later when the modules are actually loaded and
   8518 	 * registered.)
   8519 	 */
   8520 	result = isccfg_check_namedconf(config, BIND_CHECK_ALGORITHMS,
   8521 					named_g_lctx, named_g_mctx);
   8522 	if (result != ISC_R_SUCCESS) {
   8523 		goto cleanup_config;
   8524 	}
   8525 
   8526 	/* Let's recreate the TLS context cache */
   8527 	if (server->tlsctx_server_cache != NULL) {
   8528 		isc_tlsctx_cache_detach(&server->tlsctx_server_cache);
   8529 	}
   8530 
   8531 	isc_tlsctx_cache_create(named_g_mctx, &server->tlsctx_server_cache);
   8532 
   8533 	if (server->tlsctx_client_cache != NULL) {
   8534 		isc_tlsctx_cache_detach(&server->tlsctx_client_cache);
   8535 	}
   8536 
   8537 	isc_tlsctx_cache_create(named_g_mctx, &server->tlsctx_client_cache);
   8538 
   8539 	dns_zonemgr_set_tlsctx_cache(server->zonemgr,
   8540 				     server->tlsctx_client_cache);
   8541 
   8542 	/*
   8543 	 * Fill in the maps array, used for resolving defaults.
   8544 	 */
   8545 	i = 0;
   8546 	options = NULL;
   8547 	result = cfg_map_get(config, "options", &options);
   8548 	if (result == ISC_R_SUCCESS) {
   8549 		maps[i++] = options;
   8550 	}
   8551 	maps[i++] = named_g_defaults;
   8552 	maps[i] = NULL;
   8553 
   8554 #if HAVE_LIBNGHTTP2
   8555 	obj = NULL;
   8556 	result = named_config_get(maps, "http-port", &obj);
   8557 	INSIST(result == ISC_R_SUCCESS);
   8558 	named_g_httpport = (in_port_t)cfg_obj_asuint32(obj);
   8559 
   8560 	obj = NULL;
   8561 	result = named_config_get(maps, "https-port", &obj);
   8562 	INSIST(result == ISC_R_SUCCESS);
   8563 	named_g_httpsport = (in_port_t)cfg_obj_asuint32(obj);
   8564 
   8565 	obj = NULL;
   8566 	result = named_config_get(maps, "http-listener-clients", &obj);
   8567 	INSIST(result == ISC_R_SUCCESS);
   8568 	named_g_http_listener_clients = cfg_obj_asuint32(obj);
   8569 
   8570 	obj = NULL;
   8571 	result = named_config_get(maps, "http-streams-per-connection", &obj);
   8572 	INSIST(result == ISC_R_SUCCESS);
   8573 	named_g_http_streams_per_conn = cfg_obj_asuint32(obj);
   8574 #endif
   8575 
   8576 	/*
   8577 	 * If "dnssec-validation auto" is turned on, the root key
   8578 	 * will be used as a default trust anchor. The root key
   8579 	 * is built in, but if bindkeys-file is set, then it will
   8580 	 * be overridden with the key in that file.
   8581 	 */
   8582 	obj = NULL;
   8583 	(void)named_config_get(maps, "bindkeys-file", &obj);
   8584 	if (obj != NULL) {
   8585 		setstring(server, &server->bindkeysfile, cfg_obj_asstring(obj));
   8586 		INSIST(server->bindkeysfile != NULL);
   8587 		if (access(server->bindkeysfile, R_OK) != 0) {
   8588 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8589 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8590 				      "unable to open '%s'; using built-in "
   8591 				      "keys instead",
   8592 				      server->bindkeysfile);
   8593 		} else {
   8594 			result = cfg_parser_create(named_g_mctx, named_g_lctx,
   8595 						   &bindkeys_parser);
   8596 			if (result != ISC_R_SUCCESS) {
   8597 				goto cleanup_config;
   8598 			}
   8599 
   8600 			result = cfg_parse_file(bindkeys_parser,
   8601 						server->bindkeysfile,
   8602 						&cfg_type_bindkeys, &bindkeys);
   8603 			if (result != ISC_R_SUCCESS) {
   8604 				isc_log_write(
   8605 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8606 					NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8607 					"unable to parse '%s' "
   8608 					"error '%s'; using "
   8609 					"built-in keys instead",
   8610 					server->bindkeysfile,
   8611 					isc_result_totext(result));
   8612 			}
   8613 		}
   8614 	} else {
   8615 		setstring(server, &server->bindkeysfile, NULL);
   8616 	}
   8617 
   8618 #if defined(HAVE_GEOIP2)
   8619 	/*
   8620 	 * Release any previously opened GeoIP2 databases.
   8621 	 */
   8622 	named_geoip_unload();
   8623 
   8624 	/*
   8625 	 * Initialize GeoIP databases from the configured location.
   8626 	 * This should happen before configuring any ACLs, so that we
   8627 	 * know what databases are available and can reject any GeoIP
   8628 	 * ACLs that can't work.
   8629 	 */
   8630 	obj = NULL;
   8631 	result = named_config_get(maps, "geoip-directory", &obj);
   8632 	INSIST(result == ISC_R_SUCCESS);
   8633 	if (cfg_obj_isstring(obj)) {
   8634 		char *dir = UNCONST(cfg_obj_asstring(obj));
   8635 		named_geoip_load(dir);
   8636 	}
   8637 	named_g_aclconfctx->geoip = named_g_geoip;
   8638 #endif /* HAVE_GEOIP2 */
   8639 
   8640 	/*
   8641 	 * Configure various server options.
   8642 	 */
   8643 	configure_server_quota(maps, "transfers-out",
   8644 			       &server->sctx->xfroutquota);
   8645 	configure_server_quota(maps, "tcp-clients", &server->sctx->tcpquota);
   8646 	configure_server_quota(maps, "recursive-clients",
   8647 			       &server->sctx->recursionquota);
   8648 	configure_server_quota(maps, "update-quota", &server->sctx->updquota);
   8649 	configure_server_quota(maps, "sig0checks-quota",
   8650 			       &server->sctx->sig0checksquota);
   8651 
   8652 	max = isc_quota_getmax(&server->sctx->recursionquota);
   8653 	if (max > 1000) {
   8654 		unsigned int margin = ISC_MAX(100, named_g_cpus + 1);
   8655 		if (margin + 100 > max) {
   8656 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8657 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   8658 				      "'recursive-clients %d' too low when "
   8659 				      "running with %d worker threads",
   8660 				      max, named_g_cpus);
   8661 			result = ISC_R_RANGE;
   8662 
   8663 			goto cleanup_bindkeys_parser;
   8664 		}
   8665 		softquota = max - margin;
   8666 	} else {
   8667 		softquota = (max * 90) / 100;
   8668 	}
   8669 	isc_quota_soft(&server->sctx->recursionquota, softquota);
   8670 
   8671 	obj = NULL;
   8672 	result = named_config_get(maps, "sig0checks-quota-exempt", &obj);
   8673 	if (result == ISC_R_SUCCESS) {
   8674 		result = cfg_acl_fromconfig(
   8675 			obj, config, named_g_lctx, named_g_aclconfctx,
   8676 			named_g_mctx, 0, &server->sctx->sig0checksquota_exempt);
   8677 		INSIST(result == ISC_R_SUCCESS);
   8678 	}
   8679 
   8680 	/*
   8681 	 * Set "blackhole". Only legal at options level; there is
   8682 	 * no default.
   8683 	 */
   8684 	result = configure_view_acl(NULL, config, NULL, "blackhole", NULL,
   8685 				    named_g_aclconfctx, named_g_mctx,
   8686 				    &server->sctx->blackholeacl);
   8687 	if (result != ISC_R_SUCCESS) {
   8688 		goto cleanup_bindkeys_parser;
   8689 	}
   8690 
   8691 	if (server->sctx->blackholeacl != NULL) {
   8692 		dns_dispatchmgr_setblackhole(named_g_dispatchmgr,
   8693 					     server->sctx->blackholeacl);
   8694 	}
   8695 
   8696 	obj = NULL;
   8697 	result = named_config_get(maps, "match-mapped-addresses", &obj);
   8698 	INSIST(result == ISC_R_SUCCESS);
   8699 	env->match_mapped = cfg_obj_asboolean(obj);
   8700 
   8701 	/*
   8702 	 * Configure the network manager
   8703 	 */
   8704 	obj = NULL;
   8705 	result = named_config_get(maps, "tcp-initial-timeout", &obj);
   8706 	INSIST(result == ISC_R_SUCCESS);
   8707 	initial = cfg_obj_asuint32(obj) * 100;
   8708 	if (initial > MAX_INITIAL_TIMEOUT) {
   8709 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   8710 			    "tcp-initial-timeout value is out of range: "
   8711 			    "lowering to %" PRIu32,
   8712 			    MAX_INITIAL_TIMEOUT / 100);
   8713 		initial = MAX_INITIAL_TIMEOUT;
   8714 	} else if (initial < MIN_INITIAL_TIMEOUT) {
   8715 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   8716 			    "tcp-initial-timeout value is out of range: "
   8717 			    "raising to %" PRIu32,
   8718 			    MIN_INITIAL_TIMEOUT / 100);
   8719 		initial = MIN_INITIAL_TIMEOUT;
   8720 	}
   8721 
   8722 	obj = NULL;
   8723 	result = named_config_get(maps, "tcp-idle-timeout", &obj);
   8724 	INSIST(result == ISC_R_SUCCESS);
   8725 	idle = cfg_obj_asuint32(obj) * 100;
   8726 	if (idle > MAX_IDLE_TIMEOUT) {
   8727 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   8728 			    "tcp-idle-timeout value is out of range: "
   8729 			    "lowering to %" PRIu32,
   8730 			    MAX_IDLE_TIMEOUT / 100);
   8731 		idle = MAX_IDLE_TIMEOUT;
   8732 	} else if (idle < MIN_IDLE_TIMEOUT) {
   8733 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   8734 			    "tcp-idle-timeout value is out of range: "
   8735 			    "raising to %" PRIu32,
   8736 			    MIN_IDLE_TIMEOUT / 100);
   8737 		idle = MIN_IDLE_TIMEOUT;
   8738 	}
   8739 
   8740 	obj = NULL;
   8741 	result = named_config_get(maps, "tcp-keepalive-timeout", &obj);
   8742 	INSIST(result == ISC_R_SUCCESS);
   8743 	keepalive = cfg_obj_asuint32(obj) * 100;
   8744 	if (keepalive > MAX_KEEPALIVE_TIMEOUT) {
   8745 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   8746 			    "tcp-keepalive-timeout value is out of range: "
   8747 			    "lowering to %" PRIu32,
   8748 			    MAX_KEEPALIVE_TIMEOUT / 100);
   8749 		keepalive = MAX_KEEPALIVE_TIMEOUT;
   8750 	} else if (keepalive < MIN_KEEPALIVE_TIMEOUT) {
   8751 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   8752 			    "tcp-keepalive-timeout value is out of range: "
   8753 			    "raising to %" PRIu32,
   8754 			    MIN_KEEPALIVE_TIMEOUT / 100);
   8755 		keepalive = MIN_KEEPALIVE_TIMEOUT;
   8756 	}
   8757 
   8758 	obj = NULL;
   8759 	result = named_config_get(maps, "tcp-advertised-timeout", &obj);
   8760 	INSIST(result == ISC_R_SUCCESS);
   8761 	advertised = cfg_obj_asuint32(obj) * 100;
   8762 	if (advertised > MAX_ADVERTISED_TIMEOUT) {
   8763 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   8764 			    "tcp-advertized-timeout value is out of range: "
   8765 			    "lowering to %" PRIu32,
   8766 			    MAX_ADVERTISED_TIMEOUT / 100);
   8767 		advertised = MAX_ADVERTISED_TIMEOUT;
   8768 	}
   8769 
   8770 	isc_nm_settimeouts(named_g_netmgr, initial, idle, keepalive,
   8771 			   advertised);
   8772 
   8773 #define CAP_IF_NOT_ZERO(v, min, max) \
   8774 	if (v > 0 && v < min) {      \
   8775 		v = min;             \
   8776 	} else if (v > max) {        \
   8777 		v = max;             \
   8778 	}
   8779 
   8780 	/* Set the kernel send and receive buffer sizes */
   8781 	obj = NULL;
   8782 	result = named_config_get(maps, "tcp-receive-buffer", &obj);
   8783 	INSIST(result == ISC_R_SUCCESS);
   8784 	recv_tcp_buffer_size = cfg_obj_asuint32(obj);
   8785 	CAP_IF_NOT_ZERO(recv_tcp_buffer_size, 4096, INT32_MAX);
   8786 
   8787 	obj = NULL;
   8788 	result = named_config_get(maps, "tcp-send-buffer", &obj);
   8789 	INSIST(result == ISC_R_SUCCESS);
   8790 	send_tcp_buffer_size = cfg_obj_asuint32(obj);
   8791 	CAP_IF_NOT_ZERO(send_tcp_buffer_size, 4096, INT32_MAX);
   8792 
   8793 	obj = NULL;
   8794 	result = named_config_get(maps, "udp-receive-buffer", &obj);
   8795 	INSIST(result == ISC_R_SUCCESS);
   8796 	recv_udp_buffer_size = cfg_obj_asuint32(obj);
   8797 	CAP_IF_NOT_ZERO(recv_udp_buffer_size, 4096, INT32_MAX);
   8798 
   8799 	obj = NULL;
   8800 	result = named_config_get(maps, "udp-send-buffer", &obj);
   8801 	INSIST(result == ISC_R_SUCCESS);
   8802 	send_udp_buffer_size = cfg_obj_asuint32(obj);
   8803 	CAP_IF_NOT_ZERO(send_udp_buffer_size, 4096, INT32_MAX);
   8804 
   8805 	isc_nm_setnetbuffers(named_g_netmgr, recv_tcp_buffer_size,
   8806 			     send_tcp_buffer_size, recv_udp_buffer_size,
   8807 			     send_udp_buffer_size);
   8808 
   8809 #undef CAP_IF_NOT_ZERO
   8810 
   8811 	/*
   8812 	 * Configure sets of UDP query source ports.
   8813 	 */
   8814 	result = isc_portset_create(named_g_mctx, &v4portset);
   8815 	if (result != ISC_R_SUCCESS) {
   8816 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8817 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   8818 			      "creating UDP/IPv4 port set: %s",
   8819 			      isc_result_totext(result));
   8820 		goto cleanup_bindkeys_parser;
   8821 	}
   8822 	result = isc_portset_create(named_g_mctx, &v6portset);
   8823 	if (result != ISC_R_SUCCESS) {
   8824 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8825 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   8826 			      "creating UDP/IPv6 port set: %s",
   8827 			      isc_result_totext(result));
   8828 		goto cleanup_v4portset;
   8829 	}
   8830 
   8831 	usev4ports = NULL;
   8832 	usev6ports = NULL;
   8833 	avoidv4ports = NULL;
   8834 	avoidv6ports = NULL;
   8835 
   8836 	(void)named_config_get(maps, "use-v4-udp-ports", &usev4ports);
   8837 	if (usev4ports != NULL) {
   8838 		portset_fromconf(v4portset, usev4ports, true);
   8839 	} else {
   8840 		isc_net_getportrange(AF_INET, &port_low, &port_high);
   8841 		if (port_low == port_high) {
   8842 			isc_portset_add(v4portset, port_low);
   8843 		} else {
   8844 			isc_portset_addrange(v4portset, port_low, port_high);
   8845 		}
   8846 		if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE4)) {
   8847 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8848 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8849 				      "using default UDP/IPv4 port range: "
   8850 				      "[%d, %d]",
   8851 				      port_low, port_high);
   8852 		}
   8853 	}
   8854 	(void)named_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
   8855 	if (avoidv4ports != NULL) {
   8856 		portset_fromconf(v4portset, avoidv4ports, false);
   8857 	}
   8858 
   8859 	(void)named_config_get(maps, "use-v6-udp-ports", &usev6ports);
   8860 	if (usev6ports != NULL) {
   8861 		portset_fromconf(v6portset, usev6ports, true);
   8862 	} else {
   8863 		isc_net_getportrange(AF_INET6, &port_low, &port_high);
   8864 		if (port_low == port_high) {
   8865 			isc_portset_add(v6portset, port_low);
   8866 		} else {
   8867 			isc_portset_addrange(v6portset, port_low, port_high);
   8868 		}
   8869 		if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE6)) {
   8870 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8871 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8872 				      "using default UDP/IPv6 port range: "
   8873 				      "[%d, %d]",
   8874 				      port_low, port_high);
   8875 		}
   8876 	}
   8877 	(void)named_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
   8878 	if (avoidv6ports != NULL) {
   8879 		portset_fromconf(v6portset, avoidv6ports, false);
   8880 	}
   8881 
   8882 	dns_dispatchmgr_setavailports(named_g_dispatchmgr, v4portset,
   8883 				      v6portset);
   8884 
   8885 	/*
   8886 	 * Set the EDNS UDP size when we don't match a view.
   8887 	 */
   8888 	obj = NULL;
   8889 	result = named_config_get(maps, "edns-udp-size", &obj);
   8890 	INSIST(result == ISC_R_SUCCESS);
   8891 	udpsize = cfg_obj_asuint32(obj);
   8892 	if (udpsize < 512) {
   8893 		udpsize = 512;
   8894 	}
   8895 	if (udpsize > 4096) {
   8896 		udpsize = 4096;
   8897 	}
   8898 	server->sctx->udpsize = (uint16_t)udpsize;
   8899 
   8900 	/* Set the transfer message size for TCP */
   8901 	obj = NULL;
   8902 	result = named_config_get(maps, "transfer-message-size", &obj);
   8903 	INSIST(result == ISC_R_SUCCESS);
   8904 	transfer_message_size = cfg_obj_asuint32(obj);
   8905 	if (transfer_message_size < 512) {
   8906 		transfer_message_size = 512;
   8907 	} else if (transfer_message_size > 65535) {
   8908 		transfer_message_size = 65535;
   8909 	}
   8910 	server->sctx->transfer_tcp_message_size =
   8911 		(uint16_t)transfer_message_size;
   8912 
   8913 	/*
   8914 	 * Configure the zone manager.
   8915 	 */
   8916 	obj = NULL;
   8917 	result = named_config_get(maps, "transfers-in", &obj);
   8918 	INSIST(result == ISC_R_SUCCESS);
   8919 	dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
   8920 
   8921 	obj = NULL;
   8922 	result = named_config_get(maps, "transfers-per-ns", &obj);
   8923 	INSIST(result == ISC_R_SUCCESS);
   8924 	dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
   8925 
   8926 	obj = NULL;
   8927 	result = named_config_get(maps, "notify-rate", &obj);
   8928 	INSIST(result == ISC_R_SUCCESS);
   8929 	dns_zonemgr_setnotifyrate(server->zonemgr, cfg_obj_asuint32(obj));
   8930 
   8931 	obj = NULL;
   8932 	result = named_config_get(maps, "startup-notify-rate", &obj);
   8933 	INSIST(result == ISC_R_SUCCESS);
   8934 	dns_zonemgr_setstartupnotifyrate(server->zonemgr,
   8935 					 cfg_obj_asuint32(obj));
   8936 
   8937 	obj = NULL;
   8938 	result = named_config_get(maps, "serial-query-rate", &obj);
   8939 	INSIST(result == ISC_R_SUCCESS);
   8940 	dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
   8941 
   8942 	/*
   8943 	 * Determine which port to use for listening for incoming connections.
   8944 	 */
   8945 	if (named_g_port != 0) {
   8946 		listen_port = named_g_port;
   8947 	} else {
   8948 		result = named_config_getport(config, "port", &listen_port);
   8949 		if (result != ISC_R_SUCCESS) {
   8950 			goto cleanup_v6portset;
   8951 		}
   8952 	}
   8953 
   8954 	/*
   8955 	 * Find the listen queue depth.
   8956 	 */
   8957 	obj = NULL;
   8958 	result = named_config_get(maps, "tcp-listen-queue", &obj);
   8959 	INSIST(result == ISC_R_SUCCESS);
   8960 	backlog = cfg_obj_asuint32(obj);
   8961 	if ((backlog > 0) && (backlog < 10)) {
   8962 		backlog = 10;
   8963 	}
   8964 	ns_interfacemgr_setbacklog(server->interfacemgr, backlog);
   8965 
   8966 	obj = NULL;
   8967 	result = named_config_get(maps, "reuseport", &obj);
   8968 	INSIST(result == ISC_R_SUCCESS);
   8969 	loadbalancesockets = cfg_obj_asboolean(obj);
   8970 #if HAVE_SO_REUSEPORT_LB
   8971 	if (first_time) {
   8972 		isc_nm_setloadbalancesockets(named_g_netmgr,
   8973 					     cfg_obj_asboolean(obj));
   8974 	} else if (loadbalancesockets !=
   8975 		   isc_nm_getloadbalancesockets(named_g_netmgr))
   8976 	{
   8977 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   8978 			    "changing reuseport value requires server restart");
   8979 	}
   8980 #else
   8981 	if (loadbalancesockets) {
   8982 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   8983 			    "reuseport has no effect on this system");
   8984 	}
   8985 #endif
   8986 
   8987 	/*
   8988 	 * Configure the interface manager according to the "listen-on"
   8989 	 * statement.
   8990 	 */
   8991 	{
   8992 		const cfg_obj_t *clistenon = NULL;
   8993 		ns_listenlist_t *listenon = NULL;
   8994 
   8995 		/*
   8996 		 * Even though listen-on is present in the default
   8997 		 * configuration, this way is easier.
   8998 		 */
   8999 		if (options != NULL) {
   9000 			(void)cfg_map_get(options, "listen-on", &clistenon);
   9001 		}
   9002 		if (clistenon != NULL) {
   9003 			result = listenlist_fromconfig(
   9004 				clistenon, config, named_g_aclconfctx,
   9005 				named_g_mctx, AF_INET,
   9006 				server->tlsctx_server_cache, &listenon);
   9007 		} else {
   9008 			/*
   9009 			 * Not specified, use default.
   9010 			 */
   9011 			result = ns_listenlist_default(named_g_mctx,
   9012 						       listen_port, true,
   9013 						       AF_INET, &listenon);
   9014 		}
   9015 		if (result != ISC_R_SUCCESS) {
   9016 			goto cleanup_v6portset;
   9017 		}
   9018 
   9019 		if (listenon != NULL) {
   9020 			ns_interfacemgr_setlistenon4(server->interfacemgr,
   9021 						     listenon);
   9022 			ns_listenlist_detach(&listenon);
   9023 		}
   9024 	}
   9025 
   9026 	/*
   9027 	 * Ditto for IPv6.
   9028 	 */
   9029 	{
   9030 		const cfg_obj_t *clistenon = NULL;
   9031 		ns_listenlist_t *listenon = NULL;
   9032 
   9033 		if (options != NULL) {
   9034 			(void)cfg_map_get(options, "listen-on-v6", &clistenon);
   9035 		}
   9036 		if (clistenon != NULL) {
   9037 			result = listenlist_fromconfig(
   9038 				clistenon, config, named_g_aclconfctx,
   9039 				named_g_mctx, AF_INET6,
   9040 				server->tlsctx_server_cache, &listenon);
   9041 		} else {
   9042 			/*
   9043 			 * Not specified, use default.
   9044 			 */
   9045 			result = ns_listenlist_default(named_g_mctx,
   9046 						       listen_port, true,
   9047 						       AF_INET6, &listenon);
   9048 		}
   9049 		if (result != ISC_R_SUCCESS) {
   9050 			goto cleanup_v6portset;
   9051 		}
   9052 		if (listenon != NULL) {
   9053 			ns_interfacemgr_setlistenon6(server->interfacemgr,
   9054 						     listenon);
   9055 			ns_listenlist_detach(&listenon);
   9056 		}
   9057 	}
   9058 
   9059 	if (first_time) {
   9060 		/*
   9061 		 * Rescan the interface list to pick up changes in the
   9062 		 * listen-on option. This requires the loopmgr to be
   9063 		 * temporarily resumed.
   9064 		 */
   9065 		isc_loopmgr_resume(named_g_loopmgr);
   9066 		result = ns_interfacemgr_scan(server->interfacemgr, true, true);
   9067 		isc_loopmgr_pause(named_g_loopmgr);
   9068 
   9069 		/*
   9070 		 * Check that named is able to TCP listen on at least one
   9071 		 * interface. Otherwise, another named process could be running
   9072 		 * and we should fail.
   9073 		 */
   9074 		if (result == ISC_R_ADDRINUSE) {
   9075 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9076 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9077 				      "unable to listen on any configured "
   9078 				      "interfaces");
   9079 			result = ISC_R_FAILURE;
   9080 			goto cleanup_v6portset;
   9081 		}
   9082 	}
   9083 
   9084 	/*
   9085 	 * Arrange for further interface scanning to occur periodically
   9086 	 * as specified by the "interface-interval" option.
   9087 	 */
   9088 	obj = NULL;
   9089 	result = named_config_get(maps, "interface-interval", &obj);
   9090 	INSIST(result == ISC_R_SUCCESS);
   9091 	interface_interval = cfg_obj_asduration(obj);
   9092 	server->interface_interval = interface_interval;
   9093 
   9094 	/*
   9095 	 * Enable automatic interface scans.
   9096 	 */
   9097 	obj = NULL;
   9098 	result = named_config_get(maps, "automatic-interface-scan", &obj);
   9099 	INSIST(result == ISC_R_SUCCESS);
   9100 	server->sctx->interface_auto = cfg_obj_asboolean(obj);
   9101 
   9102 	if (server->sctx->interface_auto) {
   9103 		if (ns_interfacemgr_dynamic_updates_are_reliable() &&
   9104 		    server->interface_interval != 0)
   9105 		{
   9106 			/*
   9107 			 * In some cases the user might expect a certain
   9108 			 * behaviour from the rescan timer, let's try to deduce
   9109 			 * that from the configuration options.
   9110 			 */
   9111 			isc_log_write(
   9112 				named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9113 				NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   9114 				"Disabling periodic interface re-scans timer");
   9115 			server->interface_interval = 0;
   9116 		}
   9117 
   9118 		ns_interfacemgr_routeconnect(server->interfacemgr);
   9119 	} else {
   9120 		ns_interfacemgr_routedisconnect(server->interfacemgr);
   9121 	}
   9122 
   9123 	if (server->interface_interval == 0) {
   9124 		isc_timer_stop(server->interface_timer);
   9125 	} else {
   9126 		isc_interval_set(&interval, interface_interval, 0);
   9127 		isc_timer_start(server->interface_timer, isc_timertype_ticker,
   9128 				&interval);
   9129 	}
   9130 
   9131 	/*
   9132 	 * Configure the dialup heartbeat timer.
   9133 	 */
   9134 	obj = NULL;
   9135 	result = named_config_get(maps, "heartbeat-interval", &obj);
   9136 	INSIST(result == ISC_R_SUCCESS);
   9137 	heartbeat_interval = cfg_obj_asuint32(obj) * 60;
   9138 	if (heartbeat_interval == 0) {
   9139 		isc_timer_stop(server->heartbeat_timer);
   9140 	} else if (server->heartbeat_interval != heartbeat_interval) {
   9141 		isc_interval_set(&interval, heartbeat_interval, 0);
   9142 		isc_timer_start(server->heartbeat_timer, isc_timertype_ticker,
   9143 				&interval);
   9144 	}
   9145 	server->heartbeat_interval = heartbeat_interval;
   9146 
   9147 	isc_interval_set(&interval, 1200, 0);
   9148 	isc_timer_start(server->pps_timer, isc_timertype_ticker, &interval);
   9149 
   9150 	isc_interval_set(&interval, named_g_tat_interval, 0);
   9151 	isc_timer_start(server->tat_timer, isc_timertype_ticker, &interval);
   9152 
   9153 	/*
   9154 	 * Write the PID file.
   9155 	 */
   9156 	obj = NULL;
   9157 	if (named_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) {
   9158 		if (cfg_obj_isvoid(obj)) {
   9159 			named_os_writepidfile(NULL, first_time);
   9160 		} else {
   9161 			named_os_writepidfile(cfg_obj_asstring(obj),
   9162 					      first_time);
   9163 		}
   9164 	} else {
   9165 		named_os_writepidfile(named_g_defaultpidfile, first_time);
   9166 	}
   9167 
   9168 	/*
   9169 	 * Configure the server-wide session key.  This must be done before
   9170 	 * configure views because zone configuration may need to know
   9171 	 * session-keyname.
   9172 	 *
   9173 	 * Failure of session key generation isn't fatal at this time; if it
   9174 	 * turns out that a session key is really needed but doesn't exist,
   9175 	 * we'll treat it as a fatal error then.
   9176 	 */
   9177 	(void)configure_session_key(maps, server, named_g_mctx, first_time);
   9178 
   9179 	/*
   9180 	 * Create the built-in key store ("key-directory").
   9181 	 */
   9182 	result = cfg_keystore_fromconfig(NULL, named_g_mctx, named_g_lctx,
   9183 					 named_g_engine, &keystorelist, NULL);
   9184 	if (result != ISC_R_SUCCESS) {
   9185 		goto cleanup_keystorelist;
   9186 	}
   9187 
   9188 	/*
   9189 	 * Create the DNSSEC key stores.
   9190 	 */
   9191 	keystores = NULL;
   9192 	(void)cfg_map_get(config, "key-store", &keystores);
   9193 	for (element = cfg_list_first(keystores); element != NULL;
   9194 	     element = cfg_list_next(element))
   9195 	{
   9196 		cfg_obj_t *kconfig = cfg_listelt_value(element);
   9197 		keystore = NULL;
   9198 		result = cfg_keystore_fromconfig(kconfig, named_g_mctx,
   9199 						 named_g_lctx, named_g_engine,
   9200 						 &keystorelist, NULL);
   9201 		if (result != ISC_R_SUCCESS) {
   9202 			goto cleanup_keystorelist;
   9203 		}
   9204 	}
   9205 
   9206 	/*
   9207 	 * Create the built-in kasp policies ("default", "insecure").
   9208 	 */
   9209 	kasps = NULL;
   9210 	(void)cfg_map_get(named_g_config, "dnssec-policy", &kasps);
   9211 	for (element = cfg_list_first(kasps); element != NULL;
   9212 	     element = cfg_list_next(element))
   9213 	{
   9214 		cfg_obj_t *kconfig = cfg_listelt_value(element);
   9215 
   9216 		kasp = NULL;
   9217 		result = cfg_kasp_fromconfig(kconfig, default_kasp, kaspopts,
   9218 					     named_g_mctx, named_g_lctx,
   9219 					     &keystorelist, &kasplist, &kasp);
   9220 		if (result != ISC_R_SUCCESS) {
   9221 			goto cleanup_kasplist;
   9222 		}
   9223 		INSIST(kasp != NULL);
   9224 		dns_kasp_freeze(kasp);
   9225 
   9226 		/* Insist that the first built-in policy is the default one. */
   9227 		if (default_kasp == NULL) {
   9228 			INSIST(strcmp(dns_kasp_getname(kasp), "default") == 0);
   9229 			dns_kasp_attach(kasp, &default_kasp);
   9230 		}
   9231 
   9232 		dns_kasp_detach(&kasp);
   9233 	}
   9234 	INSIST(default_kasp != NULL);
   9235 
   9236 	/*
   9237 	 * Create the DNSSEC key and signing policies (KASP).
   9238 	 */
   9239 	kasps = NULL;
   9240 	(void)cfg_map_get(config, "dnssec-policy", &kasps);
   9241 	for (element = cfg_list_first(kasps); element != NULL;
   9242 	     element = cfg_list_next(element))
   9243 	{
   9244 		cfg_obj_t *kconfig = cfg_listelt_value(element);
   9245 		kasp = NULL;
   9246 		result = cfg_kasp_fromconfig(kconfig, default_kasp, kaspopts,
   9247 					     named_g_mctx, named_g_lctx,
   9248 					     &keystorelist, &kasplist, &kasp);
   9249 		if (result != ISC_R_SUCCESS) {
   9250 			goto cleanup_kasplist;
   9251 		}
   9252 		INSIST(kasp != NULL);
   9253 		dns_kasp_freeze(kasp);
   9254 		dns_kasp_detach(&kasp);
   9255 	}
   9256 	dns_kasp_detach(&default_kasp);
   9257 
   9258 	/*
   9259 	 * Save keystore list and kasp list.
   9260 	 */
   9261 	tmpkeystorelist = server->keystorelist;
   9262 	server->keystorelist = keystorelist;
   9263 	keystorelist = tmpkeystorelist;
   9264 
   9265 	tmpkasplist = server->kasplist;
   9266 	server->kasplist = kasplist;
   9267 	kasplist = tmpkasplist;
   9268 
   9269 #ifdef USE_DNSRPS
   9270 	/*
   9271 	 * Find the path to the DNSRPS implementation library.
   9272 	 */
   9273 	obj = NULL;
   9274 	if (named_config_get(maps, "dnsrps-library", &obj) == ISC_R_SUCCESS) {
   9275 		if (server->dnsrpslib != NULL) {
   9276 			dns_dnsrps_server_destroy();
   9277 			isc_mem_free(server->mctx, server->dnsrpslib);
   9278 			server->dnsrpslib = NULL;
   9279 		}
   9280 		setstring(server, &server->dnsrpslib, cfg_obj_asstring(obj));
   9281 		result = dns_dnsrps_server_create(server->dnsrpslib);
   9282 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9283 			      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
   9284 			      "initializing DNSRPS RPZ provider '%s': %s",
   9285 			      server->dnsrpslib, isc_result_totext(result));
   9286 		/*
   9287 		 * It's okay if librpz isn't available. We'll complain
   9288 		 * later if it turns out to be needed for a view with
   9289 		 * "dnsrps-enable yes".
   9290 		 */
   9291 		if (result == ISC_R_FILENOTFOUND) {
   9292 			result = ISC_R_SUCCESS;
   9293 		}
   9294 		CHECKFATAL(result, "initializing RPZ service interface");
   9295 	}
   9296 #endif /* ifdef USE_DNSRPS */
   9297 
   9298 	/*
   9299 	 * Configure the views.
   9300 	 */
   9301 	views = NULL;
   9302 	(void)cfg_map_get(config, "view", &views);
   9303 
   9304 	/*
   9305 	 * Create the views.
   9306 	 */
   9307 	for (element = cfg_list_first(views); element != NULL;
   9308 	     element = cfg_list_next(element))
   9309 	{
   9310 		cfg_obj_t *vconfig = cfg_listelt_value(element);
   9311 		dns_view_t *view = NULL;
   9312 
   9313 		result = create_view(vconfig, &viewlist, &view);
   9314 		if (result != ISC_R_SUCCESS) {
   9315 			goto cleanup_viewlist;
   9316 		}
   9317 		INSIST(view != NULL);
   9318 
   9319 		result = setup_newzones(view, config, vconfig, conf_parser,
   9320 					named_g_aclconfctx);
   9321 		dns_view_detach(&view);
   9322 
   9323 		if (result != ISC_R_SUCCESS) {
   9324 			goto cleanup_viewlist;
   9325 		}
   9326 	}
   9327 
   9328 	/*
   9329 	 * If there were no explicit views then we do the default
   9330 	 * view here.
   9331 	 */
   9332 	if (views == NULL) {
   9333 		dns_view_t *view = NULL;
   9334 
   9335 		result = create_view(NULL, &viewlist, &view);
   9336 		if (result != ISC_R_SUCCESS) {
   9337 			goto cleanup_viewlist;
   9338 		}
   9339 		INSIST(view != NULL);
   9340 
   9341 		result = setup_newzones(view, config, NULL, conf_parser,
   9342 					named_g_aclconfctx);
   9343 
   9344 		dns_view_detach(&view);
   9345 		if (result != ISC_R_SUCCESS) {
   9346 			goto cleanup_viewlist;
   9347 		}
   9348 	}
   9349 
   9350 	/*
   9351 	 * Configure and freeze all explicit views.  Explicit
   9352 	 * views that have zones were already created at parsing
   9353 	 * time, but views with no zones must be created here.
   9354 	 */
   9355 	for (element = cfg_list_first(views); element != NULL;
   9356 	     element = cfg_list_next(element))
   9357 	{
   9358 		cfg_obj_t *vconfig = cfg_listelt_value(element);
   9359 		dns_view_t *view = NULL;
   9360 
   9361 		view = NULL;
   9362 		result = find_view(vconfig, &viewlist, &view);
   9363 		if (result != ISC_R_SUCCESS) {
   9364 			goto cleanup_cachelist;
   9365 		}
   9366 
   9367 		result = configure_view(
   9368 			view, &viewlist, config, vconfig, &cachelist,
   9369 			&server->cachelist, &server->kasplist,
   9370 			&server->keystorelist, bindkeys, named_g_mctx,
   9371 			named_g_aclconfctx, true, first_time);
   9372 		if (result != ISC_R_SUCCESS) {
   9373 			dns_view_detach(&view);
   9374 			goto cleanup_cachelist;
   9375 		}
   9376 		dns_view_freeze(view);
   9377 		dns_view_detach(&view);
   9378 	}
   9379 
   9380 	/*
   9381 	 * Make sure we have a default view if and only if there
   9382 	 * were no explicit views.
   9383 	 */
   9384 	if (views == NULL) {
   9385 		dns_view_t *view = NULL;
   9386 		result = find_view(NULL, &viewlist, &view);
   9387 		if (result != ISC_R_SUCCESS) {
   9388 			goto cleanup_cachelist;
   9389 		}
   9390 		result = configure_view(
   9391 			view, &viewlist, config, NULL, &cachelist,
   9392 			&server->cachelist, &server->kasplist,
   9393 			&server->keystorelist, bindkeys, named_g_mctx,
   9394 			named_g_aclconfctx, true, first_time);
   9395 		if (result != ISC_R_SUCCESS) {
   9396 			dns_view_detach(&view);
   9397 			goto cleanup_cachelist;
   9398 		}
   9399 		dns_view_freeze(view);
   9400 		dns_view_detach(&view);
   9401 	}
   9402 
   9403 	/*
   9404 	 * Create (or recreate) the built-in views.
   9405 	 */
   9406 	builtin_views = NULL;
   9407 	RUNTIME_CHECK(cfg_map_get(named_g_config, "view", &builtin_views) ==
   9408 		      ISC_R_SUCCESS);
   9409 	for (element = cfg_list_first(builtin_views); element != NULL;
   9410 	     element = cfg_list_next(element))
   9411 	{
   9412 		cfg_obj_t *vconfig = cfg_listelt_value(element);
   9413 		dns_view_t *view = NULL;
   9414 
   9415 		result = create_view(vconfig, &builtin_viewlist, &view);
   9416 		if (result != ISC_R_SUCCESS) {
   9417 			goto cleanup_cachelist;
   9418 		}
   9419 
   9420 		result = configure_view(
   9421 			view, &viewlist, config, vconfig, &cachelist,
   9422 			&server->cachelist, &server->kasplist,
   9423 			&server->keystorelist, bindkeys, named_g_mctx,
   9424 			named_g_aclconfctx, false, first_time);
   9425 		if (result != ISC_R_SUCCESS) {
   9426 			dns_view_detach(&view);
   9427 			goto cleanup_cachelist;
   9428 		}
   9429 		dns_view_freeze(view);
   9430 		dns_view_detach(&view);
   9431 	}
   9432 
   9433 	/* Now combine the two viewlists into one */
   9434 	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
   9435 
   9436 	/*
   9437 	 * Commit any dns_zone_setview() calls on all zones in the new
   9438 	 * view.
   9439 	 */
   9440 	for (dns_view_t *view = ISC_LIST_HEAD(viewlist); view != NULL;
   9441 	     view = ISC_LIST_NEXT(view, link))
   9442 	{
   9443 		dns_view_setviewcommit(view);
   9444 	}
   9445 
   9446 	/* Swap our new view list with the production one. */
   9447 	tmpviewlist = server->viewlist;
   9448 	server->viewlist = viewlist;
   9449 	viewlist = tmpviewlist;
   9450 
   9451 	/* Make the view list available to each of the views */
   9452 	for (dns_view_t *view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   9453 	     view = ISC_LIST_NEXT(view, link))
   9454 	{
   9455 		view->viewlist = &server->viewlist;
   9456 	}
   9457 
   9458 	/* Swap our new cache list with the production one. */
   9459 	tmpcachelist = server->cachelist;
   9460 	server->cachelist = cachelist;
   9461 	cachelist = tmpcachelist;
   9462 
   9463 	/* Load the TKEY information from the configuration. */
   9464 	if (options != NULL) {
   9465 		dns_tkeyctx_t *tkeyctx = NULL;
   9466 
   9467 		result = named_tkeyctx_fromconfig(options, named_g_mctx,
   9468 						  &tkeyctx);
   9469 		if (result != ISC_R_SUCCESS) {
   9470 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9471 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9472 				      "configuring TKEY: %s",
   9473 				      isc_result_totext(result));
   9474 			goto cleanup_cachelist;
   9475 		}
   9476 		if (server->sctx->tkeyctx != NULL) {
   9477 			dns_tkeyctx_destroy(&server->sctx->tkeyctx);
   9478 		}
   9479 		server->sctx->tkeyctx = tkeyctx;
   9480 	}
   9481 
   9482 #ifdef HAVE_LMDB
   9483 	/*
   9484 	 * If we're using LMDB, we may have created newzones databases
   9485 	 * as root, making it impossible to reopen them later after
   9486 	 * switching to a new userid. We close them now, and reopen
   9487 	 * after relinquishing privileges them.
   9488 	 */
   9489 	if (first_time) {
   9490 		for (dns_view_t *view = ISC_LIST_HEAD(server->viewlist);
   9491 		     view != NULL; view = ISC_LIST_NEXT(view, link))
   9492 		{
   9493 			nzd_env_close(view);
   9494 		}
   9495 	}
   9496 #endif /* HAVE_LMDB */
   9497 
   9498 	/*
   9499 	 * Switch to the effective UID for setting up files.
   9500 	 * Later, after configuring all the listening ports,
   9501 	 * we'll relinquish root privileges permanently.
   9502 	 */
   9503 	if (first_time) {
   9504 		named_os_changeuser(false);
   9505 	}
   9506 
   9507 	/*
   9508 	 * Check that the working directory is writable.
   9509 	 */
   9510 	if (!isc_file_isdirwritable(".")) {
   9511 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9512 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9513 			      "the working directory is not writable");
   9514 		result = ISC_R_NOPERM;
   9515 		goto cleanup_cachelist;
   9516 	}
   9517 
   9518 #ifdef HAVE_LMDB
   9519 	/*
   9520 	 * Reopen NZD databases.
   9521 	 */
   9522 	if (first_time) {
   9523 		for (dns_view_t *view = ISC_LIST_HEAD(server->viewlist);
   9524 		     view != NULL; view = ISC_LIST_NEXT(view, link))
   9525 		{
   9526 			nzd_env_reopen(view);
   9527 		}
   9528 	}
   9529 #endif /* HAVE_LMDB */
   9530 
   9531 	/*
   9532 	 * Configure the logging system.
   9533 	 *
   9534 	 * Do this after changing UID to make sure that any log
   9535 	 * files specified in named.conf get created by the
   9536 	 * unprivileged user, not root.
   9537 	 */
   9538 	if (named_g_logstderr) {
   9539 		const cfg_obj_t *logobj = NULL;
   9540 
   9541 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9542 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   9543 			      "not using config file logging "
   9544 			      "statement for logging due to "
   9545 			      "-g option");
   9546 
   9547 		(void)cfg_map_get(config, "logging", &logobj);
   9548 		if (logobj != NULL) {
   9549 			result = named_logconfig(NULL, logobj);
   9550 			if (result != ISC_R_SUCCESS) {
   9551 				isc_log_write(
   9552 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9553 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9554 					"checking logging configuration "
   9555 					"failed: %s",
   9556 					isc_result_totext(result));
   9557 				goto cleanup_cachelist;
   9558 			}
   9559 		}
   9560 	} else {
   9561 		const cfg_obj_t *logobj = NULL;
   9562 
   9563 		isc_logconfig_create(named_g_lctx, &logc);
   9564 
   9565 		logobj = NULL;
   9566 		(void)cfg_map_get(config, "logging", &logobj);
   9567 		if (logobj != NULL) {
   9568 			result = named_logconfig(logc, logobj);
   9569 			if (result != ISC_R_SUCCESS) {
   9570 				isc_log_write(
   9571 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9572 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9573 					"configuring logging: %s",
   9574 					isc_result_totext(result));
   9575 				goto cleanup_logc;
   9576 			}
   9577 		} else {
   9578 			named_log_setdefaultchannels(logc);
   9579 			named_log_setdefaultsslkeylogfile(logc);
   9580 			result = named_log_setunmatchedcategory(logc);
   9581 			if (result != ISC_R_SUCCESS) {
   9582 				isc_log_write(
   9583 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9584 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9585 					"setting up default 'category "
   9586 					"unmatched': %s",
   9587 					isc_result_totext(result));
   9588 				goto cleanup_logc;
   9589 			}
   9590 			result = named_log_setdefaultcategory(logc);
   9591 			if (result != ISC_R_SUCCESS) {
   9592 				isc_log_write(
   9593 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9594 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9595 					"setting up default 'category "
   9596 					"default': %s",
   9597 					isc_result_totext(result));
   9598 				goto cleanup_logc;
   9599 			}
   9600 		}
   9601 
   9602 		isc_logconfig_use(named_g_lctx, logc);
   9603 		logc = NULL;
   9604 
   9605 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9606 			      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
   9607 			      "now using logging configuration from "
   9608 			      "config file");
   9609 	}
   9610 
   9611 	/*
   9612 	 * Set the default value of the query logging flag depending
   9613 	 * whether a "queries" category has been defined.  This is
   9614 	 * a disgusting hack, but we need to do this for BIND 8
   9615 	 * compatibility.
   9616 	 */
   9617 	if (first_time) {
   9618 		const cfg_obj_t *logobj = NULL;
   9619 		const cfg_obj_t *categories = NULL;
   9620 
   9621 		obj = NULL;
   9622 		if (named_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
   9623 			ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES,
   9624 					    cfg_obj_asboolean(obj));
   9625 		} else {
   9626 			(void)cfg_map_get(config, "logging", &logobj);
   9627 			if (logobj != NULL) {
   9628 				(void)cfg_map_get(logobj, "category",
   9629 						  &categories);
   9630 			}
   9631 			if (categories != NULL) {
   9632 				for (element = cfg_list_first(categories);
   9633 				     element != NULL;
   9634 				     element = cfg_list_next(element))
   9635 				{
   9636 					const cfg_obj_t *catobj;
   9637 					const char *str;
   9638 
   9639 					obj = cfg_listelt_value(element);
   9640 					catobj = cfg_tuple_get(obj, "name");
   9641 					str = cfg_obj_asstring(catobj);
   9642 					if (strcasecmp(str, "queries") == 0) {
   9643 						ns_server_setoption(
   9644 							server->sctx,
   9645 							NS_SERVER_LOGQUERIES,
   9646 							true);
   9647 					}
   9648 				}
   9649 			}
   9650 		}
   9651 		obj = NULL;
   9652 		result = named_config_get(maps, "responselog", &obj);
   9653 		if (result == ISC_R_SUCCESS) {
   9654 			ns_server_setoption(server->sctx,
   9655 					    NS_SERVER_LOGRESPONSES,
   9656 					    cfg_obj_asboolean(obj));
   9657 		}
   9658 	}
   9659 
   9660 	obj = NULL;
   9661 	if (options != NULL &&
   9662 	    cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS)
   9663 	{
   9664 		named_g_memstatistics = cfg_obj_asboolean(obj);
   9665 	} else {
   9666 		named_g_memstatistics =
   9667 			((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0);
   9668 	}
   9669 
   9670 	obj = NULL;
   9671 	if (named_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS)
   9672 	{
   9673 		named_main_setmemstats(cfg_obj_asstring(obj));
   9674 	} else if (named_g_memstatistics) {
   9675 		named_main_setmemstats("named.memstats");
   9676 	} else {
   9677 		named_main_setmemstats(NULL);
   9678 	}
   9679 
   9680 	obj = NULL;
   9681 	result = named_config_get(maps, "statistics-file", &obj);
   9682 	INSIST(result == ISC_R_SUCCESS);
   9683 	setstring(server, &server->statsfile, cfg_obj_asstring(obj));
   9684 
   9685 	obj = NULL;
   9686 	result = named_config_get(maps, "dump-file", &obj);
   9687 	INSIST(result == ISC_R_SUCCESS);
   9688 	setstring(server, &server->dumpfile, cfg_obj_asstring(obj));
   9689 
   9690 	obj = NULL;
   9691 	result = named_config_get(maps, "secroots-file", &obj);
   9692 	INSIST(result == ISC_R_SUCCESS);
   9693 	setstring(server, &server->secrootsfile, cfg_obj_asstring(obj));
   9694 
   9695 	obj = NULL;
   9696 	result = named_config_get(maps, "recursing-file", &obj);
   9697 	INSIST(result == ISC_R_SUCCESS);
   9698 	setstring(server, &server->recfile, cfg_obj_asstring(obj));
   9699 
   9700 	obj = NULL;
   9701 	result = named_config_get(maps, "version", &obj);
   9702 	if (result == ISC_R_SUCCESS) {
   9703 		setoptstring(server, &server->version, obj);
   9704 		server->version_set = true;
   9705 	} else {
   9706 		server->version_set = false;
   9707 	}
   9708 
   9709 	obj = NULL;
   9710 	result = named_config_get(maps, "hostname", &obj);
   9711 	if (result == ISC_R_SUCCESS) {
   9712 		setoptstring(server, &server->hostname, obj);
   9713 		server->hostname_set = true;
   9714 	} else {
   9715 		server->hostname_set = false;
   9716 	}
   9717 
   9718 	obj = NULL;
   9719 	result = named_config_get(maps, "server-id", &obj);
   9720 	server->sctx->usehostname = false;
   9721 	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
   9722 		/* The parser translates "hostname" to true */
   9723 		server->sctx->usehostname = true;
   9724 		result = ns_server_setserverid(server->sctx, NULL);
   9725 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
   9726 		/* Found a quoted string */
   9727 		result = ns_server_setserverid(server->sctx,
   9728 					       cfg_obj_asstring(obj));
   9729 	} else {
   9730 		result = ns_server_setserverid(server->sctx, NULL);
   9731 	}
   9732 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   9733 
   9734 	obj = NULL;
   9735 	result = named_config_get(maps, "flush-zones-on-shutdown", &obj);
   9736 	if (result == ISC_R_SUCCESS) {
   9737 		server->flushonshutdown = cfg_obj_asboolean(obj);
   9738 	} else {
   9739 		server->flushonshutdown = false;
   9740 	}
   9741 
   9742 	obj = NULL;
   9743 	result = named_config_get(maps, "answer-cookie", &obj);
   9744 	INSIST(result == ISC_R_SUCCESS);
   9745 	server->sctx->answercookie = cfg_obj_asboolean(obj);
   9746 
   9747 	obj = NULL;
   9748 	result = named_config_get(maps, "cookie-algorithm", &obj);
   9749 	INSIST(result == ISC_R_SUCCESS);
   9750 	if (strcasecmp(cfg_obj_asstring(obj), "siphash24") == 0) {
   9751 		server->sctx->cookiealg = ns_cookiealg_siphash24;
   9752 	} else {
   9753 		UNREACHABLE();
   9754 	}
   9755 
   9756 	obj = NULL;
   9757 	result = named_config_get(maps, "cookie-secret", &obj);
   9758 	if (result == ISC_R_SUCCESS) {
   9759 		const char *str;
   9760 		bool first = true;
   9761 		isc_buffer_t b;
   9762 		unsigned int usedlength;
   9763 		unsigned int expectedlength;
   9764 
   9765 		for (element = cfg_list_first(obj); element != NULL;
   9766 		     element = cfg_list_next(element))
   9767 		{
   9768 			obj = cfg_listelt_value(element);
   9769 			str = cfg_obj_asstring(obj);
   9770 
   9771 			if (first) {
   9772 				memset(server->sctx->secret, 0,
   9773 				       sizeof(server->sctx->secret));
   9774 				isc_buffer_init(&b, server->sctx->secret,
   9775 						sizeof(server->sctx->secret));
   9776 				result = isc_hex_decodestring(str, &b);
   9777 				if (result != ISC_R_SUCCESS &&
   9778 				    result != ISC_R_NOSPACE)
   9779 				{
   9780 					goto cleanup_altsecrets;
   9781 				}
   9782 				first = false;
   9783 			} else {
   9784 				altsecret = isc_mem_get(server->sctx->mctx,
   9785 							sizeof(*altsecret));
   9786 				isc_buffer_init(&b, altsecret->secret,
   9787 						sizeof(altsecret->secret));
   9788 				result = isc_hex_decodestring(str, &b);
   9789 				if (result != ISC_R_SUCCESS &&
   9790 				    result != ISC_R_NOSPACE)
   9791 				{
   9792 					isc_mem_put(server->sctx->mctx,
   9793 						    altsecret,
   9794 						    sizeof(*altsecret));
   9795 					goto cleanup_altsecrets;
   9796 				}
   9797 				ISC_LIST_INITANDAPPEND(altsecrets, altsecret,
   9798 						       link);
   9799 			}
   9800 
   9801 			usedlength = isc_buffer_usedlength(&b);
   9802 			switch (server->sctx->cookiealg) {
   9803 			case ns_cookiealg_siphash24:
   9804 				expectedlength = ISC_SIPHASH24_KEY_LENGTH;
   9805 				if (usedlength != expectedlength) {
   9806 					result = ISC_R_RANGE;
   9807 					isc_log_write(
   9808 						named_g_lctx,
   9809 						NAMED_LOGCATEGORY_GENERAL,
   9810 						NAMED_LOGMODULE_SERVER,
   9811 						ISC_LOG_ERROR,
   9812 						"SipHash-2-4 cookie-secret "
   9813 						"must be 128 bits: %s",
   9814 						isc_result_totext(result));
   9815 					goto cleanup_altsecrets;
   9816 				}
   9817 				break;
   9818 			}
   9819 		}
   9820 	} else {
   9821 		isc_nonce_buf(server->sctx->secret,
   9822 			      sizeof(server->sctx->secret));
   9823 	}
   9824 
   9825 	/*
   9826 	 * Swap altsecrets lists.
   9827 	 */
   9828 	tmpaltsecrets = server->sctx->altsecrets;
   9829 	server->sctx->altsecrets = altsecrets;
   9830 	altsecrets = tmpaltsecrets;
   9831 
   9832 	(void)named_server_loadnta(server);
   9833 
   9834 #ifdef USE_DNSRPS
   9835 	/*
   9836 	 * Start and connect to the DNS Response Policy Service
   9837 	 * daemon, dnsrpzd, for each view that uses DNSRPS.
   9838 	 */
   9839 	for (dns_view_t *view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   9840 	     view = ISC_LIST_NEXT(view, link))
   9841 	{
   9842 		result = dns_dnsrps_connect(view->rpzs);
   9843 		if (result != ISC_R_SUCCESS) {
   9844 			view = NULL;
   9845 			goto cleanup_altsecrets;
   9846 		}
   9847 	}
   9848 #endif /* ifdef USE_DNSRPS */
   9849 
   9850 	/*
   9851 	 * Record the time of most recent configuration
   9852 	 */
   9853 	named_g_configtime = isc_time_now();
   9854 
   9855 	isc_loopmgr_resume(named_g_loopmgr);
   9856 	exclusive = false;
   9857 
   9858 	/* Take back root privileges temporarily */
   9859 	if (first_time) {
   9860 		named_os_restoreuser();
   9861 	}
   9862 
   9863 	/* Configure the statistics channel(s) */
   9864 	result = named_statschannels_configure(named_g_server, config,
   9865 					       named_g_aclconfctx);
   9866 	if (result != ISC_R_SUCCESS) {
   9867 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9868 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9869 			      "configuring statistics server(s): %s",
   9870 			      isc_result_totext(result));
   9871 		goto cleanup_altsecrets;
   9872 	}
   9873 
   9874 	/*
   9875 	 * Bind the control port(s).
   9876 	 */
   9877 	result = named_controls_configure(named_g_server->controls, config,
   9878 					  named_g_aclconfctx);
   9879 	if (result != ISC_R_SUCCESS) {
   9880 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9881 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9882 			      "binding control channel(s): %s",
   9883 			      isc_result_totext(result));
   9884 		goto cleanup_altsecrets;
   9885 	}
   9886 
   9887 	(void)ns_interfacemgr_scan(server->interfacemgr, true, true);
   9888 
   9889 	/*
   9890 	 * Permanently drop root privileges now.
   9891 	 */
   9892 	if (first_time) {
   9893 		named_os_changeuser(true);
   9894 	}
   9895 
   9896 	/*
   9897 	 * These cleans up either the old production view list
   9898 	 * or our temporary list depending on whether they
   9899 	 * were swapped above or not.
   9900 	 */
   9901 cleanup_altsecrets:
   9902 	while ((altsecret = ISC_LIST_HEAD(altsecrets)) != NULL) {
   9903 		ISC_LIST_UNLINK(altsecrets, altsecret, link);
   9904 		isc_mem_put(server->sctx->mctx, altsecret, sizeof(*altsecret));
   9905 	}
   9906 
   9907 cleanup_logc:
   9908 	if (logc != NULL) {
   9909 		isc_logconfig_destroy(&logc);
   9910 	}
   9911 
   9912 cleanup_cachelist:
   9913 	while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
   9914 		ISC_LIST_UNLINK(cachelist, nsc, link);
   9915 		dns_cache_detach(&nsc->cache);
   9916 		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
   9917 	}
   9918 
   9919 	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
   9920 
   9921 cleanup_viewlist:
   9922 	for (dns_view_t *view = ISC_LIST_HEAD(viewlist); view != NULL;
   9923 	     view = view_next)
   9924 	{
   9925 		view_next = ISC_LIST_NEXT(view, link);
   9926 		ISC_LIST_UNLINK(viewlist, view, link);
   9927 		if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0)
   9928 		{
   9929 			dns_view_setviewrevert(view);
   9930 			(void)dns_view_apply(view, false, NULL, removed, view);
   9931 		}
   9932 		dns_view_detach(&view);
   9933 	}
   9934 
   9935 cleanup_kasplist:
   9936 	for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) {
   9937 		kasp_next = ISC_LIST_NEXT(kasp, link);
   9938 		ISC_LIST_UNLINK(kasplist, kasp, link);
   9939 		dns_kasp_detach(&kasp);
   9940 	}
   9941 
   9942 cleanup_keystorelist:
   9943 	for (keystore = ISC_LIST_HEAD(keystorelist); keystore != NULL;
   9944 	     keystore = keystore_next)
   9945 	{
   9946 		keystore_next = ISC_LIST_NEXT(keystore, link);
   9947 		ISC_LIST_UNLINK(keystorelist, keystore, link);
   9948 		dns_keystore_detach(&keystore);
   9949 	}
   9950 
   9951 cleanup_v6portset:
   9952 	isc_portset_destroy(named_g_mctx, &v6portset);
   9953 
   9954 cleanup_v4portset:
   9955 	isc_portset_destroy(named_g_mctx, &v4portset);
   9956 
   9957 cleanup_bindkeys_parser:
   9958 
   9959 	if (bindkeys_parser != NULL) {
   9960 		if (bindkeys != NULL) {
   9961 			cfg_obj_destroy(bindkeys_parser, &bindkeys);
   9962 		}
   9963 		cfg_parser_destroy(&bindkeys_parser);
   9964 	}
   9965 
   9966 cleanup_config:
   9967 	cfg_obj_destroy(conf_parser, &config);
   9968 
   9969 cleanup_conf_parser:
   9970 	cfg_parser_destroy(&conf_parser);
   9971 
   9972 cleanup_exclusive:
   9973 	if (exclusive) {
   9974 		isc_loopmgr_resume(named_g_loopmgr);
   9975 	}
   9976 
   9977 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9978 		      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
   9979 		      "load_configuration: %s", isc_result_totext(result));
   9980 
   9981 	return result;
   9982 }
   9983 
   9984 static isc_result_t
   9985 view_loaded(void *arg) {
   9986 	isc_result_t result;
   9987 	ns_zoneload_t *zl = (ns_zoneload_t *)arg;
   9988 
   9989 	/*
   9990 	 * Force zone maintenance.  Do this after loading
   9991 	 * so that we know when we need to force AXFR of
   9992 	 * secondary zones whose master files are missing.
   9993 	 *
   9994 	 * We use the zoneload reference counter to let us
   9995 	 * know when all views are finished.
   9996 	 */
   9997 	if (isc_refcount_decrement(&zl->refs) == 1) {
   9998 		named_server_t *server = zl->server;
   9999 		bool reconfig = zl->reconfig;
   10000 		dns_view_t *view = NULL;
   10001 
   10002 		isc_refcount_destroy(&zl->refs);
   10003 		isc_mem_put(server->mctx, zl, sizeof(*zl));
   10004 
   10005 		/*
   10006 		 * To maintain compatibility with log parsing tools that might
   10007 		 * be looking for this string after "rndc reconfig", we keep it
   10008 		 * as it is
   10009 		 */
   10010 		if (reconfig) {
   10011 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10012 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   10013 				      "any newly configured zones are now "
   10014 				      "loaded");
   10015 		} else {
   10016 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10017 				      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
   10018 				      "all zones loaded");
   10019 		}
   10020 
   10021 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   10022 		     view = ISC_LIST_NEXT(view, link))
   10023 		{
   10024 			if (view->managed_keys != NULL) {
   10025 				result = dns_zone_synckeyzone(
   10026 					view->managed_keys);
   10027 				if (result != ISC_R_SUCCESS) {
   10028 					isc_log_write(
   10029 						named_g_lctx,
   10030 						DNS_LOGCATEGORY_DNSSEC,
   10031 						DNS_LOGMODULE_DNSSEC,
   10032 						ISC_LOG_ERROR,
   10033 						"failed to initialize "
   10034 						"managed-keys for view %s "
   10035 						"(%s): DNSSEC validation is "
   10036 						"at risk",
   10037 						view->name,
   10038 						isc_result_totext(result));
   10039 				}
   10040 			}
   10041 		}
   10042 
   10043 		CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr),
   10044 			   "forcing zone maintenance");
   10045 
   10046 		named_os_started();
   10047 
   10048 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10049 			      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
   10050 			      "FIPS mode is %s",
   10051 			      isc_fips_mode() ? "enabled" : "disabled");
   10052 
   10053 		named_os_notify_systemd("READY=1\n"
   10054 					"STATUS=running\n"
   10055 					"MAINPID=%" PRId64 "\n",
   10056 					(int64_t)getpid());
   10057 
   10058 		atomic_store(&server->reload_status, NAMED_RELOAD_DONE);
   10059 
   10060 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10061 			      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
   10062 			      "running");
   10063 	}
   10064 
   10065 	return ISC_R_SUCCESS;
   10066 }
   10067 
   10068 static isc_result_t
   10069 load_zones(named_server_t *server, bool reconfig) {
   10070 	isc_result_t result = ISC_R_SUCCESS;
   10071 	ns_zoneload_t *zl = NULL;
   10072 	dns_view_t *view = NULL;
   10073 
   10074 	zl = isc_mem_get(server->mctx, sizeof(*zl));
   10075 	zl->server = server;
   10076 	zl->reconfig = reconfig;
   10077 
   10078 	isc_loopmgr_pause(named_g_loopmgr);
   10079 
   10080 	isc_refcount_init(&zl->refs, 1);
   10081 
   10082 	/*
   10083 	 * Schedule zones to be loaded from disk.
   10084 	 */
   10085 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   10086 	     view = ISC_LIST_NEXT(view, link))
   10087 	{
   10088 		if (view->managed_keys != NULL) {
   10089 			result = dns_zone_load(view->managed_keys, false);
   10090 			if (result != ISC_R_SUCCESS &&
   10091 			    result != DNS_R_UPTODATE &&
   10092 			    result != DNS_R_CONTINUE)
   10093 			{
   10094 				goto cleanup;
   10095 			}
   10096 		}
   10097 		if (view->redirect != NULL) {
   10098 			result = dns_zone_load(view->redirect, false);
   10099 			if (result != ISC_R_SUCCESS &&
   10100 			    result != DNS_R_UPTODATE &&
   10101 			    result != DNS_R_CONTINUE)
   10102 			{
   10103 				goto cleanup;
   10104 			}
   10105 		}
   10106 
   10107 		/*
   10108 		 * 'dns_view_asyncload' calls view_loaded if there are no
   10109 		 * zones.
   10110 		 */
   10111 		isc_refcount_increment(&zl->refs);
   10112 		result = dns_view_asyncload(view, reconfig, view_loaded, zl);
   10113 		if (result != ISC_R_SUCCESS) {
   10114 			isc_refcount_decrement1(&zl->refs);
   10115 			goto cleanup;
   10116 		}
   10117 	}
   10118 
   10119 cleanup:
   10120 	if (isc_refcount_decrement(&zl->refs) == 1) {
   10121 		isc_refcount_destroy(&zl->refs);
   10122 		isc_mem_put(server->mctx, zl, sizeof(*zl));
   10123 	}
   10124 
   10125 	isc_loopmgr_resume(named_g_loopmgr);
   10126 
   10127 	return result;
   10128 }
   10129 
   10130 static void
   10131 run_server(void *arg) {
   10132 	isc_result_t result;
   10133 	named_server_t *server = (named_server_t *)arg;
   10134 	dns_geoip_databases_t *geoip = NULL;
   10135 
   10136 	dns_zonemgr_create(named_g_mctx, named_g_netmgr, &server->zonemgr);
   10137 
   10138 	CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, named_g_loopmgr,
   10139 					  named_g_netmgr, &named_g_dispatchmgr),
   10140 		   "creating dispatch manager");
   10141 
   10142 	dns_dispatchmgr_setstats(named_g_dispatchmgr, server->resolverstats);
   10143 
   10144 #if defined(HAVE_GEOIP2)
   10145 	geoip = named_g_geoip;
   10146 #else  /* if defined(HAVE_GEOIP2) */
   10147 	geoip = NULL;
   10148 #endif /* if defined(HAVE_GEOIP2) */
   10149 
   10150 	CHECKFATAL(ns_interfacemgr_create(named_g_mctx, server->sctx,
   10151 					  named_g_loopmgr, named_g_netmgr,
   10152 					  named_g_dispatchmgr, geoip,
   10153 					  &server->interfacemgr),
   10154 		   "creating interface manager");
   10155 
   10156 	isc_timer_create(named_g_mainloop, interface_timer_tick, server,
   10157 			 &server->interface_timer);
   10158 
   10159 	isc_timer_create(named_g_mainloop, heartbeat_timer_tick, server,
   10160 			 &server->heartbeat_timer);
   10161 
   10162 	isc_timer_create(named_g_mainloop, tat_timer_tick, server,
   10163 			 &server->tat_timer);
   10164 
   10165 	isc_timer_create(named_g_mainloop, pps_timer_tick, server,
   10166 			 &server->pps_timer);
   10167 
   10168 	CHECKFATAL(
   10169 		cfg_parser_create(named_g_mctx, named_g_lctx, &named_g_parser),
   10170 		"creating default configuration parser");
   10171 
   10172 	CHECKFATAL(cfg_parser_create(named_g_mctx, named_g_lctx,
   10173 				     &named_g_addparser),
   10174 		   "creating additional configuration parser");
   10175 
   10176 	CHECKFATAL(load_configuration(named_g_conffile, server, true),
   10177 		   "loading configuration");
   10178 
   10179 	CHECKFATAL(load_zones(server, false), "loading zones");
   10180 #ifdef ENABLE_AFL
   10181 	named_g_run_done = true;
   10182 #endif /* ifdef ENABLE_AFL */
   10183 }
   10184 
   10185 void
   10186 named_server_flushonshutdown(named_server_t *server, bool flush) {
   10187 	REQUIRE(NAMED_SERVER_VALID(server));
   10188 
   10189 	server->flushonshutdown = flush;
   10190 }
   10191 
   10192 static void
   10193 shutdown_server(void *arg) {
   10194 	named_server_t *server = (named_server_t *)arg;
   10195 	dns_view_t *view = NULL, *view_next = NULL;
   10196 	dns_kasp_t *kasp = NULL, *kasp_next = NULL;
   10197 	dns_keystore_t *keystore = NULL, *keystore_next = NULL;
   10198 	bool flush = server->flushonshutdown;
   10199 	named_cache_t *nsc = NULL;
   10200 
   10201 	named_os_notify_systemd("STOPPING=1\n");
   10202 	named_os_notify_close();
   10203 
   10204 	isc_signal_stop(server->sighup);
   10205 	isc_signal_destroy(&server->sighup);
   10206 
   10207 	/*
   10208 	 * We need to shutdown the interface before going
   10209 	 * exclusive (which would pause the netmgr).
   10210 	 */
   10211 	ns_interfacemgr_shutdown(server->interfacemgr);
   10212 
   10213 	named_controls_shutdown(server->controls);
   10214 
   10215 	named_statschannels_shutdown(server);
   10216 
   10217 	isc_loopmgr_pause(named_g_loopmgr);
   10218 
   10219 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10220 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, "shutting down%s",
   10221 		      flush ? ": flushing changes" : "");
   10222 
   10223 	cleanup_session_key(server, server->mctx);
   10224 
   10225 	if (named_g_aclconfctx != NULL) {
   10226 		cfg_aclconfctx_detach(&named_g_aclconfctx);
   10227 	}
   10228 
   10229 	cfg_obj_destroy(named_g_parser, &named_g_config);
   10230 	cfg_parser_destroy(&named_g_parser);
   10231 	cfg_parser_destroy(&named_g_addparser);
   10232 
   10233 	(void)named_server_saventa(server);
   10234 
   10235 	for (kasp = ISC_LIST_HEAD(server->kasplist); kasp != NULL;
   10236 	     kasp = kasp_next)
   10237 	{
   10238 		kasp_next = ISC_LIST_NEXT(kasp, link);
   10239 		ISC_LIST_UNLINK(server->kasplist, kasp, link);
   10240 		dns_kasp_detach(&kasp);
   10241 	}
   10242 
   10243 	for (keystore = ISC_LIST_HEAD(server->keystorelist); keystore != NULL;
   10244 	     keystore = keystore_next)
   10245 	{
   10246 		keystore_next = ISC_LIST_NEXT(keystore, link);
   10247 		ISC_LIST_UNLINK(server->keystorelist, keystore, link);
   10248 		dns_keystore_detach(&keystore);
   10249 	}
   10250 
   10251 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   10252 	     view = view_next)
   10253 	{
   10254 		view_next = ISC_LIST_NEXT(view, link);
   10255 		ISC_LIST_UNLINK(server->viewlist, view, link);
   10256 		dns_view_flushonshutdown(view, flush);
   10257 		dns_view_detach(&view);
   10258 	}
   10259 
   10260 	/*
   10261 	 * Shut down all dyndb instances.
   10262 	 */
   10263 	dns_dyndb_cleanup(true);
   10264 
   10265 	while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
   10266 		ISC_LIST_UNLINK(server->cachelist, nsc, link);
   10267 		dns_cache_detach(&nsc->cache);
   10268 		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
   10269 	}
   10270 
   10271 	isc_timer_destroy(&server->interface_timer);
   10272 	isc_timer_destroy(&server->heartbeat_timer);
   10273 	isc_timer_destroy(&server->pps_timer);
   10274 	isc_timer_destroy(&server->tat_timer);
   10275 
   10276 	ns_interfacemgr_detach(&server->interfacemgr);
   10277 
   10278 	dns_dispatchmgr_detach(&named_g_dispatchmgr);
   10279 
   10280 	dns_zonemgr_shutdown(server->zonemgr);
   10281 
   10282 #if defined(HAVE_GEOIP2)
   10283 	named_geoip_shutdown();
   10284 #endif /* HAVE_GEOIP2 */
   10285 
   10286 	dns_db_detach(&server->in_roothints);
   10287 
   10288 	isc_loopmgr_resume(named_g_loopmgr);
   10289 }
   10290 
   10291 static isc_result_t
   10292 get_matching_view_sync(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
   10293 		       dns_message_t *message, dns_aclenv_t *env,
   10294 		       isc_result_t *sigresult, dns_view_t **viewp) {
   10295 	dns_view_t *view;
   10296 
   10297 	/*
   10298 	 * We should not be running synchronous view matching if signature
   10299 	 * checking involves SIG(0). TSIG has priority of SIG(0), so if TSIG
   10300 	 * is set then we proceed anyway.
   10301 	 */
   10302 	INSIST(message->tsigkey != NULL || message->tsig != NULL ||
   10303 	       message->sig0 == NULL);
   10304 
   10305 	for (view = ISC_LIST_HEAD(named_g_server->viewlist); view != NULL;
   10306 	     view = ISC_LIST_NEXT(view, link))
   10307 	{
   10308 		if (message->rdclass == view->rdclass ||
   10309 		    message->rdclass == dns_rdataclass_any)
   10310 		{
   10311 			const dns_name_t *tsig = NULL;
   10312 
   10313 			dns_message_resetsig(message);
   10314 			*sigresult = dns_message_checksig(message, view);
   10315 			if (*sigresult == ISC_R_SUCCESS) {
   10316 				tsig = dns_tsigkey_identity(message->tsigkey);
   10317 			}
   10318 
   10319 			if (dns_acl_allowed(srcaddr, tsig, view->matchclients,
   10320 					    env) &&
   10321 			    dns_acl_allowed(destaddr, tsig,
   10322 					    view->matchdestinations, env) &&
   10323 			    !(view->matchrecursiveonly &&
   10324 			      (message->flags & DNS_MESSAGEFLAG_RD) == 0))
   10325 			{
   10326 				dns_view_attach(view, viewp);
   10327 				return ISC_R_SUCCESS;
   10328 			}
   10329 		}
   10330 	}
   10331 
   10332 	return ISC_R_NOTFOUND;
   10333 }
   10334 
   10335 static void
   10336 get_matching_view_done(void *cbarg) {
   10337 	matching_view_ctx_t *mvctx = cbarg;
   10338 	dns_message_t *message = mvctx->message;
   10339 
   10340 	if (*mvctx->viewmatchresult == ISC_R_SUCCESS) {
   10341 		INSIST(mvctx->view != NULL);
   10342 		dns_view_attach(mvctx->view, mvctx->viewp);
   10343 	}
   10344 
   10345 	mvctx->cb(mvctx->cbarg);
   10346 
   10347 	dns_aclenv_detach(&mvctx->aclenv);
   10348 
   10349 	if (mvctx->quota_result == ISC_R_SUCCESS) {
   10350 		isc_quota_release(&mvctx->sctx->sig0checksquota);
   10351 	}
   10352 	if (mvctx->view != NULL) {
   10353 		dns_view_detach(&mvctx->view);
   10354 	}
   10355 	isc_loop_detach(&mvctx->loop);
   10356 	ns_server_detach(&mvctx->sctx);
   10357 	isc_mem_put(message->mctx, mvctx, sizeof(*mvctx));
   10358 	dns_message_detach(&message);
   10359 }
   10360 
   10361 static dns_view_t *
   10362 get_matching_view_next(dns_view_t *view, dns_rdataclass_t rdclass) {
   10363 	if (view == NULL) {
   10364 		view = ISC_LIST_HEAD(named_g_server->viewlist);
   10365 	} else {
   10366 		view = ISC_LIST_NEXT(view, link);
   10367 	}
   10368 	while (true) {
   10369 		if (view == NULL || rdclass == view->rdclass ||
   10370 		    rdclass == dns_rdataclass_any)
   10371 		{
   10372 			return view;
   10373 		}
   10374 		view = ISC_LIST_NEXT(view, link);
   10375 	};
   10376 }
   10377 
   10378 static void
   10379 get_matching_view_continue(void *cbarg, isc_result_t result) {
   10380 	matching_view_ctx_t *mvctx = cbarg;
   10381 	dns_view_t *view = NULL;
   10382 	const dns_name_t *tsig = NULL;
   10383 
   10384 	*mvctx->sigresult = result;
   10385 
   10386 	if (result == ISC_R_SUCCESS) {
   10387 		tsig = dns_tsigkey_identity(mvctx->message->tsigkey);
   10388 	}
   10389 
   10390 	if (dns_acl_allowed(&mvctx->srcaddr, tsig, mvctx->view->matchclients,
   10391 			    mvctx->aclenv) &&
   10392 	    dns_acl_allowed(&mvctx->destaddr, tsig,
   10393 			    mvctx->view->matchdestinations, mvctx->aclenv) &&
   10394 	    !(mvctx->view->matchrecursiveonly &&
   10395 	      (mvctx->message->flags & DNS_MESSAGEFLAG_RD) == 0))
   10396 	{
   10397 		/*
   10398 		 * A matching view is found.
   10399 		 */
   10400 		*mvctx->viewmatchresult = ISC_R_SUCCESS;
   10401 		get_matching_view_done(cbarg);
   10402 		return;
   10403 	}
   10404 
   10405 	dns_message_resetsig(mvctx->message);
   10406 
   10407 	view = get_matching_view_next(mvctx->view, mvctx->message->rdclass);
   10408 	dns_view_detach(&mvctx->view);
   10409 	if (view != NULL) {
   10410 		/*
   10411 		 * Try the next view.
   10412 		 */
   10413 		dns_view_attach(view, &mvctx->view);
   10414 		result = dns_message_checksig_async(
   10415 			mvctx->message, view, mvctx->loop,
   10416 			get_matching_view_continue, mvctx);
   10417 		INSIST(result == DNS_R_WAIT);
   10418 		return;
   10419 	}
   10420 
   10421 	/*
   10422 	 * No matching view is found.
   10423 	 */
   10424 	*mvctx->viewmatchresult = ISC_R_NOTFOUND;
   10425 	get_matching_view_done(cbarg);
   10426 }
   10427 
   10428 /*%
   10429  * Find a view that matches the source and destination addresses of a query.
   10430  */
   10431 static isc_result_t
   10432 get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
   10433 		  dns_message_t *message, dns_aclenv_t *env, ns_server_t *sctx,
   10434 		  isc_loop_t *loop, isc_job_cb cb, void *cbarg,
   10435 		  isc_result_t *sigresult, isc_result_t *viewmatchresult,
   10436 		  dns_view_t **viewp) {
   10437 	dns_view_t *view = NULL;
   10438 	isc_result_t result;
   10439 
   10440 	REQUIRE(message != NULL);
   10441 	REQUIRE(sctx != NULL);
   10442 	REQUIRE(loop == NULL || cb != NULL);
   10443 	REQUIRE(sigresult != NULL);
   10444 	REQUIRE(viewmatchresult != NULL);
   10445 	REQUIRE(viewp != NULL && *viewp == NULL);
   10446 
   10447 	/* No offloading is requested if the loop is unset. */
   10448 	if (loop == NULL) {
   10449 		*viewmatchresult = get_matching_view_sync(
   10450 			srcaddr, destaddr, message, env, sigresult, viewp);
   10451 		return *viewmatchresult;
   10452 	}
   10453 
   10454 	/* Also no offloading when there is no view at all to match against. */
   10455 	view = get_matching_view_next(NULL, message->rdclass);
   10456 	if (view == NULL) {
   10457 		*viewmatchresult = ISC_R_NOTFOUND;
   10458 		return *viewmatchresult;
   10459 	}
   10460 
   10461 	dns_message_resetsig(message);
   10462 
   10463 	matching_view_ctx_t *mvctx = isc_mem_get(message->mctx, sizeof(*mvctx));
   10464 	*mvctx = (matching_view_ctx_t){
   10465 		.srcaddr = *srcaddr,
   10466 		.destaddr = *destaddr,
   10467 		.aclenv = dns_aclenv_ref(env),
   10468 		.cb = cb,
   10469 		.cbarg = cbarg,
   10470 		.sigresult = sigresult,
   10471 		.viewmatchresult = viewmatchresult,
   10472 		.quota_result = ISC_R_UNSET,
   10473 		.viewp = viewp,
   10474 	};
   10475 	ns_server_attach(sctx, &mvctx->sctx);
   10476 	isc_loop_attach(loop, &mvctx->loop);
   10477 	dns_message_attach(message, &mvctx->message);
   10478 
   10479 	/*
   10480 	 * If the message has a SIG0 signature which we are going to
   10481 	 * check, and the client is not exempt from the SIG(0) quota,
   10482 	 * then acquire a quota. TSIG has priority over SIG(0), so if
   10483 	 * TSIG is set then we don't care.
   10484 	 */
   10485 	if (message->tsigkey == NULL && message->tsig == NULL &&
   10486 	    message->sig0 != NULL)
   10487 	{
   10488 		if (sctx->sig0checksquota_exempt != NULL) {
   10489 			int exempt_match;
   10490 
   10491 			result = dns_acl_match(srcaddr, NULL,
   10492 					       sctx->sig0checksquota_exempt,
   10493 					       env, &exempt_match, NULL);
   10494 			if (result == ISC_R_SUCCESS && exempt_match > 0) {
   10495 				mvctx->quota_result = ISC_R_EXISTS;
   10496 			}
   10497 		}
   10498 		if (mvctx->quota_result == ISC_R_UNSET) {
   10499 			mvctx->quota_result =
   10500 				isc_quota_acquire(&sctx->sig0checksquota);
   10501 		}
   10502 		if (mvctx->quota_result == ISC_R_SOFTQUOTA) {
   10503 			isc_quota_release(&sctx->sig0checksquota);
   10504 		}
   10505 		if (mvctx->quota_result != ISC_R_SUCCESS &&
   10506 		    mvctx->quota_result != ISC_R_EXISTS)
   10507 		{
   10508 			*mvctx->viewmatchresult = ISC_R_QUOTA;
   10509 			isc_async_run(loop, get_matching_view_done, mvctx);
   10510 			return DNS_R_WAIT;
   10511 		}
   10512 	}
   10513 
   10514 	dns_view_attach(view, &mvctx->view);
   10515 	result = dns_message_checksig_async(message, view, loop,
   10516 					    get_matching_view_continue, mvctx);
   10517 	INSIST(result == DNS_R_WAIT);
   10518 
   10519 	return DNS_R_WAIT;
   10520 }
   10521 
   10522 void
   10523 named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
   10524 	isc_result_t result;
   10525 	named_server_t *server = isc_mem_get(mctx, sizeof(*server));
   10526 
   10527 	*server = (named_server_t){
   10528 		.mctx = mctx,
   10529 		.statsfile = isc_mem_strdup(mctx, "named.stats"),
   10530 		.dumpfile = isc_mem_strdup(mctx, "named_dump.db"),
   10531 		.secrootsfile = isc_mem_strdup(mctx, "named.secroots"),
   10532 		.recfile = isc_mem_strdup(mctx, "named.recursing"),
   10533 	};
   10534 
   10535 	/* Initialize server data structures. */
   10536 	ISC_LIST_INIT(server->kasplist);
   10537 	ISC_LIST_INIT(server->keystorelist);
   10538 	ISC_LIST_INIT(server->viewlist);
   10539 
   10540 	/* Must be first. */
   10541 	CHECKFATAL(dst_lib_init(named_g_mctx, named_g_engine),
   10542 		   "initializing DST");
   10543 
   10544 	CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
   10545 				     &server->in_roothints),
   10546 		   "setting up root hints");
   10547 
   10548 	atomic_init(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
   10549 
   10550 	ns_server_create(mctx, get_matching_view, &server->sctx);
   10551 
   10552 #if defined(HAVE_GEOIP2)
   10553 	/*
   10554 	 * GeoIP must be initialized before the interface
   10555 	 * manager (which includes the ACL environment)
   10556 	 * is created.
   10557 	 */
   10558 	named_geoip_init();
   10559 #endif /* HAVE_GEOIP2 */
   10560 
   10561 #ifdef ENABLE_AFL
   10562 	server->sctx->fuzztype = named_g_fuzz_type;
   10563 	server->sctx->fuzznotify = named_fuzz_notify;
   10564 #endif /* ifdef ENABLE_AFL */
   10565 
   10566 	named_g_mainloop = isc_loop_main(named_g_loopmgr);
   10567 
   10568 	isc_loop_setup(named_g_mainloop, run_server, server);
   10569 	isc_loop_teardown(named_g_mainloop, shutdown_server, server);
   10570 
   10571 	/* Add SIGHUP reload handler  */
   10572 	server->sighup = isc_signal_new(
   10573 		named_g_loopmgr, named_server_reloadwanted, server, SIGHUP);
   10574 
   10575 	isc_stats_create(server->mctx, &server->sockstats,
   10576 			 isc_sockstatscounter_max);
   10577 	isc_nm_setstats(named_g_netmgr, server->sockstats);
   10578 
   10579 	isc_stats_create(named_g_mctx, &server->zonestats,
   10580 			 dns_zonestatscounter_max);
   10581 
   10582 	isc_stats_create(named_g_mctx, &server->resolverstats,
   10583 			 dns_resstatscounter_max);
   10584 
   10585 	CHECKFATAL(named_controls_create(server, &server->controls),
   10586 		   "named_controls_create");
   10587 
   10588 	ISC_LIST_INIT(server->statschannels);
   10589 
   10590 	ISC_LIST_INIT(server->cachelist);
   10591 
   10592 	server->magic = NAMED_SERVER_MAGIC;
   10593 
   10594 	*serverp = server;
   10595 }
   10596 
   10597 void
   10598 named_server_destroy(named_server_t **serverp) {
   10599 	named_server_t *server = *serverp;
   10600 	REQUIRE(NAMED_SERVER_VALID(server));
   10601 
   10602 #ifdef HAVE_DNSTAP
   10603 	if (server->dtenv != NULL) {
   10604 		dns_dtenv_detach(&server->dtenv);
   10605 	}
   10606 #endif /* HAVE_DNSTAP */
   10607 
   10608 #ifdef USE_DNSRPS
   10609 	dns_dnsrps_server_destroy();
   10610 	isc_mem_free(server->mctx, server->dnsrpslib);
   10611 #endif /* ifdef USE_DNSRPS */
   10612 
   10613 	named_controls_destroy(&server->controls);
   10614 
   10615 	isc_stats_detach(&server->zonestats);
   10616 	isc_stats_detach(&server->sockstats);
   10617 	isc_stats_detach(&server->resolverstats);
   10618 
   10619 	if (server->sctx != NULL) {
   10620 		ns_server_detach(&server->sctx);
   10621 	}
   10622 
   10623 	isc_mem_free(server->mctx, server->statsfile);
   10624 	isc_mem_free(server->mctx, server->dumpfile);
   10625 	isc_mem_free(server->mctx, server->secrootsfile);
   10626 	isc_mem_free(server->mctx, server->recfile);
   10627 
   10628 	if (server->bindkeysfile != NULL) {
   10629 		isc_mem_free(server->mctx, server->bindkeysfile);
   10630 	}
   10631 
   10632 	if (server->version != NULL) {
   10633 		isc_mem_free(server->mctx, server->version);
   10634 	}
   10635 	if (server->hostname != NULL) {
   10636 		isc_mem_free(server->mctx, server->hostname);
   10637 	}
   10638 
   10639 	if (server->zonemgr != NULL) {
   10640 		dns_zonemgr_detach(&server->zonemgr);
   10641 	}
   10642 
   10643 	dst_lib_destroy();
   10644 
   10645 	INSIST(ISC_LIST_EMPTY(server->kasplist));
   10646 	INSIST(ISC_LIST_EMPTY(server->keystorelist));
   10647 	INSIST(ISC_LIST_EMPTY(server->viewlist));
   10648 	INSIST(ISC_LIST_EMPTY(server->cachelist));
   10649 
   10650 	if (server->tlsctx_server_cache != NULL) {
   10651 		isc_tlsctx_cache_detach(&server->tlsctx_server_cache);
   10652 	}
   10653 
   10654 	if (server->tlsctx_client_cache != NULL) {
   10655 		isc_tlsctx_cache_detach(&server->tlsctx_client_cache);
   10656 	}
   10657 
   10658 	server->magic = 0;
   10659 	isc_mem_put(server->mctx, server, sizeof(*server));
   10660 	*serverp = NULL;
   10661 }
   10662 
   10663 static void
   10664 fatal(const char *msg, isc_result_t result) {
   10665 	if (named_g_loopmgr_running) {
   10666 		isc_loopmgr_pause(named_g_loopmgr);
   10667 	}
   10668 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10669 		      NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL, "%s: %s", msg,
   10670 		      isc_result_totext(result));
   10671 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10672 		      NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL,
   10673 		      "exiting (due to fatal error)");
   10674 	named_os_shutdown();
   10675 	_exit(EXIT_FAILURE);
   10676 }
   10677 
   10678 static isc_result_t
   10679 loadconfig(named_server_t *server) {
   10680 	isc_result_t result;
   10681 	result = load_configuration(named_g_conffile, server, false);
   10682 	if (result == ISC_R_SUCCESS) {
   10683 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10684 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   10685 			      "reloading configuration succeeded");
   10686 	} else {
   10687 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10688 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   10689 			      "reloading configuration failed: %s",
   10690 			      isc_result_totext(result));
   10691 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
   10692 	}
   10693 
   10694 	return result;
   10695 }
   10696 
   10697 static isc_result_t
   10698 reload(named_server_t *server) {
   10699 	isc_result_t result;
   10700 
   10701 	atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
   10702 
   10703 	named_os_notify_systemd("RELOADING=1\n"
   10704 				"MONOTONIC_USEC=%" PRIu64 "\n"
   10705 				"STATUS=reload command received\n",
   10706 				(uint64_t)isc_time_monotonic() / NS_PER_US);
   10707 
   10708 	CHECK(loadconfig(server));
   10709 
   10710 	result = load_zones(server, false);
   10711 	if (result == ISC_R_SUCCESS) {
   10712 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10713 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   10714 			      "reloading zones succeeded");
   10715 	} else {
   10716 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10717 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   10718 			      "reloading zones failed: %s",
   10719 			      isc_result_totext(result));
   10720 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
   10721 	}
   10722 cleanup:
   10723 	named_os_notify_systemd("READY=1\n"
   10724 				"STATUS=reload command finished: %s\n",
   10725 				isc_result_totext(result));
   10726 
   10727 	return result;
   10728 }
   10729 
   10730 /*
   10731  * Handle a reload event (from SIGHUP).
   10732  */
   10733 static void
   10734 named_server_reload(void *arg) {
   10735 	named_server_t *server = (named_server_t *)arg;
   10736 
   10737 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10738 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   10739 		      "received SIGHUP signal to reload zones");
   10740 	(void)reload(server);
   10741 }
   10742 
   10743 void
   10744 named_server_reloadwanted(void *arg, int signum) {
   10745 	named_server_t *server = (named_server_t *)arg;
   10746 
   10747 	REQUIRE(signum == SIGHUP);
   10748 
   10749 	isc_async_run(named_g_mainloop, named_server_reload, server);
   10750 }
   10751 
   10752 #ifdef JEMALLOC_API_SUPPORTED
   10753 static isc_result_t
   10754 memprof_toggle(bool active) {
   10755 	if (mallctl("prof.active", NULL, NULL, &active, sizeof(active)) != 0) {
   10756 		return ISC_R_FAILURE;
   10757 	}
   10758 
   10759 	return ISC_R_SUCCESS;
   10760 }
   10761 
   10762 static isc_result_t
   10763 memprof_dump(void) {
   10764 	if (mallctl("prof.dump", NULL, NULL, NULL, 0) != 0) {
   10765 		return ISC_R_FAILURE;
   10766 	}
   10767 
   10768 	return ISC_R_SUCCESS;
   10769 }
   10770 #else
   10771 static isc_result_t
   10772 memprof_toggle(bool active) {
   10773 	UNUSED(active);
   10774 
   10775 	return ISC_R_NOTIMPLEMENTED;
   10776 }
   10777 
   10778 static isc_result_t
   10779 memprof_dump(void) {
   10780 	return ISC_R_NOTIMPLEMENTED;
   10781 }
   10782 
   10783 #endif /* JEMALLOC_API_SUPPORTED */
   10784 
   10785 void
   10786 named_server_scan_interfaces(named_server_t *server) {
   10787 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10788 		      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
   10789 		      "automatic interface rescan");
   10790 
   10791 	ns_interfacemgr_scan(server->interfacemgr, true, false);
   10792 }
   10793 
   10794 /*
   10795  * Get the next token from lexer 'lex'.
   10796  *
   10797  * NOTE: the token value for string tokens always uses the same pointer
   10798  * value.  Multiple calls to this function on the same lexer will always
   10799  * return either that value (lex->data) or NULL. It is necessary to copy
   10800  * the token into local storage if it needs to be referenced after the next
   10801  * call to next_token().
   10802  */
   10803 static char *
   10804 next_token(isc_lex_t *lex, isc_buffer_t **text) {
   10805 	isc_result_t result;
   10806 	isc_token_t token;
   10807 
   10808 	token.type = isc_tokentype_unknown;
   10809 	result = isc_lex_gettoken(lex, ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING,
   10810 				  &token);
   10811 
   10812 	switch (result) {
   10813 	case ISC_R_NOMORE:
   10814 		(void)isc_lex_close(lex);
   10815 		break;
   10816 	case ISC_R_SUCCESS:
   10817 		if (token.type == isc_tokentype_eof) {
   10818 			(void)isc_lex_close(lex);
   10819 		}
   10820 		break;
   10821 	case ISC_R_NOSPACE:
   10822 		if (text != NULL) {
   10823 			(void)putstr(text, "token too large");
   10824 			(void)putnull(text);
   10825 		}
   10826 		return NULL;
   10827 	default:
   10828 		if (text != NULL) {
   10829 			(void)putstr(text, isc_result_totext(result));
   10830 			(void)putnull(text);
   10831 		}
   10832 		return NULL;
   10833 	}
   10834 
   10835 	if (token.type == isc_tokentype_string ||
   10836 	    token.type == isc_tokentype_qstring)
   10837 	{
   10838 		return token.value.as_textregion.base;
   10839 	}
   10840 
   10841 	return NULL;
   10842 }
   10843 
   10844 /*
   10845  * Find the zone specified in the control channel command, if any.
   10846  * If a zone is specified, point '*zonep' at it, otherwise
   10847  * set '*zonep' to NULL, and f 'zonename' is not NULL, copy
   10848  * the zone name into it (N.B. 'zonename' must have space to hold
   10849  * a full DNS name).
   10850  *
   10851  * If 'zonetxt' is set, the caller has already pulled a token
   10852  * off the command line that is to be used as the zone name. (This
   10853  * is sometimes done when it's necessary to check for an optional
   10854  * argument before the zone name, as in "rndc sync [-clean] zone".)
   10855  */
   10856 static isc_result_t
   10857 zone_from_args(named_server_t *server, isc_lex_t *lex, const char *zonetxt,
   10858 	       dns_zone_t **zonep, char *zonename, isc_buffer_t **text,
   10859 	       bool skip) {
   10860 	char *ptr;
   10861 	char *classtxt;
   10862 	const char *viewtxt = NULL;
   10863 	dns_fixedname_t fname;
   10864 	dns_name_t *name;
   10865 	isc_result_t result;
   10866 	dns_view_t *view = NULL;
   10867 	dns_rdataclass_t rdclass;
   10868 	char problem[DNS_NAME_FORMATSIZE + 500] = "";
   10869 	char zonebuf[DNS_NAME_FORMATSIZE];
   10870 	bool redirect = false;
   10871 
   10872 	REQUIRE(zonep != NULL && *zonep == NULL);
   10873 
   10874 	if (skip) {
   10875 		/* Skip the command name. */
   10876 		ptr = next_token(lex, text);
   10877 		if (ptr == NULL) {
   10878 			return ISC_R_UNEXPECTEDEND;
   10879 		}
   10880 	}
   10881 
   10882 	/* Look for the zone name. */
   10883 	if (zonetxt == NULL) {
   10884 		zonetxt = next_token(lex, text);
   10885 	}
   10886 	if (zonetxt == NULL) {
   10887 		return ISC_R_SUCCESS;
   10888 	}
   10889 
   10890 	/* Copy zonetxt because it'll be overwritten by next_token() */
   10891 	/* To locate a zone named "-redirect" use "-redirect." */
   10892 	if (strcmp(zonetxt, "-redirect") == 0) {
   10893 		redirect = true;
   10894 		strlcpy(zonebuf, ".", DNS_NAME_FORMATSIZE);
   10895 	} else {
   10896 		strlcpy(zonebuf, zonetxt, DNS_NAME_FORMATSIZE);
   10897 	}
   10898 	if (zonename != NULL) {
   10899 		strlcpy(zonename, redirect ? "." : zonetxt,
   10900 			DNS_NAME_FORMATSIZE);
   10901 	}
   10902 
   10903 	name = dns_fixedname_initname(&fname);
   10904 	CHECK(dns_name_fromstring(name, zonebuf, dns_rootname, 0, NULL));
   10905 
   10906 	/* Look for the optional class name. */
   10907 	classtxt = next_token(lex, text);
   10908 	if (classtxt != NULL) {
   10909 		isc_textregion_t r;
   10910 		r.base = classtxt;
   10911 		r.length = strlen(classtxt);
   10912 		CHECK(dns_rdataclass_fromtext(&rdclass, &r));
   10913 
   10914 		/* Look for the optional view name. */
   10915 		viewtxt = next_token(lex, text);
   10916 	} else {
   10917 		rdclass = dns_rdataclass_in;
   10918 	}
   10919 
   10920 	if (viewtxt == NULL) {
   10921 		if (redirect) {
   10922 			result = dns_viewlist_find(&server->viewlist,
   10923 						   "_default",
   10924 						   dns_rdataclass_in, &view);
   10925 			if (result != ISC_R_SUCCESS || view->redirect == NULL) {
   10926 				result = ISC_R_NOTFOUND;
   10927 				snprintf(problem, sizeof(problem),
   10928 					 "redirect zone not found in "
   10929 					 "_default view");
   10930 			} else {
   10931 				dns_zone_attach(view->redirect, zonep);
   10932 				result = ISC_R_SUCCESS;
   10933 			}
   10934 		} else {
   10935 			result = dns_viewlist_findzone(&server->viewlist, name,
   10936 						       classtxt == NULL,
   10937 						       rdclass, zonep);
   10938 			if (result == ISC_R_NOTFOUND) {
   10939 				snprintf(problem, sizeof(problem),
   10940 					 "no matching zone '%s' in any view",
   10941 					 zonebuf);
   10942 			} else if (result == ISC_R_MULTIPLE) {
   10943 				snprintf(problem, sizeof(problem),
   10944 					 "zone '%s' was found in multiple "
   10945 					 "views",
   10946 					 zonebuf);
   10947 			}
   10948 		}
   10949 	} else {
   10950 		result = dns_viewlist_find(&server->viewlist, viewtxt, rdclass,
   10951 					   &view);
   10952 		if (result != ISC_R_SUCCESS) {
   10953 			snprintf(problem, sizeof(problem),
   10954 				 "no matching view '%s'", viewtxt);
   10955 			goto report;
   10956 		}
   10957 
   10958 		if (redirect) {
   10959 			if (view->redirect != NULL) {
   10960 				dns_zone_attach(view->redirect, zonep);
   10961 				result = ISC_R_SUCCESS;
   10962 			} else {
   10963 				result = ISC_R_NOTFOUND;
   10964 			}
   10965 		} else {
   10966 			result = dns_view_findzone(view, name, DNS_ZTFIND_EXACT,
   10967 						   zonep);
   10968 		}
   10969 		if (result != ISC_R_SUCCESS) {
   10970 			snprintf(problem, sizeof(problem),
   10971 				 "no matching zone '%s' in view '%s'", zonebuf,
   10972 				 viewtxt);
   10973 		}
   10974 	}
   10975 
   10976 	/* Partial match? */
   10977 	if (result != ISC_R_SUCCESS && *zonep != NULL) {
   10978 		dns_zone_detach(zonep);
   10979 	}
   10980 	if (result == DNS_R_PARTIALMATCH) {
   10981 		result = ISC_R_NOTFOUND;
   10982 	}
   10983 report:
   10984 	if (result != ISC_R_SUCCESS) {
   10985 		isc_result_t tresult;
   10986 
   10987 		tresult = putstr(text, problem);
   10988 		if (tresult == ISC_R_SUCCESS) {
   10989 			(void)putnull(text);
   10990 		}
   10991 	}
   10992 
   10993 cleanup:
   10994 	if (view != NULL) {
   10995 		dns_view_detach(&view);
   10996 	}
   10997 
   10998 	return result;
   10999 }
   11000 
   11001 /*
   11002  * Act on a "retransfer" command from the command channel.
   11003  */
   11004 isc_result_t
   11005 named_server_retransfercommand(named_server_t *server, isc_lex_t *lex,
   11006 			       isc_buffer_t **text) {
   11007 	isc_result_t result;
   11008 	const char *arg = NULL;
   11009 	dns_zone_t *zone = NULL;
   11010 	dns_zone_t *raw = NULL;
   11011 	dns_zonetype_t type;
   11012 	bool force = false;
   11013 
   11014 	REQUIRE(text != NULL);
   11015 
   11016 	/* Skip the command name. */
   11017 	(void)next_token(lex, text);
   11018 
   11019 	arg = next_token(lex, text);
   11020 	if (arg != NULL && (strcmp(arg, "-force") == 0)) {
   11021 		force = true;
   11022 		arg = next_token(lex, text);
   11023 	}
   11024 
   11025 	result = zone_from_args(server, lex, arg, &zone, NULL, text, false);
   11026 	if (result != ISC_R_SUCCESS) {
   11027 		return result;
   11028 	}
   11029 	if (zone == NULL) {
   11030 		return ISC_R_UNEXPECTEDEND;
   11031 	}
   11032 	dns_zone_getraw(zone, &raw);
   11033 	if (raw != NULL) {
   11034 		dns_zone_detach(&zone);
   11035 		dns_zone_attach(raw, &zone);
   11036 		dns_zone_detach(&raw);
   11037 	}
   11038 	type = dns_zone_gettype(zone);
   11039 	if (type == dns_zone_secondary || type == dns_zone_mirror ||
   11040 	    type == dns_zone_stub ||
   11041 	    (type == dns_zone_redirect &&
   11042 	     dns_zone_getredirecttype(zone) == dns_zone_secondary))
   11043 	{
   11044 		if (force) {
   11045 			dns_zone_stopxfr(zone);
   11046 		}
   11047 		dns_zone_forcexfr(zone);
   11048 	} else {
   11049 		(void)putstr(text, "retransfer: inappropriate zone type: ");
   11050 		(void)putstr(text, dns_zonetype_name(type));
   11051 		if (type == dns_zone_redirect) {
   11052 			type = dns_zone_getredirecttype(zone);
   11053 			(void)putstr(text, "(");
   11054 			(void)putstr(text, dns_zonetype_name(type));
   11055 			(void)putstr(text, ")");
   11056 		}
   11057 		(void)putnull(text);
   11058 		result = ISC_R_FAILURE;
   11059 	}
   11060 	dns_zone_detach(&zone);
   11061 	return result;
   11062 }
   11063 
   11064 /*
   11065  * Act on a "reload" command from the command channel.
   11066  */
   11067 isc_result_t
   11068 named_server_reloadcommand(named_server_t *server, isc_lex_t *lex,
   11069 			   isc_buffer_t **text) {
   11070 	isc_result_t result;
   11071 	dns_zone_t *zone = NULL;
   11072 	dns_zonetype_t type;
   11073 	const char *msg = NULL;
   11074 
   11075 	REQUIRE(text != NULL);
   11076 
   11077 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
   11078 	if (result != ISC_R_SUCCESS) {
   11079 		return result;
   11080 	}
   11081 	if (zone == NULL) {
   11082 		result = reload(server);
   11083 		if (result == ISC_R_SUCCESS) {
   11084 			msg = "server reload successful";
   11085 		}
   11086 	} else {
   11087 		type = dns_zone_gettype(zone);
   11088 		if (type == dns_zone_secondary || type == dns_zone_mirror ||
   11089 		    type == dns_zone_stub)
   11090 		{
   11091 			dns_zone_refresh(zone);
   11092 			dns_zone_detach(&zone);
   11093 			msg = "zone refresh queued";
   11094 		} else {
   11095 			result = dns_zone_load(zone, false);
   11096 			dns_zone_detach(&zone);
   11097 			switch (result) {
   11098 			case ISC_R_SUCCESS:
   11099 				msg = "zone reload successful";
   11100 				break;
   11101 			case DNS_R_CONTINUE:
   11102 				msg = "zone reload queued";
   11103 				result = ISC_R_SUCCESS;
   11104 				break;
   11105 			case DNS_R_UPTODATE:
   11106 				msg = "zone reload up-to-date";
   11107 				result = ISC_R_SUCCESS;
   11108 				break;
   11109 			default:
   11110 				/* failure message will be generated by rndc */
   11111 				break;
   11112 			}
   11113 		}
   11114 	}
   11115 	if (msg != NULL) {
   11116 		(void)putstr(text, msg);
   11117 		(void)putnull(text);
   11118 	}
   11119 	return result;
   11120 }
   11121 
   11122 /*
   11123  * Act on a "reset-stats" command from the command channel.
   11124  */
   11125 isc_result_t
   11126 named_server_resetstatscommand(named_server_t *server, isc_lex_t *lex,
   11127 			       isc_buffer_t **text) {
   11128 	const char *arg = NULL;
   11129 	bool recursive_high_water = false;
   11130 	bool tcp_high_water = false;
   11131 
   11132 	REQUIRE(text != NULL);
   11133 
   11134 	/* Skip the command name. */
   11135 	(void)next_token(lex, text);
   11136 
   11137 	arg = next_token(lex, text);
   11138 	if (arg == NULL) {
   11139 		(void)putstr(text, "reset-stats: argument expected");
   11140 		(void)putnull(text);
   11141 		return ISC_R_UNEXPECTEDEND;
   11142 	}
   11143 	while (arg != NULL) {
   11144 		if (strcmp(arg, "recursive-high-water") == 0) {
   11145 			recursive_high_water = true;
   11146 		} else if (strcmp(arg, "tcp-high-water") == 0) {
   11147 			tcp_high_water = true;
   11148 		} else {
   11149 			(void)putstr(text, "reset-stats: "
   11150 					   "unrecognized argument: ");
   11151 			(void)putstr(text, arg);
   11152 			(void)putnull(text);
   11153 			return ISC_R_FAILURE;
   11154 		}
   11155 		arg = next_token(lex, text);
   11156 	}
   11157 
   11158 	if (recursive_high_water) {
   11159 		isc_stats_set(ns_stats_get(server->sctx->nsstats), 0,
   11160 			      ns_statscounter_recurshighwater);
   11161 	}
   11162 	if (tcp_high_water) {
   11163 		isc_stats_set(ns_stats_get(server->sctx->nsstats), 0,
   11164 			      ns_statscounter_tcphighwater);
   11165 	}
   11166 
   11167 	return ISC_R_SUCCESS;
   11168 }
   11169 
   11170 /*
   11171  * Act on a "reconfig" command from the command channel.
   11172  */
   11173 isc_result_t
   11174 named_server_reconfigcommand(named_server_t *server) {
   11175 	isc_result_t result;
   11176 	atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
   11177 
   11178 	named_os_notify_systemd("RELOADING=1\n"
   11179 				"MONOTONIC_USEC=%" PRIu64 "\n"
   11180 				"STATUS=reconfig command received\n",
   11181 				(uint64_t)isc_time_monotonic() / NS_PER_US);
   11182 
   11183 	CHECK(loadconfig(server));
   11184 
   11185 	result = load_zones(server, true);
   11186 	if (result == ISC_R_SUCCESS) {
   11187 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   11188 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   11189 			      "scheduled loading new zones");
   11190 	} else {
   11191 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   11192 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   11193 			      "loading new zones failed: %s",
   11194 			      isc_result_totext(result));
   11195 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
   11196 	}
   11197 cleanup:
   11198 	named_os_notify_systemd("READY=1\n"
   11199 				"STATUS=reconfig command finished: %s\n",
   11200 				isc_result_totext(result));
   11201 
   11202 	return result;
   11203 }
   11204 
   11205 /*
   11206  * Act on a "notify" command from the command channel.
   11207  */
   11208 isc_result_t
   11209 named_server_notifycommand(named_server_t *server, isc_lex_t *lex,
   11210 			   isc_buffer_t **text) {
   11211 	isc_result_t result;
   11212 	dns_zone_t *zone = NULL;
   11213 	const char msg[] = "zone notify queued";
   11214 
   11215 	REQUIRE(text != NULL);
   11216 
   11217 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
   11218 	if (result != ISC_R_SUCCESS) {
   11219 		return result;
   11220 	}
   11221 	if (zone == NULL) {
   11222 		return ISC_R_UNEXPECTEDEND;
   11223 	}
   11224 
   11225 	dns_zone_notify(zone, true);
   11226 	dns_zone_detach(&zone);
   11227 	(void)putstr(text, msg);
   11228 	(void)putnull(text);
   11229 
   11230 	return ISC_R_SUCCESS;
   11231 }
   11232 
   11233 /*
   11234  * Act on a "refresh" command from the command channel.
   11235  */
   11236 isc_result_t
   11237 named_server_refreshcommand(named_server_t *server, isc_lex_t *lex,
   11238 			    isc_buffer_t **text) {
   11239 	isc_result_t result;
   11240 	dns_zone_t *zone = NULL, *raw = NULL;
   11241 	const char msg1[] = "zone refresh queued";
   11242 	const char msg2[] = "not a secondary, mirror, or stub zone";
   11243 	dns_zonetype_t type;
   11244 
   11245 	REQUIRE(text != NULL);
   11246 
   11247 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
   11248 	if (result != ISC_R_SUCCESS) {
   11249 		return result;
   11250 	}
   11251 	if (zone == NULL) {
   11252 		return ISC_R_UNEXPECTEDEND;
   11253 	}
   11254 
   11255 	dns_zone_getraw(zone, &raw);
   11256 	if (raw != NULL) {
   11257 		dns_zone_detach(&zone);
   11258 		dns_zone_attach(raw, &zone);
   11259 		dns_zone_detach(&raw);
   11260 	}
   11261 
   11262 	type = dns_zone_gettype(zone);
   11263 	if (type == dns_zone_secondary || type == dns_zone_mirror ||
   11264 	    type == dns_zone_stub)
   11265 	{
   11266 		dns_zone_refresh(zone);
   11267 		dns_zone_detach(&zone);
   11268 		(void)putstr(text, msg1);
   11269 		(void)putnull(text);
   11270 		return ISC_R_SUCCESS;
   11271 	}
   11272 
   11273 	dns_zone_detach(&zone);
   11274 	(void)putstr(text, msg2);
   11275 	(void)putnull(text);
   11276 	return ISC_R_FAILURE;
   11277 }
   11278 
   11279 isc_result_t
   11280 named_server_setortoggle(named_server_t *server, const char *optname,
   11281 			 unsigned int option, isc_lex_t *lex) {
   11282 	bool prev, value;
   11283 	char *ptr = NULL;
   11284 
   11285 	/* Skip the command name. */
   11286 	ptr = next_token(lex, NULL);
   11287 	if (ptr == NULL) {
   11288 		return ISC_R_UNEXPECTEDEND;
   11289 	}
   11290 
   11291 	prev = ns_server_getoption(server->sctx, option);
   11292 
   11293 	ptr = next_token(lex, NULL);
   11294 	if (ptr == NULL) {
   11295 		value = !prev;
   11296 	} else if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
   11297 		   !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
   11298 	{
   11299 		value = true;
   11300 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
   11301 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
   11302 	{
   11303 		value = false;
   11304 	} else {
   11305 		return DNS_R_SYNTAX;
   11306 	}
   11307 
   11308 	if (value == prev) {
   11309 		return ISC_R_SUCCESS;
   11310 	}
   11311 
   11312 	ns_server_setoption(server->sctx, option, value);
   11313 
   11314 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   11315 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, "%s is now %s",
   11316 		      optname, value ? "on" : "off");
   11317 	return ISC_R_SUCCESS;
   11318 }
   11319 
   11320 static isc_result_t
   11321 listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
   11322 		      cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
   11323 		      isc_tlsctx_cache_t *tlsctx_cache,
   11324 		      ns_listenlist_t **target) {
   11325 	isc_result_t result;
   11326 	const cfg_listelt_t *element;
   11327 	ns_listenlist_t *dlist = NULL;
   11328 
   11329 	REQUIRE(target != NULL && *target == NULL);
   11330 
   11331 	result = ns_listenlist_create(mctx, &dlist);
   11332 	if (result != ISC_R_SUCCESS) {
   11333 		return result;
   11334 	}
   11335 
   11336 	for (element = cfg_list_first(listenlist); element != NULL;
   11337 	     element = cfg_list_next(element))
   11338 	{
   11339 		ns_listenelt_t *delt = NULL;
   11340 		const cfg_obj_t *listener = cfg_listelt_value(element);
   11341 		result = listenelt_fromconfig(listener, config, actx, mctx,
   11342 					      family, tlsctx_cache, &delt);
   11343 		if (result != ISC_R_SUCCESS) {
   11344 			goto cleanup;
   11345 		}
   11346 		ISC_LIST_APPEND(dlist->elts, delt, link);
   11347 	}
   11348 	*target = dlist;
   11349 	return ISC_R_SUCCESS;
   11350 
   11351 cleanup:
   11352 	ns_listenlist_detach(&dlist);
   11353 	return result;
   11354 }
   11355 
   11356 static const cfg_obj_t *
   11357 find_maplist(const cfg_obj_t *config, const char *listname, const char *name) {
   11358 	isc_result_t result;
   11359 	const cfg_obj_t *maplist = NULL;
   11360 	const cfg_listelt_t *elt = NULL;
   11361 
   11362 	REQUIRE(config != NULL);
   11363 	REQUIRE(name != NULL);
   11364 
   11365 	result = cfg_map_get(config, listname, &maplist);
   11366 	if (result != ISC_R_SUCCESS) {
   11367 		return NULL;
   11368 	}
   11369 
   11370 	for (elt = cfg_list_first(maplist); elt != NULL;
   11371 	     elt = cfg_list_next(elt))
   11372 	{
   11373 		const cfg_obj_t *map = cfg_listelt_value(elt);
   11374 		if (strcasecmp(cfg_obj_asstring(cfg_map_getname(map)), name) ==
   11375 		    0)
   11376 		{
   11377 			return map;
   11378 		}
   11379 	}
   11380 
   11381 	return NULL;
   11382 }
   11383 
   11384 /*
   11385  * Create a listen list from the corresponding configuration
   11386  * data structure.
   11387  */
   11388 static isc_result_t
   11389 listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
   11390 		     cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
   11391 		     isc_tlsctx_cache_t *tlsctx_cache,
   11392 		     ns_listenelt_t **target) {
   11393 	isc_result_t result;
   11394 	const cfg_obj_t *ltup = NULL;
   11395 	const cfg_obj_t *tlsobj = NULL, *httpobj = NULL;
   11396 	const cfg_obj_t *portobj = NULL;
   11397 	const cfg_obj_t *http_server = NULL;
   11398 	const cfg_obj_t *proxyobj = NULL;
   11399 	in_port_t port = 0;
   11400 	const char *key = NULL, *cert = NULL, *ca_file = NULL,
   11401 		   *dhparam_file = NULL, *ciphers = NULL, *cipher_suites = NULL;
   11402 	bool tls_prefer_server_ciphers = false,
   11403 	     tls_prefer_server_ciphers_set = false;
   11404 	bool tls_session_tickets = false, tls_session_tickets_set = false;
   11405 	bool do_tls = false, no_tls = false, http = false;
   11406 	ns_listenelt_t *delt = NULL;
   11407 	uint32_t tls_protos = 0;
   11408 	ns_listen_tls_params_t tls_params = { 0 };
   11409 	const char *tlsname = NULL;
   11410 	isc_nm_proxy_type_t proxy = ISC_NM_PROXY_NONE;
   11411 
   11412 	REQUIRE(target != NULL && *target == NULL);
   11413 
   11414 	ltup = cfg_tuple_get(listener, "tuple");
   11415 	RUNTIME_CHECK(ltup != NULL);
   11416 
   11417 	tlsobj = cfg_tuple_get(ltup, "tls");
   11418 	if (tlsobj != NULL && cfg_obj_isstring(tlsobj)) {
   11419 		tlsname = cfg_obj_asstring(tlsobj);
   11420 
   11421 		if (strcasecmp(tlsname, "none") == 0) {
   11422 			no_tls = true;
   11423 		} else if (strcasecmp(tlsname, "ephemeral") == 0) {
   11424 			do_tls = true;
   11425 		} else {
   11426 			const cfg_obj_t *keyobj = NULL, *certobj = NULL,
   11427 					*ca_obj = NULL, *dhparam_obj = NULL;
   11428 			const cfg_obj_t *tlsmap = NULL;
   11429 			const cfg_obj_t *tls_proto_list = NULL;
   11430 			const cfg_obj_t *ciphers_obj = NULL;
   11431 			const cfg_obj_t *cipher_suites_obj = NULL;
   11432 			const cfg_obj_t *prefer_server_ciphers_obj = NULL;
   11433 			const cfg_obj_t *session_tickets_obj = NULL;
   11434 
   11435 			do_tls = true;
   11436 
   11437 			tlsmap = find_maplist(config, "tls", tlsname);
   11438 			if (tlsmap == NULL) {
   11439 				cfg_obj_log(tlsobj, named_g_lctx, ISC_LOG_ERROR,
   11440 					    "tls '%s' is not defined",
   11441 					    cfg_obj_asstring(tlsobj));
   11442 				return ISC_R_FAILURE;
   11443 			}
   11444 
   11445 			CHECK(cfg_map_get(tlsmap, "key-file", &keyobj));
   11446 			key = cfg_obj_asstring(keyobj);
   11447 
   11448 			CHECK(cfg_map_get(tlsmap, "cert-file", &certobj));
   11449 			cert = cfg_obj_asstring(certobj);
   11450 
   11451 			if (cfg_map_get(tlsmap, "ca-file", &ca_obj) ==
   11452 			    ISC_R_SUCCESS)
   11453 			{
   11454 				ca_file = cfg_obj_asstring(ca_obj);
   11455 			}
   11456 
   11457 			if (cfg_map_get(tlsmap, "protocols", &tls_proto_list) ==
   11458 			    ISC_R_SUCCESS)
   11459 			{
   11460 				const cfg_listelt_t *proto = NULL;
   11461 				INSIST(tls_proto_list != NULL);
   11462 				for (proto = cfg_list_first(tls_proto_list);
   11463 				     proto != 0; proto = cfg_list_next(proto))
   11464 				{
   11465 					const cfg_obj_t *tls_proto_obj =
   11466 						cfg_listelt_value(proto);
   11467 					const char *tls_sver =
   11468 						cfg_obj_asstring(tls_proto_obj);
   11469 					const isc_tls_protocol_version_t ver =
   11470 						isc_tls_protocol_name_to_version(
   11471 							tls_sver);
   11472 
   11473 					INSIST(ver !=
   11474 					       ISC_TLS_PROTO_VER_UNDEFINED);
   11475 					INSIST(isc_tls_protocol_supported(ver));
   11476 					tls_protos |= ver;
   11477 				}
   11478 			}
   11479 
   11480 			if (cfg_map_get(tlsmap, "dhparam-file", &dhparam_obj) ==
   11481 			    ISC_R_SUCCESS)
   11482 			{
   11483 				dhparam_file = cfg_obj_asstring(dhparam_obj);
   11484 			}
   11485 
   11486 			if (cfg_map_get(tlsmap, "ciphers", &ciphers_obj) ==
   11487 			    ISC_R_SUCCESS)
   11488 			{
   11489 				ciphers = cfg_obj_asstring(ciphers_obj);
   11490 			}
   11491 
   11492 			if (cfg_map_get(tlsmap, "cipher-suites",
   11493 					&cipher_suites_obj) == ISC_R_SUCCESS)
   11494 			{
   11495 				cipher_suites =
   11496 					cfg_obj_asstring(cipher_suites_obj);
   11497 			}
   11498 
   11499 			if (cfg_map_get(tlsmap, "prefer-server-ciphers",
   11500 					&prefer_server_ciphers_obj) ==
   11501 			    ISC_R_SUCCESS)
   11502 			{
   11503 				tls_prefer_server_ciphers = cfg_obj_asboolean(
   11504 					prefer_server_ciphers_obj);
   11505 				tls_prefer_server_ciphers_set = true;
   11506 			}
   11507 
   11508 			if (cfg_map_get(tlsmap, "session-tickets",
   11509 					&session_tickets_obj) == ISC_R_SUCCESS)
   11510 			{
   11511 				tls_session_tickets =
   11512 					cfg_obj_asboolean(session_tickets_obj);
   11513 				tls_session_tickets_set = true;
   11514 			}
   11515 		}
   11516 	}
   11517 
   11518 	tls_params = (ns_listen_tls_params_t){
   11519 		.name = tlsname,
   11520 		.key = key,
   11521 		.cert = cert,
   11522 		.ca_file = ca_file,
   11523 		.protocols = tls_protos,
   11524 		.dhparam_file = dhparam_file,
   11525 		.ciphers = ciphers,
   11526 		.cipher_suites = cipher_suites,
   11527 		.prefer_server_ciphers = tls_prefer_server_ciphers,
   11528 		.prefer_server_ciphers_set = tls_prefer_server_ciphers_set,
   11529 		.session_tickets = tls_session_tickets,
   11530 		.session_tickets_set = tls_session_tickets_set
   11531 	};
   11532 
   11533 	httpobj = cfg_tuple_get(ltup, "http");
   11534 	if (httpobj != NULL && cfg_obj_isstring(httpobj)) {
   11535 		const char *httpname = cfg_obj_asstring(httpobj);
   11536 
   11537 		if (!do_tls && !no_tls) {
   11538 			return ISC_R_FAILURE;
   11539 		}
   11540 
   11541 		http_server = find_maplist(config, "http", httpname);
   11542 		if (http_server == NULL && strcasecmp(httpname, "default") != 0)
   11543 		{
   11544 			cfg_obj_log(httpobj, named_g_lctx, ISC_LOG_ERROR,
   11545 				    "http '%s' is not defined",
   11546 				    cfg_obj_asstring(httpobj));
   11547 			return ISC_R_FAILURE;
   11548 		}
   11549 
   11550 		http = true;
   11551 	}
   11552 
   11553 	portobj = cfg_tuple_get(ltup, "port");
   11554 	if (!cfg_obj_isuint32(portobj)) {
   11555 		if (http && do_tls) {
   11556 			if (named_g_httpsport != 0) {
   11557 				port = named_g_httpsport;
   11558 			} else {
   11559 				result = named_config_getport(
   11560 					config, "https-port", &port);
   11561 				if (result != ISC_R_SUCCESS) {
   11562 					return result;
   11563 				}
   11564 			}
   11565 		} else if (http && !do_tls) {
   11566 			if (named_g_httpport != 0) {
   11567 				port = named_g_httpport;
   11568 			} else {
   11569 				result = named_config_getport(
   11570 					config, "http-port", &port);
   11571 				if (result != ISC_R_SUCCESS) {
   11572 					return result;
   11573 				}
   11574 			}
   11575 		} else if (do_tls) {
   11576 			if (named_g_tlsport != 0) {
   11577 				port = named_g_tlsport;
   11578 			} else {
   11579 				result = named_config_getport(
   11580 					config, "tls-port", &port);
   11581 				if (result != ISC_R_SUCCESS) {
   11582 					return result;
   11583 				}
   11584 			}
   11585 		} else {
   11586 			if (named_g_port != 0) {
   11587 				port = named_g_port;
   11588 			} else {
   11589 				result = named_config_getport(config, "port",
   11590 							      &port);
   11591 				if (result != ISC_R_SUCCESS) {
   11592 					return result;
   11593 				}
   11594 			}
   11595 		}
   11596 	} else {
   11597 		if (cfg_obj_asuint32(portobj) >= UINT16_MAX) {
   11598 			return ISC_R_RANGE;
   11599 		}
   11600 		port = (in_port_t)cfg_obj_asuint32(portobj);
   11601 	}
   11602 
   11603 	proxyobj = cfg_tuple_get(ltup, "proxy");
   11604 	if (proxyobj != NULL && cfg_obj_isstring(proxyobj)) {
   11605 		const char *proxyval = cfg_obj_asstring(proxyobj);
   11606 
   11607 		if (strcasecmp(proxyval, "encrypted") == 0) {
   11608 			INSIST(do_tls == true);
   11609 			proxy = ISC_NM_PROXY_ENCRYPTED;
   11610 		} else if (strcasecmp(proxyval, "plain") == 0) {
   11611 			proxy = ISC_NM_PROXY_PLAIN;
   11612 		} else {
   11613 			UNREACHABLE();
   11614 		}
   11615 	}
   11616 
   11617 #ifdef HAVE_LIBNGHTTP2
   11618 	if (http) {
   11619 		CHECK(listenelt_http(http_server, family, do_tls, &tls_params,
   11620 				     tlsctx_cache, port, mctx, proxy, &delt));
   11621 	}
   11622 #endif /* HAVE_LIBNGHTTP2 */
   11623 
   11624 	if (!http) {
   11625 		CHECK(ns_listenelt_create(mctx, port, NULL, family, do_tls,
   11626 					  &tls_params, tlsctx_cache, proxy,
   11627 					  &delt));
   11628 	}
   11629 
   11630 	result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"), config,
   11631 				    named_g_lctx, actx, mctx, family,
   11632 				    &delt->acl);
   11633 	if (result != ISC_R_SUCCESS) {
   11634 		ns_listenelt_destroy(delt);
   11635 		return result;
   11636 	}
   11637 	*target = delt;
   11638 
   11639 cleanup:
   11640 	return result;
   11641 }
   11642 
   11643 #ifdef HAVE_LIBNGHTTP2
   11644 static isc_result_t
   11645 listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls,
   11646 	       const ns_listen_tls_params_t *tls_params,
   11647 	       isc_tlsctx_cache_t *tlsctx_cache, in_port_t port,
   11648 	       isc_mem_t *mctx, isc_nm_proxy_type_t proxy,
   11649 	       ns_listenelt_t **target) {
   11650 	isc_result_t result = ISC_R_SUCCESS;
   11651 	ns_listenelt_t *delt = NULL;
   11652 	char **endpoints = NULL;
   11653 	const cfg_obj_t *eplist = NULL;
   11654 	const cfg_listelt_t *elt = NULL;
   11655 	size_t len = 1, i = 0;
   11656 	uint32_t max_clients = named_g_http_listener_clients;
   11657 	uint32_t max_streams = named_g_http_streams_per_conn;
   11658 
   11659 	REQUIRE(target != NULL && *target == NULL);
   11660 
   11661 	if (tls) {
   11662 		INSIST(tls_params != NULL);
   11663 		INSIST((tls_params->key == NULL) == (tls_params->cert == NULL));
   11664 	}
   11665 
   11666 	if (port == 0) {
   11667 		port = tls ? named_g_httpsport : named_g_httpport;
   11668 	}
   11669 
   11670 	/*
   11671 	 * If "default" was used, we set up the default endpoint
   11672 	 * of "/dns-query".
   11673 	 */
   11674 	if (http != NULL) {
   11675 		const cfg_obj_t *cfg_max_clients = NULL;
   11676 		const cfg_obj_t *cfg_max_streams = NULL;
   11677 
   11678 		if (cfg_map_get(http, "endpoints", &eplist) == ISC_R_SUCCESS) {
   11679 			INSIST(eplist != NULL);
   11680 			len = cfg_list_length(eplist, false);
   11681 		}
   11682 
   11683 		if (cfg_map_get(http, "listener-clients", &cfg_max_clients) ==
   11684 		    ISC_R_SUCCESS)
   11685 		{
   11686 			INSIST(cfg_max_clients != NULL);
   11687 			max_clients = cfg_obj_asuint32(cfg_max_clients);
   11688 		}
   11689 
   11690 		if (cfg_map_get(http, "streams-per-connection",
   11691 				&cfg_max_streams) == ISC_R_SUCCESS)
   11692 		{
   11693 			INSIST(cfg_max_streams != NULL);
   11694 			max_streams = cfg_obj_asuint32(cfg_max_streams);
   11695 		}
   11696 	}
   11697 
   11698 	endpoints = isc_mem_allocate(mctx, sizeof(endpoints[0]) * len);
   11699 
   11700 	if (http != NULL && eplist != NULL) {
   11701 		for (elt = cfg_list_first(eplist); elt != NULL;
   11702 		     elt = cfg_list_next(elt))
   11703 		{
   11704 			const cfg_obj_t *ep = cfg_listelt_value(elt);
   11705 			const char *path = cfg_obj_asstring(ep);
   11706 			endpoints[i++] = isc_mem_strdup(mctx, path);
   11707 		}
   11708 	} else {
   11709 		endpoints[i++] = isc_mem_strdup(mctx, ISC_NM_HTTP_DEFAULT_PATH);
   11710 	}
   11711 
   11712 	INSIST(i == len);
   11713 
   11714 	result = ns_listenelt_create_http(
   11715 		mctx, port, NULL, family, tls, tls_params, tlsctx_cache, proxy,
   11716 		endpoints, len, max_clients, max_streams, &delt);
   11717 	if (result != ISC_R_SUCCESS) {
   11718 		goto error;
   11719 	}
   11720 
   11721 	*target = delt;
   11722 
   11723 	return result;
   11724 error:
   11725 	if (delt != NULL) {
   11726 		ns_listenelt_destroy(delt);
   11727 	}
   11728 	return result;
   11729 }
   11730 #endif /* HAVE_LIBNGHTTP2 */
   11731 
   11732 isc_result_t
   11733 named_server_dumpstats(named_server_t *server) {
   11734 	isc_result_t result;
   11735 	FILE *fp = NULL;
   11736 
   11737 	CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
   11738 		"could not open statistics dump file", server->statsfile);
   11739 
   11740 	result = named_stats_dump(server, fp);
   11741 
   11742 cleanup:
   11743 	if (fp != NULL) {
   11744 		(void)isc_stdio_close(fp);
   11745 	}
   11746 	if (result == ISC_R_SUCCESS) {
   11747 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   11748 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   11749 			      "dumpstats complete");
   11750 	} else {
   11751 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   11752 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   11753 			      "dumpstats failed: %s",
   11754 			      isc_result_totext(result));
   11755 	}
   11756 	return result;
   11757 }
   11758 
   11759 static isc_result_t
   11760 add_zone_tolist(dns_zone_t *zone, void *uap) {
   11761 	struct dumpcontext *dctx = uap;
   11762 	struct zonelistentry *zle;
   11763 
   11764 	zle = isc_mem_get(dctx->mctx, sizeof *zle);
   11765 	zle->zone = NULL;
   11766 	dns_zone_attach(zone, &zle->zone);
   11767 	ISC_LINK_INIT(zle, link);
   11768 	ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
   11769 	return ISC_R_SUCCESS;
   11770 }
   11771 
   11772 static isc_result_t
   11773 add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
   11774 	struct viewlistentry *vle;
   11775 	isc_result_t result = ISC_R_SUCCESS;
   11776 
   11777 	/*
   11778 	 * Prevent duplicate views.
   11779 	 */
   11780 	for (vle = ISC_LIST_HEAD(dctx->viewlist); vle != NULL;
   11781 	     vle = ISC_LIST_NEXT(vle, link))
   11782 	{
   11783 		if (vle->view == view) {
   11784 			return ISC_R_SUCCESS;
   11785 		}
   11786 	}
   11787 
   11788 	vle = isc_mem_get(dctx->mctx, sizeof *vle);
   11789 	vle->view = NULL;
   11790 	dns_view_attach(view, &vle->view);
   11791 	ISC_LINK_INIT(vle, link);
   11792 	ISC_LIST_INIT(vle->zonelist);
   11793 	ISC_LIST_APPEND(dctx->viewlist, vle, link);
   11794 	if (dctx->dumpzones) {
   11795 		result = dns_view_apply(view, true, NULL, add_zone_tolist,
   11796 					dctx);
   11797 	}
   11798 	return result;
   11799 }
   11800 
   11801 static void
   11802 dumpcontext_destroy(struct dumpcontext *dctx) {
   11803 	struct viewlistentry *vle;
   11804 	struct zonelistentry *zle;
   11805 
   11806 	vle = ISC_LIST_HEAD(dctx->viewlist);
   11807 	while (vle != NULL) {
   11808 		ISC_LIST_UNLINK(dctx->viewlist, vle, link);
   11809 		zle = ISC_LIST_HEAD(vle->zonelist);
   11810 		while (zle != NULL) {
   11811 			ISC_LIST_UNLINK(vle->zonelist, zle, link);
   11812 			dns_zone_detach(&zle->zone);
   11813 			isc_mem_put(dctx->mctx, zle, sizeof *zle);
   11814 			zle = ISC_LIST_HEAD(vle->zonelist);
   11815 		}
   11816 		dns_view_detach(&vle->view);
   11817 		isc_mem_put(dctx->mctx, vle, sizeof *vle);
   11818 		vle = ISC_LIST_HEAD(dctx->viewlist);
   11819 	}
   11820 	if (dctx->version != NULL) {
   11821 		dns_db_closeversion(dctx->db, &dctx->version, false);
   11822 	}
   11823 	if (dctx->db != NULL) {
   11824 		dns_db_detach(&dctx->db);
   11825 	}
   11826 	if (dctx->cache != NULL) {
   11827 		dns_db_detach(&dctx->cache);
   11828 	}
   11829 	if (dctx->fp != NULL) {
   11830 		(void)isc_stdio_close(dctx->fp);
   11831 	}
   11832 	if (dctx->mdctx != NULL) {
   11833 		dns_dumpctx_detach(&dctx->mdctx);
   11834 	}
   11835 	isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
   11836 }
   11837 
   11838 static void
   11839 dumpdone(void *arg, isc_result_t result) {
   11840 	struct dumpcontext *dctx = arg;
   11841 	char buf[1024 + 32];
   11842 	const dns_master_style_t *style;
   11843 
   11844 	if (result != ISC_R_SUCCESS) {
   11845 		goto cleanup;
   11846 	}
   11847 	if (dctx->mdctx != NULL) {
   11848 		dns_dumpctx_detach(&dctx->mdctx);
   11849 	}
   11850 	if (dctx->view == NULL) {
   11851 		dctx->view = ISC_LIST_HEAD(dctx->viewlist);
   11852 		if (dctx->view == NULL) {
   11853 			goto done;
   11854 		}
   11855 		INSIST(dctx->zone == NULL);
   11856 	} else {
   11857 		goto resume;
   11858 	}
   11859 nextview:
   11860 	fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
   11861 resume:
   11862 	if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) {
   11863 		fprintf(dctx->fp, ";\n; Cache of view '%s' is shared as '%s'\n",
   11864 			dctx->view->view->name,
   11865 			dns_cache_getname(dctx->view->view->cache));
   11866 	} else if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache)
   11867 	{
   11868 		if (dctx->dumpexpired) {
   11869 			style = &dns_master_style_cache_with_expired;
   11870 		} else {
   11871 			style = &dns_master_style_cache;
   11872 		}
   11873 		/* start cache dump */
   11874 		if (dctx->view->view->cachedb != NULL) {
   11875 			dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
   11876 		}
   11877 		if (dctx->cache != NULL) {
   11878 			fprintf(dctx->fp,
   11879 				";\n; Cache dump of view '%s' (cache %s)\n;\n",
   11880 				dctx->view->view->name,
   11881 				dns_cache_getname(dctx->view->view->cache));
   11882 			result = dns_master_dumptostreamasync(
   11883 				dctx->mctx, dctx->cache, NULL, style, dctx->fp,
   11884 				named_g_mainloop, dumpdone, dctx, &dctx->mdctx);
   11885 			if (result == ISC_R_SUCCESS) {
   11886 				return;
   11887 			}
   11888 			if (result == ISC_R_NOTIMPLEMENTED) {
   11889 				fprintf(dctx->fp, "; %s\n",
   11890 					isc_result_totext(result));
   11891 			} else if (result != ISC_R_SUCCESS) {
   11892 				goto cleanup;
   11893 			}
   11894 		}
   11895 	}
   11896 
   11897 	if ((dctx->dumpadb || dctx->dumpfail) && dctx->cache == NULL &&
   11898 	    dctx->view->view->cachedb != NULL)
   11899 	{
   11900 		dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
   11901 	}
   11902 
   11903 	if (dctx->cache != NULL) {
   11904 		if (dctx->dumpadb) {
   11905 			dns_adb_t *adb = NULL;
   11906 			dns_view_getadb(dctx->view->view, &adb);
   11907 			if (adb != NULL) {
   11908 				dns_adb_dump(adb, dctx->fp);
   11909 				dns_adb_detach(&adb);
   11910 			}
   11911 		}
   11912 		if (dctx->dumpfail) {
   11913 			dns_badcache_print(dctx->view->view->failcache,
   11914 					   "SERVFAIL cache", dctx->fp);
   11915 		}
   11916 		dns_db_detach(&dctx->cache);
   11917 	}
   11918 	if (dctx->dumpzones) {
   11919 		style = &dns_master_style_full;
   11920 	nextzone:
   11921 		if (dctx->version != NULL) {
   11922 			dns_db_closeversion(dctx->db, &dctx->version, false);
   11923 		}
   11924 		if (dctx->db != NULL) {
   11925 			dns_db_detach(&dctx->db);
   11926 		}
   11927 		if (dctx->zone == NULL) {
   11928 			dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
   11929 		} else {
   11930 			dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
   11931 		}
   11932 		if (dctx->zone != NULL) {
   11933 			/* start zone dump */
   11934 			dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
   11935 			fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
   11936 			result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
   11937 			if (result != ISC_R_SUCCESS) {
   11938 				fprintf(dctx->fp, "; %s\n",
   11939 					isc_result_totext(result));
   11940 				goto nextzone;
   11941 			}
   11942 			dns_db_currentversion(dctx->db, &dctx->version);
   11943 			result = dns_master_dumptostreamasync(
   11944 				dctx->mctx, dctx->db, dctx->version, style,
   11945 				dctx->fp, dns_zone_getloop(dctx->zone->zone),
   11946 				dumpdone, dctx, &dctx->mdctx);
   11947 			if (result == ISC_R_SUCCESS) {
   11948 				return;
   11949 			}
   11950 			if (result == ISC_R_NOTIMPLEMENTED) {
   11951 				fprintf(dctx->fp, "; %s\n",
   11952 					isc_result_totext(result));
   11953 				result = ISC_R_SUCCESS;
   11954 				POST(result);
   11955 				goto nextzone;
   11956 			}
   11957 			if (result != ISC_R_SUCCESS) {
   11958 				goto cleanup;
   11959 			}
   11960 		}
   11961 	}
   11962 	if (dctx->view != NULL) {
   11963 		dctx->view = ISC_LIST_NEXT(dctx->view, link);
   11964 		if (dctx->view != NULL) {
   11965 			goto nextview;
   11966 		}
   11967 	}
   11968 done:
   11969 	fprintf(dctx->fp, "; Dump complete\n");
   11970 	result = isc_stdio_flush(dctx->fp);
   11971 	if (result == ISC_R_SUCCESS) {
   11972 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   11973 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   11974 			      "dumpdb complete");
   11975 	}
   11976 cleanup:
   11977 	if (result != ISC_R_SUCCESS) {
   11978 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   11979 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   11980 			      "dumpdb failed: %s", isc_result_totext(result));
   11981 	}
   11982 	dumpcontext_destroy(dctx);
   11983 }
   11984 
   11985 isc_result_t
   11986 named_server_dumpdb(named_server_t *server, isc_lex_t *lex,
   11987 		    isc_buffer_t **text) {
   11988 	struct dumpcontext *dctx = NULL;
   11989 	dns_view_t *view;
   11990 	isc_result_t result;
   11991 	char *ptr;
   11992 	const char *sep;
   11993 	bool found;
   11994 
   11995 	REQUIRE(text != NULL);
   11996 
   11997 	/* Skip the command name. */
   11998 	ptr = next_token(lex, NULL);
   11999 	if (ptr == NULL) {
   12000 		return ISC_R_UNEXPECTEDEND;
   12001 	}
   12002 
   12003 	dctx = isc_mem_get(server->mctx, sizeof(*dctx));
   12004 	*dctx = (struct dumpcontext){
   12005 		.mctx = server->mctx,
   12006 		.dumpcache = true,
   12007 		.dumpadb = true,
   12008 		.dumpfail = true,
   12009 		.viewlist = ISC_LIST_INITIALIZER,
   12010 	};
   12011 
   12012 	CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
   12013 		"could not open dump file", server->dumpfile);
   12014 
   12015 	ptr = next_token(lex, NULL);
   12016 	sep = (ptr == NULL) ? "" : ": ";
   12017 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12018 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12019 		      "dumpdb started%s%s", sep, (ptr != NULL) ? ptr : "");
   12020 
   12021 	if (ptr != NULL && strcmp(ptr, "-all") == 0) {
   12022 		/* also dump zones */
   12023 		dctx->dumpzones = true;
   12024 		ptr = next_token(lex, NULL);
   12025 	} else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
   12026 		/* this is the default */
   12027 		ptr = next_token(lex, NULL);
   12028 	} else if (ptr != NULL && strcmp(ptr, "-expired") == 0) {
   12029 		/* this is the same as -cache but includes expired data */
   12030 		dctx->dumpexpired = true;
   12031 		ptr = next_token(lex, NULL);
   12032 	} else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
   12033 		/* only dump zones, suppress caches */
   12034 		dctx->dumpadb = false;
   12035 		dctx->dumpcache = false;
   12036 		dctx->dumpfail = false;
   12037 		dctx->dumpzones = true;
   12038 		ptr = next_token(lex, NULL);
   12039 	} else if (ptr != NULL && strcmp(ptr, "-adb") == 0) {
   12040 		/* only dump adb, suppress other caches */
   12041 		dctx->dumpcache = false;
   12042 		dctx->dumpfail = false;
   12043 		ptr = next_token(lex, NULL);
   12044 	} else if (ptr != NULL && strcmp(ptr, "-bad") == 0) {
   12045 		/* only dump badcache, suppress other caches */
   12046 		dctx->dumpadb = false;
   12047 		dctx->dumpcache = false;
   12048 		dctx->dumpfail = false;
   12049 		ptr = next_token(lex, NULL);
   12050 	} else if (ptr != NULL && strcmp(ptr, "-fail") == 0) {
   12051 		/* only dump servfail cache, suppress other caches */
   12052 		dctx->dumpadb = false;
   12053 		dctx->dumpcache = false;
   12054 		ptr = next_token(lex, NULL);
   12055 	}
   12056 
   12057 nextview:
   12058 	found = false;
   12059 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12060 	     view = ISC_LIST_NEXT(view, link))
   12061 	{
   12062 		if (ptr != NULL && strcmp(view->name, ptr) != 0) {
   12063 			continue;
   12064 		}
   12065 		found = true;
   12066 		CHECK(add_view_tolist(dctx, view));
   12067 	}
   12068 	if (ptr != NULL) {
   12069 		if (!found) {
   12070 			CHECK(putstr(text, "view '"));
   12071 			CHECK(putstr(text, ptr));
   12072 			CHECK(putstr(text, "' not found"));
   12073 			CHECK(putnull(text));
   12074 			result = ISC_R_NOTFOUND;
   12075 			dumpdone(dctx, result);
   12076 			return result;
   12077 		}
   12078 		ptr = next_token(lex, NULL);
   12079 		if (ptr != NULL) {
   12080 			goto nextview;
   12081 		}
   12082 	}
   12083 	dumpdone(dctx, ISC_R_SUCCESS);
   12084 	return ISC_R_SUCCESS;
   12085 
   12086 cleanup:
   12087 	dumpcontext_destroy(dctx);
   12088 	return result;
   12089 }
   12090 
   12091 isc_result_t
   12092 named_server_dumpsecroots(named_server_t *server, isc_lex_t *lex,
   12093 			  isc_buffer_t **text) {
   12094 	dns_view_t *view;
   12095 	dns_keytable_t *secroots = NULL;
   12096 	dns_ntatable_t *ntatable = NULL;
   12097 	isc_result_t result;
   12098 	char *ptr;
   12099 	FILE *fp = NULL;
   12100 	isc_time_t now;
   12101 	char tbuf[64];
   12102 	unsigned int used = isc_buffer_usedlength(*text);
   12103 	bool first = true;
   12104 
   12105 	REQUIRE(text != NULL);
   12106 
   12107 	/* Skip the command name. */
   12108 	ptr = next_token(lex, text);
   12109 	if (ptr == NULL) {
   12110 		return ISC_R_UNEXPECTEDEND;
   12111 	}
   12112 
   12113 	/* "-" here means print the output instead of dumping to file */
   12114 	ptr = next_token(lex, text);
   12115 	if (ptr != NULL && strcmp(ptr, "-") == 0) {
   12116 		ptr = next_token(lex, text);
   12117 	} else {
   12118 		result = isc_stdio_open(server->secrootsfile, "w", &fp);
   12119 		if (result != ISC_R_SUCCESS) {
   12120 			(void)putstr(text, "could not open ");
   12121 			(void)putstr(text, server->secrootsfile);
   12122 			CHECKMF(result, "could not open secroots dump file",
   12123 				server->secrootsfile);
   12124 		}
   12125 	}
   12126 
   12127 	now = isc_time_now();
   12128 	isc_time_formattimestamp(&now, tbuf, sizeof(tbuf));
   12129 	CHECK(putstr(text, "secure roots as of "));
   12130 	CHECK(putstr(text, tbuf));
   12131 	CHECK(putstr(text, ":\n"));
   12132 	used = isc_buffer_usedlength(*text);
   12133 
   12134 	do {
   12135 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12136 		     view = ISC_LIST_NEXT(view, link))
   12137 		{
   12138 			if (ptr != NULL && strcmp(view->name, ptr) != 0) {
   12139 				continue;
   12140 			}
   12141 			if (secroots != NULL) {
   12142 				dns_keytable_detach(&secroots);
   12143 			}
   12144 			result = dns_view_getsecroots(view, &secroots);
   12145 			if (result == ISC_R_NOTFOUND) {
   12146 				result = ISC_R_SUCCESS;
   12147 				continue;
   12148 			}
   12149 			if (first || used != isc_buffer_usedlength(*text)) {
   12150 				CHECK(putstr(text, "\n"));
   12151 				first = false;
   12152 			}
   12153 			CHECK(putstr(text, " Start view "));
   12154 			CHECK(putstr(text, view->name));
   12155 			CHECK(putstr(text, "\n   Secure roots:\n\n"));
   12156 			used = isc_buffer_usedlength(*text);
   12157 			CHECK(dns_keytable_totext(secroots, text));
   12158 
   12159 			if (ntatable != NULL) {
   12160 				dns_ntatable_detach(&ntatable);
   12161 			}
   12162 			result = dns_view_getntatable(view, &ntatable);
   12163 			if (result == ISC_R_NOTFOUND) {
   12164 				result = ISC_R_SUCCESS;
   12165 				continue;
   12166 			}
   12167 			if (used != isc_buffer_usedlength(*text)) {
   12168 				CHECK(putstr(text, "\n"));
   12169 			}
   12170 			CHECK(putstr(text, "   Negative trust anchors:\n\n"));
   12171 			used = isc_buffer_usedlength(*text);
   12172 			CHECK(dns_ntatable_totext(ntatable, NULL, text));
   12173 		}
   12174 
   12175 		if (ptr != NULL) {
   12176 			ptr = next_token(lex, text);
   12177 		}
   12178 	} while (ptr != NULL);
   12179 
   12180 cleanup:
   12181 	if (secroots != NULL) {
   12182 		dns_keytable_detach(&secroots);
   12183 	}
   12184 	if (ntatable != NULL) {
   12185 		dns_ntatable_detach(&ntatable);
   12186 	}
   12187 
   12188 	if (fp != NULL) {
   12189 		if (used != isc_buffer_usedlength(*text)) {
   12190 			(void)putstr(text, "\n");
   12191 		}
   12192 		fprintf(fp, "%.*s", (int)isc_buffer_usedlength(*text),
   12193 			(char *)isc_buffer_base(*text));
   12194 		isc_buffer_clear(*text);
   12195 		(void)isc_stdio_close(fp);
   12196 	} else if (isc_buffer_usedlength(*text) > 0) {
   12197 		(void)putnull(text);
   12198 	}
   12199 
   12200 	if (result == ISC_R_SUCCESS) {
   12201 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12202 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12203 			      "dumpsecroots complete");
   12204 	} else {
   12205 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12206 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   12207 			      "dumpsecroots failed: %s",
   12208 			      isc_result_totext(result));
   12209 	}
   12210 	return result;
   12211 }
   12212 
   12213 isc_result_t
   12214 named_server_dumprecursing(named_server_t *server) {
   12215 	FILE *fp = NULL;
   12216 	dns_view_t *view;
   12217 	isc_result_t result;
   12218 
   12219 	CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
   12220 		"could not open dump file", server->recfile);
   12221 	fprintf(fp, ";\n; Recursing Queries\n;\n");
   12222 	ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
   12223 
   12224 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12225 	     view = ISC_LIST_NEXT(view, link))
   12226 	{
   12227 		fprintf(fp, ";\n; Active fetch domains [view: %s]\n;\n",
   12228 			view->name);
   12229 		dns_resolver_dumpfetches(view->resolver, isc_statsformat_file,
   12230 					 fp);
   12231 	}
   12232 
   12233 	fprintf(fp, "; Dump complete\n");
   12234 
   12235 cleanup:
   12236 	if (fp != NULL) {
   12237 		result = isc_stdio_close(fp);
   12238 	}
   12239 	if (result == ISC_R_SUCCESS) {
   12240 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12241 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12242 			      "dumprecursing complete");
   12243 	} else {
   12244 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12245 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   12246 			      "dumprecursing failed: %s",
   12247 			      isc_result_totext(result));
   12248 	}
   12249 	return result;
   12250 }
   12251 
   12252 isc_result_t
   12253 named_server_setdebuglevel(named_server_t *server, isc_lex_t *lex) {
   12254 	char *ptr;
   12255 	char *endp;
   12256 	long newlevel;
   12257 
   12258 	UNUSED(server);
   12259 
   12260 	/* Skip the command name. */
   12261 	ptr = next_token(lex, NULL);
   12262 	if (ptr == NULL) {
   12263 		return ISC_R_UNEXPECTEDEND;
   12264 	}
   12265 
   12266 	/* Look for the new level name. */
   12267 	ptr = next_token(lex, NULL);
   12268 	if (ptr == NULL) {
   12269 		if (named_g_debuglevel < 99) {
   12270 			named_g_debuglevel++;
   12271 		}
   12272 	} else {
   12273 		newlevel = strtol(ptr, &endp, 10);
   12274 		if (*endp != '\0' || newlevel < 0 || newlevel > 99) {
   12275 			return ISC_R_RANGE;
   12276 		}
   12277 		named_g_debuglevel = (unsigned int)newlevel;
   12278 	}
   12279 	isc_log_setdebuglevel(named_g_lctx, named_g_debuglevel);
   12280 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12281 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12282 		      "debug level is now %u", named_g_debuglevel);
   12283 	return ISC_R_SUCCESS;
   12284 }
   12285 
   12286 isc_result_t
   12287 named_server_validation(named_server_t *server, isc_lex_t *lex,
   12288 			isc_buffer_t **text) {
   12289 	char *ptr;
   12290 	dns_view_t *view;
   12291 	bool changed = false;
   12292 	isc_result_t result;
   12293 	bool enable = true, set = true, first = true;
   12294 
   12295 	REQUIRE(text != NULL);
   12296 
   12297 	/* Skip the command name. */
   12298 	ptr = next_token(lex, text);
   12299 	if (ptr == NULL) {
   12300 		return ISC_R_UNEXPECTEDEND;
   12301 	}
   12302 
   12303 	/* Find out what we are to do. */
   12304 	ptr = next_token(lex, text);
   12305 	if (ptr == NULL) {
   12306 		return ISC_R_UNEXPECTEDEND;
   12307 	}
   12308 
   12309 	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
   12310 	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
   12311 	{
   12312 		enable = true;
   12313 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
   12314 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
   12315 	{
   12316 		enable = false;
   12317 	} else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
   12318 		set = false;
   12319 	} else {
   12320 		return DNS_R_SYNTAX;
   12321 	}
   12322 
   12323 	/* Look for the view name. */
   12324 	ptr = next_token(lex, text);
   12325 
   12326 	isc_loopmgr_pause(named_g_loopmgr);
   12327 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12328 	     view = ISC_LIST_NEXT(view, link))
   12329 	{
   12330 		if ((ptr != NULL && strcasecmp(ptr, view->name) != 0) ||
   12331 		    strcasecmp("_bind", view->name) == 0)
   12332 		{
   12333 			continue;
   12334 		}
   12335 
   12336 		if (set) {
   12337 			CHECK(dns_view_flushcache(view, false));
   12338 			view->enablevalidation = enable;
   12339 			changed = true;
   12340 		} else {
   12341 			if (!first) {
   12342 				CHECK(putstr(text, "\n"));
   12343 			}
   12344 			CHECK(putstr(text, "DNSSEC validation is "));
   12345 			CHECK(putstr(text, view->enablevalidation
   12346 						   ? "enabled"
   12347 						   : "disabled"));
   12348 			CHECK(putstr(text, " (view "));
   12349 			CHECK(putstr(text, view->name));
   12350 			CHECK(putstr(text, ")"));
   12351 			first = false;
   12352 		}
   12353 	}
   12354 	CHECK(putnull(text));
   12355 
   12356 	if (!set) {
   12357 		result = ISC_R_SUCCESS;
   12358 	} else if (changed) {
   12359 		result = ISC_R_SUCCESS;
   12360 	} else {
   12361 		result = ISC_R_FAILURE;
   12362 	}
   12363 cleanup:
   12364 	isc_loopmgr_resume(named_g_loopmgr);
   12365 	return result;
   12366 }
   12367 
   12368 isc_result_t
   12369 named_server_flushcache(named_server_t *server, isc_lex_t *lex) {
   12370 	char *ptr;
   12371 	dns_view_t *view;
   12372 	bool flushed;
   12373 	bool found;
   12374 	isc_result_t result;
   12375 	named_cache_t *nsc;
   12376 
   12377 	/* Skip the command name. */
   12378 	ptr = next_token(lex, NULL);
   12379 	if (ptr == NULL) {
   12380 		return ISC_R_UNEXPECTEDEND;
   12381 	}
   12382 
   12383 	/* Look for the view name. */
   12384 	ptr = next_token(lex, NULL);
   12385 
   12386 	isc_loopmgr_pause(named_g_loopmgr);
   12387 	flushed = true;
   12388 	found = false;
   12389 
   12390 	/*
   12391 	 * Flushing a cache is tricky when caches are shared by multiple views.
   12392 	 * We first identify which caches should be flushed in the local cache
   12393 	 * list, flush these caches, and then update other views that refer to
   12394 	 * the flushed cache DB.
   12395 	 */
   12396 	if (ptr != NULL) {
   12397 		/*
   12398 		 * Mark caches that need to be flushed.  This is an O(#view^2)
   12399 		 * operation in the very worst case, but should be normally
   12400 		 * much more lightweight because only a few (most typically just
   12401 		 * one) views will match.
   12402 		 */
   12403 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12404 		     view = ISC_LIST_NEXT(view, link))
   12405 		{
   12406 			if (strcasecmp(ptr, view->name) != 0) {
   12407 				continue;
   12408 			}
   12409 			found = true;
   12410 			for (nsc = ISC_LIST_HEAD(server->cachelist);
   12411 			     nsc != NULL; nsc = ISC_LIST_NEXT(nsc, link))
   12412 			{
   12413 				if (nsc->cache == view->cache) {
   12414 					break;
   12415 				}
   12416 			}
   12417 			INSIST(nsc != NULL);
   12418 			nsc->needflush = true;
   12419 		}
   12420 	} else {
   12421 		found = true;
   12422 	}
   12423 
   12424 	/* Perform flush */
   12425 	for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
   12426 	     nsc = ISC_LIST_NEXT(nsc, link))
   12427 	{
   12428 		if (ptr != NULL && !nsc->needflush) {
   12429 			continue;
   12430 		}
   12431 		nsc->needflush = true;
   12432 		result = dns_view_flushcache(nsc->primaryview, false);
   12433 		if (result != ISC_R_SUCCESS) {
   12434 			flushed = false;
   12435 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12436 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   12437 				      "flushing cache in view '%s' failed: %s",
   12438 				      nsc->primaryview->name,
   12439 				      isc_result_totext(result));
   12440 		}
   12441 	}
   12442 
   12443 	/*
   12444 	 * Fix up views that share a flushed cache: let the views update the
   12445 	 * cache DB they're referring to.  This could also be an expensive
   12446 	 * operation, but should typically be marginal: the inner loop is only
   12447 	 * necessary for views that share a cache, and if there are many such
   12448 	 * views the number of shared cache should normally be small.
   12449 	 * A worst case is that we have n views and n/2 caches, each shared by
   12450 	 * two views.  Then this will be a O(n^2/4) operation.
   12451 	 */
   12452 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12453 	     view = ISC_LIST_NEXT(view, link))
   12454 	{
   12455 		if (!dns_view_iscacheshared(view)) {
   12456 			continue;
   12457 		}
   12458 		for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
   12459 		     nsc = ISC_LIST_NEXT(nsc, link))
   12460 		{
   12461 			if (!nsc->needflush || nsc->cache != view->cache) {
   12462 				continue;
   12463 			}
   12464 			result = dns_view_flushcache(view, true);
   12465 			if (result != ISC_R_SUCCESS) {
   12466 				flushed = false;
   12467 				isc_log_write(
   12468 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12469 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   12470 					"fixing cache in view '%s' "
   12471 					"failed: %s",
   12472 					view->name, isc_result_totext(result));
   12473 			}
   12474 		}
   12475 	}
   12476 
   12477 	/* Cleanup the cache list. */
   12478 	for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
   12479 	     nsc = ISC_LIST_NEXT(nsc, link))
   12480 	{
   12481 		nsc->needflush = false;
   12482 	}
   12483 
   12484 	if (flushed && found) {
   12485 		if (ptr != NULL) {
   12486 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12487 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12488 				      "flushing cache in view '%s' succeeded",
   12489 				      ptr);
   12490 		} else {
   12491 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12492 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12493 				      "flushing caches in all views succeeded");
   12494 		}
   12495 		result = ISC_R_SUCCESS;
   12496 	} else {
   12497 		if (!found) {
   12498 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12499 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   12500 				      "flushing cache in view '%s' failed: "
   12501 				      "view not found",
   12502 				      ptr);
   12503 			result = ISC_R_NOTFOUND;
   12504 		} else {
   12505 			result = ISC_R_FAILURE;
   12506 		}
   12507 	}
   12508 	isc_loopmgr_resume(named_g_loopmgr);
   12509 	return result;
   12510 }
   12511 
   12512 isc_result_t
   12513 named_server_flushnode(named_server_t *server, isc_lex_t *lex, bool tree) {
   12514 	char *ptr, *viewname;
   12515 	char target[DNS_NAME_FORMATSIZE];
   12516 	dns_view_t *view;
   12517 	bool flushed;
   12518 	bool found;
   12519 	isc_result_t result;
   12520 	isc_buffer_t b;
   12521 	dns_fixedname_t fixed;
   12522 	dns_name_t *name;
   12523 
   12524 	/* Skip the command name. */
   12525 	ptr = next_token(lex, NULL);
   12526 	if (ptr == NULL) {
   12527 		return ISC_R_UNEXPECTEDEND;
   12528 	}
   12529 
   12530 	/* Find the domain name to flush. */
   12531 	ptr = next_token(lex, NULL);
   12532 	if (ptr == NULL) {
   12533 		return ISC_R_UNEXPECTEDEND;
   12534 	}
   12535 
   12536 	strlcpy(target, ptr, DNS_NAME_FORMATSIZE);
   12537 	isc_buffer_constinit(&b, target, strlen(target));
   12538 	isc_buffer_add(&b, strlen(target));
   12539 	name = dns_fixedname_initname(&fixed);
   12540 	result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
   12541 	if (result != ISC_R_SUCCESS) {
   12542 		return result;
   12543 	}
   12544 
   12545 	/* Look for the view name. */
   12546 	viewname = next_token(lex, NULL);
   12547 
   12548 	isc_loopmgr_pause(named_g_loopmgr);
   12549 	flushed = true;
   12550 	found = false;
   12551 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12552 	     view = ISC_LIST_NEXT(view, link))
   12553 	{
   12554 		if (viewname != NULL && strcasecmp(viewname, view->name) != 0) {
   12555 			continue;
   12556 		}
   12557 		found = true;
   12558 		/*
   12559 		 * It's a little inefficient to try flushing name for all views
   12560 		 * if some of the views share a single cache.  But since the
   12561 		 * operation is lightweight we prefer simplicity here.
   12562 		 */
   12563 		result = dns_view_flushnode(view, name, tree);
   12564 		if (result != ISC_R_SUCCESS) {
   12565 			flushed = false;
   12566 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12567 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   12568 				      "flushing %s '%s' in cache view '%s' "
   12569 				      "failed: %s",
   12570 				      tree ? "tree" : "name", target,
   12571 				      view->name, isc_result_totext(result));
   12572 		}
   12573 	}
   12574 	if (flushed && found) {
   12575 		if (viewname != NULL) {
   12576 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12577 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12578 				      "flushing %s '%s' in cache view '%s' "
   12579 				      "succeeded",
   12580 				      tree ? "tree" : "name", target, viewname);
   12581 		} else {
   12582 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12583 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12584 				      "flushing %s '%s' in all cache views "
   12585 				      "succeeded",
   12586 				      tree ? "tree" : "name", target);
   12587 		}
   12588 		result = ISC_R_SUCCESS;
   12589 	} else {
   12590 		if (!found) {
   12591 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12592 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   12593 				      "flushing %s '%s' in cache view '%s' "
   12594 				      "failed: view not found",
   12595 				      tree ? "tree" : "name", target, viewname);
   12596 		}
   12597 		result = ISC_R_FAILURE;
   12598 	}
   12599 	isc_loopmgr_resume(named_g_loopmgr);
   12600 	return result;
   12601 }
   12602 
   12603 isc_result_t
   12604 named_server_status(named_server_t *server, isc_buffer_t **text) {
   12605 	isc_result_t result;
   12606 	unsigned int zonecount, xferrunning, xferdeferred, xferfirstrefresh;
   12607 	unsigned int soaqueries, automatic;
   12608 	const char *ob = "", *cb = "", *alt = "";
   12609 	char boottime[ISC_FORMATHTTPTIMESTAMP_SIZE];
   12610 	char configtime[ISC_FORMATHTTPTIMESTAMP_SIZE];
   12611 	char line[1024], hostname[256];
   12612 	named_reload_t reload_status;
   12613 
   12614 	REQUIRE(text != NULL);
   12615 
   12616 	if (named_g_server->version_set) {
   12617 		ob = " (";
   12618 		cb = ")";
   12619 		if (named_g_server->version == NULL) {
   12620 			alt = "version.bind/txt/ch disabled";
   12621 		} else {
   12622 			alt = named_g_server->version;
   12623 		}
   12624 	}
   12625 	zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
   12626 	xferrunning = dns_zonemgr_getcount(server->zonemgr,
   12627 					   DNS_ZONESTATE_XFERRUNNING);
   12628 	xferdeferred = dns_zonemgr_getcount(server->zonemgr,
   12629 					    DNS_ZONESTATE_XFERDEFERRED);
   12630 	xferfirstrefresh = dns_zonemgr_getcount(server->zonemgr,
   12631 						DNS_ZONESTATE_XFERFIRSTREFRESH);
   12632 	soaqueries = dns_zonemgr_getcount(server->zonemgr,
   12633 					  DNS_ZONESTATE_SOAQUERY);
   12634 	automatic = dns_zonemgr_getcount(server->zonemgr,
   12635 					 DNS_ZONESTATE_AUTOMATIC);
   12636 
   12637 	isc_time_formathttptimestamp(&named_g_boottime, boottime,
   12638 				     sizeof(boottime));
   12639 	isc_time_formathttptimestamp(&named_g_configtime, configtime,
   12640 				     sizeof(configtime));
   12641 
   12642 	snprintf(line, sizeof(line), "version: %s%s <id:%s>%s%s%s\n",
   12643 		 PACKAGE_STRING, PACKAGE_DESCRIPTION, PACKAGE_SRCID, ob, alt,
   12644 		 cb);
   12645 	CHECK(putstr(text, line));
   12646 
   12647 	if (gethostname(hostname, sizeof(hostname)) != 0) {
   12648 		strlcpy(hostname, "localhost", sizeof(hostname));
   12649 	}
   12650 	snprintf(line, sizeof(line), "running on %s: %s\n", hostname,
   12651 		 named_os_uname());
   12652 	CHECK(putstr(text, line));
   12653 
   12654 	snprintf(line, sizeof(line), "boot time: %s\n", boottime);
   12655 	CHECK(putstr(text, line));
   12656 
   12657 	snprintf(line, sizeof(line), "last configured: %s\n", configtime);
   12658 	CHECK(putstr(text, line));
   12659 
   12660 	if (named_g_chrootdir != NULL) {
   12661 		snprintf(line, sizeof(line), "configuration file: %s (%s%s)\n",
   12662 			 named_g_conffile, named_g_chrootdir, named_g_conffile);
   12663 	} else {
   12664 		snprintf(line, sizeof(line), "configuration file: %s\n",
   12665 			 named_g_conffile);
   12666 	}
   12667 	CHECK(putstr(text, line));
   12668 
   12669 	snprintf(line, sizeof(line), "CPUs found: %u\n", named_g_cpus_detected);
   12670 	CHECK(putstr(text, line));
   12671 
   12672 	snprintf(line, sizeof(line), "worker threads: %u\n", named_g_cpus);
   12673 	CHECK(putstr(text, line));
   12674 
   12675 	snprintf(line, sizeof(line), "number of zones: %u (%u automatic)\n",
   12676 		 zonecount, automatic);
   12677 	CHECK(putstr(text, line));
   12678 
   12679 	snprintf(line, sizeof(line), "debug level: %u\n", named_g_debuglevel);
   12680 	CHECK(putstr(text, line));
   12681 
   12682 	snprintf(line, sizeof(line), "xfers running: %u\n", xferrunning);
   12683 	CHECK(putstr(text, line));
   12684 
   12685 	snprintf(line, sizeof(line), "xfers deferred: %u\n", xferdeferred);
   12686 	CHECK(putstr(text, line));
   12687 
   12688 	snprintf(line, sizeof(line), "xfers first refresh: %u\n",
   12689 		 xferfirstrefresh);
   12690 	CHECK(putstr(text, line));
   12691 
   12692 	snprintf(line, sizeof(line), "soa queries in progress: %u\n",
   12693 		 soaqueries);
   12694 	CHECK(putstr(text, line));
   12695 
   12696 	snprintf(line, sizeof(line), "query logging is %s\n",
   12697 		 ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES)
   12698 			 ? "ON"
   12699 			 : "OFF");
   12700 	CHECK(putstr(text, line));
   12701 
   12702 	snprintf(line, sizeof(line), "response logging is %s\n",
   12703 		 ns_server_getoption(server->sctx, NS_SERVER_LOGRESPONSES)
   12704 			 ? "ON"
   12705 			 : "OFF");
   12706 	CHECK(putstr(text, line));
   12707 
   12708 	snprintf(line, sizeof(line), "memory profiling is %s\n",
   12709 		 named_server_getmemprof());
   12710 	CHECK(putstr(text, line));
   12711 
   12712 	snprintf(line, sizeof(line), "recursive clients: %u/%u/%u\n",
   12713 		 isc_quota_getused(&server->sctx->recursionquota),
   12714 		 isc_quota_getsoft(&server->sctx->recursionquota),
   12715 		 isc_quota_getmax(&server->sctx->recursionquota));
   12716 	CHECK(putstr(text, line));
   12717 
   12718 	snprintf(line, sizeof(line), "recursive high-water: %u\n",
   12719 		 (unsigned int)ns_stats_get_counter(
   12720 			 server->sctx->nsstats,
   12721 			 ns_statscounter_recurshighwater));
   12722 	CHECK(putstr(text, line));
   12723 
   12724 	snprintf(line, sizeof(line), "tcp clients: %u/%u\n",
   12725 		 isc_quota_getused(&server->sctx->tcpquota),
   12726 		 isc_quota_getmax(&server->sctx->tcpquota));
   12727 	CHECK(putstr(text, line));
   12728 
   12729 	snprintf(line, sizeof(line), "TCP high-water: %u\n",
   12730 		 (unsigned int)ns_stats_get_counter(
   12731 			 server->sctx->nsstats, ns_statscounter_tcphighwater));
   12732 	CHECK(putstr(text, line));
   12733 
   12734 	reload_status = atomic_load(&server->reload_status);
   12735 	if (reload_status != NAMED_RELOAD_DONE) {
   12736 		snprintf(line, sizeof(line), "reload/reconfig %s\n",
   12737 			 reload_status == NAMED_RELOAD_FAILED ? "failed"
   12738 							      : "in progress");
   12739 		CHECK(putstr(text, line));
   12740 	}
   12741 
   12742 	CHECK(putstr(text, "server is up and running"));
   12743 	CHECK(putnull(text));
   12744 
   12745 	return ISC_R_SUCCESS;
   12746 cleanup:
   12747 	return result;
   12748 }
   12749 
   12750 isc_result_t
   12751 named_server_testgen(isc_lex_t *lex, isc_buffer_t **text) {
   12752 	isc_result_t result;
   12753 	char *ptr;
   12754 	unsigned long count;
   12755 	unsigned long i;
   12756 	const unsigned char chars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
   12757 
   12758 	REQUIRE(text != NULL);
   12759 
   12760 	/* Skip the command name. */
   12761 	ptr = next_token(lex, text);
   12762 	if (ptr == NULL) {
   12763 		return ISC_R_UNEXPECTEDEND;
   12764 	}
   12765 
   12766 	ptr = next_token(lex, text);
   12767 	if (ptr == NULL) {
   12768 		count = 26;
   12769 	} else {
   12770 		count = strtoul(ptr, NULL, 10);
   12771 	}
   12772 
   12773 	CHECK(isc_buffer_reserve(*text, count));
   12774 	for (i = 0; i < count; i++) {
   12775 		CHECK(putuint8(text, chars[i % (sizeof(chars) - 1)]));
   12776 	}
   12777 
   12778 	CHECK(putnull(text));
   12779 
   12780 cleanup:
   12781 	return result;
   12782 }
   12783 
   12784 /*
   12785  * Act on a "sign" or "loadkeys" command from the command channel.
   12786  */
   12787 isc_result_t
   12788 named_server_rekey(named_server_t *server, isc_lex_t *lex,
   12789 		   isc_buffer_t **text) {
   12790 	isc_result_t result;
   12791 	dns_zone_t *zone = NULL;
   12792 	dns_zonetype_t type;
   12793 	uint16_t keyopts;
   12794 	bool fullsign = false;
   12795 	char *ptr;
   12796 
   12797 	REQUIRE(text != NULL);
   12798 
   12799 	ptr = next_token(lex, text);
   12800 	if (ptr == NULL) {
   12801 		return ISC_R_UNEXPECTEDEND;
   12802 	}
   12803 
   12804 	if (strcasecmp(ptr, NAMED_COMMAND_SIGN) == 0) {
   12805 		fullsign = true;
   12806 	}
   12807 
   12808 	REQUIRE(text != NULL);
   12809 
   12810 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, false);
   12811 	if (result != ISC_R_SUCCESS) {
   12812 		return result;
   12813 	}
   12814 	if (zone == NULL) {
   12815 		return ISC_R_UNEXPECTEDEND; /* XXX: or do all zones? */
   12816 	}
   12817 
   12818 	type = dns_zone_gettype(zone);
   12819 	if (type != dns_zone_primary) {
   12820 		dns_zone_detach(&zone);
   12821 		return DNS_R_NOTPRIMARY;
   12822 	}
   12823 
   12824 	keyopts = dns_zone_getkeyopts(zone);
   12825 
   12826 	/*
   12827 	 * "rndc loadkeys" requires a "dnssec-policy".
   12828 	 */
   12829 	if ((keyopts & DNS_ZONEKEY_ALLOW) == 0) {
   12830 		result = ISC_R_NOPERM;
   12831 	} else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign) {
   12832 		result = ISC_R_NOPERM;
   12833 	} else {
   12834 		dns_zone_rekey(zone, fullsign, false);
   12835 	}
   12836 
   12837 	dns_zone_detach(&zone);
   12838 	return result;
   12839 }
   12840 
   12841 /*
   12842  * Act on a "sync" command from the command channel.
   12843  */
   12844 static isc_result_t
   12845 synczone(dns_zone_t *zone, void *uap) {
   12846 	bool cleanup = *(bool *)uap;
   12847 	isc_result_t result;
   12848 	dns_zone_t *raw = NULL;
   12849 	char *journal;
   12850 
   12851 	dns_zone_getraw(zone, &raw);
   12852 	if (raw != NULL) {
   12853 		synczone(raw, uap);
   12854 		dns_zone_detach(&raw);
   12855 	}
   12856 
   12857 	result = dns_zone_flush(zone);
   12858 	if (result != ISC_R_SUCCESS) {
   12859 		cleanup = false;
   12860 	}
   12861 	if (cleanup) {
   12862 		journal = dns_zone_getjournal(zone);
   12863 		if (journal != NULL) {
   12864 			(void)isc_file_remove(journal);
   12865 		}
   12866 	}
   12867 
   12868 	return result;
   12869 }
   12870 
   12871 isc_result_t
   12872 named_server_sync(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
   12873 	isc_result_t result, tresult;
   12874 	dns_view_t *view = NULL;
   12875 	dns_zone_t *zone = NULL;
   12876 	char classstr[DNS_RDATACLASS_FORMATSIZE];
   12877 	char zonename[DNS_NAME_FORMATSIZE];
   12878 	const char *vname = NULL, *sep = NULL, *arg = NULL;
   12879 	bool cleanup = false;
   12880 
   12881 	REQUIRE(text != NULL);
   12882 
   12883 	(void)next_token(lex, text);
   12884 
   12885 	arg = next_token(lex, text);
   12886 	if (arg != NULL &&
   12887 	    (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0))
   12888 	{
   12889 		cleanup = true;
   12890 		arg = next_token(lex, text);
   12891 	}
   12892 
   12893 	REQUIRE(text != NULL);
   12894 
   12895 	result = zone_from_args(server, lex, arg, &zone, NULL, text, false);
   12896 	if (result != ISC_R_SUCCESS) {
   12897 		return result;
   12898 	}
   12899 
   12900 	if (zone == NULL) {
   12901 		isc_loopmgr_pause(named_g_loopmgr);
   12902 		tresult = ISC_R_SUCCESS;
   12903 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12904 		     view = ISC_LIST_NEXT(view, link))
   12905 		{
   12906 			result = dns_view_apply(view, false, NULL, synczone,
   12907 						&cleanup);
   12908 			if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
   12909 			{
   12910 				tresult = result;
   12911 			}
   12912 		}
   12913 		isc_loopmgr_resume(named_g_loopmgr);
   12914 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12915 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12916 			      "dumping all zones%s: %s",
   12917 			      cleanup ? ", removing journal files" : "",
   12918 			      isc_result_totext(result));
   12919 		return tresult;
   12920 	}
   12921 
   12922 	isc_loopmgr_pause(named_g_loopmgr);
   12923 	result = synczone(zone, &cleanup);
   12924 	isc_loopmgr_resume(named_g_loopmgr);
   12925 
   12926 	view = dns_zone_getview(zone);
   12927 	if (strcmp(view->name, "_default") == 0 ||
   12928 	    strcmp(view->name, "_bind") == 0)
   12929 	{
   12930 		vname = "";
   12931 		sep = "";
   12932 	} else {
   12933 		vname = view->name;
   12934 		sep = " ";
   12935 	}
   12936 	dns_rdataclass_format(dns_zone_getclass(zone), classstr,
   12937 			      sizeof(classstr));
   12938 	dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
   12939 	isc_log_write(
   12940 		named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
   12941 		ISC_LOG_INFO, "sync: dumping zone '%s/%s'%s%s%s: %s", zonename,
   12942 		classstr, sep, vname, cleanup ? ", removing journal file" : "",
   12943 		isc_result_totext(result));
   12944 	dns_zone_detach(&zone);
   12945 	return result;
   12946 }
   12947 
   12948 /*
   12949  * Act on a "freeze" or "thaw" command from the command channel.
   12950  */
   12951 isc_result_t
   12952 named_server_freeze(named_server_t *server, bool freeze, isc_lex_t *lex,
   12953 		    isc_buffer_t **text) {
   12954 	isc_result_t result, tresult;
   12955 	dns_zone_t *mayberaw = NULL, *raw = NULL;
   12956 	dns_zonetype_t type;
   12957 	char classstr[DNS_RDATACLASS_FORMATSIZE];
   12958 	char zonename[DNS_NAME_FORMATSIZE];
   12959 	dns_view_t *view;
   12960 	const char *vname, *sep;
   12961 	bool frozen;
   12962 	const char *msg = NULL;
   12963 
   12964 	REQUIRE(text != NULL);
   12965 
   12966 	result = zone_from_args(server, lex, NULL, &mayberaw, NULL, text, true);
   12967 	if (result != ISC_R_SUCCESS) {
   12968 		return result;
   12969 	}
   12970 	if (mayberaw == NULL) {
   12971 		isc_loopmgr_pause(named_g_loopmgr);
   12972 		tresult = ISC_R_SUCCESS;
   12973 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12974 		     view = ISC_LIST_NEXT(view, link))
   12975 		{
   12976 			result = dns_view_freezezones(view, freeze);
   12977 			if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
   12978 			{
   12979 				tresult = result;
   12980 			}
   12981 		}
   12982 		isc_loopmgr_resume(named_g_loopmgr);
   12983 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12984 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12985 			      "%s all zones: %s",
   12986 			      freeze ? "freezing" : "thawing",
   12987 			      isc_result_totext(tresult));
   12988 		return tresult;
   12989 	}
   12990 	dns_zone_getraw(mayberaw, &raw);
   12991 	if (raw != NULL) {
   12992 		dns_zone_detach(&mayberaw);
   12993 		dns_zone_attach(raw, &mayberaw);
   12994 		dns_zone_detach(&raw);
   12995 	}
   12996 	type = dns_zone_gettype(mayberaw);
   12997 	if (type != dns_zone_primary) {
   12998 		dns_zone_detach(&mayberaw);
   12999 		return DNS_R_NOTPRIMARY;
   13000 	}
   13001 
   13002 	if (freeze && !dns_zone_isdynamic(mayberaw, true)) {
   13003 		dns_zone_detach(&mayberaw);
   13004 		return DNS_R_NOTDYNAMIC;
   13005 	}
   13006 
   13007 	isc_loopmgr_pause(named_g_loopmgr);
   13008 	frozen = dns_zone_getupdatedisabled(mayberaw);
   13009 	if (freeze) {
   13010 		if (frozen) {
   13011 			msg = "WARNING: The zone was already frozen.\n"
   13012 			      "Someone else may be editing it or "
   13013 			      "it may still be re-loading.";
   13014 			result = DNS_R_FROZEN;
   13015 		}
   13016 		if (result == ISC_R_SUCCESS) {
   13017 			result = dns_zone_flush(mayberaw);
   13018 			if (result != ISC_R_SUCCESS) {
   13019 				msg = "Flushing the zone updates to "
   13020 				      "disk failed.";
   13021 			}
   13022 		}
   13023 		if (result == ISC_R_SUCCESS) {
   13024 			dns_zone_setupdatedisabled(mayberaw, freeze);
   13025 		}
   13026 	} else {
   13027 		if (frozen) {
   13028 			result = dns_zone_loadandthaw(mayberaw);
   13029 			switch (result) {
   13030 			case ISC_R_SUCCESS:
   13031 			case DNS_R_UPTODATE:
   13032 				msg = "The zone reload and thaw was "
   13033 				      "successful.";
   13034 				result = ISC_R_SUCCESS;
   13035 				break;
   13036 			case DNS_R_CONTINUE:
   13037 				msg = "A zone reload and thaw was started.\n"
   13038 				      "Check the logs to see the result.";
   13039 				result = ISC_R_SUCCESS;
   13040 				break;
   13041 			default:
   13042 				break;
   13043 			}
   13044 		}
   13045 	}
   13046 	isc_loopmgr_resume(named_g_loopmgr);
   13047 
   13048 	if (msg != NULL) {
   13049 		(void)putstr(text, msg);
   13050 		(void)putnull(text);
   13051 	}
   13052 
   13053 	view = dns_zone_getview(mayberaw);
   13054 	if (strcmp(view->name, "_default") == 0 ||
   13055 	    strcmp(view->name, "_bind") == 0)
   13056 	{
   13057 		vname = "";
   13058 		sep = "";
   13059 	} else {
   13060 		vname = view->name;
   13061 		sep = " ";
   13062 	}
   13063 	dns_rdataclass_format(dns_zone_getclass(mayberaw), classstr,
   13064 			      sizeof(classstr));
   13065 	dns_name_format(dns_zone_getorigin(mayberaw), zonename,
   13066 			sizeof(zonename));
   13067 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13068 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   13069 		      "%s zone '%s/%s'%s%s: %s",
   13070 		      freeze ? "freezing" : "thawing", zonename, classstr, sep,
   13071 		      vname, isc_result_totext(result));
   13072 	dns_zone_detach(&mayberaw);
   13073 	return result;
   13074 }
   13075 
   13076 #ifdef HAVE_LIBSCF
   13077 /*
   13078  * This function adds a message for rndc to echo if named
   13079  * is managed by smf and is also running chroot.
   13080  */
   13081 isc_result_t
   13082 named_smf_add_message(isc_buffer_t **text) {
   13083 	REQUIRE(text != NULL);
   13084 
   13085 	return putstr(text, "use svcadm(1M) to manage named");
   13086 }
   13087 #endif /* HAVE_LIBSCF */
   13088 
   13089 #ifndef HAVE_LMDB
   13090 
   13091 /*
   13092  * Emit a comment at the top of the nzf file containing the viewname
   13093  * Expects the fp to already be open for writing
   13094  */
   13095 #define HEADER1 "# New zone file for view: "
   13096 #define HEADER2                                                     \
   13097 	"\n# This file contains configuration for zones added by\n" \
   13098 	"# the 'rndc addzone' command. DO NOT EDIT BY HAND.\n"
   13099 static isc_result_t
   13100 add_comment(FILE *fp, const char *viewname) {
   13101 	isc_result_t result;
   13102 	CHECK(isc_stdio_write(HEADER1, sizeof(HEADER1) - 1, 1, fp, NULL));
   13103 	CHECK(isc_stdio_write(viewname, strlen(viewname), 1, fp, NULL));
   13104 	CHECK(isc_stdio_write(HEADER2, sizeof(HEADER2) - 1, 1, fp, NULL));
   13105 cleanup:
   13106 	return result;
   13107 }
   13108 
   13109 static void
   13110 dumpzone(void *arg, const char *buf, int len) {
   13111 	FILE *fp = arg;
   13112 
   13113 	(void)isc_stdio_write(buf, len, 1, fp, NULL);
   13114 }
   13115 
   13116 static isc_result_t
   13117 nzf_append(dns_view_t *view, const cfg_obj_t *zconfig) {
   13118 	isc_result_t result;
   13119 	off_t offset;
   13120 	FILE *fp = NULL;
   13121 	bool offsetok = false;
   13122 
   13123 	LOCK(&view->new_zone_lock);
   13124 
   13125 	CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
   13126 	CHECK(isc_stdio_seek(fp, 0, SEEK_END));
   13127 
   13128 	CHECK(isc_stdio_tell(fp, &offset));
   13129 	offsetok = true;
   13130 	if (offset == 0) {
   13131 		CHECK(add_comment(fp, view->name));
   13132 	}
   13133 
   13134 	CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
   13135 	cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
   13136 	CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
   13137 	CHECK(isc_stdio_flush(fp));
   13138 	result = isc_stdio_close(fp);
   13139 	fp = NULL;
   13140 
   13141 cleanup:
   13142 	if (fp != NULL) {
   13143 		(void)isc_stdio_close(fp);
   13144 		if (offsetok) {
   13145 			isc_result_t result2;
   13146 
   13147 			result2 = isc_file_truncate(view->new_zone_file,
   13148 						    offset);
   13149 			if (result2 != ISC_R_SUCCESS) {
   13150 				isc_log_write(
   13151 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13152 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13153 					"Error truncating NZF file '%s' "
   13154 					"during rollback from append: "
   13155 					"%s",
   13156 					view->new_zone_file,
   13157 					isc_result_totext(result2));
   13158 			}
   13159 		}
   13160 	}
   13161 	UNLOCK(&view->new_zone_lock);
   13162 	return result;
   13163 }
   13164 
   13165 static isc_result_t
   13166 nzf_writeconf(const cfg_obj_t *config, dns_view_t *view) {
   13167 	const cfg_obj_t *zl = NULL;
   13168 	cfg_list_t *list;
   13169 	const cfg_listelt_t *elt;
   13170 
   13171 	FILE *fp = NULL;
   13172 	char tmp[1024];
   13173 	isc_result_t result;
   13174 
   13175 	result = isc_file_template(view->new_zone_file, "nzf-XXXXXXXX", tmp,
   13176 				   sizeof(tmp));
   13177 	if (result == ISC_R_SUCCESS) {
   13178 		result = isc_file_openunique(tmp, &fp);
   13179 	}
   13180 	if (result != ISC_R_SUCCESS) {
   13181 		return result;
   13182 	}
   13183 
   13184 	cfg_map_get(config, "zone", &zl);
   13185 	if (!cfg_obj_islist(zl)) {
   13186 		CHECK(ISC_R_FAILURE);
   13187 	}
   13188 
   13189 	list = UNCONST(&zl->value.list);
   13190 
   13191 	CHECK(add_comment(fp, view->name)); /* force a comment */
   13192 
   13193 	for (elt = ISC_LIST_HEAD(*list); elt != NULL;
   13194 	     elt = ISC_LIST_NEXT(elt, link))
   13195 	{
   13196 		const cfg_obj_t *zconfig = cfg_listelt_value(elt);
   13197 
   13198 		CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
   13199 		cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
   13200 		CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
   13201 	}
   13202 
   13203 	CHECK(isc_stdio_flush(fp));
   13204 	result = isc_stdio_close(fp);
   13205 	fp = NULL;
   13206 	if (result != ISC_R_SUCCESS) {
   13207 		goto cleanup;
   13208 	}
   13209 	CHECK(isc_file_rename(tmp, view->new_zone_file));
   13210 	return result;
   13211 
   13212 cleanup:
   13213 	if (fp != NULL) {
   13214 		(void)isc_stdio_close(fp);
   13215 	}
   13216 	(void)isc_file_remove(tmp);
   13217 	return result;
   13218 }
   13219 
   13220 static isc_result_t
   13221 load_nzf(dns_view_t *view, ns_cfgctx_t *nzcfg) {
   13222 	isc_result_t result;
   13223 
   13224 	/* The new zone file may not exist. That is OK. */
   13225 	if (!isc_file_exists(view->new_zone_file)) {
   13226 		return ISC_R_SUCCESS;
   13227 	}
   13228 
   13229 	/*
   13230 	 * Parse the configuration in the NZF file.  This may be called in
   13231 	 * multiple views, so we reset the parser each time.
   13232 	 */
   13233 	cfg_parser_reset(named_g_addparser);
   13234 	result = cfg_parse_file(named_g_addparser, view->new_zone_file,
   13235 				&cfg_type_addzoneconf, &nzcfg->nzf_config);
   13236 	if (result != ISC_R_SUCCESS) {
   13237 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13238 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13239 			      "Error parsing NZF file '%s': %s",
   13240 			      view->new_zone_file, isc_result_totext(result));
   13241 	}
   13242 
   13243 	return result;
   13244 }
   13245 #else  /* HAVE_LMDB */
   13246 
   13247 static void
   13248 nzd_setkey(MDB_val *key, dns_name_t *name, char *namebuf, size_t buflen) {
   13249 	dns_fixedname_t fixed;
   13250 
   13251 	dns_fixedname_init(&fixed);
   13252 	dns_name_downcase(name, dns_fixedname_name(&fixed), NULL);
   13253 	dns_name_format(dns_fixedname_name(&fixed), namebuf, buflen);
   13254 
   13255 	key->mv_data = namebuf;
   13256 	key->mv_size = strlen(namebuf);
   13257 }
   13258 
   13259 static void
   13260 dumpzone(void *arg, const char *buf, int len) {
   13261 	ns_dzarg_t *dzarg = arg;
   13262 	isc_result_t result;
   13263 
   13264 	REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
   13265 
   13266 	result = putmem(dzarg->text, buf, len);
   13267 	if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
   13268 		dzarg->result = result;
   13269 	}
   13270 }
   13271 
   13272 static isc_result_t
   13273 nzd_save(MDB_txn **txnp, MDB_dbi dbi, dns_zone_t *zone,
   13274 	 const cfg_obj_t *zconfig) {
   13275 	isc_result_t result;
   13276 	int status;
   13277 	dns_view_t *view;
   13278 	bool commit = false;
   13279 	isc_buffer_t *text = NULL;
   13280 	char namebuf[1024];
   13281 	MDB_val key, data;
   13282 	ns_dzarg_t dzarg;
   13283 
   13284 	view = dns_zone_getview(zone);
   13285 
   13286 	nzd_setkey(&key, dns_zone_getorigin(zone), namebuf, sizeof(namebuf));
   13287 
   13288 	if (zconfig == NULL) {
   13289 		/* We're deleting the zone from the database */
   13290 		status = mdb_del(*txnp, dbi, &key, NULL);
   13291 		if (status != MDB_SUCCESS && status != MDB_NOTFOUND) {
   13292 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13293 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13294 				      "Error deleting zone %s "
   13295 				      "from NZD database: %s",
   13296 				      namebuf, mdb_strerror(status));
   13297 			result = ISC_R_FAILURE;
   13298 			goto cleanup;
   13299 		} else if (status != MDB_NOTFOUND) {
   13300 			commit = true;
   13301 		}
   13302 	} else {
   13303 		/* We're creating or overwriting the zone */
   13304 		const cfg_obj_t *zoptions;
   13305 
   13306 		isc_buffer_allocate(view->mctx, &text, 256);
   13307 
   13308 		zoptions = cfg_tuple_get(zconfig, "options");
   13309 		if (zoptions == NULL) {
   13310 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13311 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13312 				      "Unable to get options from config in "
   13313 				      "nzd_save()");
   13314 			result = ISC_R_FAILURE;
   13315 			goto cleanup;
   13316 		}
   13317 
   13318 		dzarg.magic = DZARG_MAGIC;
   13319 		dzarg.text = &text;
   13320 		dzarg.result = ISC_R_SUCCESS;
   13321 		cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
   13322 		if (dzarg.result != ISC_R_SUCCESS) {
   13323 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13324 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13325 				      "Error writing zone config to "
   13326 				      "buffer in nzd_save(): %s",
   13327 				      isc_result_totext(dzarg.result));
   13328 			result = dzarg.result;
   13329 			goto cleanup;
   13330 		}
   13331 
   13332 		data.mv_data = isc_buffer_base(text);
   13333 		data.mv_size = isc_buffer_usedlength(text);
   13334 
   13335 		status = mdb_put(*txnp, dbi, &key, &data, 0);
   13336 		if (status != MDB_SUCCESS) {
   13337 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13338 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13339 				      "Error inserting zone in "
   13340 				      "NZD database: %s",
   13341 				      mdb_strerror(status));
   13342 			result = ISC_R_FAILURE;
   13343 			goto cleanup;
   13344 		}
   13345 
   13346 		commit = true;
   13347 	}
   13348 
   13349 	result = ISC_R_SUCCESS;
   13350 
   13351 cleanup:
   13352 	if (!commit || result != ISC_R_SUCCESS) {
   13353 		(void)mdb_txn_abort(*txnp);
   13354 	} else {
   13355 		status = mdb_txn_commit(*txnp);
   13356 		if (status != MDB_SUCCESS) {
   13357 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13358 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13359 				      "Error committing "
   13360 				      "NZD database: %s",
   13361 				      mdb_strerror(status));
   13362 			result = ISC_R_FAILURE;
   13363 		}
   13364 	}
   13365 	*txnp = NULL;
   13366 
   13367 	if (text != NULL) {
   13368 		isc_buffer_free(&text);
   13369 	}
   13370 
   13371 	return result;
   13372 }
   13373 
   13374 /*
   13375  * Check whether the new zone database for 'view' can be opened for writing.
   13376  *
   13377  * Caller must hold 'view->new_zone_lock'.
   13378  */
   13379 static isc_result_t
   13380 nzd_writable(dns_view_t *view) {
   13381 	isc_result_t result = ISC_R_SUCCESS;
   13382 	int status;
   13383 	MDB_dbi dbi;
   13384 	MDB_txn *txn = NULL;
   13385 
   13386 	REQUIRE(view != NULL);
   13387 
   13388 	status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, 0, &txn);
   13389 	if (status != MDB_SUCCESS) {
   13390 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13391 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   13392 			      "mdb_txn_begin: %s", mdb_strerror(status));
   13393 		return ISC_R_FAILURE;
   13394 	}
   13395 
   13396 	status = mdb_dbi_open(txn, NULL, 0, &dbi);
   13397 	if (status != MDB_SUCCESS) {
   13398 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13399 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   13400 			      "mdb_dbi_open: %s", mdb_strerror(status));
   13401 		result = ISC_R_FAILURE;
   13402 	}
   13403 
   13404 	mdb_txn_abort(txn);
   13405 	return result;
   13406 }
   13407 
   13408 /*
   13409  * Open the new zone database for 'view' and start a transaction for it.
   13410  *
   13411  * Caller must hold 'view->new_zone_lock'.
   13412  */
   13413 static isc_result_t
   13414 nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi) {
   13415 	int status;
   13416 	MDB_txn *txn = NULL;
   13417 
   13418 	REQUIRE(view != NULL);
   13419 	REQUIRE(txnp != NULL && *txnp == NULL);
   13420 	REQUIRE(dbi != NULL);
   13421 
   13422 	status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, flags, &txn);
   13423 	if (status != MDB_SUCCESS) {
   13424 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13425 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   13426 			      "mdb_txn_begin: %s", mdb_strerror(status));
   13427 		goto cleanup;
   13428 	}
   13429 
   13430 	status = mdb_dbi_open(txn, NULL, 0, dbi);
   13431 	if (status != MDB_SUCCESS) {
   13432 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13433 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   13434 			      "mdb_dbi_open: %s", mdb_strerror(status));
   13435 		goto cleanup;
   13436 	}
   13437 
   13438 	*txnp = txn;
   13439 
   13440 cleanup:
   13441 	if (status != MDB_SUCCESS) {
   13442 		if (txn != NULL) {
   13443 			mdb_txn_abort(txn);
   13444 		}
   13445 		return ISC_R_FAILURE;
   13446 	}
   13447 
   13448 	return ISC_R_SUCCESS;
   13449 }
   13450 
   13451 /*
   13452  * nzd_env_close() and nzd_env_reopen are a kluge to address the
   13453  * problem of an NZD file possibly being created before we drop
   13454  * root privileges.
   13455  */
   13456 static void
   13457 nzd_env_close(dns_view_t *view) {
   13458 	const char *dbpath = NULL;
   13459 	char dbpath_copy[PATH_MAX];
   13460 	char lockpath[PATH_MAX];
   13461 	int status, ret;
   13462 
   13463 	if (view->new_zone_dbenv == NULL) {
   13464 		return;
   13465 	}
   13466 
   13467 	status = mdb_env_get_path(view->new_zone_dbenv, &dbpath);
   13468 	INSIST(status == MDB_SUCCESS);
   13469 	snprintf(lockpath, sizeof(lockpath), "%s-lock", dbpath);
   13470 	strlcpy(dbpath_copy, dbpath, sizeof(dbpath_copy));
   13471 	mdb_env_close((MDB_env *)view->new_zone_dbenv);
   13472 
   13473 	/*
   13474 	 * Database files must be owned by the eventual user, not by root.
   13475 	 */
   13476 	ret = chown(dbpath_copy, named_os_uid(), -1);
   13477 	UNUSED(ret);
   13478 
   13479 	/*
   13480 	 * Some platforms need the lockfile not to exist when we reopen the
   13481 	 * environment.
   13482 	 */
   13483 	(void)isc_file_remove(lockpath);
   13484 
   13485 	view->new_zone_dbenv = NULL;
   13486 }
   13487 
   13488 static isc_result_t
   13489 nzd_env_reopen(dns_view_t *view) {
   13490 	isc_result_t result;
   13491 	MDB_env *env = NULL;
   13492 	int status;
   13493 
   13494 	if (view->new_zone_db == NULL) {
   13495 		return ISC_R_SUCCESS;
   13496 	}
   13497 
   13498 	nzd_env_close(view);
   13499 
   13500 	status = mdb_env_create(&env);
   13501 	if (status != MDB_SUCCESS) {
   13502 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   13503 			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
   13504 			      "mdb_env_create failed: %s",
   13505 			      mdb_strerror(status));
   13506 		CHECK(ISC_R_FAILURE);
   13507 	}
   13508 
   13509 	if (view->new_zone_mapsize != 0ULL) {
   13510 		status = mdb_env_set_mapsize(env, view->new_zone_mapsize);
   13511 		if (status != MDB_SUCCESS) {
   13512 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   13513 				      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
   13514 				      "mdb_env_set_mapsize failed: %s",
   13515 				      mdb_strerror(status));
   13516 			CHECK(ISC_R_FAILURE);
   13517 		}
   13518 	}
   13519 
   13520 	status = mdb_env_open(env, view->new_zone_db, DNS_LMDB_FLAGS, 0600);
   13521 	if (status != MDB_SUCCESS) {
   13522 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   13523 			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
   13524 			      "mdb_env_open of '%s' failed: %s",
   13525 			      view->new_zone_db, mdb_strerror(status));
   13526 		CHECK(ISC_R_FAILURE);
   13527 	}
   13528 
   13529 	view->new_zone_dbenv = env;
   13530 	env = NULL;
   13531 	result = ISC_R_SUCCESS;
   13532 
   13533 cleanup:
   13534 	if (env != NULL) {
   13535 		mdb_env_close(env);
   13536 	}
   13537 	return result;
   13538 }
   13539 
   13540 /*
   13541  * If 'commit' is true, commit the new zone database transaction pointed to by
   13542  * 'txnp'; otherwise, abort that transaction.
   13543  *
   13544  * Caller must hold 'view->new_zone_lock' for the view that the transaction
   13545  * pointed to by 'txnp' was started for.
   13546  */
   13547 static isc_result_t
   13548 nzd_close(MDB_txn **txnp, bool commit) {
   13549 	isc_result_t result = ISC_R_SUCCESS;
   13550 	int status;
   13551 
   13552 	REQUIRE(txnp != NULL);
   13553 
   13554 	if (*txnp != NULL) {
   13555 		if (commit) {
   13556 			status = mdb_txn_commit(*txnp);
   13557 			if (status != MDB_SUCCESS) {
   13558 				result = ISC_R_FAILURE;
   13559 			}
   13560 		} else {
   13561 			mdb_txn_abort(*txnp);
   13562 		}
   13563 		*txnp = NULL;
   13564 	}
   13565 
   13566 	return result;
   13567 }
   13568 
   13569 /*
   13570  * If there's an existing NZF file, load it and migrate its data
   13571  * to the NZD.
   13572  *
   13573  * Caller must hold view->new_zone_lock.
   13574  */
   13575 static isc_result_t
   13576 load_nzf(dns_view_t *view, ns_cfgctx_t *nzcfg) {
   13577 	isc_result_t result;
   13578 	cfg_obj_t *nzf_config = NULL;
   13579 	int status;
   13580 	isc_buffer_t *text = NULL;
   13581 	bool commit = false;
   13582 	const cfg_obj_t *zonelist;
   13583 	const cfg_listelt_t *element;
   13584 	char tempname[PATH_MAX];
   13585 	MDB_txn *txn = NULL;
   13586 	MDB_dbi dbi;
   13587 	MDB_val key, data;
   13588 	ns_dzarg_t dzarg;
   13589 
   13590 	UNUSED(nzcfg);
   13591 
   13592 	/*
   13593 	 * If NZF file doesn't exist, or NZD DB exists and already
   13594 	 * has data, return without attempting migration.
   13595 	 */
   13596 	if (!isc_file_exists(view->new_zone_file)) {
   13597 		result = ISC_R_SUCCESS;
   13598 		goto cleanup;
   13599 	}
   13600 
   13601 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13602 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   13603 		      "Migrating zones from NZF file '%s' to "
   13604 		      "NZD database '%s'",
   13605 		      view->new_zone_file, view->new_zone_db);
   13606 	/*
   13607 	 * Instead of blindly copying lines, we parse the NZF file using
   13608 	 * the configuration parser, because it validates it against the
   13609 	 * config type, giving us a guarantee that valid configuration
   13610 	 * will be written to DB.
   13611 	 */
   13612 	cfg_parser_reset(named_g_addparser);
   13613 	result = cfg_parse_file(named_g_addparser, view->new_zone_file,
   13614 				&cfg_type_addzoneconf, &nzf_config);
   13615 	if (result != ISC_R_SUCCESS) {
   13616 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13617 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13618 			      "Error parsing NZF file '%s': %s",
   13619 			      view->new_zone_file, isc_result_totext(result));
   13620 		goto cleanup;
   13621 	}
   13622 
   13623 	zonelist = NULL;
   13624 	CHECK(cfg_map_get(nzf_config, "zone", &zonelist));
   13625 	if (!cfg_obj_islist(zonelist)) {
   13626 		CHECK(ISC_R_FAILURE);
   13627 	}
   13628 
   13629 	CHECK(nzd_open(view, 0, &txn, &dbi));
   13630 
   13631 	isc_buffer_allocate(view->mctx, &text, 256);
   13632 
   13633 	for (element = cfg_list_first(zonelist); element != NULL;
   13634 	     element = cfg_list_next(element))
   13635 	{
   13636 		const cfg_obj_t *zconfig;
   13637 		const cfg_obj_t *zoptions;
   13638 		char zname[DNS_NAME_FORMATSIZE];
   13639 		dns_fixedname_t fname;
   13640 		dns_name_t *name;
   13641 		const char *origin;
   13642 		isc_buffer_t b;
   13643 
   13644 		zconfig = cfg_listelt_value(element);
   13645 
   13646 		origin = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
   13647 		if (origin == NULL) {
   13648 			result = ISC_R_FAILURE;
   13649 			goto cleanup;
   13650 		}
   13651 
   13652 		/* Normalize zone name */
   13653 		isc_buffer_constinit(&b, origin, strlen(origin));
   13654 		isc_buffer_add(&b, strlen(origin));
   13655 		name = dns_fixedname_initname(&fname);
   13656 		CHECK(dns_name_fromtext(name, &b, dns_rootname,
   13657 					DNS_NAME_DOWNCASE, NULL));
   13658 		dns_name_format(name, zname, sizeof(zname));
   13659 
   13660 		key.mv_data = zname;
   13661 		key.mv_size = strlen(zname);
   13662 
   13663 		zoptions = cfg_tuple_get(zconfig, "options");
   13664 		if (zoptions == NULL) {
   13665 			result = ISC_R_FAILURE;
   13666 			goto cleanup;
   13667 		}
   13668 
   13669 		isc_buffer_clear(text);
   13670 		dzarg.magic = DZARG_MAGIC;
   13671 		dzarg.text = &text;
   13672 		dzarg.result = ISC_R_SUCCESS;
   13673 		cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
   13674 		if (dzarg.result != ISC_R_SUCCESS) {
   13675 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13676 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13677 				      "Error writing zone config to "
   13678 				      "buffer in load_nzf(): %s",
   13679 				      isc_result_totext(result));
   13680 			result = dzarg.result;
   13681 			goto cleanup;
   13682 		}
   13683 
   13684 		data.mv_data = isc_buffer_base(text);
   13685 		data.mv_size = isc_buffer_usedlength(text);
   13686 
   13687 		status = mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE);
   13688 		if (status != MDB_SUCCESS) {
   13689 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13690 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13691 				      "Error inserting zone in "
   13692 				      "NZD database: %s",
   13693 				      mdb_strerror(status));
   13694 			result = ISC_R_FAILURE;
   13695 			goto cleanup;
   13696 		}
   13697 
   13698 		commit = true;
   13699 	}
   13700 
   13701 	result = ISC_R_SUCCESS;
   13702 
   13703 	/*
   13704 	 * Leaving the NZF file in place is harmless as we won't use it
   13705 	 * if an NZD database is found for the view. But we rename NZF file
   13706 	 * to a backup name here.
   13707 	 */
   13708 	strlcpy(tempname, view->new_zone_file, sizeof(tempname));
   13709 	if (strlen(tempname) < sizeof(tempname) - 1) {
   13710 		strlcat(tempname, "~", sizeof(tempname));
   13711 		isc_file_rename(view->new_zone_file, tempname);
   13712 	}
   13713 
   13714 cleanup:
   13715 	if (result != ISC_R_SUCCESS) {
   13716 		(void)nzd_close(&txn, false);
   13717 	} else {
   13718 		result = nzd_close(&txn, commit);
   13719 	}
   13720 
   13721 	if (text != NULL) {
   13722 		isc_buffer_free(&text);
   13723 	}
   13724 
   13725 	if (nzf_config != NULL) {
   13726 		cfg_obj_destroy(named_g_addparser, &nzf_config);
   13727 	}
   13728 
   13729 	return result;
   13730 }
   13731 #endif /* HAVE_LMDB */
   13732 
   13733 static isc_result_t
   13734 newzone_parse(named_server_t *server, char *command, dns_view_t **viewp,
   13735 	      cfg_obj_t **zoneconfp, const cfg_obj_t **zoneobjp,
   13736 	      bool *redirectp, isc_buffer_t **text) {
   13737 	isc_result_t result;
   13738 	isc_buffer_t argbuf;
   13739 	bool redirect = false;
   13740 	cfg_obj_t *zoneconf = NULL;
   13741 	const cfg_obj_t *zlist = NULL;
   13742 	const cfg_obj_t *zoneobj = NULL;
   13743 	const cfg_obj_t *zoptions = NULL;
   13744 	const cfg_obj_t *obj = NULL;
   13745 	const char *viewname = NULL;
   13746 	dns_rdataclass_t rdclass;
   13747 	dns_view_t *view = NULL;
   13748 	const char *bn = NULL;
   13749 
   13750 	REQUIRE(viewp != NULL && *viewp == NULL);
   13751 	REQUIRE(zoneobjp != NULL && *zoneobjp == NULL);
   13752 	REQUIRE(zoneconfp != NULL && *zoneconfp == NULL);
   13753 	REQUIRE(redirectp != NULL);
   13754 
   13755 	/* Try to parse the argument string */
   13756 	isc_buffer_init(&argbuf, command, (unsigned int)strlen(command));
   13757 	isc_buffer_add(&argbuf, strlen(command));
   13758 
   13759 	if (strncasecmp(command, "add", 3) == 0) {
   13760 		bn = "addzone";
   13761 	} else if (strncasecmp(command, "mod", 3) == 0) {
   13762 		bn = "modzone";
   13763 	} else {
   13764 		UNREACHABLE();
   13765 	}
   13766 
   13767 	/*
   13768 	 * Convert the "addzone" or "modzone" to just "zone", for
   13769 	 * the benefit of the parser
   13770 	 */
   13771 	isc_buffer_forward(&argbuf, 3);
   13772 
   13773 	cfg_parser_reset(named_g_addparser);
   13774 	CHECK(cfg_parse_buffer(named_g_addparser, &argbuf, bn, 0,
   13775 			       &cfg_type_addzoneconf, 0, &zoneconf));
   13776 	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
   13777 	if (!cfg_obj_islist(zlist)) {
   13778 		CHECK(ISC_R_FAILURE);
   13779 	}
   13780 
   13781 	/* For now we only support adding one zone at a time */
   13782 	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
   13783 
   13784 	/* Check the zone type for ones that are not supported by addzone. */
   13785 	zoptions = cfg_tuple_get(zoneobj, "options");
   13786 
   13787 	obj = NULL;
   13788 	(void)cfg_map_get(zoptions, "type", &obj);
   13789 	if (obj == NULL) {
   13790 		(void)cfg_map_get(zoptions, "in-view", &obj);
   13791 		if (obj != NULL) {
   13792 			(void)putstr(text, "'in-view' zones not supported by ");
   13793 			(void)putstr(text, bn);
   13794 		} else {
   13795 			(void)putstr(text, "zone type not specified");
   13796 		}
   13797 		CHECK(ISC_R_FAILURE);
   13798 	}
   13799 
   13800 	if (strcasecmp(cfg_obj_asstring(obj), "hint") == 0 ||
   13801 	    strcasecmp(cfg_obj_asstring(obj), "forward") == 0)
   13802 	{
   13803 		(void)putstr(text, "'");
   13804 		(void)putstr(text, cfg_obj_asstring(obj));
   13805 		(void)putstr(text, "' zones not supported by ");
   13806 		(void)putstr(text, bn);
   13807 		CHECK(ISC_R_FAILURE);
   13808 	}
   13809 
   13810 	if (strcasecmp(cfg_obj_asstring(obj), "redirect") == 0) {
   13811 		redirect = true;
   13812 	}
   13813 
   13814 	/* Make sense of optional class argument */
   13815 	obj = cfg_tuple_get(zoneobj, "class");
   13816 	CHECK(named_config_getclass(obj, dns_rdataclass_in, &rdclass));
   13817 
   13818 	/* Make sense of optional view argument */
   13819 	obj = cfg_tuple_get(zoneobj, "view");
   13820 	if (obj && cfg_obj_isstring(obj)) {
   13821 		viewname = cfg_obj_asstring(obj);
   13822 	}
   13823 	if (viewname == NULL || *viewname == '\0') {
   13824 		viewname = "_default";
   13825 	}
   13826 	result = dns_viewlist_find(&server->viewlist, viewname, rdclass, &view);
   13827 	if (result == ISC_R_NOTFOUND) {
   13828 		(void)putstr(text, "no matching view found for '");
   13829 		(void)putstr(text, viewname);
   13830 		(void)putstr(text, "'");
   13831 		goto cleanup;
   13832 	} else if (result != ISC_R_SUCCESS) {
   13833 		goto cleanup;
   13834 	}
   13835 
   13836 	*viewp = view;
   13837 	*zoneobjp = zoneobj;
   13838 	*zoneconfp = zoneconf;
   13839 	*redirectp = redirect;
   13840 
   13841 	return ISC_R_SUCCESS;
   13842 
   13843 cleanup:
   13844 	if (zoneconf != NULL) {
   13845 		cfg_obj_destroy(named_g_addparser, &zoneconf);
   13846 	}
   13847 	if (view != NULL) {
   13848 		dns_view_detach(&view);
   13849 	}
   13850 
   13851 	return result;
   13852 }
   13853 
   13854 static isc_result_t
   13855 delete_zoneconf(dns_view_t *view, cfg_parser_t *pctx, const cfg_obj_t *config,
   13856 		const dns_name_t *zname, nzfwriter_t nzfwriter, bool locked) {
   13857 	isc_result_t result = ISC_R_NOTFOUND;
   13858 	const cfg_listelt_t *elt = NULL;
   13859 	const cfg_obj_t *zl = NULL;
   13860 	cfg_list_t *list;
   13861 	dns_fixedname_t myfixed;
   13862 	dns_name_t *myname;
   13863 
   13864 	REQUIRE(view != NULL);
   13865 	REQUIRE(pctx != NULL);
   13866 	REQUIRE(config != NULL);
   13867 	REQUIRE(zname != NULL);
   13868 
   13869 	if (!locked) {
   13870 		LOCK(&view->new_zone_lock);
   13871 	}
   13872 
   13873 	cfg_map_get(config, "zone", &zl);
   13874 
   13875 	if (!cfg_obj_islist(zl)) {
   13876 		CHECK(ISC_R_FAILURE);
   13877 	}
   13878 
   13879 	list = UNCONST(&zl->value.list);
   13880 
   13881 	myname = dns_fixedname_initname(&myfixed);
   13882 
   13883 	for (elt = ISC_LIST_HEAD(*list); elt != NULL;
   13884 	     elt = ISC_LIST_NEXT(elt, link))
   13885 	{
   13886 		const cfg_obj_t *zconf = cfg_listelt_value(elt);
   13887 		const char *zn;
   13888 		cfg_listelt_t *e;
   13889 
   13890 		zn = cfg_obj_asstring(cfg_tuple_get(zconf, "name"));
   13891 		result = dns_name_fromstring(myname, zn, dns_rootname, 0, NULL);
   13892 		if (result != ISC_R_SUCCESS || !dns_name_equal(zname, myname)) {
   13893 			continue;
   13894 		}
   13895 
   13896 		e = UNCONST(elt);
   13897 		ISC_LIST_UNLINK(*list, e, link);
   13898 		cfg_obj_destroy(pctx, &e->obj);
   13899 		isc_mem_put(pctx->mctx, e, sizeof(*e));
   13900 		result = ISC_R_SUCCESS;
   13901 		break;
   13902 	}
   13903 
   13904 	/*
   13905 	 * Write config to NZF file if appropriate
   13906 	 */
   13907 	if (nzfwriter != NULL && view->new_zone_file != NULL) {
   13908 		result = nzfwriter(config, view);
   13909 	}
   13910 
   13911 cleanup:
   13912 	if (!locked) {
   13913 		UNLOCK(&view->new_zone_lock);
   13914 	}
   13915 	return result;
   13916 }
   13917 
   13918 static isc_result_t
   13919 do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
   13920 	   dns_name_t *name, cfg_obj_t *zoneconf, const cfg_obj_t *zoneobj,
   13921 	   bool redirect, isc_buffer_t **text) {
   13922 	isc_result_t result, tresult;
   13923 	dns_zone_t *zone = NULL;
   13924 	bool locked = false;
   13925 #ifndef HAVE_LMDB
   13926 	FILE *fp = NULL;
   13927 	bool cleanup_config = false;
   13928 #else /* HAVE_LMDB */
   13929 	MDB_txn *txn = NULL;
   13930 	MDB_dbi dbi;
   13931 
   13932 	UNUSED(zoneconf);
   13933 #endif
   13934 
   13935 	/* Zone shouldn't already exist */
   13936 	if (redirect) {
   13937 		result = (view->redirect == NULL) ? ISC_R_NOTFOUND
   13938 						  : ISC_R_EXISTS;
   13939 	} else {
   13940 		result = dns_view_findzone(view, name, DNS_ZTFIND_EXACT, &zone);
   13941 		if (result == ISC_R_SUCCESS) {
   13942 			result = ISC_R_EXISTS;
   13943 		}
   13944 	}
   13945 	if (result != ISC_R_NOTFOUND) {
   13946 		goto cleanup;
   13947 	}
   13948 
   13949 	isc_loopmgr_pause(named_g_loopmgr);
   13950 
   13951 #ifndef HAVE_LMDB
   13952 	/*
   13953 	 * Make sure we can open the configuration save file
   13954 	 */
   13955 	result = isc_stdio_open(view->new_zone_file, "a", &fp);
   13956 	if (result != ISC_R_SUCCESS) {
   13957 		isc_loopmgr_resume(named_g_loopmgr);
   13958 		TCHECK(putstr(text, "unable to create '"));
   13959 		TCHECK(putstr(text, view->new_zone_file));
   13960 		TCHECK(putstr(text, "': "));
   13961 		TCHECK(putstr(text, isc_result_totext(result)));
   13962 		goto cleanup;
   13963 	}
   13964 
   13965 	(void)isc_stdio_close(fp);
   13966 	fp = NULL;
   13967 #else  /* HAVE_LMDB */
   13968 	LOCK(&view->new_zone_lock);
   13969 	locked = true;
   13970 	/* Make sure we can open the NZD database */
   13971 	result = nzd_writable(view);
   13972 	if (result != ISC_R_SUCCESS) {
   13973 		isc_loopmgr_resume(named_g_loopmgr);
   13974 		TCHECK(putstr(text, "unable to open NZD database for '"));
   13975 		TCHECK(putstr(text, view->new_zone_db));
   13976 		TCHECK(putstr(text, "'"));
   13977 		result = ISC_R_FAILURE;
   13978 		goto cleanup;
   13979 	}
   13980 #endif /* HAVE_LMDB */
   13981 
   13982 	/* Mark view unfrozen and configure zone */
   13983 	dns_view_thaw(view);
   13984 	result = configure_zone(cfg->config, zoneobj, cfg->vconfig, view,
   13985 				&server->viewlist, &server->kasplist,
   13986 				&server->keystorelist, cfg->actx, true, false,
   13987 				false, false);
   13988 	dns_view_freeze(view);
   13989 
   13990 	isc_loopmgr_resume(named_g_loopmgr);
   13991 
   13992 	if (result != ISC_R_SUCCESS) {
   13993 		TCHECK(putstr(text, "configure_zone failed: "));
   13994 		TCHECK(putstr(text, isc_result_totext(result)));
   13995 		goto cleanup;
   13996 	}
   13997 
   13998 	/* Is it there yet? */
   13999 	if (redirect) {
   14000 		if (view->redirect == NULL) {
   14001 			CHECK(ISC_R_NOTFOUND);
   14002 		}
   14003 		dns_zone_attach(view->redirect, &zone);
   14004 	} else {
   14005 		result = dns_view_findzone(view, name, DNS_ZTFIND_EXACT, &zone);
   14006 		if (result != ISC_R_SUCCESS) {
   14007 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14008 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   14009 				      "added new zone was not found: %s",
   14010 				      isc_result_totext(result));
   14011 			goto cleanup;
   14012 		}
   14013 	}
   14014 
   14015 #ifndef HAVE_LMDB
   14016 	/*
   14017 	 * If there wasn't a previous newzone config, just save the one
   14018 	 * we've created. If there was a previous one, merge the new
   14019 	 * zone into it.
   14020 	 */
   14021 	if (cfg->nzf_config == NULL) {
   14022 		cfg_obj_attach(zoneconf, &cfg->nzf_config);
   14023 	} else {
   14024 		cfg_obj_t *z = UNCONST(zoneobj);
   14025 		CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z,
   14026 					"zone"));
   14027 	}
   14028 	cleanup_config = true;
   14029 #endif /* HAVE_LMDB */
   14030 
   14031 	/*
   14032 	 * Load the zone from the master file.  If this fails, we'll
   14033 	 * need to undo the configuration we've done already.
   14034 	 */
   14035 	result = dns_zone_load(zone, true);
   14036 	if (result != ISC_R_SUCCESS) {
   14037 		dns_db_t *dbp = NULL;
   14038 
   14039 		TCHECK(putstr(text, "dns_zone_loadnew failed: "));
   14040 		TCHECK(putstr(text, isc_result_totext(result)));
   14041 
   14042 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14043 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   14044 			      "addzone failed; reverting.");
   14045 
   14046 		/* If the zone loaded partially, unload it */
   14047 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
   14048 			dns_db_detach(&dbp);
   14049 			dns_zone_unload(zone);
   14050 		}
   14051 
   14052 		/* Remove the zone from the zone table */
   14053 		dns_view_delzone(view, zone);
   14054 		goto cleanup;
   14055 	}
   14056 
   14057 	/* Flag the zone as having been added at runtime */
   14058 	dns_zone_setadded(zone, true);
   14059 
   14060 #ifdef HAVE_LMDB
   14061 	/* Save the new zone configuration into the NZD */
   14062 	CHECK(nzd_open(view, 0, &txn, &dbi));
   14063 	CHECK(nzd_save(&txn, dbi, zone, zoneobj));
   14064 #else  /* ifdef HAVE_LMDB */
   14065 	/* Append the zone configuration to the NZF */
   14066 	result = nzf_append(view, zoneobj);
   14067 #endif /* HAVE_LMDB */
   14068 
   14069 cleanup:
   14070 
   14071 #ifndef HAVE_LMDB
   14072 	if (fp != NULL) {
   14073 		(void)isc_stdio_close(fp);
   14074 	}
   14075 	if (result != ISC_R_SUCCESS && cleanup_config) {
   14076 		tresult = delete_zoneconf(view, cfg->add_parser,
   14077 					  cfg->nzf_config, name, NULL, locked);
   14078 		RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
   14079 	}
   14080 #else  /* HAVE_LMDB */
   14081 	if (txn != NULL) {
   14082 		(void)nzd_close(&txn, false);
   14083 	}
   14084 	if (locked) {
   14085 		UNLOCK(&view->new_zone_lock);
   14086 	}
   14087 #endif /* HAVE_LMDB */
   14088 
   14089 	if (zone != NULL) {
   14090 		dns_zone_detach(&zone);
   14091 	}
   14092 
   14093 	return result;
   14094 }
   14095 
   14096 static isc_result_t
   14097 do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
   14098 	   dns_name_t *name, const char *zname, const cfg_obj_t *zoneobj,
   14099 	   bool redirect, isc_buffer_t **text) {
   14100 	isc_result_t result, tresult;
   14101 	dns_zone_t *zone = NULL;
   14102 	bool added;
   14103 	bool locked = false;
   14104 	const cfg_obj_t *options = NULL;
   14105 #ifndef HAVE_LMDB
   14106 	FILE *fp = NULL;
   14107 	cfg_obj_t *z;
   14108 #else  /* HAVE_LMDB */
   14109 	MDB_txn *txn = NULL;
   14110 	MDB_dbi dbi;
   14111 #endif /* HAVE_LMDB */
   14112 
   14113 	/* Zone must already exist */
   14114 	if (redirect) {
   14115 		if (view->redirect != NULL) {
   14116 			dns_zone_attach(view->redirect, &zone);
   14117 			result = ISC_R_SUCCESS;
   14118 		} else {
   14119 			result = ISC_R_NOTFOUND;
   14120 		}
   14121 	} else {
   14122 		result = dns_view_findzone(view, name, DNS_ZTFIND_EXACT, &zone);
   14123 	}
   14124 	if (result != ISC_R_SUCCESS) {
   14125 		goto cleanup;
   14126 	}
   14127 
   14128 	added = dns_zone_getadded(zone);
   14129 	dns_zone_detach(&zone);
   14130 
   14131 #ifndef HAVE_LMDB
   14132 	cfg = (ns_cfgctx_t *)view->new_zone_config;
   14133 	if (cfg == NULL) {
   14134 		TCHECK(putstr(text, "new zone config is not set"));
   14135 		CHECK(ISC_R_FAILURE);
   14136 	}
   14137 #endif /* ifndef HAVE_LMDB */
   14138 
   14139 	isc_loopmgr_pause(named_g_loopmgr);
   14140 
   14141 #ifndef HAVE_LMDB
   14142 	/* Make sure we can open the configuration save file */
   14143 	result = isc_stdio_open(view->new_zone_file, "a", &fp);
   14144 	if (result != ISC_R_SUCCESS) {
   14145 		TCHECK(putstr(text, "unable to open '"));
   14146 		TCHECK(putstr(text, view->new_zone_file));
   14147 		TCHECK(putstr(text, "': "));
   14148 		TCHECK(putstr(text, isc_result_totext(result)));
   14149 		isc_loopmgr_resume(named_g_loopmgr);
   14150 		goto cleanup;
   14151 	}
   14152 	(void)isc_stdio_close(fp);
   14153 	fp = NULL;
   14154 #else  /* HAVE_LMDB */
   14155 	LOCK(&view->new_zone_lock);
   14156 	locked = true;
   14157 	/* Make sure we can open the NZD database */
   14158 	result = nzd_writable(view);
   14159 	if (result != ISC_R_SUCCESS) {
   14160 		TCHECK(putstr(text, "unable to open NZD database for '"));
   14161 		TCHECK(putstr(text, view->new_zone_db));
   14162 		TCHECK(putstr(text, "'"));
   14163 		result = ISC_R_FAILURE;
   14164 		isc_loopmgr_resume(named_g_loopmgr);
   14165 		goto cleanup;
   14166 	}
   14167 #endif /* HAVE_LMDB */
   14168 
   14169 	/* Reconfigure the zone */
   14170 	dns_view_thaw(view);
   14171 	result = configure_zone(cfg->config, zoneobj, cfg->vconfig, view,
   14172 				&server->viewlist, &server->kasplist,
   14173 				&server->keystorelist, cfg->actx, false, false,
   14174 				false, true);
   14175 	dns_view_freeze(view);
   14176 
   14177 	isc_loopmgr_resume(named_g_loopmgr);
   14178 
   14179 	if (result != ISC_R_SUCCESS) {
   14180 		TCHECK(putstr(text, "configure_zone failed: "));
   14181 		TCHECK(putstr(text, isc_result_totext(result)));
   14182 		goto cleanup;
   14183 	}
   14184 
   14185 	/* Is it there yet? */
   14186 	if (redirect) {
   14187 		if (view->redirect == NULL) {
   14188 			CHECK(ISC_R_NOTFOUND);
   14189 		}
   14190 		dns_zone_attach(view->redirect, &zone);
   14191 	} else {
   14192 		CHECK(dns_view_findzone(view, name, DNS_ZTFIND_EXACT, &zone));
   14193 	}
   14194 
   14195 #ifndef HAVE_LMDB
   14196 	/* Remove old zone from configuration (and NZF file if applicable) */
   14197 	if (added) {
   14198 		result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config,
   14199 					 dns_zone_getorigin(zone),
   14200 					 nzf_writeconf, locked);
   14201 		if (result != ISC_R_SUCCESS) {
   14202 			TCHECK(putstr(text, "former zone configuration "
   14203 					    "not deleted: "));
   14204 			TCHECK(putstr(text, isc_result_totext(result)));
   14205 			goto cleanup;
   14206 		}
   14207 	}
   14208 #endif /* HAVE_LMDB */
   14209 
   14210 	if (!added) {
   14211 		if (cfg->vconfig == NULL) {
   14212 			options = cfg->config;
   14213 		} else {
   14214 			options = cfg_tuple_get(cfg->vconfig, "options");
   14215 		}
   14216 		result = delete_zoneconf(view, cfg->conf_parser, options,
   14217 					 dns_zone_getorigin(zone), NULL,
   14218 					 locked);
   14219 		if (result != ISC_R_SUCCESS) {
   14220 			TCHECK(putstr(text, "former zone configuration "
   14221 					    "not deleted: "));
   14222 			TCHECK(putstr(text, isc_result_totext(result)));
   14223 			goto cleanup;
   14224 		}
   14225 	}
   14226 
   14227 	/* Load the zone from the master file if it needs reloading. */
   14228 	result = dns_zone_load(zone, true);
   14229 
   14230 	/*
   14231 	 * Dynamic zones need no reloading, so we can pass this result.
   14232 	 */
   14233 	if (result == DNS_R_DYNAMIC) {
   14234 		result = ISC_R_SUCCESS;
   14235 	}
   14236 
   14237 	if (result != ISC_R_SUCCESS) {
   14238 		dns_db_t *dbp = NULL;
   14239 
   14240 		TCHECK(putstr(text, "failed to load zone '"));
   14241 		TCHECK(putstr(text, zname));
   14242 		TCHECK(putstr(text, "': "));
   14243 		TCHECK(putstr(text, isc_result_totext(result)));
   14244 		TCHECK(putstr(text, "\nThe zone is no longer being served. "));
   14245 		TCHECK(putstr(text, "Use 'rndc addzone' to correct\n"));
   14246 		TCHECK(putstr(text, "the problem and restore service."));
   14247 
   14248 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14249 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   14250 			      "modzone failed; removing zone.");
   14251 
   14252 		/* If the zone loaded partially, unload it */
   14253 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
   14254 			dns_db_detach(&dbp);
   14255 			dns_zone_unload(zone);
   14256 		}
   14257 
   14258 		/* Remove the zone from the zone table */
   14259 		dns_view_delzone(view, zone);
   14260 		goto cleanup;
   14261 	}
   14262 
   14263 #ifndef HAVE_LMDB
   14264 	/* Store the new zone configuration; also in NZF if applicable */
   14265 	if (cfg->nzf_config != NULL) {
   14266 		z = UNCONST(zoneobj);
   14267 		CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z,
   14268 					"zone"));
   14269 	}
   14270 #endif /* HAVE_LMDB */
   14271 
   14272 	if (added) {
   14273 #ifdef HAVE_LMDB
   14274 		CHECK(nzd_open(view, 0, &txn, &dbi));
   14275 		CHECK(nzd_save(&txn, dbi, zone, zoneobj));
   14276 #else  /* ifdef HAVE_LMDB */
   14277 		result = nzf_append(view, zoneobj);
   14278 		if (result != ISC_R_SUCCESS) {
   14279 			TCHECK(putstr(text, "\nNew zone config not saved: "));
   14280 			TCHECK(putstr(text, isc_result_totext(result)));
   14281 			goto cleanup;
   14282 		}
   14283 #endif /* HAVE_LMDB */
   14284 
   14285 		TCHECK(putstr(text, "zone '"));
   14286 		TCHECK(putstr(text, zname));
   14287 		TCHECK(putstr(text, "' reconfigured."));
   14288 	} else {
   14289 		CHECK(cfg_parser_mapadd(cfg->conf_parser, UNCONST(options),
   14290 					UNCONST(zoneobj), "zone"));
   14291 
   14292 		TCHECK(putstr(text, "zone '"));
   14293 		TCHECK(putstr(text, zname));
   14294 		TCHECK(putstr(text, "' must also be reconfigured in\n"));
   14295 		TCHECK(putstr(text, "named.conf to make changes permanent."));
   14296 	}
   14297 
   14298 cleanup:
   14299 
   14300 #ifndef HAVE_LMDB
   14301 	if (fp != NULL) {
   14302 		(void)isc_stdio_close(fp);
   14303 	}
   14304 #else  /* HAVE_LMDB */
   14305 	if (txn != NULL) {
   14306 		(void)nzd_close(&txn, false);
   14307 	}
   14308 	if (locked) {
   14309 		UNLOCK(&view->new_zone_lock);
   14310 	}
   14311 #endif /* HAVE_LMDB */
   14312 
   14313 	if (zone != NULL) {
   14314 		dns_zone_detach(&zone);
   14315 	}
   14316 
   14317 	return result;
   14318 }
   14319 
   14320 /*
   14321  * Act on an "addzone" or "modzone" command from the command channel.
   14322  */
   14323 isc_result_t
   14324 named_server_changezone(named_server_t *server, char *command,
   14325 			isc_buffer_t **text) {
   14326 	isc_result_t result;
   14327 	bool addzone;
   14328 	bool redirect = false;
   14329 	ns_cfgctx_t *cfg = NULL;
   14330 	cfg_obj_t *zoneconf = NULL;
   14331 	const cfg_obj_t *zoneobj = NULL;
   14332 	const char *zonename;
   14333 	dns_view_t *view = NULL;
   14334 	isc_buffer_t buf;
   14335 	dns_fixedname_t fname;
   14336 	dns_name_t *dnsname;
   14337 
   14338 	REQUIRE(text != NULL);
   14339 
   14340 	if (strncasecmp(command, "add", 3) == 0) {
   14341 		addzone = true;
   14342 	} else {
   14343 		INSIST(strncasecmp(command, "mod", 3) == 0);
   14344 		addzone = false;
   14345 	}
   14346 
   14347 	CHECK(newzone_parse(server, command, &view, &zoneconf, &zoneobj,
   14348 			    &redirect, text));
   14349 
   14350 	/* Are we accepting new zones in this view? */
   14351 #ifdef HAVE_LMDB
   14352 	if (view->new_zone_db == NULL)
   14353 #else  /* ifdef HAVE_LMDB */
   14354 	if (view->new_zone_file == NULL)
   14355 #endif /* HAVE_LMDB */
   14356 	{
   14357 		(void)putstr(text, "Not allowing new zones in view '");
   14358 		(void)putstr(text, view->name);
   14359 		(void)putstr(text, "'");
   14360 		result = ISC_R_NOPERM;
   14361 		goto cleanup;
   14362 	}
   14363 
   14364 	cfg = (ns_cfgctx_t *)view->new_zone_config;
   14365 	if (cfg == NULL) {
   14366 		result = ISC_R_FAILURE;
   14367 		goto cleanup;
   14368 	}
   14369 
   14370 	zonename = cfg_obj_asstring(cfg_tuple_get(zoneobj, "name"));
   14371 	isc_buffer_constinit(&buf, zonename, strlen(zonename));
   14372 	isc_buffer_add(&buf, strlen(zonename));
   14373 
   14374 	dnsname = dns_fixedname_initname(&fname);
   14375 	CHECK(dns_name_fromtext(dnsname, &buf, dns_rootname, 0, NULL));
   14376 
   14377 	if (redirect) {
   14378 		if (!dns_name_equal(dnsname, dns_rootname)) {
   14379 			(void)putstr(text, "redirect zones must be called "
   14380 					   "\".\"");
   14381 			CHECK(ISC_R_FAILURE);
   14382 		}
   14383 	}
   14384 
   14385 	if (addzone) {
   14386 		CHECK(do_addzone(server, cfg, view, dnsname, zoneconf, zoneobj,
   14387 				 redirect, text));
   14388 	} else {
   14389 		CHECK(do_modzone(server, cfg, view, dnsname, zonename, zoneobj,
   14390 				 redirect, text));
   14391 	}
   14392 
   14393 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14394 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   14395 		      "%s zone %s in view %s via %s",
   14396 		      addzone ? "added" : "updated", zonename, view->name,
   14397 		      addzone ? NAMED_COMMAND_ADDZONE : NAMED_COMMAND_MODZONE);
   14398 
   14399 	/* Changing a zone counts as reconfiguration */
   14400 	named_g_configtime = isc_time_now();
   14401 
   14402 cleanup:
   14403 	if (isc_buffer_usedlength(*text) > 0) {
   14404 		(void)putnull(text);
   14405 	}
   14406 	if (zoneconf != NULL) {
   14407 		cfg_obj_destroy(named_g_addparser, &zoneconf);
   14408 	}
   14409 	if (view != NULL) {
   14410 		dns_view_detach(&view);
   14411 	}
   14412 
   14413 	return result;
   14414 }
   14415 
   14416 static bool
   14417 inuse(const char *file, bool first, isc_buffer_t **text) {
   14418 	if (file != NULL && isc_file_exists(file)) {
   14419 		if (first) {
   14420 			(void)putstr(text, "The following files were in use "
   14421 					   "and may now be removed:\n");
   14422 		} else {
   14423 			(void)putstr(text, "\n");
   14424 		}
   14425 		(void)putstr(text, file);
   14426 		(void)putnull(text);
   14427 		return false;
   14428 	}
   14429 	return first;
   14430 }
   14431 
   14432 typedef struct {
   14433 	dns_zone_t *zone;
   14434 	bool cleanup;
   14435 } ns_dzctx_t;
   14436 
   14437 /*
   14438  * Carry out a zone deletion scheduled by named_server_delzone().
   14439  */
   14440 static void
   14441 rmzone(void *arg) {
   14442 	ns_dzctx_t *dz = (ns_dzctx_t *)arg;
   14443 	dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
   14444 	dns_catz_zone_t *catz = NULL;
   14445 	char zonename[DNS_NAME_FORMATSIZE];
   14446 	dns_view_t *view = NULL;
   14447 	ns_cfgctx_t *cfg = NULL;
   14448 	dns_db_t *dbp = NULL;
   14449 	bool added;
   14450 	isc_result_t result;
   14451 #ifdef HAVE_LMDB
   14452 	MDB_txn *txn = NULL;
   14453 	MDB_dbi dbi;
   14454 #endif /* ifdef HAVE_LMDB */
   14455 
   14456 	REQUIRE(dz != NULL);
   14457 
   14458 	/* Dig out configuration for this zone */
   14459 	zone = dz->zone;
   14460 	view = dns_zone_getview(zone);
   14461 	cfg = (ns_cfgctx_t *)view->new_zone_config;
   14462 	dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
   14463 
   14464 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14465 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   14466 		      "deleting zone %s in view %s via delzone", zonename,
   14467 		      view->name);
   14468 
   14469 	/*
   14470 	 * Remove the zone from configuration (and NZF file if applicable)
   14471 	 * (If this is a catalog zone member then nzf_config can be NULL)
   14472 	 */
   14473 	added = dns_zone_getadded(zone);
   14474 	catz = dns_zone_get_parentcatz(zone);
   14475 
   14476 	if (added && catz == NULL && cfg != NULL) {
   14477 #ifdef HAVE_LMDB
   14478 		/* Make sure we can open the NZD database */
   14479 		LOCK(&view->new_zone_lock);
   14480 		result = nzd_open(view, 0, &txn, &dbi);
   14481 		if (result != ISC_R_SUCCESS) {
   14482 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14483 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   14484 				      "unable to open NZD database for '%s'",
   14485 				      view->new_zone_db);
   14486 		} else {
   14487 			result = nzd_save(&txn, dbi, zone, NULL);
   14488 		}
   14489 
   14490 		if (result != ISC_R_SUCCESS) {
   14491 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14492 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   14493 				      "unable to delete zone configuration: %s",
   14494 				      isc_result_totext(result));
   14495 		}
   14496 
   14497 		if (txn != NULL) {
   14498 			(void)nzd_close(&txn, false);
   14499 		}
   14500 		UNLOCK(&view->new_zone_lock);
   14501 #else  /* ifdef HAVE_LMDB */
   14502 		result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config,
   14503 					 dns_zone_getorigin(zone),
   14504 					 nzf_writeconf, false);
   14505 		if (result != ISC_R_SUCCESS) {
   14506 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14507 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   14508 				      "unable to delete zone configuration: %s",
   14509 				      isc_result_totext(result));
   14510 		}
   14511 #endif /* HAVE_LMDB */
   14512 	}
   14513 
   14514 	if (!added && cfg != NULL) {
   14515 		if (cfg->vconfig != NULL) {
   14516 			const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig,
   14517 								  "options");
   14518 			result = delete_zoneconf(
   14519 				view, cfg->conf_parser, voptions,
   14520 				dns_zone_getorigin(zone), NULL, false);
   14521 		} else {
   14522 			result = delete_zoneconf(
   14523 				view, cfg->conf_parser, cfg->config,
   14524 				dns_zone_getorigin(zone), NULL, false);
   14525 		}
   14526 		if (result != ISC_R_SUCCESS) {
   14527 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14528 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   14529 				      "unable to delete zone configuration: %s",
   14530 				      isc_result_totext(result));
   14531 		}
   14532 	}
   14533 
   14534 	/* Unload zone database */
   14535 	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
   14536 		dns_db_detach(&dbp);
   14537 		dns_zone_unload(zone);
   14538 	}
   14539 
   14540 	/* Clean up stub/secondary zone files if requested to do so */
   14541 	dns_zone_getraw(zone, &raw);
   14542 	mayberaw = (raw != NULL) ? raw : zone;
   14543 
   14544 	if (added && dz->cleanup) {
   14545 		const char *file;
   14546 
   14547 		file = dns_zone_getfile(mayberaw);
   14548 		result = isc_file_remove(file);
   14549 		if (result != ISC_R_SUCCESS) {
   14550 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14551 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   14552 				      "file %s not removed: %s", file,
   14553 				      isc_result_totext(result));
   14554 		}
   14555 
   14556 		file = dns_zone_getjournal(mayberaw);
   14557 		result = isc_file_remove(file);
   14558 		if (result != ISC_R_SUCCESS) {
   14559 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14560 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   14561 				      "file %s not removed: %s", file,
   14562 				      isc_result_totext(result));
   14563 		}
   14564 
   14565 		if (zone != mayberaw) {
   14566 			file = dns_zone_getfile(zone);
   14567 			result = isc_file_remove(file);
   14568 			if (result != ISC_R_SUCCESS) {
   14569 				isc_log_write(
   14570 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14571 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   14572 					"file %s not removed: %s", file,
   14573 					isc_result_totext(result));
   14574 			}
   14575 
   14576 			file = dns_zone_getjournal(zone);
   14577 			result = isc_file_remove(file);
   14578 			if (result != ISC_R_SUCCESS) {
   14579 				isc_log_write(
   14580 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14581 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   14582 					"file %s not removed: %s", file,
   14583 					isc_result_totext(result));
   14584 			}
   14585 		}
   14586 	}
   14587 
   14588 	if (raw != NULL) {
   14589 		dns_zone_detach(&raw);
   14590 	}
   14591 	dns_zone_detach(&zone);
   14592 	isc_mem_put(named_g_mctx, dz, sizeof(*dz));
   14593 }
   14594 
   14595 /*
   14596  * Act on a "delzone" command from the command channel.
   14597  */
   14598 isc_result_t
   14599 named_server_delzone(named_server_t *server, isc_lex_t *lex,
   14600 		     isc_buffer_t **text) {
   14601 	isc_result_t result, tresult;
   14602 	dns_zone_t *zone = NULL;
   14603 	dns_zone_t *raw = NULL;
   14604 	dns_zone_t *mayberaw;
   14605 	dns_view_t *view = NULL;
   14606 	char zonename[DNS_NAME_FORMATSIZE];
   14607 	bool cleanup = false;
   14608 	const char *ptr;
   14609 	bool added;
   14610 	ns_dzctx_t *dz = NULL;
   14611 
   14612 	REQUIRE(text != NULL);
   14613 
   14614 	/* Skip the command name. */
   14615 	ptr = next_token(lex, text);
   14616 	if (ptr == NULL) {
   14617 		return ISC_R_UNEXPECTEDEND;
   14618 	}
   14619 
   14620 	/* Find out what we are to do. */
   14621 	ptr = next_token(lex, text);
   14622 	if (ptr == NULL) {
   14623 		return ISC_R_UNEXPECTEDEND;
   14624 	}
   14625 
   14626 	if (strcmp(ptr, "-clean") == 0 || strcmp(ptr, "-clear") == 0) {
   14627 		cleanup = true;
   14628 		ptr = next_token(lex, text);
   14629 	}
   14630 
   14631 	CHECK(zone_from_args(server, lex, ptr, &zone, zonename, text, false));
   14632 	if (zone == NULL) {
   14633 		result = ISC_R_UNEXPECTEDEND;
   14634 		goto cleanup;
   14635 	}
   14636 
   14637 	INSIST(zonename != NULL);
   14638 
   14639 	/* Is this a policy zone? */
   14640 	if (dns_zone_get_rpz_num(zone) != DNS_RPZ_INVALID_NUM) {
   14641 		TCHECK(putstr(text, "zone '"));
   14642 		TCHECK(putstr(text, zonename));
   14643 		TCHECK(putstr(text,
   14644 			      "' cannot be deleted: response-policy zone."));
   14645 		result = ISC_R_FAILURE;
   14646 		goto cleanup;
   14647 	}
   14648 
   14649 	view = dns_zone_getview(zone);
   14650 	if (dns_zone_gettype(zone) == dns_zone_redirect) {
   14651 		dns_zone_detach(&view->redirect);
   14652 	} else {
   14653 		CHECK(dns_view_delzone(view, zone));
   14654 	}
   14655 
   14656 	/* Send cleanup event */
   14657 	dz = isc_mem_get(named_g_mctx, sizeof(*dz));
   14658 	*dz = (ns_dzctx_t){
   14659 		.cleanup = cleanup,
   14660 	};
   14661 	dns_zone_attach(zone, &dz->zone);
   14662 	isc_async_run(dns_zone_getloop(zone), rmzone, dz);
   14663 
   14664 	/* Inform user about cleaning up stub/secondary zone files */
   14665 	dns_zone_getraw(zone, &raw);
   14666 	mayberaw = (raw != NULL) ? raw : zone;
   14667 
   14668 	added = dns_zone_getadded(zone);
   14669 	if (!added) {
   14670 		TCHECK(putstr(text, "zone '"));
   14671 		TCHECK(putstr(text, zonename));
   14672 		TCHECK(putstr(text, "' is no longer active and will be "
   14673 				    "deleted.\n"));
   14674 		TCHECK(putstr(text, "To keep it from returning "));
   14675 		TCHECK(putstr(text, "when the server is restarted, it\n"));
   14676 		TCHECK(putstr(text, "must also be removed from named.conf."));
   14677 	} else if (cleanup) {
   14678 		TCHECK(putstr(text, "zone '"));
   14679 		TCHECK(putstr(text, zonename));
   14680 		TCHECK(putstr(text, "' and associated files will be deleted."));
   14681 	} else if (dns_zone_gettype(mayberaw) == dns_zone_secondary ||
   14682 		   dns_zone_gettype(mayberaw) == dns_zone_mirror ||
   14683 		   dns_zone_gettype(mayberaw) == dns_zone_stub)
   14684 	{
   14685 		bool first;
   14686 		const char *file;
   14687 
   14688 		TCHECK(putstr(text, "zone '"));
   14689 		TCHECK(putstr(text, zonename));
   14690 		TCHECK(putstr(text, "' will be deleted."));
   14691 
   14692 		file = dns_zone_getfile(mayberaw);
   14693 		first = inuse(file, true, text);
   14694 
   14695 		file = dns_zone_getjournal(mayberaw);
   14696 		first = inuse(file, first, text);
   14697 
   14698 		if (zone != mayberaw) {
   14699 			file = dns_zone_getfile(zone);
   14700 			first = inuse(file, first, text);
   14701 
   14702 			file = dns_zone_getjournal(zone);
   14703 			(void)inuse(file, first, text);
   14704 		}
   14705 	}
   14706 
   14707 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14708 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   14709 		      "zone %s scheduled for removal via delzone", zonename);
   14710 
   14711 	/* Removing a zone counts as reconfiguration */
   14712 	named_g_configtime = isc_time_now();
   14713 
   14714 	result = ISC_R_SUCCESS;
   14715 
   14716 cleanup:
   14717 	if (isc_buffer_usedlength(*text) > 0) {
   14718 		(void)putnull(text);
   14719 	}
   14720 	if (raw != NULL) {
   14721 		dns_zone_detach(&raw);
   14722 	}
   14723 	if (zone != NULL) {
   14724 		dns_zone_detach(&zone);
   14725 	}
   14726 
   14727 	return result;
   14728 }
   14729 
   14730 static const cfg_obj_t *
   14731 find_name_in_list_from_map(const cfg_obj_t *config,
   14732 			   const char *map_key_for_list, const char *name,
   14733 			   bool redirect) {
   14734 	const cfg_obj_t *list = NULL;
   14735 	const cfg_listelt_t *element;
   14736 	const cfg_obj_t *obj = NULL;
   14737 	dns_fixedname_t fixed1, fixed2;
   14738 	dns_name_t *name1 = NULL, *name2 = NULL;
   14739 	isc_result_t result;
   14740 
   14741 	if (strcmp(map_key_for_list, "zone") == 0) {
   14742 		name1 = dns_fixedname_initname(&fixed1);
   14743 		name2 = dns_fixedname_initname(&fixed2);
   14744 		result = dns_name_fromstring(name1, name, dns_rootname, 0,
   14745 					     NULL);
   14746 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   14747 	}
   14748 
   14749 	cfg_map_get(config, map_key_for_list, &list);
   14750 	for (element = cfg_list_first(list); element != NULL;
   14751 	     element = cfg_list_next(element))
   14752 	{
   14753 		const char *vname;
   14754 
   14755 		obj = cfg_listelt_value(element);
   14756 		INSIST(obj != NULL);
   14757 		vname = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
   14758 		if (vname == NULL) {
   14759 			obj = NULL;
   14760 			continue;
   14761 		}
   14762 
   14763 		if (name1 != NULL) {
   14764 			result = dns_name_fromstring(name2, vname, dns_rootname,
   14765 						     0, NULL);
   14766 			if (result == ISC_R_SUCCESS &&
   14767 			    dns_name_equal(name1, name2))
   14768 			{
   14769 				const cfg_obj_t *zoptions;
   14770 				const cfg_obj_t *typeobj = NULL;
   14771 				zoptions = cfg_tuple_get(obj, "options");
   14772 
   14773 				if (zoptions != NULL) {
   14774 					cfg_map_get(zoptions, "type", &typeobj);
   14775 				}
   14776 				if (redirect && typeobj != NULL &&
   14777 				    strcasecmp(cfg_obj_asstring(typeobj),
   14778 					       "redirect") == 0)
   14779 				{
   14780 					break;
   14781 				} else if (!redirect) {
   14782 					break;
   14783 				}
   14784 			}
   14785 		} else if (strcasecmp(vname, name) == 0) {
   14786 			break;
   14787 		}
   14788 
   14789 		obj = NULL;
   14790 	}
   14791 
   14792 	return obj;
   14793 }
   14794 
   14795 static void
   14796 emitzone(void *arg, const char *buf, int len) {
   14797 	ns_dzarg_t *dzarg = arg;
   14798 	isc_result_t result;
   14799 
   14800 	REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
   14801 	result = putmem(dzarg->text, buf, len);
   14802 	if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
   14803 		dzarg->result = result;
   14804 	}
   14805 }
   14806 
   14807 /*
   14808  * Act on a "showzone" command from the command channel.
   14809  */
   14810 isc_result_t
   14811 named_server_showzone(named_server_t *server, isc_lex_t *lex,
   14812 		      isc_buffer_t **text) {
   14813 	isc_result_t result;
   14814 	const cfg_obj_t *vconfig = NULL, *zconfig = NULL;
   14815 	char zonename[DNS_NAME_FORMATSIZE];
   14816 	const cfg_obj_t *map;
   14817 	dns_view_t *view = NULL;
   14818 	dns_zone_t *zone = NULL;
   14819 	ns_cfgctx_t *cfg = NULL;
   14820 #ifdef HAVE_LMDB
   14821 	cfg_obj_t *nzconfig = NULL;
   14822 #endif /* HAVE_LMDB */
   14823 	bool added, redirect;
   14824 	ns_dzarg_t dzarg;
   14825 
   14826 	REQUIRE(text != NULL);
   14827 
   14828 	/* Parse parameters */
   14829 	CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true));
   14830 	if (zone == NULL) {
   14831 		result = ISC_R_UNEXPECTEDEND;
   14832 		goto cleanup;
   14833 	}
   14834 
   14835 	redirect = dns_zone_gettype(zone) == dns_zone_redirect;
   14836 	added = dns_zone_getadded(zone);
   14837 	view = dns_zone_getview(zone);
   14838 	dns_zone_detach(&zone);
   14839 
   14840 	cfg = (ns_cfgctx_t *)view->new_zone_config;
   14841 	if (cfg == NULL) {
   14842 		result = ISC_R_FAILURE;
   14843 		goto cleanup;
   14844 	}
   14845 
   14846 	if (!added) {
   14847 		/* Find the view statement */
   14848 		vconfig = find_name_in_list_from_map(cfg->config, "view",
   14849 						     view->name, false);
   14850 
   14851 		/* Find the zone statement */
   14852 		if (vconfig != NULL) {
   14853 			map = cfg_tuple_get(vconfig, "options");
   14854 		} else {
   14855 			map = cfg->config;
   14856 		}
   14857 
   14858 		zconfig = find_name_in_list_from_map(map, "zone", zonename,
   14859 						     redirect);
   14860 	}
   14861 
   14862 #ifndef HAVE_LMDB
   14863 	if (zconfig == NULL && cfg->nzf_config != NULL) {
   14864 		zconfig = find_name_in_list_from_map(cfg->nzf_config, "zone",
   14865 						     zonename, redirect);
   14866 	}
   14867 #else  /* HAVE_LMDB */
   14868 	if (zconfig == NULL) {
   14869 		const cfg_obj_t *zlist = NULL;
   14870 		CHECK(get_newzone_config(view, zonename, &nzconfig));
   14871 		CHECK(cfg_map_get(nzconfig, "zone", &zlist));
   14872 		if (!cfg_obj_islist(zlist)) {
   14873 			CHECK(ISC_R_FAILURE);
   14874 		}
   14875 
   14876 		zconfig = cfg_listelt_value(cfg_list_first(zlist));
   14877 	}
   14878 #endif /* HAVE_LMDB */
   14879 
   14880 	if (zconfig == NULL) {
   14881 		CHECK(ISC_R_NOTFOUND);
   14882 	}
   14883 
   14884 	CHECK(putstr(text, "zone "));
   14885 	dzarg.magic = DZARG_MAGIC;
   14886 	dzarg.text = text;
   14887 	dzarg.result = ISC_R_SUCCESS;
   14888 	cfg_printx(zconfig, CFG_PRINTER_ONELINE, emitzone, &dzarg);
   14889 	CHECK(dzarg.result);
   14890 
   14891 	CHECK(putstr(text, ";"));
   14892 
   14893 	result = ISC_R_SUCCESS;
   14894 
   14895 cleanup:
   14896 #ifdef HAVE_LMDB
   14897 	if (nzconfig != NULL) {
   14898 		cfg_obj_destroy(named_g_addparser, &nzconfig);
   14899 	}
   14900 #endif /* HAVE_LMDB */
   14901 	if (isc_buffer_usedlength(*text) > 0) {
   14902 		(void)putnull(text);
   14903 	}
   14904 
   14905 	return result;
   14906 }
   14907 
   14908 static void
   14909 newzone_cfgctx_destroy(void **cfgp) {
   14910 	ns_cfgctx_t *cfg;
   14911 
   14912 	REQUIRE(cfgp != NULL && *cfgp != NULL);
   14913 
   14914 	cfg = *cfgp;
   14915 
   14916 	if (cfg->conf_parser != NULL) {
   14917 		if (cfg->config != NULL) {
   14918 			cfg_obj_destroy(cfg->conf_parser, &cfg->config);
   14919 		}
   14920 		if (cfg->vconfig != NULL) {
   14921 			cfg_obj_destroy(cfg->conf_parser, &cfg->vconfig);
   14922 		}
   14923 		cfg_parser_destroy(&cfg->conf_parser);
   14924 	}
   14925 	if (cfg->add_parser != NULL) {
   14926 		if (cfg->nzf_config != NULL) {
   14927 			cfg_obj_destroy(cfg->add_parser, &cfg->nzf_config);
   14928 		}
   14929 		cfg_parser_destroy(&cfg->add_parser);
   14930 	}
   14931 
   14932 	if (cfg->actx != NULL) {
   14933 		cfg_aclconfctx_detach(&cfg->actx);
   14934 	}
   14935 
   14936 	isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
   14937 	*cfgp = NULL;
   14938 }
   14939 
   14940 isc_result_t
   14941 named_server_signing(named_server_t *server, isc_lex_t *lex,
   14942 		     isc_buffer_t **text) {
   14943 	isc_result_t result = ISC_R_SUCCESS;
   14944 	dns_zone_t *zone = NULL;
   14945 	dns_name_t *origin;
   14946 	dns_db_t *db = NULL;
   14947 	dns_dbnode_t *node = NULL;
   14948 	dns_dbversion_t *version = NULL;
   14949 	dns_rdatatype_t privatetype;
   14950 	dns_rdataset_t privset;
   14951 	bool first = true;
   14952 	bool list = false, clear = false;
   14953 	bool chain = false;
   14954 	bool setserial = false;
   14955 	bool resalt = false;
   14956 	uint32_t serial = 0;
   14957 	char keystr[DNS_SECALG_FORMATSIZE + 7]; /* <5-digit keyid>/<alg> */
   14958 	unsigned short hash = 0, flags = 0, iter = 0, saltlen = 0;
   14959 	unsigned char salt[255];
   14960 	const char *ptr;
   14961 	size_t n;
   14962 	bool kasp = false;
   14963 
   14964 	REQUIRE(text != NULL);
   14965 
   14966 	dns_rdataset_init(&privset);
   14967 
   14968 	/* Skip the command name. */
   14969 	ptr = next_token(lex, text);
   14970 	if (ptr == NULL) {
   14971 		return ISC_R_UNEXPECTEDEND;
   14972 	}
   14973 
   14974 	/* Find out what we are to do. */
   14975 	ptr = next_token(lex, text);
   14976 	if (ptr == NULL) {
   14977 		return ISC_R_UNEXPECTEDEND;
   14978 	}
   14979 
   14980 	if (strcasecmp(ptr, "-list") == 0) {
   14981 		list = true;
   14982 	} else if ((strcasecmp(ptr, "-clear") == 0) ||
   14983 		   (strcasecmp(ptr, "-clean") == 0))
   14984 	{
   14985 		clear = true;
   14986 		ptr = next_token(lex, text);
   14987 		if (ptr == NULL) {
   14988 			return ISC_R_UNEXPECTEDEND;
   14989 		}
   14990 		strlcpy(keystr, ptr, sizeof(keystr));
   14991 	} else if (strcasecmp(ptr, "-nsec3param") == 0) {
   14992 		char hashbuf[64], flagbuf[64], iterbuf[64];
   14993 		char nbuf[256];
   14994 
   14995 		chain = true;
   14996 		ptr = next_token(lex, text);
   14997 		if (ptr == NULL) {
   14998 			return ISC_R_UNEXPECTEDEND;
   14999 		}
   15000 
   15001 		if (strcasecmp(ptr, "none") == 0) {
   15002 			hash = 0;
   15003 		} else {
   15004 			strlcpy(hashbuf, ptr, sizeof(hashbuf));
   15005 
   15006 			ptr = next_token(lex, text);
   15007 			if (ptr == NULL) {
   15008 				return ISC_R_UNEXPECTEDEND;
   15009 			}
   15010 			strlcpy(flagbuf, ptr, sizeof(flagbuf));
   15011 
   15012 			ptr = next_token(lex, text);
   15013 			if (ptr == NULL) {
   15014 				return ISC_R_UNEXPECTEDEND;
   15015 			}
   15016 			strlcpy(iterbuf, ptr, sizeof(iterbuf));
   15017 			n = snprintf(nbuf, sizeof(nbuf), "%s %s %s", hashbuf,
   15018 				     flagbuf, iterbuf);
   15019 			if (n == sizeof(nbuf)) {
   15020 				return ISC_R_NOSPACE;
   15021 			}
   15022 			n = sscanf(nbuf, "%hu %hu %hu", &hash, &flags, &iter);
   15023 			if (n != 3U) {
   15024 				return ISC_R_BADNUMBER;
   15025 			}
   15026 
   15027 			if (hash > 0xffU || flags > 0xffU ||
   15028 			    iter > dns_nsec3_maxiterations())
   15029 			{
   15030 				return ISC_R_RANGE;
   15031 			}
   15032 
   15033 			ptr = next_token(lex, text);
   15034 			if (ptr == NULL) {
   15035 				return ISC_R_UNEXPECTEDEND;
   15036 			} else if (strcasecmp(ptr, "auto") == 0) {
   15037 				/* Auto-generate a random salt.
   15038 				 * XXXMUKS: This currently uses the
   15039 				 * minimum recommended length by RFC
   15040 				 * 5155 (64 bits). It should be made
   15041 				 * configurable.
   15042 				 */
   15043 				saltlen = 8;
   15044 				resalt = true;
   15045 			} else if (strcmp(ptr, "-") != 0) {
   15046 				isc_buffer_t buf;
   15047 
   15048 				isc_buffer_init(&buf, salt, sizeof(salt));
   15049 				CHECK(isc_hex_decodestring(ptr, &buf));
   15050 				saltlen = isc_buffer_usedlength(&buf);
   15051 			}
   15052 		}
   15053 	} else if (strcasecmp(ptr, "-serial") == 0) {
   15054 		ptr = next_token(lex, text);
   15055 		if (ptr == NULL) {
   15056 			return ISC_R_UNEXPECTEDEND;
   15057 		}
   15058 		CHECK(isc_parse_uint32(&serial, ptr, 10));
   15059 		setserial = true;
   15060 	} else {
   15061 		CHECK(DNS_R_SYNTAX);
   15062 	}
   15063 
   15064 	CHECK(zone_from_args(server, lex, NULL, &zone, NULL, text, false));
   15065 	if (zone == NULL) {
   15066 		CHECK(ISC_R_UNEXPECTEDEND);
   15067 	}
   15068 
   15069 	if (dns_zone_getkasp(zone) != NULL) {
   15070 		kasp = true;
   15071 	}
   15072 
   15073 	if (clear) {
   15074 		CHECK(dns_zone_keydone(zone, keystr));
   15075 		(void)putstr(text, "request queued");
   15076 		(void)putnull(text);
   15077 	} else if (chain && !kasp) {
   15078 		CHECK(dns_zone_setnsec3param(
   15079 			zone, (uint8_t)hash, (uint8_t)flags, iter,
   15080 			(uint8_t)saltlen, salt, true, resalt));
   15081 		(void)putstr(text, "nsec3param request queued");
   15082 		(void)putnull(text);
   15083 	} else if (setserial) {
   15084 		CHECK(dns_zone_setserial(zone, serial));
   15085 		(void)putstr(text, "serial request queued");
   15086 		(void)putnull(text);
   15087 	} else if (list) {
   15088 		privatetype = dns_zone_getprivatetype(zone);
   15089 		origin = dns_zone_getorigin(zone);
   15090 		CHECK(dns_zone_getdb(zone, &db));
   15091 		CHECK(dns_db_findnode(db, origin, false, &node));
   15092 		dns_db_currentversion(db, &version);
   15093 
   15094 		result = dns_db_findrdataset(db, node, version, privatetype,
   15095 					     dns_rdatatype_none, 0, &privset,
   15096 					     NULL);
   15097 		if (result == ISC_R_NOTFOUND) {
   15098 			(void)putstr(text, "No signing records found");
   15099 			(void)putnull(text);
   15100 			result = ISC_R_SUCCESS;
   15101 			goto cleanup;
   15102 		}
   15103 
   15104 		for (result = dns_rdataset_first(&privset);
   15105 		     result == ISC_R_SUCCESS;
   15106 		     result = dns_rdataset_next(&privset))
   15107 		{
   15108 			dns_rdata_t priv = DNS_RDATA_INIT;
   15109 			/*
   15110 			 * In theory, the output buffer could hold a full RDATA
   15111 			 * record which is 16-bit and then some text around
   15112 			 * it
   15113 			 */
   15114 			char output[UINT16_MAX + BUFSIZ];
   15115 			isc_buffer_t buf;
   15116 
   15117 			dns_rdataset_current(&privset, &priv);
   15118 
   15119 			isc_buffer_init(&buf, output, sizeof(output));
   15120 			CHECK(dns_private_totext(&priv, &buf));
   15121 			if (!first) {
   15122 				CHECK(putstr(text, "\n"));
   15123 			}
   15124 			CHECK(putstr(text, output));
   15125 			first = false;
   15126 		}
   15127 		if (!first) {
   15128 			CHECK(putnull(text));
   15129 		}
   15130 
   15131 		if (result == ISC_R_NOMORE) {
   15132 			result = ISC_R_SUCCESS;
   15133 		}
   15134 	} else if (kasp) {
   15135 		(void)putstr(text, "zone uses dnssec-policy, use rndc dnssec "
   15136 				   "command instead");
   15137 		(void)putnull(text);
   15138 	}
   15139 
   15140 cleanup:
   15141 	if (dns_rdataset_isassociated(&privset)) {
   15142 		dns_rdataset_disassociate(&privset);
   15143 	}
   15144 	if (node != NULL) {
   15145 		dns_db_detachnode(db, &node);
   15146 	}
   15147 	if (version != NULL) {
   15148 		dns_db_closeversion(db, &version, false);
   15149 	}
   15150 	if (db != NULL) {
   15151 		dns_db_detach(&db);
   15152 	}
   15153 	if (zone != NULL) {
   15154 		dns_zone_detach(&zone);
   15155 	}
   15156 
   15157 	return result;
   15158 }
   15159 
   15160 static bool
   15161 argcheck(char *cmd, const char *full) {
   15162 	size_t l;
   15163 
   15164 	if (cmd == NULL || cmd[0] != '-') {
   15165 		return false;
   15166 	}
   15167 
   15168 	cmd++;
   15169 	l = strlen(cmd);
   15170 	if (l > strlen(full) || strncasecmp(cmd, full, l) != 0) {
   15171 		return false;
   15172 	}
   15173 
   15174 	return true;
   15175 }
   15176 
   15177 isc_result_t
   15178 named_server_dnssec(named_server_t *server, isc_lex_t *lex,
   15179 		    isc_buffer_t **text) {
   15180 	isc_result_t result = ISC_R_SUCCESS;
   15181 	dns_zone_t *zone = NULL;
   15182 	dns_kasp_t *kasp = NULL;
   15183 	dns_dnsseckeylist_t keys;
   15184 	dns_dnsseckey_t *key;
   15185 	char *ptr, *zonetext = NULL;
   15186 	const char *msg = NULL;
   15187 	/* variables for -step */
   15188 	bool forcestep = false;
   15189 	/* variables for -checkds */
   15190 	bool checkds = false, dspublish = false;
   15191 	/* variables for -rollover */
   15192 	bool rollover = false;
   15193 	/* variables for -key */
   15194 	bool use_keyid = false;
   15195 	dns_keytag_t keyid = 0;
   15196 	uint8_t algorithm = 0;
   15197 	/* variables for -status */
   15198 	bool status = false;
   15199 	char output[4096];
   15200 	isc_stdtime_t now, when;
   15201 	isc_time_t timenow, timewhen;
   15202 	dns_db_t *db = NULL;
   15203 	dns_dbversion_t *version = NULL;
   15204 
   15205 	REQUIRE(text != NULL);
   15206 
   15207 	/* Skip the command name. */
   15208 	ptr = next_token(lex, text);
   15209 	if (ptr == NULL) {
   15210 		return ISC_R_UNEXPECTEDEND;
   15211 	}
   15212 
   15213 	/* Find out what we are to do. */
   15214 	ptr = next_token(lex, text);
   15215 	if (ptr == NULL) {
   15216 		return ISC_R_UNEXPECTEDEND;
   15217 	}
   15218 
   15219 	/* Initialize current time and key list. */
   15220 	timenow = isc_time_now();
   15221 	now = isc_time_seconds(&timenow);
   15222 	when = now;
   15223 
   15224 	ISC_LIST_INIT(keys);
   15225 
   15226 	if (strcasecmp(ptr, "-status") == 0) {
   15227 		status = true;
   15228 	} else if (strcasecmp(ptr, "-rollover") == 0) {
   15229 		rollover = true;
   15230 	} else if (strcasecmp(ptr, "-checkds") == 0) {
   15231 		checkds = true;
   15232 	} else if (strcasecmp(ptr, "-step") == 0) {
   15233 		forcestep = true;
   15234 	} else {
   15235 		CHECK(DNS_R_SYNTAX);
   15236 	}
   15237 
   15238 	if (rollover || checkds) {
   15239 		/* Check for options */
   15240 		for (;;) {
   15241 			ptr = next_token(lex, text);
   15242 			if (ptr == NULL) {
   15243 				msg = "Bad format";
   15244 				CHECK(ISC_R_UNEXPECTEDEND);
   15245 			} else if (argcheck(ptr, "alg")) {
   15246 				isc_consttextregion_t alg;
   15247 				ptr = next_token(lex, text);
   15248 				if (ptr == NULL) {
   15249 					msg = "No key algorithm specified";
   15250 					CHECK(ISC_R_UNEXPECTEDEND);
   15251 				}
   15252 				alg.base = ptr;
   15253 				alg.length = strlen(alg.base);
   15254 				result = dns_secalg_fromtext(
   15255 					&algorithm, (isc_textregion_t *)&alg);
   15256 				if (result != ISC_R_SUCCESS) {
   15257 					msg = "Bad algorithm";
   15258 					CHECK(DNS_R_SYNTAX);
   15259 				}
   15260 				continue;
   15261 			} else if (argcheck(ptr, "key")) {
   15262 				uint16_t id;
   15263 				ptr = next_token(lex, text);
   15264 				if (ptr == NULL) {
   15265 					msg = "No key identifier specified";
   15266 					CHECK(ISC_R_UNEXPECTEDEND);
   15267 				}
   15268 				CHECK(isc_parse_uint16(&id, ptr, 10));
   15269 				keyid = (dns_keytag_t)id;
   15270 				use_keyid = true;
   15271 				continue;
   15272 			} else if (argcheck(ptr, "when")) {
   15273 				uint32_t tw;
   15274 				ptr = next_token(lex, text);
   15275 				if (ptr == NULL) {
   15276 					msg = "No time specified";
   15277 					CHECK(ISC_R_UNEXPECTEDEND);
   15278 				}
   15279 				CHECK(dns_time32_fromtext(ptr, &tw));
   15280 				when = (isc_stdtime_t)tw;
   15281 				continue;
   15282 			} else if (ptr[0] == '-') {
   15283 				msg = "Unknown option";
   15284 				CHECK(DNS_R_SYNTAX);
   15285 			} else if (checkds) {
   15286 				/*
   15287 				 * No arguments provided, so we must be
   15288 				 * parsing "published|withdrawn".
   15289 				 */
   15290 				if (strcasecmp(ptr, "published") == 0) {
   15291 					dspublish = true;
   15292 				} else if (strcasecmp(ptr, "withdrawn") != 0) {
   15293 					CHECK(DNS_R_SYNTAX);
   15294 				}
   15295 			} else if (rollover) {
   15296 				/*
   15297 				 * No arguments provided, so we must be
   15298 				 * parsing the zone.
   15299 				 */
   15300 				zonetext = ptr;
   15301 			}
   15302 			break;
   15303 		}
   15304 
   15305 		if (rollover && !use_keyid) {
   15306 			msg = "Key id is required when scheduling rollover";
   15307 			CHECK(DNS_R_SYNTAX);
   15308 		}
   15309 
   15310 		if (algorithm > 0 && !use_keyid) {
   15311 			msg = "Key id is required when setting algorithm";
   15312 			CHECK(DNS_R_SYNTAX);
   15313 		}
   15314 	}
   15315 
   15316 	/* Get zone. */
   15317 	CHECK(zone_from_args(server, lex, zonetext, &zone, NULL, text, false));
   15318 	if (zone == NULL) {
   15319 		msg = "Zone not found";
   15320 		CHECK(ISC_R_UNEXPECTEDEND);
   15321 	}
   15322 
   15323 	/* Trailing garbage? */
   15324 	ptr = next_token(lex, text);
   15325 	if (ptr != NULL) {
   15326 		msg = "Too many arguments";
   15327 		CHECK(DNS_R_SYNTAX);
   15328 	}
   15329 
   15330 	/* Get dnssec-policy. */
   15331 	kasp = dns_zone_getkasp(zone);
   15332 	if (kasp == NULL) {
   15333 		msg = "Zone does not have dnssec-policy";
   15334 		goto cleanup;
   15335 	}
   15336 
   15337 	/* Get DNSSEC keys. */
   15338 	CHECK(dns_zone_getdb(zone, &db));
   15339 	dns_db_currentversion(db, &version);
   15340 	LOCK(&kasp->lock);
   15341 	result = dns_zone_getdnsseckeys(zone, db, version, now, &keys);
   15342 	UNLOCK(&kasp->lock);
   15343 	if (result != ISC_R_SUCCESS) {
   15344 		if (result != ISC_R_NOTFOUND) {
   15345 			goto cleanup;
   15346 		}
   15347 	}
   15348 
   15349 	if (status) {
   15350 		/*
   15351 		 * Output the DNSSEC status of the key and signing policy.
   15352 		 */
   15353 		isc_result_t r;
   15354 		LOCK(&kasp->lock);
   15355 		r = dns_keymgr_status(kasp, &keys, now, &output[0],
   15356 				      sizeof(output));
   15357 		UNLOCK(&kasp->lock);
   15358 		CHECK(putstr(text, output));
   15359 		if (r != ISC_R_SUCCESS) {
   15360 			CHECK(putstr(text,
   15361 				     "\n\nStatus output is truncated..."));
   15362 		}
   15363 	} else if (checkds) {
   15364 		/*
   15365 		 * Mark DS record has been seen, so it may move to the
   15366 		 * rumoured state.
   15367 		 */
   15368 		char whenbuf[80];
   15369 		isc_time_set(&timewhen, when, 0);
   15370 		isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
   15371 		isc_result_t ret;
   15372 
   15373 		LOCK(&kasp->lock);
   15374 		if (use_keyid) {
   15375 			result = dns_keymgr_checkds_id(kasp, &keys, now, when,
   15376 						       dspublish, keyid,
   15377 						       (unsigned int)algorithm);
   15378 		} else {
   15379 			result = dns_keymgr_checkds(kasp, &keys, now, when,
   15380 						    dspublish);
   15381 		}
   15382 		UNLOCK(&kasp->lock);
   15383 
   15384 		switch (result) {
   15385 		case ISC_R_SUCCESS:
   15386 			/*
   15387 			 * Rekey after checkds command because the next key
   15388 			 * event may have changed.
   15389 			 */
   15390 			dns_zone_rekey(zone, false, false);
   15391 
   15392 			if (use_keyid) {
   15393 				char tagbuf[6];
   15394 				snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
   15395 				CHECK(putstr(text, "KSK "));
   15396 				CHECK(putstr(text, tagbuf));
   15397 				CHECK(putstr(text, ": "));
   15398 			}
   15399 			CHECK(putstr(text, "Marked DS as "));
   15400 			if (dspublish) {
   15401 				CHECK(putstr(text, "published "));
   15402 			} else {
   15403 				CHECK(putstr(text, "withdrawn "));
   15404 			}
   15405 			CHECK(putstr(text, "since "));
   15406 			CHECK(putstr(text, whenbuf));
   15407 			break;
   15408 		case DNS_R_TOOMANYKEYS:
   15409 			CHECK(putstr(text,
   15410 				     "Error: multiple possible keys found, "
   15411 				     "retry command with -key id"));
   15412 			break;
   15413 		default:
   15414 			ret = result;
   15415 			CHECK(putstr(text,
   15416 				     "Error executing checkds command: "));
   15417 			CHECK(putstr(text, isc_result_totext(ret)));
   15418 			break;
   15419 		}
   15420 	} else if (rollover) {
   15421 		/*
   15422 		 * Manually rollover a key.
   15423 		 */
   15424 		char whenbuf[80];
   15425 		isc_time_set(&timewhen, when, 0);
   15426 		isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
   15427 		isc_result_t ret;
   15428 
   15429 		LOCK(&kasp->lock);
   15430 		result = dns_keymgr_rollover(kasp, &keys, now, when, keyid,
   15431 					     (unsigned int)algorithm);
   15432 		UNLOCK(&kasp->lock);
   15433 
   15434 		switch (result) {
   15435 		case ISC_R_SUCCESS:
   15436 			/*
   15437 			 * Rekey after rollover command because the next key
   15438 			 * event may have changed.
   15439 			 */
   15440 			dns_zone_rekey(zone, false, false);
   15441 
   15442 			if (use_keyid) {
   15443 				char tagbuf[6];
   15444 				snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
   15445 				CHECK(putstr(text, "Key "));
   15446 				CHECK(putstr(text, tagbuf));
   15447 				CHECK(putstr(text, ": "));
   15448 			}
   15449 			CHECK(putstr(text, "Rollover scheduled on "));
   15450 			CHECK(putstr(text, whenbuf));
   15451 			break;
   15452 		case DNS_R_TOOMANYKEYS:
   15453 			CHECK(putstr(text,
   15454 				     "Error: multiple possible keys found, "
   15455 				     "retry command with -alg algorithm"));
   15456 			break;
   15457 		default:
   15458 			ret = result;
   15459 			CHECK(putstr(text,
   15460 				     "Error executing rollover command: "));
   15461 			CHECK(putstr(text, isc_result_totext(ret)));
   15462 			break;
   15463 		}
   15464 	} else if (forcestep) {
   15465 		dns_zone_rekey(zone, false, true);
   15466 	}
   15467 
   15468 	CHECK(putnull(text));
   15469 
   15470 cleanup:
   15471 	if (msg != NULL) {
   15472 		(void)putstr(text, msg);
   15473 		(void)putnull(text);
   15474 	}
   15475 
   15476 	if (version != NULL) {
   15477 		dns_db_closeversion(db, &version, false);
   15478 	}
   15479 	if (db != NULL) {
   15480 		dns_db_detach(&db);
   15481 	}
   15482 
   15483 	while (!ISC_LIST_EMPTY(keys)) {
   15484 		key = ISC_LIST_HEAD(keys);
   15485 		ISC_LIST_UNLINK(keys, key, link);
   15486 		dns_dnsseckey_destroy(dns_zone_getmctx(zone), &key);
   15487 	}
   15488 
   15489 	if (zone != NULL) {
   15490 		dns_zone_detach(&zone);
   15491 	}
   15492 
   15493 	return result;
   15494 }
   15495 
   15496 static isc_result_t
   15497 putmem(isc_buffer_t **b, const char *str, size_t len) {
   15498 	isc_result_t result;
   15499 
   15500 	result = isc_buffer_reserve(*b, (unsigned int)len);
   15501 	if (result != ISC_R_SUCCESS) {
   15502 		return ISC_R_NOSPACE;
   15503 	}
   15504 
   15505 	isc_buffer_putmem(*b, (const unsigned char *)str, (unsigned int)len);
   15506 	return ISC_R_SUCCESS;
   15507 }
   15508 
   15509 static isc_result_t
   15510 putstr(isc_buffer_t **b, const char *str) {
   15511 	return putmem(b, str, strlen(str));
   15512 }
   15513 
   15514 static isc_result_t
   15515 putuint8(isc_buffer_t **b, uint8_t val) {
   15516 	isc_result_t result;
   15517 
   15518 	result = isc_buffer_reserve(*b, 1);
   15519 	if (result != ISC_R_SUCCESS) {
   15520 		return ISC_R_NOSPACE;
   15521 	}
   15522 
   15523 	isc_buffer_putuint8(*b, val);
   15524 	return ISC_R_SUCCESS;
   15525 }
   15526 
   15527 static isc_result_t
   15528 putnull(isc_buffer_t **b) {
   15529 	return putuint8(b, 0);
   15530 }
   15531 
   15532 isc_result_t
   15533 named_server_zonestatus(named_server_t *server, isc_lex_t *lex,
   15534 			isc_buffer_t **text) {
   15535 	isc_result_t result = ISC_R_SUCCESS;
   15536 	dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
   15537 	const char *type, *file;
   15538 	char zonename[DNS_NAME_FORMATSIZE];
   15539 	uint32_t serial, signed_serial, nodes;
   15540 	char serbuf[16], sserbuf[16], nodebuf[16];
   15541 	char resignbuf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 2];
   15542 	char lbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
   15543 	char xbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
   15544 	char rbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
   15545 	char kbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
   15546 	char rtbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
   15547 	isc_time_t loadtime, expiretime, refreshtime;
   15548 	isc_time_t refreshkeytime, resigntime;
   15549 	dns_zonetype_t zonetype;
   15550 	bool dynamic = false, frozen = false;
   15551 	bool hasraw = false;
   15552 	bool secure, maintain, allow;
   15553 	dns_db_t *db = NULL, *rawdb = NULL;
   15554 	char **incfiles = NULL;
   15555 	int nfiles = 0;
   15556 
   15557 	REQUIRE(text != NULL);
   15558 
   15559 	isc_time_settoepoch(&loadtime);
   15560 	isc_time_settoepoch(&refreshtime);
   15561 	isc_time_settoepoch(&expiretime);
   15562 	isc_time_settoepoch(&refreshkeytime);
   15563 	isc_time_settoepoch(&resigntime);
   15564 
   15565 	CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true));
   15566 	if (zone == NULL) {
   15567 		result = ISC_R_UNEXPECTEDEND;
   15568 		goto cleanup;
   15569 	}
   15570 
   15571 	/* Inline signing? */
   15572 	CHECK(dns_zone_getdb(zone, &db));
   15573 	dns_zone_getraw(zone, &raw);
   15574 	hasraw = (raw != NULL);
   15575 	if (hasraw) {
   15576 		mayberaw = raw;
   15577 		zonetype = dns_zone_gettype(raw);
   15578 		CHECK(dns_zone_getdb(raw, &rawdb));
   15579 	} else {
   15580 		mayberaw = zone;
   15581 		zonetype = dns_zone_gettype(zone);
   15582 	}
   15583 
   15584 	type = dns_zonetype_name(zonetype);
   15585 
   15586 	/* Serial number */
   15587 	result = dns_zone_getserial(mayberaw, &serial);
   15588 
   15589 	/* This is to mirror old behavior with dns_zone_getserial */
   15590 	if (result != ISC_R_SUCCESS) {
   15591 		serial = 0;
   15592 	}
   15593 
   15594 	snprintf(serbuf, sizeof(serbuf), "%u", serial);
   15595 	if (hasraw) {
   15596 		result = dns_zone_getserial(zone, &signed_serial);
   15597 		if (result != ISC_R_SUCCESS) {
   15598 			serial = 0;
   15599 		}
   15600 		snprintf(sserbuf, sizeof(sserbuf), "%u", signed_serial);
   15601 	}
   15602 
   15603 	/* Database node count */
   15604 	nodes = dns_db_nodecount(hasraw ? rawdb : db, dns_dbtree_main);
   15605 	snprintf(nodebuf, sizeof(nodebuf), "%u", nodes);
   15606 
   15607 	/* Security */
   15608 	secure = dns_db_issecure(db);
   15609 	allow = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_ALLOW) != 0);
   15610 	maintain = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0);
   15611 
   15612 	/* Master files */
   15613 	file = dns_zone_getfile(mayberaw);
   15614 	nfiles = dns_zone_getincludes(mayberaw, &incfiles);
   15615 
   15616 	/* Load time */
   15617 	dns_zone_getloadtime(zone, &loadtime);
   15618 	isc_time_formathttptimestamp(&loadtime, lbuf, sizeof(lbuf));
   15619 
   15620 	/* Refresh/expire times */
   15621 	if (zonetype == dns_zone_secondary || zonetype == dns_zone_mirror ||
   15622 	    zonetype == dns_zone_stub || zonetype == dns_zone_redirect)
   15623 	{
   15624 		dns_zone_getexpiretime(mayberaw, &expiretime);
   15625 		isc_time_formathttptimestamp(&expiretime, xbuf, sizeof(xbuf));
   15626 		dns_zone_getrefreshtime(mayberaw, &refreshtime);
   15627 		isc_time_formathttptimestamp(&refreshtime, rbuf, sizeof(rbuf));
   15628 	}
   15629 
   15630 	/* Key refresh time */
   15631 	if (zonetype == dns_zone_primary ||
   15632 	    (zonetype == dns_zone_secondary && hasraw))
   15633 	{
   15634 		dns_zone_getrefreshkeytime(zone, &refreshkeytime);
   15635 		isc_time_formathttptimestamp(&refreshkeytime, kbuf,
   15636 					     sizeof(kbuf));
   15637 	}
   15638 
   15639 	/* Dynamic? */
   15640 	if (zonetype == dns_zone_primary) {
   15641 		dynamic = dns_zone_isdynamic(mayberaw, true);
   15642 		frozen = dynamic && !dns_zone_isdynamic(mayberaw, false);
   15643 	}
   15644 
   15645 	/* Next resign event */
   15646 	if (secure && (zonetype == dns_zone_primary ||
   15647 		       (zonetype == dns_zone_secondary && hasraw)))
   15648 	{
   15649 		dns_name_t *name;
   15650 		dns_fixedname_t fixed;
   15651 		isc_stdtime_t resign;
   15652 		dns_typepair_t typepair;
   15653 
   15654 		name = dns_fixedname_initname(&fixed);
   15655 
   15656 		result = dns_db_getsigningtime(db, &resign, name, &typepair);
   15657 		if (result == ISC_R_SUCCESS) {
   15658 			char namebuf[DNS_NAME_FORMATSIZE];
   15659 			char typebuf[DNS_RDATATYPE_FORMATSIZE];
   15660 
   15661 			resign -= dns_zone_getsigresigninginterval(zone);
   15662 
   15663 			dns_name_format(name, namebuf, sizeof(namebuf));
   15664 			dns_rdatatype_format(DNS_TYPEPAIR_COVERS(typepair),
   15665 					     typebuf, sizeof(typebuf));
   15666 			snprintf(resignbuf, sizeof(resignbuf), "%s/%s", namebuf,
   15667 				 typebuf);
   15668 			isc_time_set(&resigntime, resign, 0);
   15669 			isc_time_formathttptimestamp(&resigntime, rtbuf,
   15670 						     sizeof(rtbuf));
   15671 		}
   15672 	}
   15673 
   15674 	/* Create text */
   15675 	CHECK(putstr(text, "name: "));
   15676 	CHECK(putstr(text, zonename));
   15677 
   15678 	CHECK(putstr(text, "\ntype: "));
   15679 	CHECK(putstr(text, type));
   15680 
   15681 	if (file != NULL) {
   15682 		int i;
   15683 		CHECK(putstr(text, "\nfiles: "));
   15684 		CHECK(putstr(text, file));
   15685 		for (i = 0; i < nfiles; i++) {
   15686 			CHECK(putstr(text, ", "));
   15687 			if (incfiles[i] != NULL) {
   15688 				CHECK(putstr(text, incfiles[i]));
   15689 			}
   15690 		}
   15691 	}
   15692 
   15693 	CHECK(putstr(text, "\nserial: "));
   15694 	CHECK(putstr(text, serbuf));
   15695 	if (hasraw) {
   15696 		CHECK(putstr(text, "\nsigned serial: "));
   15697 		CHECK(putstr(text, sserbuf));
   15698 	}
   15699 
   15700 	CHECK(putstr(text, "\nnodes: "));
   15701 	CHECK(putstr(text, nodebuf));
   15702 
   15703 	if (!isc_time_isepoch(&loadtime)) {
   15704 		CHECK(putstr(text, "\nlast loaded: "));
   15705 		CHECK(putstr(text, lbuf));
   15706 	}
   15707 
   15708 	if (!isc_time_isepoch(&refreshtime)) {
   15709 		CHECK(putstr(text, "\nnext refresh: "));
   15710 		CHECK(putstr(text, rbuf));
   15711 	}
   15712 
   15713 	if (!isc_time_isepoch(&expiretime)) {
   15714 		CHECK(putstr(text, "\nexpires: "));
   15715 		CHECK(putstr(text, xbuf));
   15716 	}
   15717 
   15718 	if (secure) {
   15719 		CHECK(putstr(text, "\nsecure: yes"));
   15720 		if (hasraw) {
   15721 			CHECK(putstr(text, "\ninline signing: yes"));
   15722 		} else {
   15723 			CHECK(putstr(text, "\ninline signing: no"));
   15724 		}
   15725 	} else {
   15726 		CHECK(putstr(text, "\nsecure: no"));
   15727 	}
   15728 
   15729 	if (maintain) {
   15730 		CHECK(putstr(text, "\nkey maintenance: automatic"));
   15731 		if (!isc_time_isepoch(&refreshkeytime)) {
   15732 			CHECK(putstr(text, "\nnext key event: "));
   15733 			CHECK(putstr(text, kbuf));
   15734 		}
   15735 	} else if (allow) {
   15736 		CHECK(putstr(text, "\nkey maintenance: on command"));
   15737 	} else if (secure || hasraw) {
   15738 		CHECK(putstr(text, "\nkey maintenance: none"));
   15739 	}
   15740 
   15741 	if (!isc_time_isepoch(&resigntime)) {
   15742 		CHECK(putstr(text, "\nnext resign node: "));
   15743 		CHECK(putstr(text, resignbuf));
   15744 		CHECK(putstr(text, "\nnext resign time: "));
   15745 		CHECK(putstr(text, rtbuf));
   15746 	}
   15747 
   15748 	if (dynamic) {
   15749 		CHECK(putstr(text, "\ndynamic: yes"));
   15750 		if (frozen) {
   15751 			CHECK(putstr(text, "\nfrozen: yes"));
   15752 		} else {
   15753 			CHECK(putstr(text, "\nfrozen: no"));
   15754 		}
   15755 	} else {
   15756 		CHECK(putstr(text, "\ndynamic: no"));
   15757 	}
   15758 
   15759 	CHECK(putstr(text, "\nreconfigurable via modzone: "));
   15760 	CHECK(putstr(text, dns_zone_getadded(zone) ? "yes" : "no"));
   15761 
   15762 cleanup:
   15763 	/* Indicate truncated output if possible. */
   15764 	if (result == ISC_R_NOSPACE) {
   15765 		(void)putstr(text, "\n...");
   15766 	}
   15767 	if (result == ISC_R_SUCCESS || result == ISC_R_NOSPACE) {
   15768 		(void)putnull(text);
   15769 	}
   15770 
   15771 	if (db != NULL) {
   15772 		dns_db_detach(&db);
   15773 	}
   15774 	if (rawdb != NULL) {
   15775 		dns_db_detach(&rawdb);
   15776 	}
   15777 	if (incfiles != NULL && mayberaw != NULL) {
   15778 		int i;
   15779 		isc_mem_t *mctx = dns_zone_getmctx(mayberaw);
   15780 
   15781 		for (i = 0; i < nfiles; i++) {
   15782 			if (incfiles[i] != NULL) {
   15783 				isc_mem_free(mctx, incfiles[i]);
   15784 			}
   15785 		}
   15786 		isc_mem_free(mctx, incfiles);
   15787 	}
   15788 	if (raw != NULL) {
   15789 		dns_zone_detach(&raw);
   15790 	}
   15791 	if (zone != NULL) {
   15792 		dns_zone_detach(&zone);
   15793 	}
   15794 	return result;
   15795 }
   15796 
   15797 isc_result_t
   15798 named_server_nta(named_server_t *server, isc_lex_t *lex, bool readonly,
   15799 		 isc_buffer_t **text) {
   15800 	dns_view_t *view;
   15801 	dns_ntatable_t *ntatable = NULL;
   15802 	isc_result_t result = ISC_R_SUCCESS;
   15803 	char *ptr, *nametext = NULL, *viewname;
   15804 	char namebuf[DNS_NAME_FORMATSIZE];
   15805 	char viewbuf[DNS_NAME_FORMATSIZE];
   15806 	isc_stdtime_t now, when;
   15807 	isc_time_t t;
   15808 	char tbuf[64];
   15809 	const char *msg = NULL;
   15810 	bool dump = false, force = false;
   15811 	dns_fixedname_t fn;
   15812 	const dns_name_t *ntaname;
   15813 	dns_name_t *fname;
   15814 	dns_ttl_t ntattl;
   15815 	bool ttlset = false, viewfound = false;
   15816 	dns_rdataclass_t rdclass = dns_rdataclass_in;
   15817 	bool first = true;
   15818 
   15819 	REQUIRE(text != NULL);
   15820 
   15821 	UNUSED(force);
   15822 
   15823 	fname = dns_fixedname_initname(&fn);
   15824 
   15825 	/* Skip the command name. */
   15826 	ptr = next_token(lex, text);
   15827 	if (ptr == NULL) {
   15828 		return ISC_R_UNEXPECTEDEND;
   15829 	}
   15830 
   15831 	for (;;) {
   15832 		/* Check for options */
   15833 		ptr = next_token(lex, text);
   15834 		if (ptr == NULL) {
   15835 			return ISC_R_UNEXPECTEDEND;
   15836 		}
   15837 
   15838 		if (strcmp(ptr, "--") == 0) {
   15839 			break;
   15840 		} else if (argcheck(ptr, "dump")) {
   15841 			dump = true;
   15842 		} else if (argcheck(ptr, "remove")) {
   15843 			ntattl = 0;
   15844 			ttlset = true;
   15845 		} else if (argcheck(ptr, "force")) {
   15846 			force = true;
   15847 			continue;
   15848 		} else if (argcheck(ptr, "lifetime")) {
   15849 			isc_textregion_t tr;
   15850 
   15851 			ptr = next_token(lex, text);
   15852 			if (ptr == NULL) {
   15853 				msg = "No lifetime specified";
   15854 				CHECK(ISC_R_UNEXPECTEDEND);
   15855 			}
   15856 
   15857 			tr.base = ptr;
   15858 			tr.length = strlen(ptr);
   15859 			result = dns_ttl_fromtext(&tr, &ntattl);
   15860 			if (result != ISC_R_SUCCESS) {
   15861 				msg = "could not parse NTA lifetime";
   15862 				CHECK(result);
   15863 			}
   15864 
   15865 			if (ntattl > 604800) {
   15866 				msg = "NTA lifetime cannot exceed one week";
   15867 				CHECK(ISC_R_RANGE);
   15868 			}
   15869 
   15870 			ttlset = true;
   15871 			continue;
   15872 		} else if (argcheck(ptr, "class")) {
   15873 			isc_textregion_t tr;
   15874 
   15875 			ptr = next_token(lex, text);
   15876 			if (ptr == NULL) {
   15877 				msg = "No class specified";
   15878 				CHECK(ISC_R_UNEXPECTEDEND);
   15879 			}
   15880 
   15881 			tr.base = ptr;
   15882 			tr.length = strlen(ptr);
   15883 			CHECK(dns_rdataclass_fromtext(&rdclass, &tr));
   15884 			continue;
   15885 		} else if (ptr[0] == '-') {
   15886 			msg = "Unknown option";
   15887 			CHECK(DNS_R_SYNTAX);
   15888 		} else {
   15889 			nametext = ptr;
   15890 		}
   15891 
   15892 		break;
   15893 	}
   15894 
   15895 	/*
   15896 	 * If -dump was specified, list NTA's and return
   15897 	 */
   15898 	if (dump) {
   15899 		size_t last = 0;
   15900 
   15901 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   15902 		     view = ISC_LIST_NEXT(view, link))
   15903 		{
   15904 			if (ntatable != NULL) {
   15905 				dns_ntatable_detach(&ntatable);
   15906 			}
   15907 			result = dns_view_getntatable(view, &ntatable);
   15908 			if (result == ISC_R_NOTFOUND) {
   15909 				continue;
   15910 			}
   15911 
   15912 			if (last != isc_buffer_usedlength(*text)) {
   15913 				CHECK(putstr(text, "\n"));
   15914 			}
   15915 
   15916 			last = isc_buffer_usedlength(*text);
   15917 
   15918 			CHECK(dns_ntatable_totext(ntatable, view->name, text));
   15919 		}
   15920 		CHECK(putnull(text));
   15921 
   15922 		goto cleanup;
   15923 	}
   15924 
   15925 	if (readonly) {
   15926 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   15927 			      NAMED_LOGMODULE_CONTROL, ISC_LOG_INFO,
   15928 			      "rejecting restricted control channel "
   15929 			      "NTA command");
   15930 		CHECK(ISC_R_FAILURE);
   15931 	}
   15932 
   15933 	/* Get the NTA name if not found above. */
   15934 	if (nametext == NULL) {
   15935 		nametext = next_token(lex, text);
   15936 	}
   15937 	if (nametext == NULL) {
   15938 		return ISC_R_UNEXPECTEDEND;
   15939 	}
   15940 
   15941 	/* Copy nametext as it'll be overwritten by next_token() */
   15942 	strlcpy(namebuf, nametext, DNS_NAME_FORMATSIZE);
   15943 
   15944 	if (strcmp(namebuf, ".") == 0) {
   15945 		ntaname = dns_rootname;
   15946 	} else {
   15947 		isc_buffer_t b;
   15948 		isc_buffer_init(&b, namebuf, strlen(namebuf));
   15949 		isc_buffer_add(&b, strlen(namebuf));
   15950 		CHECK(dns_name_fromtext(fname, &b, dns_rootname, 0, NULL));
   15951 		ntaname = fname;
   15952 	}
   15953 
   15954 	/* Look for the view name. */
   15955 	viewname = next_token(lex, text);
   15956 	if (viewname != NULL) {
   15957 		strlcpy(viewbuf, viewname, DNS_NAME_FORMATSIZE);
   15958 		viewname = viewbuf;
   15959 	}
   15960 
   15961 	if (next_token(lex, text) != NULL) {
   15962 		CHECK(DNS_R_SYNTAX);
   15963 	}
   15964 
   15965 	now = isc_stdtime_now();
   15966 
   15967 	isc_loopmgr_pause(named_g_loopmgr);
   15968 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   15969 	     view = ISC_LIST_NEXT(view, link))
   15970 	{
   15971 		if (viewname != NULL && strcmp(view->name, viewname) != 0) {
   15972 			continue;
   15973 		}
   15974 		viewfound = true;
   15975 
   15976 		if (view->rdclass != rdclass && rdclass != dns_rdataclass_any) {
   15977 			continue;
   15978 		}
   15979 
   15980 		if (view->nta_lifetime == 0) {
   15981 			continue;
   15982 		}
   15983 
   15984 		if (!ttlset) {
   15985 			ntattl = view->nta_lifetime;
   15986 		}
   15987 
   15988 		if (ntatable != NULL) {
   15989 			dns_ntatable_detach(&ntatable);
   15990 		}
   15991 
   15992 		result = dns_view_getntatable(view, &ntatable);
   15993 		if (result == ISC_R_NOTFOUND) {
   15994 			result = ISC_R_SUCCESS;
   15995 			continue;
   15996 		}
   15997 
   15998 		result = dns_view_flushnode(view, ntaname, true);
   15999 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16000 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   16001 			      "flush tree '%s' in cache view '%s': %s", namebuf,
   16002 			      view->name, isc_result_totext(result));
   16003 
   16004 		if (ntattl != 0) {
   16005 			CHECK(dns_ntatable_add(ntatable, ntaname, force, now,
   16006 					       ntattl));
   16007 
   16008 			when = now + ntattl;
   16009 			isc_time_set(&t, when, 0);
   16010 			isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
   16011 
   16012 			if (!first) {
   16013 				CHECK(putstr(text, "\n"));
   16014 			}
   16015 			first = false;
   16016 
   16017 			CHECK(putstr(text, "Negative trust anchor added: "));
   16018 			CHECK(putstr(text, namebuf));
   16019 			CHECK(putstr(text, "/"));
   16020 			CHECK(putstr(text, view->name));
   16021 			CHECK(putstr(text, ", expires "));
   16022 			CHECK(putstr(text, tbuf));
   16023 
   16024 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16025 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   16026 				      "added NTA '%s' (%d sec) in view '%s'",
   16027 				      namebuf, ntattl, view->name);
   16028 		} else {
   16029 			bool wasremoved;
   16030 
   16031 			result = dns_ntatable_delete(ntatable, ntaname);
   16032 			if (result == ISC_R_SUCCESS) {
   16033 				wasremoved = true;
   16034 			} else if (result == ISC_R_NOTFOUND) {
   16035 				wasremoved = false;
   16036 			} else {
   16037 				goto cleanup_exclusive;
   16038 			}
   16039 
   16040 			if (!first) {
   16041 				CHECK(putstr(text, "\n"));
   16042 			}
   16043 			first = false;
   16044 
   16045 			CHECK(putstr(text, "Negative trust anchor "));
   16046 			CHECK(putstr(text,
   16047 				     wasremoved ? "removed: " : "not found: "));
   16048 			CHECK(putstr(text, namebuf));
   16049 			CHECK(putstr(text, "/"));
   16050 			CHECK(putstr(text, view->name));
   16051 
   16052 			if (wasremoved) {
   16053 				isc_log_write(
   16054 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16055 					NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   16056 					"removed NTA '%s' in view %s", namebuf,
   16057 					view->name);
   16058 			}
   16059 		}
   16060 
   16061 		result = dns_view_saventa(view);
   16062 		if (result != ISC_R_SUCCESS) {
   16063 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16064 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   16065 				      "error writing NTA file "
   16066 				      "for view '%s': %s",
   16067 				      view->name, isc_result_totext(result));
   16068 		}
   16069 	}
   16070 
   16071 	if (!viewfound) {
   16072 		msg = "No such view";
   16073 		result = ISC_R_NOTFOUND;
   16074 	} else {
   16075 		(void)putnull(text);
   16076 	}
   16077 
   16078 cleanup_exclusive:
   16079 	isc_loopmgr_resume(named_g_loopmgr);
   16080 
   16081 cleanup:
   16082 
   16083 	if (msg != NULL) {
   16084 		(void)putstr(text, msg);
   16085 		(void)putnull(text);
   16086 	}
   16087 
   16088 	if (ntatable != NULL) {
   16089 		dns_ntatable_detach(&ntatable);
   16090 	}
   16091 	return result;
   16092 }
   16093 
   16094 isc_result_t
   16095 named_server_saventa(named_server_t *server) {
   16096 	dns_view_t *view;
   16097 
   16098 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   16099 	     view = ISC_LIST_NEXT(view, link))
   16100 	{
   16101 		isc_result_t result = dns_view_saventa(view);
   16102 
   16103 		if (result != ISC_R_SUCCESS) {
   16104 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16105 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   16106 				      "error writing NTA file "
   16107 				      "for view '%s': %s",
   16108 				      view->name, isc_result_totext(result));
   16109 		}
   16110 	}
   16111 
   16112 	return ISC_R_SUCCESS;
   16113 }
   16114 
   16115 isc_result_t
   16116 named_server_loadnta(named_server_t *server) {
   16117 	dns_view_t *view;
   16118 
   16119 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   16120 	     view = ISC_LIST_NEXT(view, link))
   16121 	{
   16122 		isc_result_t result = dns_view_loadnta(view);
   16123 
   16124 		if ((result != ISC_R_SUCCESS) &&
   16125 		    (result != ISC_R_FILENOTFOUND) &&
   16126 		    (result != ISC_R_NOTFOUND))
   16127 		{
   16128 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16129 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   16130 				      "error loading NTA file "
   16131 				      "for view '%s': %s",
   16132 				      view->name, isc_result_totext(result));
   16133 		}
   16134 	}
   16135 
   16136 	return ISC_R_SUCCESS;
   16137 }
   16138 
   16139 static isc_result_t
   16140 mkey_refresh(dns_view_t *view, isc_buffer_t **text) {
   16141 	isc_result_t result;
   16142 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
   16143 
   16144 	snprintf(msg, sizeof(msg), "refreshing managed keys for '%s'",
   16145 		 view->name);
   16146 	CHECK(putstr(text, msg));
   16147 	CHECK(dns_zone_synckeyzone(view->managed_keys));
   16148 
   16149 cleanup:
   16150 	return result;
   16151 }
   16152 
   16153 static isc_result_t
   16154 mkey_destroy(dns_view_t *view, isc_buffer_t **text) {
   16155 	isc_result_t result;
   16156 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
   16157 	const char *file = NULL;
   16158 	dns_db_t *dbp = NULL;
   16159 	dns_zone_t *mkzone = NULL;
   16160 	bool removed_a_file = false;
   16161 
   16162 	if (view->managed_keys == NULL) {
   16163 		CHECK(ISC_R_NOTFOUND);
   16164 	}
   16165 
   16166 	snprintf(msg, sizeof(msg), "destroying managed-keys database for '%s'",
   16167 		 view->name);
   16168 	CHECK(putstr(text, msg));
   16169 
   16170 	isc_loopmgr_pause(named_g_loopmgr);
   16171 
   16172 	/* Remove and clean up managed keys zone from view */
   16173 	mkzone = view->managed_keys;
   16174 	view->managed_keys = NULL;
   16175 	(void)dns_zone_flush(mkzone);
   16176 
   16177 	/* Unload zone database */
   16178 	if (dns_zone_getdb(mkzone, &dbp) == ISC_R_SUCCESS) {
   16179 		dns_db_detach(&dbp);
   16180 		dns_zone_unload(mkzone);
   16181 	}
   16182 
   16183 	/* Delete files */
   16184 	file = dns_zone_getfile(mkzone);
   16185 	result = isc_file_remove(file);
   16186 	if (result == ISC_R_SUCCESS) {
   16187 		removed_a_file = true;
   16188 	} else {
   16189 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16190 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   16191 			      "file %s not removed: %s", file,
   16192 			      isc_result_totext(result));
   16193 	}
   16194 
   16195 	file = dns_zone_getjournal(mkzone);
   16196 	result = isc_file_remove(file);
   16197 	if (result == ISC_R_SUCCESS) {
   16198 		removed_a_file = true;
   16199 	} else {
   16200 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16201 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   16202 			      "file %s not removed: %s", file,
   16203 			      isc_result_totext(result));
   16204 	}
   16205 
   16206 	if (!removed_a_file) {
   16207 		CHECK(putstr(text, "error: no files could be removed"));
   16208 		CHECK(ISC_R_FAILURE);
   16209 	}
   16210 
   16211 	dns_zone_detach(&mkzone);
   16212 	result = ISC_R_SUCCESS;
   16213 
   16214 cleanup:
   16215 	isc_loopmgr_resume(named_g_loopmgr);
   16216 	return result;
   16217 }
   16218 
   16219 static isc_result_t
   16220 mkey_dumpzone(dns_view_t *view, isc_buffer_t **text) {
   16221 	isc_result_t result;
   16222 	dns_db_t *db = NULL;
   16223 	dns_dbversion_t *ver = NULL;
   16224 	dns_rriterator_t rrit;
   16225 	isc_stdtime_t now = isc_stdtime_now();
   16226 	dns_name_t *prevname = NULL;
   16227 
   16228 	CHECK(dns_zone_getdb(view->managed_keys, &db));
   16229 	dns_db_currentversion(db, &ver);
   16230 	dns_rriterator_init(&rrit, db, ver, 0);
   16231 	for (result = dns_rriterator_first(&rrit); result == ISC_R_SUCCESS;
   16232 	     result = dns_rriterator_nextrrset(&rrit))
   16233 	{
   16234 		char buf[DNS_NAME_FORMATSIZE + 500];
   16235 		dns_name_t *name = NULL;
   16236 		dns_rdataset_t *kdset = NULL;
   16237 		dns_rdata_t rdata = DNS_RDATA_INIT;
   16238 		dns_rdata_keydata_t kd;
   16239 		uint32_t ttl;
   16240 
   16241 		dns_rriterator_current(&rrit, &name, &ttl, &kdset, NULL);
   16242 		if (kdset == NULL || kdset->type != dns_rdatatype_keydata ||
   16243 		    !dns_rdataset_isassociated(kdset))
   16244 		{
   16245 			continue;
   16246 		}
   16247 
   16248 		if (name != prevname) {
   16249 			char nbuf[DNS_NAME_FORMATSIZE];
   16250 			dns_name_format(name, nbuf, sizeof(nbuf));
   16251 			snprintf(buf, sizeof(buf), "\n\n    name: %s", nbuf);
   16252 			CHECK(putstr(text, buf));
   16253 		}
   16254 
   16255 		for (result = dns_rdataset_first(kdset);
   16256 		     result == ISC_R_SUCCESS; result = dns_rdataset_next(kdset))
   16257 		{
   16258 			char alg[DNS_SECALG_FORMATSIZE];
   16259 			char tbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
   16260 			dns_keytag_t keyid;
   16261 			isc_region_t r;
   16262 			isc_time_t t;
   16263 			bool revoked;
   16264 
   16265 			dns_rdata_reset(&rdata);
   16266 			dns_rdataset_current(kdset, &rdata);
   16267 			result = dns_rdata_tostruct(&rdata, &kd, NULL);
   16268 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   16269 
   16270 			dns_rdata_toregion(&rdata, &r);
   16271 			isc_region_consume(&r, 12);
   16272 			keyid = dst_region_computeid(&r);
   16273 
   16274 			snprintf(buf, sizeof(buf), "\n    keyid: %u", keyid);
   16275 			CHECK(putstr(text, buf));
   16276 
   16277 			dns_secalg_format(kd.algorithm, alg, sizeof(alg));
   16278 			snprintf(buf, sizeof(buf), "\n\talgorithm: %s", alg);
   16279 			CHECK(putstr(text, buf));
   16280 
   16281 			revoked = ((kd.flags & DNS_KEYFLAG_REVOKE) != 0);
   16282 			snprintf(buf, sizeof(buf), "\n\tflags:%s%s%s",
   16283 				 revoked ? " REVOKE" : "",
   16284 				 ((kd.flags & DNS_KEYFLAG_KSK) != 0) ? " SEP"
   16285 								     : "",
   16286 				 (kd.flags == 0) ? " (none)" : "");
   16287 			CHECK(putstr(text, buf));
   16288 
   16289 			isc_time_set(&t, kd.refresh, 0);
   16290 			isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
   16291 			snprintf(buf, sizeof(buf), "\n\tnext refresh: %s",
   16292 				 tbuf);
   16293 			CHECK(putstr(text, buf));
   16294 
   16295 			if (kd.removehd != 0) {
   16296 				isc_time_set(&t, kd.removehd, 0);
   16297 				isc_time_formathttptimestamp(&t, tbuf,
   16298 							     sizeof(tbuf));
   16299 				snprintf(buf, sizeof(buf), "\n\tremove at: %s",
   16300 					 tbuf);
   16301 				CHECK(putstr(text, buf));
   16302 			}
   16303 
   16304 			isc_time_set(&t, kd.addhd, 0);
   16305 			isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
   16306 			if (kd.addhd == 0) {
   16307 				snprintf(buf, sizeof(buf), "\n\tno trust");
   16308 			} else if (revoked) {
   16309 				snprintf(buf, sizeof(buf), "\n\ttrust revoked");
   16310 			} else if (kd.addhd <= now) {
   16311 				snprintf(buf, sizeof(buf),
   16312 					 "\n\ttrusted since: %s", tbuf);
   16313 			} else if (kd.addhd > now) {
   16314 				snprintf(buf, sizeof(buf),
   16315 					 "\n\ttrust pending: %s", tbuf);
   16316 			}
   16317 			CHECK(putstr(text, buf));
   16318 		}
   16319 	}
   16320 
   16321 	if (result == ISC_R_NOMORE) {
   16322 		result = ISC_R_SUCCESS;
   16323 	}
   16324 
   16325 cleanup:
   16326 	if (ver != NULL) {
   16327 		dns_rriterator_destroy(&rrit);
   16328 		dns_db_closeversion(db, &ver, false);
   16329 	}
   16330 	if (db != NULL) {
   16331 		dns_db_detach(&db);
   16332 	}
   16333 
   16334 	return result;
   16335 }
   16336 
   16337 static isc_result_t
   16338 mkey_status(dns_view_t *view, isc_buffer_t **text) {
   16339 	isc_result_t result;
   16340 	char msg[ISC_FORMATHTTPTIMESTAMP_SIZE];
   16341 	isc_time_t t;
   16342 
   16343 	CHECK(putstr(text, "view: "));
   16344 	CHECK(putstr(text, view->name));
   16345 
   16346 	CHECK(putstr(text, "\nnext scheduled event: "));
   16347 
   16348 	dns_zone_getrefreshkeytime(view->managed_keys, &t);
   16349 	if (isc_time_isepoch(&t)) {
   16350 		CHECK(putstr(text, "never"));
   16351 	} else {
   16352 		isc_time_formathttptimestamp(&t, msg, sizeof(msg));
   16353 		CHECK(putstr(text, msg));
   16354 	}
   16355 
   16356 	CHECK(mkey_dumpzone(view, text));
   16357 
   16358 cleanup:
   16359 	return result;
   16360 }
   16361 
   16362 isc_result_t
   16363 named_server_mkeys(named_server_t *server, isc_lex_t *lex,
   16364 		   isc_buffer_t **text) {
   16365 	char *cmd, *classtxt, *viewtxt = NULL;
   16366 	isc_result_t result = ISC_R_SUCCESS;
   16367 	dns_view_t *view = NULL;
   16368 	dns_rdataclass_t rdclass;
   16369 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
   16370 	enum { NONE, STAT, REFRESH, SYNC, DESTROY } opt = NONE;
   16371 	bool found = false;
   16372 	bool first = true;
   16373 
   16374 	REQUIRE(text != NULL);
   16375 
   16376 	/* Skip rndc command name */
   16377 	cmd = next_token(lex, text);
   16378 	if (cmd == NULL) {
   16379 		return ISC_R_UNEXPECTEDEND;
   16380 	}
   16381 
   16382 	/* Get managed-keys subcommand */
   16383 	cmd = next_token(lex, text);
   16384 	if (cmd == NULL) {
   16385 		return ISC_R_UNEXPECTEDEND;
   16386 	}
   16387 
   16388 	if (strcasecmp(cmd, "status") == 0) {
   16389 		opt = STAT;
   16390 	} else if (strcasecmp(cmd, "refresh") == 0) {
   16391 		opt = REFRESH;
   16392 	} else if (strcasecmp(cmd, "sync") == 0) {
   16393 		opt = SYNC;
   16394 	} else if (strcasecmp(cmd, "destroy") == 0) {
   16395 		opt = DESTROY;
   16396 	} else {
   16397 		snprintf(msg, sizeof(msg), "unknown command '%s'", cmd);
   16398 		(void)putstr(text, msg);
   16399 		result = ISC_R_UNEXPECTED;
   16400 		goto cleanup;
   16401 	}
   16402 
   16403 	/* Look for the optional class name. */
   16404 	classtxt = next_token(lex, text);
   16405 	if (classtxt != NULL) {
   16406 		isc_textregion_t r;
   16407 		r.base = classtxt;
   16408 		r.length = strlen(classtxt);
   16409 		result = dns_rdataclass_fromtext(&rdclass, &r);
   16410 		if (result != ISC_R_SUCCESS) {
   16411 			snprintf(msg, sizeof(msg), "unknown class '%s'",
   16412 				 classtxt);
   16413 			(void)putstr(text, msg);
   16414 			goto cleanup;
   16415 		}
   16416 		viewtxt = next_token(lex, text);
   16417 	}
   16418 
   16419 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   16420 	     view = ISC_LIST_NEXT(view, link))
   16421 	{
   16422 		if (viewtxt != NULL && (rdclass != view->rdclass ||
   16423 					strcmp(view->name, viewtxt) != 0))
   16424 		{
   16425 			continue;
   16426 		}
   16427 
   16428 		if (view->managed_keys == NULL) {
   16429 			if (viewtxt != NULL) {
   16430 				snprintf(msg, sizeof(msg),
   16431 					 "view '%s': no managed keys", viewtxt);
   16432 				CHECK(putstr(text, msg));
   16433 				goto cleanup;
   16434 			} else {
   16435 				continue;
   16436 			}
   16437 		}
   16438 
   16439 		found = true;
   16440 
   16441 		switch (opt) {
   16442 		case REFRESH:
   16443 			if (!first) {
   16444 				CHECK(putstr(text, "\n"));
   16445 			}
   16446 			CHECK(mkey_refresh(view, text));
   16447 			break;
   16448 		case STAT:
   16449 			if (!first) {
   16450 				CHECK(putstr(text, "\n\n"));
   16451 			}
   16452 			CHECK(mkey_status(view, text));
   16453 			break;
   16454 		case SYNC:
   16455 			CHECK(dns_zone_flush(view->managed_keys));
   16456 			break;
   16457 		case DESTROY:
   16458 			if (!first) {
   16459 				CHECK(putstr(text, "\n"));
   16460 			}
   16461 			CHECK(mkey_destroy(view, text));
   16462 			break;
   16463 		default:
   16464 			UNREACHABLE();
   16465 		}
   16466 
   16467 		if (viewtxt != NULL) {
   16468 			break;
   16469 		}
   16470 		first = false;
   16471 	}
   16472 
   16473 	if (!found) {
   16474 		CHECK(putstr(text, "no views with managed keys"));
   16475 	}
   16476 
   16477 cleanup:
   16478 	if (isc_buffer_usedlength(*text) > 0) {
   16479 		(void)putnull(text);
   16480 	}
   16481 
   16482 	return result;
   16483 }
   16484 
   16485 isc_result_t
   16486 named_server_dnstap(named_server_t *server, isc_lex_t *lex,
   16487 		    isc_buffer_t **text) {
   16488 #ifdef HAVE_DNSTAP
   16489 	char *ptr;
   16490 	isc_result_t result;
   16491 	bool reopen = false;
   16492 	int backups = 0;
   16493 
   16494 	REQUIRE(text != NULL);
   16495 
   16496 	if (server->dtenv == NULL) {
   16497 		return ISC_R_NOTFOUND;
   16498 	}
   16499 
   16500 	/* Check the command name. */
   16501 	ptr = next_token(lex, text);
   16502 	if (ptr == NULL) {
   16503 		return ISC_R_UNEXPECTEDEND;
   16504 	}
   16505 
   16506 	/* "dnstap-reopen" was used in 9.11.0b1 */
   16507 	if (strcasecmp(ptr, "dnstap-reopen") == 0) {
   16508 		reopen = true;
   16509 	} else {
   16510 		ptr = next_token(lex, text);
   16511 		if (ptr == NULL) {
   16512 			return ISC_R_UNEXPECTEDEND;
   16513 		}
   16514 	}
   16515 
   16516 	if (reopen || strcasecmp(ptr, "-reopen") == 0) {
   16517 		backups = ISC_LOG_ROLLNEVER;
   16518 	} else if (strcasecmp(ptr, "-roll") == 0) {
   16519 		unsigned int n;
   16520 		ptr = next_token(lex, text);
   16521 		if (ptr != NULL) {
   16522 			unsigned int u;
   16523 			n = sscanf(ptr, "%u", &u);
   16524 			if (n != 1U || u > INT_MAX) {
   16525 				return ISC_R_BADNUMBER;
   16526 			}
   16527 			backups = u;
   16528 		} else {
   16529 			backups = ISC_LOG_ROLLINFINITE;
   16530 		}
   16531 	} else {
   16532 		return DNS_R_SYNTAX;
   16533 	}
   16534 
   16535 	result = dns_dt_reopen(server->dtenv, backups);
   16536 	return result;
   16537 #else  /* ifdef HAVE_DNSTAP */
   16538 	UNUSED(server);
   16539 	UNUSED(lex);
   16540 	UNUSED(text);
   16541 	return ISC_R_NOTIMPLEMENTED;
   16542 #endif /* ifdef HAVE_DNSTAP */
   16543 }
   16544 
   16545 isc_result_t
   16546 named_server_tcptimeouts(isc_lex_t *lex, isc_buffer_t **text) {
   16547 	char *ptr;
   16548 	isc_result_t result = ISC_R_SUCCESS;
   16549 	uint32_t initial, idle, keepalive, advertised;
   16550 	char msg[128];
   16551 
   16552 	/* Skip the command name. */
   16553 	ptr = next_token(lex, text);
   16554 	if (ptr == NULL) {
   16555 		return ISC_R_UNEXPECTEDEND;
   16556 	}
   16557 
   16558 	isc_nm_gettimeouts(named_g_netmgr, &initial, &idle, &keepalive,
   16559 			   &advertised);
   16560 
   16561 	/* Look for optional arguments. */
   16562 	ptr = next_token(lex, NULL);
   16563 	if (ptr != NULL) {
   16564 		CHECK(isc_parse_uint32(&initial, ptr, 10));
   16565 		initial *= 100;
   16566 		if (initial > MAX_INITIAL_TIMEOUT) {
   16567 			CHECK(ISC_R_RANGE);
   16568 		}
   16569 		if (initial < MIN_INITIAL_TIMEOUT) {
   16570 			CHECK(ISC_R_RANGE);
   16571 		}
   16572 
   16573 		ptr = next_token(lex, text);
   16574 		if (ptr == NULL) {
   16575 			return ISC_R_UNEXPECTEDEND;
   16576 		}
   16577 		CHECK(isc_parse_uint32(&idle, ptr, 10));
   16578 		idle *= 100;
   16579 		if (idle > MAX_IDLE_TIMEOUT) {
   16580 			CHECK(ISC_R_RANGE);
   16581 		}
   16582 		if (idle < MIN_IDLE_TIMEOUT) {
   16583 			CHECK(ISC_R_RANGE);
   16584 		}
   16585 
   16586 		ptr = next_token(lex, text);
   16587 		if (ptr == NULL) {
   16588 			return ISC_R_UNEXPECTEDEND;
   16589 		}
   16590 		CHECK(isc_parse_uint32(&keepalive, ptr, 10));
   16591 		keepalive *= 100;
   16592 		if (keepalive > MAX_KEEPALIVE_TIMEOUT) {
   16593 			CHECK(ISC_R_RANGE);
   16594 		}
   16595 		if (keepalive < MIN_KEEPALIVE_TIMEOUT) {
   16596 			CHECK(ISC_R_RANGE);
   16597 		}
   16598 
   16599 		ptr = next_token(lex, text);
   16600 		if (ptr == NULL) {
   16601 			return ISC_R_UNEXPECTEDEND;
   16602 		}
   16603 		CHECK(isc_parse_uint32(&advertised, ptr, 10));
   16604 		advertised *= 100;
   16605 		if (advertised > MAX_ADVERTISED_TIMEOUT) {
   16606 			CHECK(ISC_R_RANGE);
   16607 		}
   16608 
   16609 		isc_nm_settimeouts(named_g_netmgr, initial, idle, keepalive,
   16610 				   advertised);
   16611 	}
   16612 
   16613 	snprintf(msg, sizeof(msg), "tcp-initial-timeout=%u\n", initial / 100);
   16614 	CHECK(putstr(text, msg));
   16615 	snprintf(msg, sizeof(msg), "tcp-idle-timeout=%u\n", idle / 100);
   16616 	CHECK(putstr(text, msg));
   16617 	snprintf(msg, sizeof(msg), "tcp-keepalive-timeout=%u\n",
   16618 		 keepalive / 100);
   16619 	CHECK(putstr(text, msg));
   16620 	snprintf(msg, sizeof(msg), "tcp-advertised-timeout=%u",
   16621 		 advertised / 100);
   16622 	CHECK(putstr(text, msg));
   16623 
   16624 cleanup:
   16625 	if (isc_buffer_usedlength(*text) > 0) {
   16626 		(void)putnull(text);
   16627 	}
   16628 
   16629 	return result;
   16630 }
   16631 
   16632 isc_result_t
   16633 named_server_servestale(named_server_t *server, isc_lex_t *lex,
   16634 			isc_buffer_t **text) {
   16635 	char *ptr, *classtxt, *viewtxt = NULL;
   16636 	char msg[128];
   16637 	dns_rdataclass_t rdclass = dns_rdataclass_in;
   16638 	dns_view_t *view;
   16639 	bool found = false;
   16640 	dns_stale_answer_t staleanswersok = dns_stale_answer_conf;
   16641 	bool wantstatus = false;
   16642 	isc_result_t result = ISC_R_SUCCESS;
   16643 
   16644 	REQUIRE(text != NULL);
   16645 
   16646 	/* Skip the command name. */
   16647 	ptr = next_token(lex, text);
   16648 	if (ptr == NULL) {
   16649 		return ISC_R_UNEXPECTEDEND;
   16650 	}
   16651 
   16652 	ptr = next_token(lex, NULL);
   16653 	if (ptr == NULL) {
   16654 		return ISC_R_UNEXPECTEDEND;
   16655 	}
   16656 
   16657 	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
   16658 	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
   16659 	{
   16660 		staleanswersok = dns_stale_answer_yes;
   16661 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
   16662 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
   16663 	{
   16664 		staleanswersok = dns_stale_answer_no;
   16665 	} else if (strcasecmp(ptr, "reset") == 0) {
   16666 		staleanswersok = dns_stale_answer_conf;
   16667 	} else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
   16668 		wantstatus = true;
   16669 	} else {
   16670 		return DNS_R_SYNTAX;
   16671 	}
   16672 
   16673 	/* Look for the optional class name. */
   16674 	classtxt = next_token(lex, text);
   16675 	if (classtxt != NULL) {
   16676 		isc_textregion_t r;
   16677 
   16678 		/* Look for the optional view name. */
   16679 		viewtxt = next_token(lex, text);
   16680 
   16681 		/*
   16682 		 * If 'classtext' is not a valid class then it us a view name.
   16683 		 */
   16684 		r.base = classtxt;
   16685 		r.length = strlen(classtxt);
   16686 		result = dns_rdataclass_fromtext(&rdclass, &r);
   16687 		if (result != ISC_R_SUCCESS) {
   16688 			if (viewtxt != NULL) {
   16689 				snprintf(msg, sizeof(msg), "unknown class '%s'",
   16690 					 classtxt);
   16691 				(void)putstr(text, msg);
   16692 				goto cleanup;
   16693 			}
   16694 
   16695 			viewtxt = classtxt;
   16696 			classtxt = NULL;
   16697 		}
   16698 	}
   16699 
   16700 	isc_loopmgr_pause(named_g_loopmgr);
   16701 
   16702 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   16703 	     view = ISC_LIST_NEXT(view, link))
   16704 	{
   16705 		dns_ttl_t stale_ttl = 0;
   16706 		uint32_t stale_refresh = 0;
   16707 		dns_db_t *db = NULL;
   16708 
   16709 		if (classtxt != NULL && rdclass != view->rdclass) {
   16710 			continue;
   16711 		}
   16712 
   16713 		if (viewtxt != NULL && strcmp(view->name, viewtxt) != 0) {
   16714 			continue;
   16715 		}
   16716 
   16717 		if (!wantstatus) {
   16718 			view->staleanswersok = staleanswersok;
   16719 			found = true;
   16720 			continue;
   16721 		}
   16722 
   16723 		db = NULL;
   16724 		dns_db_attach(view->cachedb, &db);
   16725 		(void)dns_db_getservestalettl(db, &stale_ttl);
   16726 		(void)dns_db_getservestalerefresh(db, &stale_refresh);
   16727 		dns_db_detach(&db);
   16728 		if (found) {
   16729 			CHECK(putstr(text, "\n"));
   16730 		}
   16731 		CHECK(putstr(text, view->name));
   16732 		CHECK(putstr(text, ": "));
   16733 		switch (view->staleanswersok) {
   16734 		case dns_stale_answer_yes:
   16735 			if (stale_ttl > 0) {
   16736 				CHECK(putstr(text, "stale cache "
   16737 						   "enabled; stale "
   16738 						   "answers enabled"));
   16739 			} else {
   16740 				CHECK(putstr(text, "stale cache disabled; "
   16741 						   "stale "
   16742 						   "answers unavailable"));
   16743 			}
   16744 			break;
   16745 		case dns_stale_answer_no:
   16746 			if (stale_ttl > 0) {
   16747 				CHECK(putstr(text, "stale cache "
   16748 						   "enabled; stale "
   16749 						   "answers disabled"));
   16750 			} else {
   16751 				CHECK(putstr(text, "stale cache disabled; "
   16752 						   "stale "
   16753 						   "answers unavailable"));
   16754 			}
   16755 			break;
   16756 		case dns_stale_answer_conf:
   16757 			if (view->staleanswersenable && stale_ttl > 0) {
   16758 				CHECK(putstr(text, "stale cache "
   16759 						   "enabled; stale "
   16760 						   "answers enabled"));
   16761 			} else if (stale_ttl > 0) {
   16762 				CHECK(putstr(text, "stale cache "
   16763 						   "enabled; stale "
   16764 						   "answers disabled"));
   16765 			} else {
   16766 				CHECK(putstr(text, "stale cache disabled; "
   16767 						   "stale "
   16768 						   "answers unavailable"));
   16769 			}
   16770 			break;
   16771 		}
   16772 		if (stale_ttl > 0) {
   16773 			snprintf(msg, sizeof(msg),
   16774 				 " (stale-answer-ttl=%u "
   16775 				 "max-stale-ttl=%u "
   16776 				 "stale-refresh-time=%u)",
   16777 				 view->staleanswerttl, stale_ttl,
   16778 				 stale_refresh);
   16779 			CHECK(putstr(text, msg));
   16780 		}
   16781 		found = true;
   16782 	}
   16783 
   16784 	if (!found) {
   16785 		result = ISC_R_NOTFOUND;
   16786 	}
   16787 
   16788 cleanup:
   16789 	isc_loopmgr_resume(named_g_loopmgr);
   16790 
   16791 	if (isc_buffer_usedlength(*text) > 0) {
   16792 		(void)putnull(text);
   16793 	}
   16794 
   16795 	return result;
   16796 }
   16797 
   16798 isc_result_t
   16799 named_server_fetchlimit(named_server_t *server, isc_lex_t *lex,
   16800 			isc_buffer_t **text) {
   16801 	isc_result_t result = ISC_R_SUCCESS;
   16802 	dns_view_t *view = NULL;
   16803 	char *ptr = NULL, *viewname = NULL;
   16804 	bool first = true;
   16805 	dns_adb_t *adb = NULL;
   16806 
   16807 	REQUIRE(text != NULL);
   16808 
   16809 	/* Skip the command name. */
   16810 	ptr = next_token(lex, text);
   16811 	if (ptr == NULL) {
   16812 		return ISC_R_UNEXPECTEDEND;
   16813 	}
   16814 
   16815 	/* Look for the view name. */
   16816 	viewname = next_token(lex, text);
   16817 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   16818 	     view = ISC_LIST_NEXT(view, link))
   16819 	{
   16820 		char tbuf[100];
   16821 		unsigned int used;
   16822 		uint32_t val;
   16823 		int s;
   16824 
   16825 		if (view->rdclass != dns_rdataclass_in) {
   16826 			continue;
   16827 		}
   16828 
   16829 		if (viewname != NULL && strcasecmp(view->name, viewname) != 0) {
   16830 			continue;
   16831 		}
   16832 
   16833 		dns_view_getadb(view, &adb);
   16834 		if (adb == NULL) {
   16835 			continue;
   16836 		}
   16837 
   16838 		if (!first) {
   16839 			CHECK(putstr(text, "\n"));
   16840 		}
   16841 		CHECK(putstr(text, "Rate limited servers, view "));
   16842 		CHECK(putstr(text, view->name));
   16843 
   16844 		dns_adb_getquota(adb, &val, NULL, NULL, NULL, NULL);
   16845 		s = snprintf(tbuf, sizeof(tbuf),
   16846 			     " (fetches-per-server %u):", val);
   16847 		if (s < 0 || (unsigned int)s > sizeof(tbuf)) {
   16848 			CHECK(ISC_R_NOSPACE);
   16849 		}
   16850 		first = false;
   16851 		CHECK(putstr(text, tbuf));
   16852 		used = isc_buffer_usedlength(*text);
   16853 		CHECK(dns_adb_dumpquota(adb, text));
   16854 		if (used == isc_buffer_usedlength(*text)) {
   16855 			CHECK(putstr(text, "\n  None."));
   16856 		}
   16857 
   16858 		CHECK(putstr(text, "\nRate limited servers, view "));
   16859 		CHECK(putstr(text, view->name));
   16860 		val = dns_resolver_getfetchesperzone(view->resolver);
   16861 		s = snprintf(tbuf, sizeof(tbuf),
   16862 			     " (fetches-per-zone %u):", val);
   16863 		if (s < 0 || (unsigned int)s > sizeof(tbuf)) {
   16864 			CHECK(ISC_R_NOSPACE);
   16865 		}
   16866 		CHECK(putstr(text, tbuf));
   16867 		used = isc_buffer_usedlength(*text);
   16868 		CHECK(dns_resolver_dumpquota(view->resolver, text));
   16869 		if (used == isc_buffer_usedlength(*text)) {
   16870 			CHECK(putstr(text, "\n  None."));
   16871 		}
   16872 		dns_adb_detach(&adb);
   16873 	}
   16874 cleanup:
   16875 	if (adb != NULL) {
   16876 		dns_adb_detach(&adb);
   16877 	}
   16878 	if (isc_buffer_usedlength(*text) > 0) {
   16879 		(void)putnull(text);
   16880 	}
   16881 
   16882 	return result;
   16883 }
   16884 
   16885 isc_result_t
   16886 named_server_skr(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
   16887 	isc_result_t result = ISC_R_SUCCESS;
   16888 	dns_zone_t *zone = NULL;
   16889 	dns_kasp_t *kasp = NULL;
   16890 	const char *ptr;
   16891 	char skrfile[PATH_MAX];
   16892 
   16893 	/* Skip the command name. */
   16894 	ptr = next_token(lex, text);
   16895 	if (ptr == NULL) {
   16896 		return ISC_R_UNEXPECTEDEND;
   16897 	}
   16898 
   16899 	/* Find out what we are to do. */
   16900 	ptr = next_token(lex, text);
   16901 	if (ptr == NULL) {
   16902 		return ISC_R_UNEXPECTEDEND;
   16903 	}
   16904 
   16905 	if (strcasecmp(ptr, "-import") != 0) {
   16906 		CHECK(DNS_R_SYNTAX);
   16907 	}
   16908 
   16909 	ptr = next_token(lex, NULL);
   16910 	if (ptr == NULL) {
   16911 		return ISC_R_UNEXPECTEDEND;
   16912 	}
   16913 	(void)snprintf(skrfile, sizeof(skrfile), "%s", ptr);
   16914 
   16915 	CHECK(zone_from_args(server, lex, NULL, &zone, NULL, text, false));
   16916 	if (zone == NULL) {
   16917 		CHECK(ISC_R_UNEXPECTEDEND);
   16918 	}
   16919 	kasp = dns_zone_getkasp(zone);
   16920 	if (kasp == NULL) {
   16921 		CHECK(putstr(text, "zone does not have a dnssec-policy"));
   16922 		CHECK(putnull(text));
   16923 		goto cleanup;
   16924 	}
   16925 
   16926 	if (!dns_kasp_offlineksk(kasp)) {
   16927 		CHECK(putstr(text, "zone does not have offline-ksk enabled"));
   16928 		CHECK(putnull(text));
   16929 		goto cleanup;
   16930 	}
   16931 
   16932 	result = dns_zone_import_skr(zone, skrfile);
   16933 	if (result != ISC_R_SUCCESS) {
   16934 		CHECK(putstr(text, "import failed: "));
   16935 		CHECK(putstr(text, isc_result_totext(result)));
   16936 		CHECK(putnull(text));
   16937 	} else {
   16938 		/* Schedule a rekey */
   16939 		dns_zone_rekey(zone, false, false);
   16940 	}
   16941 
   16942 cleanup:
   16943 	if (zone != NULL) {
   16944 		dns_zone_detach(&zone);
   16945 	}
   16946 
   16947 	return result;
   16948 }
   16949 
   16950 isc_result_t
   16951 named_server_togglememprof(isc_lex_t *lex) {
   16952 	isc_result_t result = ISC_R_FAILURE;
   16953 	bool active;
   16954 	char *ptr;
   16955 
   16956 	/* Skip the command name. */
   16957 	ptr = next_token(lex, NULL);
   16958 	if (ptr == NULL) {
   16959 		return ISC_R_UNEXPECTEDEND;
   16960 	}
   16961 
   16962 	ptr = next_token(lex, NULL);
   16963 	if (ptr == NULL) {
   16964 		return ISC_R_UNEXPECTEDEND;
   16965 	} else if (!strcasecmp(ptr, "dump")) {
   16966 		result = memprof_dump();
   16967 		if (result != ISC_R_SUCCESS) {
   16968 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16969 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   16970 				      "failed to dump memory profile");
   16971 
   16972 		} else {
   16973 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16974 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   16975 				      "memory profile dumped");
   16976 		}
   16977 
   16978 		goto done;
   16979 	} else if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
   16980 		   !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
   16981 	{
   16982 		active = true;
   16983 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
   16984 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
   16985 	{
   16986 		active = false;
   16987 	} else {
   16988 		return DNS_R_SYNTAX;
   16989 	}
   16990 
   16991 	result = memprof_toggle(active);
   16992 	if (result != ISC_R_SUCCESS) {
   16993 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16994 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   16995 			      "failed to toggle memory profiling");
   16996 	} else {
   16997 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16998 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   16999 			      "memory profiling %s",
   17000 			      active ? "enabled" : "disabled");
   17001 	}
   17002 
   17003 done:
   17004 	return result;
   17005 }
   17006 
   17007 #ifdef JEMALLOC_API_SUPPORTED
   17008 const char *
   17009 named_server_getmemprof(void) {
   17010 	memprof_status status = MEMPROF_ON;
   17011 	bool is_enabled;
   17012 	size_t len = sizeof(is_enabled);
   17013 
   17014 	if (mallctl("config.prof", &is_enabled, &len, NULL, 0) != 0) {
   17015 		status = MEMPROF_FAILING;
   17016 		goto done;
   17017 	}
   17018 
   17019 	INSIST(len == sizeof(is_enabled));
   17020 
   17021 	if (!is_enabled) {
   17022 		status = MEMPROF_UNSUPPORTED;
   17023 		goto done;
   17024 	}
   17025 
   17026 	if (mallctl("opt.prof", &is_enabled, &len, NULL, 0) != 0) {
   17027 		status = MEMPROF_FAILING;
   17028 		goto done;
   17029 	}
   17030 
   17031 	INSIST(len == sizeof(is_enabled));
   17032 
   17033 	if (!is_enabled) {
   17034 		status = MEMPROF_INACTIVE;
   17035 		goto done;
   17036 	}
   17037 
   17038 	len = sizeof(is_enabled);
   17039 	if (mallctl("prof.active", &is_enabled, &len, NULL, 0) != 0) {
   17040 		status = MEMPROF_FAILING;
   17041 		goto done;
   17042 	}
   17043 
   17044 	INSIST(len == sizeof(is_enabled));
   17045 
   17046 	if (!is_enabled) {
   17047 		status = MEMPROF_OFF;
   17048 	}
   17049 
   17050 done:
   17051 	return memprof_status_text[status];
   17052 }
   17053 
   17054 #else  /* JEMALLOC_API_SUPPORTED */
   17055 const char *
   17056 named_server_getmemprof(void) {
   17057 	return memprof_status_text[MEMPROF_UNSUPPORTED];
   17058 }
   17059 #endif /* JEMALLOC_API_SUPPORTED */
   17060