Home | History | Annotate | Line # | Download | only in named
      1 /*	$NetBSD: server.c,v 1.26 2026/01/29 18:36:27 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 #ifdef HAVE_DNSTAP
     30 #include <fstrm.h>
     31 #endif
     32 
     33 #include <isc/async.h>
     34 #include <isc/attributes.h>
     35 #include <isc/base64.h>
     36 #include <isc/commandline.h>
     37 #include <isc/dir.h>
     38 #include <isc/file.h>
     39 #include <isc/fips.h>
     40 #include <isc/hash.h>
     41 #include <isc/hex.h>
     42 #include <isc/hmac.h>
     43 #include <isc/httpd.h>
     44 #include <isc/job.h>
     45 #include <isc/lex.h>
     46 #include <isc/loop.h>
     47 #include <isc/meminfo.h>
     48 #include <isc/netmgr.h>
     49 #include <isc/nonce.h>
     50 #include <isc/parseint.h>
     51 #include <isc/portset.h>
     52 #include <isc/refcount.h>
     53 #include <isc/result.h>
     54 #include <isc/signal.h>
     55 #include <isc/siphash.h>
     56 #include <isc/stats.h>
     57 #include <isc/stdio.h>
     58 #include <isc/string.h>
     59 #include <isc/time.h>
     60 #include <isc/timer.h>
     61 #include <isc/util.h>
     62 
     63 #include <dns/adb.h>
     64 #include <dns/badcache.h>
     65 #include <dns/cache.h>
     66 #include <dns/catz.h>
     67 #include <dns/db.h>
     68 #include <dns/dispatch.h>
     69 #include <dns/dlz.h>
     70 #include <dns/dns64.h>
     71 #include <dns/dnsrps.h>
     72 #include <dns/dnssec.h>
     73 #include <dns/dyndb.h>
     74 #include <dns/fixedname.h>
     75 #include <dns/forward.h>
     76 #include <dns/geoip.h>
     77 #include <dns/journal.h>
     78 #include <dns/kasp.h>
     79 #include <dns/keymgr.h>
     80 #include <dns/keystore.h>
     81 #include <dns/keytable.h>
     82 #include <dns/keyvalues.h>
     83 #include <dns/master.h>
     84 #include <dns/masterdump.h>
     85 #include <dns/nametree.h>
     86 #include <dns/nsec3.h>
     87 #include <dns/nta.h>
     88 #include <dns/order.h>
     89 #include <dns/peer.h>
     90 #include <dns/private.h>
     91 #include <dns/rbt.h>
     92 #include <dns/rdataclass.h>
     93 #include <dns/rdatalist.h>
     94 #include <dns/rdataset.h>
     95 #include <dns/rdatastruct.h>
     96 #include <dns/resolver.h>
     97 #include <dns/rootns.h>
     98 #include <dns/rriterator.h>
     99 #include <dns/secalg.h>
    100 #include <dns/soa.h>
    101 #include <dns/stats.h>
    102 #include <dns/time.h>
    103 #include <dns/tkey.h>
    104 #include <dns/tsig.h>
    105 #include <dns/ttl.h>
    106 #include <dns/view.h>
    107 #include <dns/zone.h>
    108 #include <dns/zt.h>
    109 
    110 #include <dst/dst.h>
    111 
    112 #include <isccfg/check.h>
    113 #include <isccfg/grammar.h>
    114 #include <isccfg/kaspconf.h>
    115 #include <isccfg/namedconf.h>
    116 
    117 #include <ns/client.h>
    118 #include <ns/hooks.h>
    119 #include <ns/interfacemgr.h>
    120 #include <ns/listenlist.h>
    121 
    122 #include <named/config.h>
    123 #include <named/control.h>
    124 #if defined(HAVE_GEOIP2)
    125 #include <named/geoip.h>
    126 #endif /* HAVE_GEOIP2 */
    127 #include <named/log.h>
    128 #include <named/logconf.h>
    129 #include <named/main.h>
    130 #include <named/os.h>
    131 #include <named/server.h>
    132 #include <named/statschannel.h>
    133 #include <named/tkeyconf.h>
    134 #include <named/transportconf.h>
    135 #include <named/tsigconf.h>
    136 #include <named/zoneconf.h>
    137 #ifdef HAVE_LIBSCF
    138 #include <stdlib.h>
    139 
    140 #include <named/smf_globals.h>
    141 #endif /* ifdef HAVE_LIBSCF */
    142 
    143 /* On DragonFly BSD the header does not provide jemalloc API */
    144 #if defined(HAVE_MALLOC_NP_H) && !defined(__DragonFly__)
    145 #include <malloc_np.h>
    146 #define JEMALLOC_API_SUPPORTED 1
    147 #elif defined(HAVE_JEMALLOC)
    148 #include <jemalloc/jemalloc.h>
    149 #define JEMALLOC_API_SUPPORTED 1
    150 #endif
    151 
    152 #ifdef HAVE_LMDB
    153 #include <lmdb.h>
    154 #define configure_newzones configure_newzones_db
    155 #define dumpzone	   dumpzone_db
    156 #else /* HAVE_LMDB */
    157 #define configure_newzones configure_newzones_file
    158 #define dumpzone	   dumpzone_file
    159 #endif /* HAVE_LMDB */
    160 
    161 #ifndef SIZE_MAX
    162 #define SIZE_MAX ((size_t)-1)
    163 #endif /* ifndef SIZE_MAX */
    164 
    165 #ifndef SIZE_AS_PERCENT
    166 #define SIZE_AS_PERCENT ((size_t)-2)
    167 #endif /* ifndef SIZE_AS_PERCENT */
    168 
    169 /* RFC7828 defines timeout as 16-bit value specified in units of 100
    170  * milliseconds, so the maximum and minimum advertised and keepalive
    171  * timeouts are capped by the data type (it's ~109 minutes)
    172  */
    173 #define MIN_INITIAL_TIMEOUT    UINT32_C(2500)	/* 2.5 seconds */
    174 #define MAX_INITIAL_TIMEOUT    UINT32_C(120000) /* 2 minutes */
    175 #define MIN_IDLE_TIMEOUT       UINT32_C(100)	/* 0.1 seconds */
    176 #define MAX_IDLE_TIMEOUT       UINT32_C(120000) /* 2 minutes */
    177 #define MIN_KEEPALIVE_TIMEOUT  UINT32_C(100)	/* 0.1 seconds */
    178 #define MAX_KEEPALIVE_TIMEOUT  UINT32_C(UINT16_MAX * 100)
    179 #define MIN_ADVERTISED_TIMEOUT UINT32_C(0) /* No minimum */
    180 #define MAX_ADVERTISED_TIMEOUT UINT32_C(UINT16_MAX * 100)
    181 
    182 /*%
    183  * Check an operation for failure.  Assumes that the function
    184  * using it has a 'result' variable and a 'cleanup' label.
    185  */
    186 #define TCHECK(op)                               \
    187 	do {                                     \
    188 		tresult = (op);                  \
    189 		if (tresult != ISC_R_SUCCESS) {  \
    190 			isc_buffer_clear(*text); \
    191 			goto cleanup;            \
    192 		}                                \
    193 	} while (0)
    194 
    195 #define CHECKM(op, msg)                                                        \
    196 	do {                                                                   \
    197 		result = (op);                                                 \
    198 		if (result != ISC_R_SUCCESS) {                                 \
    199 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
    200 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,   \
    201 				      "%s: %s", msg,                           \
    202 				      isc_result_totext(result));              \
    203 			goto cleanup;                                          \
    204 		}                                                              \
    205 	} while (0)
    206 
    207 #define CHECKMF(op, msg, file)                                                 \
    208 	do {                                                                   \
    209 		result = (op);                                                 \
    210 		if (result != ISC_R_SUCCESS) {                                 \
    211 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
    212 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,   \
    213 				      "%s '%s': %s", msg, file,                \
    214 				      isc_result_totext(result));              \
    215 			goto cleanup;                                          \
    216 		}                                                              \
    217 	} while (0)
    218 
    219 #define CHECKFATAL(op, msg)                    \
    220 	{                                      \
    221 		result = (op);                 \
    222 		if (result != ISC_R_SUCCESS) { \
    223 			fatal(msg, result);    \
    224 		}                              \
    225 	}
    226 
    227 /*%
    228  * Maximum ADB size for views that share a cache.  Use this limit to suppress
    229  * the total of memory footprint, which should be the main reason for sharing
    230  * a cache.  Only effective when a finite max-cache-size is specified.
    231  * This is currently defined to be 8MB.
    232  */
    233 #define MAX_ADB_SIZE_FOR_CACHESHARE 8388608U
    234 
    235 struct named_dispatch {
    236 	isc_sockaddr_t addr;
    237 	unsigned int dispatchgen;
    238 	dns_dispatch_t *dispatch;
    239 	ISC_LINK(struct named_dispatch) link;
    240 };
    241 
    242 struct named_cache {
    243 	dns_cache_t *cache;
    244 	dns_view_t *primaryview;
    245 	bool needflush;
    246 	bool adbsizeadjusted;
    247 	dns_rdataclass_t rdclass;
    248 	ISC_LINK(named_cache_t) link;
    249 };
    250 
    251 struct dumpcontext {
    252 	isc_mem_t *mctx;
    253 	bool dumpcache;
    254 	bool dumpzones;
    255 	bool dumpadb;
    256 	bool dumpexpired;
    257 	bool dumpfail;
    258 	FILE *fp;
    259 	ISC_LIST(struct viewlistentry) viewlist;
    260 	struct viewlistentry *view;
    261 	struct zonelistentry *zone;
    262 	dns_dumpctx_t *mdctx;
    263 	dns_db_t *db;
    264 	dns_db_t *cache;
    265 	isc_loop_t *loop;
    266 	dns_dbversion_t *version;
    267 };
    268 
    269 struct viewlistentry {
    270 	dns_view_t *view;
    271 	ISC_LINK(struct viewlistentry) link;
    272 	ISC_LIST(struct zonelistentry) zonelist;
    273 };
    274 
    275 struct zonelistentry {
    276 	dns_zone_t *zone;
    277 	ISC_LINK(struct zonelistentry) link;
    278 };
    279 
    280 /*%
    281  * Message-to-view matching context to run message signature validation
    282  * asynchronously.
    283  */
    284 typedef struct matching_view_ctx {
    285 	isc_netaddr_t *srcaddr;
    286 	isc_netaddr_t *destaddr;
    287 	dns_message_t *message;
    288 	dns_aclenv_t *env;
    289 	ns_server_t *sctx;
    290 	isc_loop_t *loop;
    291 	isc_job_cb cb;
    292 	void *cbarg;
    293 	isc_result_t *sigresult;
    294 	isc_result_t *viewmatchresult;
    295 	isc_result_t quota_result;
    296 	dns_view_t **viewp;
    297 	dns_view_t *view;
    298 } matching_view_ctx_t;
    299 
    300 /*%
    301  * Configuration context to retain for each view that allows
    302  * new zones to be added at runtime.
    303  */
    304 typedef struct ns_cfgctx {
    305 	isc_mem_t *mctx;
    306 	cfg_parser_t *conf_parser;
    307 	cfg_parser_t *add_parser;
    308 	cfg_obj_t *config;
    309 	cfg_obj_t *vconfig;
    310 	cfg_obj_t *nzf_config;
    311 	cfg_aclconfctx_t *actx;
    312 } ns_cfgctx_t;
    313 
    314 /*%
    315  * A function to write out added-zone configuration to the new_zone_file
    316  * specified in 'view'. Maybe called by delete_zoneconf().
    317  */
    318 typedef isc_result_t (*nzfwriter_t)(const cfg_obj_t *config, dns_view_t *view);
    319 
    320 /*%
    321  * Holds state information for the initial zone loading process.
    322  * Uses the isc_refcount structure to count the number of views
    323  * with pending zone loads, dereferencing as each view finishes.
    324  */
    325 typedef struct {
    326 	named_server_t *server;
    327 	bool reconfig;
    328 	isc_refcount_t refs;
    329 } ns_zoneload_t;
    330 
    331 typedef struct {
    332 	named_server_t *server;
    333 } catz_cb_data_t;
    334 
    335 typedef struct catz_chgzone {
    336 	isc_mem_t *mctx;
    337 	dns_catz_entry_t *entry;
    338 	dns_catz_zone_t *origin;
    339 	dns_view_t *view;
    340 	catz_cb_data_t *cbd;
    341 	bool mod;
    342 } catz_chgzone_t;
    343 
    344 typedef struct catz_reconfig_data {
    345 	dns_catz_zone_t *catz;
    346 	const cfg_obj_t *config;
    347 	catz_cb_data_t *cbd;
    348 } catz_reconfig_data_t;
    349 
    350 typedef enum {
    351 	CATZ_ADDZONE,
    352 	CATZ_MODZONE,
    353 	CATZ_DELZONE,
    354 } catz_type_t;
    355 
    356 typedef struct {
    357 	unsigned int magic;
    358 #define DZARG_MAGIC ISC_MAGIC('D', 'z', 'a', 'r')
    359 	isc_buffer_t **text;
    360 	isc_result_t result;
    361 } ns_dzarg_t;
    362 
    363 typedef enum {
    364 	MEMPROF_UNSUPPORTED = 0x00,
    365 	MEMPROF_INACTIVE = 0x01,
    366 	MEMPROF_FAILING = 0x02,
    367 	MEMPROF_OFF = 0x03,
    368 	MEMPROF_ON = 0x04,
    369 } memprof_status;
    370 
    371 static const char *memprof_status_text[] = {
    372 	[MEMPROF_UNSUPPORTED] = "UNSUPPORTED",
    373 	[MEMPROF_INACTIVE] = "INACTIVE",
    374 	[MEMPROF_FAILING] = "FAILING",
    375 	[MEMPROF_OFF] = "OFF",
    376 	[MEMPROF_ON] = "ON",
    377 };
    378 
    379 /*
    380  * These zones should not leak onto the Internet.
    381  */
    382 const char *empty_zones[] = {
    383 	/* RFC 1918 */
    384 	"10.IN-ADDR.ARPA", "16.172.IN-ADDR.ARPA", "17.172.IN-ADDR.ARPA",
    385 	"18.172.IN-ADDR.ARPA", "19.172.IN-ADDR.ARPA", "20.172.IN-ADDR.ARPA",
    386 	"21.172.IN-ADDR.ARPA", "22.172.IN-ADDR.ARPA", "23.172.IN-ADDR.ARPA",
    387 	"24.172.IN-ADDR.ARPA", "25.172.IN-ADDR.ARPA", "26.172.IN-ADDR.ARPA",
    388 	"27.172.IN-ADDR.ARPA", "28.172.IN-ADDR.ARPA", "29.172.IN-ADDR.ARPA",
    389 	"30.172.IN-ADDR.ARPA", "31.172.IN-ADDR.ARPA", "168.192.IN-ADDR.ARPA",
    390 
    391 	/* RFC 6598 */
    392 	"64.100.IN-ADDR.ARPA", "65.100.IN-ADDR.ARPA", "66.100.IN-ADDR.ARPA",
    393 	"67.100.IN-ADDR.ARPA", "68.100.IN-ADDR.ARPA", "69.100.IN-ADDR.ARPA",
    394 	"70.100.IN-ADDR.ARPA", "71.100.IN-ADDR.ARPA", "72.100.IN-ADDR.ARPA",
    395 	"73.100.IN-ADDR.ARPA", "74.100.IN-ADDR.ARPA", "75.100.IN-ADDR.ARPA",
    396 	"76.100.IN-ADDR.ARPA", "77.100.IN-ADDR.ARPA", "78.100.IN-ADDR.ARPA",
    397 	"79.100.IN-ADDR.ARPA", "80.100.IN-ADDR.ARPA", "81.100.IN-ADDR.ARPA",
    398 	"82.100.IN-ADDR.ARPA", "83.100.IN-ADDR.ARPA", "84.100.IN-ADDR.ARPA",
    399 	"85.100.IN-ADDR.ARPA", "86.100.IN-ADDR.ARPA", "87.100.IN-ADDR.ARPA",
    400 	"88.100.IN-ADDR.ARPA", "89.100.IN-ADDR.ARPA", "90.100.IN-ADDR.ARPA",
    401 	"91.100.IN-ADDR.ARPA", "92.100.IN-ADDR.ARPA", "93.100.IN-ADDR.ARPA",
    402 	"94.100.IN-ADDR.ARPA", "95.100.IN-ADDR.ARPA", "96.100.IN-ADDR.ARPA",
    403 	"97.100.IN-ADDR.ARPA", "98.100.IN-ADDR.ARPA", "99.100.IN-ADDR.ARPA",
    404 	"100.100.IN-ADDR.ARPA", "101.100.IN-ADDR.ARPA", "102.100.IN-ADDR.ARPA",
    405 	"103.100.IN-ADDR.ARPA", "104.100.IN-ADDR.ARPA", "105.100.IN-ADDR.ARPA",
    406 	"106.100.IN-ADDR.ARPA", "107.100.IN-ADDR.ARPA", "108.100.IN-ADDR.ARPA",
    407 	"109.100.IN-ADDR.ARPA", "110.100.IN-ADDR.ARPA", "111.100.IN-ADDR.ARPA",
    408 	"112.100.IN-ADDR.ARPA", "113.100.IN-ADDR.ARPA", "114.100.IN-ADDR.ARPA",
    409 	"115.100.IN-ADDR.ARPA", "116.100.IN-ADDR.ARPA", "117.100.IN-ADDR.ARPA",
    410 	"118.100.IN-ADDR.ARPA", "119.100.IN-ADDR.ARPA", "120.100.IN-ADDR.ARPA",
    411 	"121.100.IN-ADDR.ARPA", "122.100.IN-ADDR.ARPA", "123.100.IN-ADDR.ARPA",
    412 	"124.100.IN-ADDR.ARPA", "125.100.IN-ADDR.ARPA", "126.100.IN-ADDR.ARPA",
    413 	"127.100.IN-ADDR.ARPA",
    414 
    415 	/* RFC 5735 and RFC 5737 */
    416 	"0.IN-ADDR.ARPA",		/* THIS NETWORK */
    417 	"127.IN-ADDR.ARPA",		/* LOOPBACK */
    418 	"254.169.IN-ADDR.ARPA",		/* LINK LOCAL */
    419 	"2.0.192.IN-ADDR.ARPA",		/* TEST NET */
    420 	"100.51.198.IN-ADDR.ARPA",	/* TEST NET 2 */
    421 	"113.0.203.IN-ADDR.ARPA",	/* TEST NET 3 */
    422 	"255.255.255.255.IN-ADDR.ARPA", /* BROADCAST */
    423 
    424 	/* Local IPv6 Unicast Addresses */
    425 	/* clang-format off */
    426 	"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",
    427 	"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",
    428 	/* clang-format on */
    429 
    430 	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
    431 	"D.F.IP6.ARPA", "8.E.F.IP6.ARPA", /* LINK LOCAL */
    432 	"9.E.F.IP6.ARPA",		  /* LINK LOCAL */
    433 	"A.E.F.IP6.ARPA",		  /* LINK LOCAL */
    434 	"B.E.F.IP6.ARPA",		  /* LINK LOCAL */
    435 
    436 	/* Example Prefix, RFC 3849. */
    437 	"8.B.D.0.1.0.0.2.IP6.ARPA",
    438 
    439 	/* RFC 7534 */
    440 	"EMPTY.AS112.ARPA",
    441 
    442 	/* RFC 8375 */
    443 	"HOME.ARPA",
    444 
    445 	/* RFC 9462 */
    446 	"RESOLVER.ARPA",
    447 
    448 	NULL
    449 };
    450 
    451 noreturn static void
    452 fatal(const char *msg, isc_result_t result);
    453 
    454 static void
    455 named_server_reload(void *arg);
    456 
    457 #ifdef HAVE_LIBNGHTTP2
    458 static isc_result_t
    459 listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls,
    460 	       const ns_listen_tls_params_t *tls_params,
    461 	       isc_tlsctx_cache_t *tlsctx_cache, in_port_t port,
    462 	       isc_mem_t *mctx, isc_nm_proxy_type_t proxy,
    463 	       ns_listenelt_t **target);
    464 #endif
    465 
    466 static isc_result_t
    467 listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
    468 		     cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
    469 		     isc_tlsctx_cache_t *tlsctx_cache, ns_listenelt_t **target);
    470 
    471 static isc_result_t
    472 listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
    473 		      cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
    474 		      isc_tlsctx_cache_t *tlsctx_cache,
    475 		      ns_listenlist_t **target);
    476 
    477 static isc_result_t
    478 configure_forward(const cfg_obj_t *config, dns_view_t *view,
    479 		  const dns_name_t *origin, const cfg_obj_t *forwarders,
    480 		  const cfg_obj_t *forwardtype);
    481 
    482 static isc_result_t
    483 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
    484 		     const cfg_obj_t *alternates);
    485 
    486 static isc_result_t
    487 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
    488 	       const cfg_obj_t *vconfig, dns_view_t *view,
    489 	       dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
    490 	       dns_keystorelist_t *keystores, cfg_aclconfctx_t *aclconf,
    491 	       bool added, bool old_rpz_ok, bool is_catz_member, bool modify);
    492 
    493 static void
    494 configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
    495 			     dns_view_t *view);
    496 
    497 static isc_result_t
    498 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
    499 		   cfg_aclconfctx_t *actx);
    500 
    501 static const cfg_obj_t *
    502 find_maplist(const cfg_obj_t *config, const char *listname, const char *name);
    503 
    504 static isc_result_t
    505 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
    506 
    507 static void
    508 newzone_cfgctx_destroy(void **cfgp);
    509 
    510 static isc_result_t
    511 putstr(isc_buffer_t **b, const char *str);
    512 
    513 static isc_result_t
    514 putmem(isc_buffer_t **b, const char *str, size_t len);
    515 
    516 static isc_result_t
    517 putuint8(isc_buffer_t **b, uint8_t val);
    518 
    519 static isc_result_t
    520 putnull(isc_buffer_t **b);
    521 
    522 #ifdef HAVE_LMDB
    523 static isc_result_t
    524 nzd_writable(dns_view_t *view);
    525 
    526 static isc_result_t
    527 nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);
    528 
    529 static isc_result_t
    530 nzd_env_reopen(dns_view_t *view);
    531 
    532 static void
    533 nzd_env_close(dns_view_t *view);
    534 
    535 static isc_result_t
    536 nzd_close(MDB_txn **txnp, bool commit);
    537 #else  /* ifdef HAVE_LMDB */
    538 static isc_result_t
    539 nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
    540 #endif /* ifdef HAVE_LMDB */
    541 
    542 static isc_result_t
    543 load_nzf(dns_view_t *view, ns_cfgctx_t *nzcfg);
    544 
    545 /*%
    546  * Configure a single view ACL at '*aclp'.  Get its configuration from
    547  * 'vconfig' (for per-view configuration) and maybe from 'config'
    548  */
    549 static isc_result_t
    550 configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
    551 		   const cfg_obj_t *gconfig, const char *aclname,
    552 		   const char *acltuplename, cfg_aclconfctx_t *actx,
    553 		   isc_mem_t *mctx, dns_acl_t **aclp) {
    554 	isc_result_t result;
    555 	const cfg_obj_t *maps[4];
    556 	const cfg_obj_t *aclobj = NULL;
    557 	int i = 0;
    558 
    559 	if (*aclp != NULL) {
    560 		dns_acl_detach(aclp);
    561 	}
    562 	if (vconfig != NULL) {
    563 		maps[i++] = cfg_tuple_get(vconfig, "options");
    564 	}
    565 	if (config != NULL) {
    566 		const cfg_obj_t *options = NULL;
    567 		(void)cfg_map_get(config, "options", &options);
    568 		if (options != NULL) {
    569 			maps[i++] = options;
    570 		}
    571 	}
    572 	if (gconfig != NULL) {
    573 		const cfg_obj_t *options = NULL;
    574 		(void)cfg_map_get(gconfig, "options", &options);
    575 		if (options != NULL) {
    576 			maps[i++] = options;
    577 		}
    578 	}
    579 	maps[i] = NULL;
    580 
    581 	(void)named_config_get(maps, aclname, &aclobj);
    582 	if (aclobj == NULL) {
    583 		/*
    584 		 * No value available.	*aclp == NULL.
    585 		 */
    586 		return ISC_R_SUCCESS;
    587 	}
    588 
    589 	if (acltuplename != NULL) {
    590 		/*
    591 		 * If the ACL is given in an optional tuple, retrieve it.
    592 		 * The parser should have ensured that a valid object be
    593 		 * returned.
    594 		 */
    595 		aclobj = cfg_tuple_get(aclobj, acltuplename);
    596 	}
    597 
    598 	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 0,
    599 				    aclp);
    600 
    601 	return result;
    602 }
    603 
    604 /*%
    605  * Configure a sortlist at '*aclp'.  Essentially the same as
    606  * configure_view_acl() except it calls cfg_acl_fromconfig with a
    607  * nest_level value of 2.
    608  */
    609 static isc_result_t
    610 configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
    611 			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
    612 			dns_acl_t **aclp) {
    613 	isc_result_t result;
    614 	const cfg_obj_t *maps[3];
    615 	const cfg_obj_t *aclobj = NULL;
    616 	int i = 0;
    617 
    618 	if (*aclp != NULL) {
    619 		dns_acl_detach(aclp);
    620 	}
    621 	if (vconfig != NULL) {
    622 		maps[i++] = cfg_tuple_get(vconfig, "options");
    623 	}
    624 	if (config != NULL) {
    625 		const cfg_obj_t *options = NULL;
    626 		(void)cfg_map_get(config, "options", &options);
    627 		if (options != NULL) {
    628 			maps[i++] = options;
    629 		}
    630 	}
    631 	maps[i] = NULL;
    632 
    633 	(void)named_config_get(maps, "sortlist", &aclobj);
    634 	if (aclobj == NULL) {
    635 		return ISC_R_SUCCESS;
    636 	}
    637 
    638 	/*
    639 	 * Use a nest level of 3 for the "top level" of the sortlist;
    640 	 * this means each entry in the top three levels will be stored
    641 	 * as lists of separate, nested ACLs, rather than merged together
    642 	 * into IP tables as is usually done with ACLs.
    643 	 */
    644 	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 3,
    645 				    aclp);
    646 
    647 	return result;
    648 }
    649 
    650 static isc_result_t
    651 configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
    652 			 const char *confname, const char *conftuplename,
    653 			 isc_mem_t *mctx, dns_nametree_t **ntp) {
    654 	isc_result_t result = ISC_R_SUCCESS;
    655 	const cfg_obj_t *maps[3];
    656 	const cfg_obj_t *obj = NULL;
    657 	const cfg_listelt_t *element = NULL;
    658 	int i = 0;
    659 	dns_fixedname_t fixed;
    660 	dns_name_t *name = NULL;
    661 	isc_buffer_t b;
    662 	const char *str = NULL;
    663 	const cfg_obj_t *nameobj = NULL;
    664 
    665 	if (*ntp != NULL) {
    666 		dns_nametree_detach(ntp);
    667 	}
    668 	dns_nametree_create(mctx, DNS_NAMETREE_BOOL, confname, ntp);
    669 
    670 	if (vconfig != NULL) {
    671 		maps[i++] = cfg_tuple_get(vconfig, "options");
    672 	}
    673 	if (config != NULL) {
    674 		const cfg_obj_t *options = NULL;
    675 		(void)cfg_map_get(config, "options", &options);
    676 		if (options != NULL) {
    677 			maps[i++] = options;
    678 		}
    679 	}
    680 	maps[i] = NULL;
    681 
    682 	(void)named_config_get(maps, confname, &obj);
    683 	if (obj == NULL) {
    684 		/*
    685 		 * No value available.	*ntp == NULL.
    686 		 */
    687 		return ISC_R_SUCCESS;
    688 	}
    689 
    690 	if (conftuplename != NULL) {
    691 		obj = cfg_tuple_get(obj, conftuplename);
    692 		if (cfg_obj_isvoid(obj)) {
    693 			return ISC_R_SUCCESS;
    694 		}
    695 	}
    696 
    697 	name = dns_fixedname_initname(&fixed);
    698 	for (element = cfg_list_first(obj); element != NULL;
    699 	     element = cfg_list_next(element))
    700 	{
    701 		nameobj = cfg_listelt_value(element);
    702 		str = cfg_obj_asstring(nameobj);
    703 		isc_buffer_constinit(&b, str, strlen(str));
    704 		isc_buffer_add(&b, strlen(str));
    705 		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
    706 		result = dns_nametree_add(*ntp, name, true);
    707 		if (result != ISC_R_SUCCESS) {
    708 			cfg_obj_log(nameobj, named_g_lctx, ISC_LOG_ERROR,
    709 				    "failed to add %s for %s: %s", str,
    710 				    confname, isc_result_totext(result));
    711 			goto cleanup;
    712 		}
    713 	}
    714 
    715 	return ISC_R_SUCCESS;
    716 
    717 cleanup:
    718 	dns_nametree_detach(ntp);
    719 	return result;
    720 }
    721 
    722 static isc_result_t
    723 ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
    724 	      unsigned char *digest, dns_rdata_ds_t *ds) {
    725 	isc_result_t result;
    726 	dns_rdata_dnskey_t keystruct;
    727 	dns_rdata_t rdata = DNS_RDATA_INIT;
    728 	uint32_t rdata1, rdata2, rdata3;
    729 	const char *datastr = NULL, *namestr = NULL;
    730 	unsigned char data[4096];
    731 	isc_buffer_t databuf;
    732 	unsigned char rrdata[4096];
    733 	isc_buffer_t rrdatabuf;
    734 	isc_region_t r;
    735 	dns_fixedname_t fname;
    736 	dns_name_t *name = NULL;
    737 	isc_buffer_t namebuf;
    738 	const char *atstr = NULL;
    739 	enum {
    740 		INIT_DNSKEY,
    741 		STATIC_DNSKEY,
    742 		INIT_DS,
    743 		STATIC_DS,
    744 		TRUSTED
    745 	} anchortype;
    746 
    747 	REQUIRE(namestrp != NULL && *namestrp == NULL);
    748 	REQUIRE(ds != NULL);
    749 
    750 	/* if DNSKEY, flags; if DS, key tag */
    751 	rdata1 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata1"));
    752 
    753 	/* if DNSKEY, protocol; if DS, algorithm */
    754 	rdata2 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata2"));
    755 
    756 	/* if DNSKEY, algorithm; if DS, digest type */
    757 	rdata3 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata3"));
    758 
    759 	namestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
    760 	*namestrp = namestr;
    761 
    762 	name = dns_fixedname_initname(&fname);
    763 	isc_buffer_constinit(&namebuf, namestr, strlen(namestr));
    764 	isc_buffer_add(&namebuf, strlen(namestr));
    765 	CHECK(dns_name_fromtext(name, &namebuf, dns_rootname, 0, NULL));
    766 
    767 	if (*initialp) {
    768 		atstr = cfg_obj_asstring(cfg_tuple_get(key, "anchortype"));
    769 
    770 		if (strcasecmp(atstr, "static-key") == 0) {
    771 			*initialp = false;
    772 			anchortype = STATIC_DNSKEY;
    773 		} else if (strcasecmp(atstr, "static-ds") == 0) {
    774 			*initialp = false;
    775 			anchortype = STATIC_DS;
    776 		} else if (strcasecmp(atstr, "initial-key") == 0) {
    777 			anchortype = INIT_DNSKEY;
    778 		} else if (strcasecmp(atstr, "initial-ds") == 0) {
    779 			anchortype = INIT_DS;
    780 		} else {
    781 			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
    782 				    "key '%s': "
    783 				    "invalid initialization method '%s'",
    784 				    namestr, atstr);
    785 			result = ISC_R_FAILURE;
    786 			goto cleanup;
    787 		}
    788 	} else {
    789 		anchortype = TRUSTED;
    790 	}
    791 
    792 	isc_buffer_init(&databuf, data, sizeof(data));
    793 	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
    794 
    795 	*ds = (dns_rdata_ds_t){ .common.rdclass = dns_rdataclass_in,
    796 				.common.rdtype = dns_rdatatype_ds };
    797 
    798 	ISC_LINK_INIT(&ds->common, link);
    799 
    800 	switch (anchortype) {
    801 	case INIT_DNSKEY:
    802 	case STATIC_DNSKEY:
    803 	case TRUSTED:
    804 		/*
    805 		 * This function should never be reached for view
    806 		 * class other than IN
    807 		 */
    808 		keystruct.common.rdclass = dns_rdataclass_in;
    809 		keystruct.common.rdtype = dns_rdatatype_dnskey;
    810 
    811 		/*
    812 		 * The key data in keystruct is not dynamically allocated.
    813 		 */
    814 		keystruct.mctx = NULL;
    815 
    816 		ISC_LINK_INIT(&keystruct.common, link);
    817 
    818 		if (rdata1 > 0xffff) {
    819 			CHECKM(ISC_R_RANGE, "key flags");
    820 		}
    821 		if (rdata1 & DNS_KEYFLAG_REVOKE) {
    822 			CHECKM(DST_R_BADKEYTYPE, "key flags revoke bit set");
    823 		}
    824 		if (rdata2 > 0xff) {
    825 			CHECKM(ISC_R_RANGE, "key protocol");
    826 		}
    827 		if (rdata3 > 0xff) {
    828 			CHECKM(ISC_R_RANGE, "key algorithm");
    829 		}
    830 
    831 		keystruct.flags = (uint16_t)rdata1;
    832 		keystruct.protocol = (uint8_t)rdata2;
    833 		keystruct.algorithm = (uint8_t)rdata3;
    834 
    835 		if (!dst_algorithm_supported(keystruct.algorithm)) {
    836 			CHECK(DST_R_UNSUPPORTEDALG);
    837 		}
    838 
    839 		datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
    840 		CHECK(isc_base64_decodestring(datastr, &databuf));
    841 		isc_buffer_usedregion(&databuf, &r);
    842 		keystruct.datalen = r.length;
    843 		keystruct.data = r.base;
    844 
    845 		CHECK(dns_rdata_fromstruct(&rdata, keystruct.common.rdclass,
    846 					   keystruct.common.rdtype, &keystruct,
    847 					   &rrdatabuf));
    848 		CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
    849 					  digest, ds));
    850 		break;
    851 
    852 	case INIT_DS:
    853 	case STATIC_DS:
    854 		if (rdata1 > 0xffff) {
    855 			CHECKM(ISC_R_RANGE, "key tag");
    856 		}
    857 		if (rdata2 > 0xff) {
    858 			CHECKM(ISC_R_RANGE, "key algorithm");
    859 		}
    860 		if (rdata3 > 0xff) {
    861 			CHECKM(ISC_R_RANGE, "digest type");
    862 		}
    863 
    864 		ds->key_tag = (uint16_t)rdata1;
    865 		ds->algorithm = (uint8_t)rdata2;
    866 		ds->digest_type = (uint8_t)rdata3;
    867 
    868 		datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
    869 		CHECK(isc_hex_decodestring(datastr, &databuf));
    870 		isc_buffer_usedregion(&databuf, &r);
    871 
    872 		switch (ds->digest_type) {
    873 		case DNS_DSDIGEST_SHA1:
    874 			if (r.length != ISC_SHA1_DIGESTLENGTH) {
    875 				CHECK(ISC_R_UNEXPECTEDEND);
    876 			}
    877 			break;
    878 		case DNS_DSDIGEST_SHA256:
    879 			if (r.length != ISC_SHA256_DIGESTLENGTH) {
    880 				CHECK(ISC_R_UNEXPECTEDEND);
    881 			}
    882 			break;
    883 		case DNS_DSDIGEST_SHA384:
    884 			if (r.length != ISC_SHA384_DIGESTLENGTH) {
    885 				CHECK(ISC_R_UNEXPECTEDEND);
    886 			}
    887 			break;
    888 		default:
    889 			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
    890 				    "key '%s': "
    891 				    "unknown ds digest type %u",
    892 				    namestr, ds->digest_type);
    893 			result = ISC_R_FAILURE;
    894 			goto cleanup;
    895 			break;
    896 		}
    897 
    898 		ds->length = r.length;
    899 		ds->digest = digest;
    900 		memmove(ds->digest, r.base, r.length);
    901 
    902 		break;
    903 
    904 	default:
    905 		UNREACHABLE();
    906 	}
    907 
    908 	return ISC_R_SUCCESS;
    909 
    910 cleanup:
    911 	return result;
    912 }
    913 
    914 static void
    915 sfd_add(const dns_name_t *name, void *arg) {
    916 	if (arg != NULL) {
    917 		dns_view_sfd_add(arg, name);
    918 	}
    919 }
    920 
    921 /*%
    922  * Parse 'key' in the context of view configuration 'vconfig'.  If successful,
    923  * add the key to 'secroots' if both of the following conditions are true:
    924  *
    925  *   - 'keyname_match' is NULL or it matches the owner name of 'key',
    926  *   - support for the algorithm used by 'key' is not disabled by 'resolver'
    927  *     for the owner name of 'key'.
    928  *
    929  * 'managed' is true for managed keys and false for trusted keys.  'mctx' is
    930  * the memory context to use for allocating memory.
    931  */
    932 static isc_result_t
    933 process_key(const cfg_obj_t *key, dns_keytable_t *secroots,
    934 	    const dns_name_t *keyname_match, dns_view_t *view, bool managed) {
    935 	dns_fixedname_t fkeyname;
    936 	dns_name_t *keyname = NULL;
    937 	const char *namestr = NULL;
    938 	dns_rdata_ds_t ds;
    939 	isc_result_t result;
    940 	bool initializing = managed;
    941 	unsigned char digest[ISC_MAX_MD_SIZE];
    942 	isc_buffer_t b;
    943 
    944 	result = ta_fromconfig(key, &initializing, &namestr, digest, &ds);
    945 
    946 	switch (result) {
    947 	case ISC_R_SUCCESS:
    948 		/*
    949 		 * Trust anchor was parsed correctly.
    950 		 */
    951 		isc_buffer_constinit(&b, namestr, strlen(namestr));
    952 		isc_buffer_add(&b, strlen(namestr));
    953 		keyname = dns_fixedname_initname(&fkeyname);
    954 		result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
    955 		if (result != ISC_R_SUCCESS) {
    956 			return result;
    957 		}
    958 		break;
    959 	case DST_R_UNSUPPORTEDALG:
    960 	case DST_R_BADKEYTYPE:
    961 		/*
    962 		 * Key was parsed correctly, but it cannot be used; this is not
    963 		 * a fatal error - log a warning about this key being ignored,
    964 		 * but do not prevent any further ones from being processed.
    965 		 */
    966 		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
    967 			    "ignoring %s for '%s': %s",
    968 			    initializing ? "initial-key" : "static-key",
    969 			    namestr, isc_result_totext(result));
    970 		return ISC_R_SUCCESS;
    971 	case DST_R_NOCRYPTO:
    972 		/*
    973 		 * Crypto support is not available.
    974 		 */
    975 		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
    976 			    "ignoring %s for '%s': no crypto support",
    977 			    initializing ? "initial-key" : "static-key",
    978 			    namestr);
    979 		return result;
    980 	default:
    981 		/*
    982 		 * Something unexpected happened; we have no choice but to
    983 		 * indicate an error so that the configuration loading process
    984 		 * is interrupted.
    985 		 */
    986 		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
    987 			    "configuring %s for '%s': %s",
    988 			    initializing ? "initial-key" : "static-key",
    989 			    namestr, isc_result_totext(result));
    990 		return ISC_R_FAILURE;
    991 	}
    992 
    993 	/*
    994 	 * If the caller requested to only load keys for a specific name and
    995 	 * the owner name of this key does not match the requested name, do not
    996 	 * load it.
    997 	 */
    998 	if (keyname_match != NULL && !dns_name_equal(keyname_match, keyname)) {
    999 		goto done;
   1000 	}
   1001 
   1002 	/*
   1003 	 * Ensure that 'resolver' allows using the algorithm of this key for
   1004 	 * its owner name.  If it does not, do not load the key and log a
   1005 	 * warning, but do not prevent further keys from being processed.
   1006 	 */
   1007 	if (!dns_resolver_algorithm_supported(view->resolver, keyname,
   1008 					      ds.algorithm))
   1009 	{
   1010 		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
   1011 			    "ignoring %s for '%s': algorithm is disabled",
   1012 			    initializing ? "initial-key" : "static-key",
   1013 			    namestr);
   1014 		goto done;
   1015 	}
   1016 
   1017 	/*
   1018 	 * Add the key to 'secroots'.  Keys from a "trust-anchors" or
   1019 	 * "managed-keys" statement may be either static or initializing
   1020 	 * keys. If it's not initializing, we don't want to treat it as
   1021 	 * managed, so we use 'initializing' twice here, for both the
   1022 	 * 'managed' and 'initializing' arguments to dns_keytable_add().
   1023 	 */
   1024 	result = dns_keytable_add(secroots, initializing, initializing, keyname,
   1025 				  &ds, sfd_add, view);
   1026 
   1027 done:
   1028 	return result;
   1029 }
   1030 
   1031 /*
   1032  * Load keys from configuration into key table. If 'keyname' is specified,
   1033  * only load keys matching that name. If 'managed' is true, load the key as
   1034  * an initializing key.
   1035  */
   1036 static isc_result_t
   1037 load_view_keys(const cfg_obj_t *keys, dns_view_t *view, bool managed,
   1038 	       const dns_name_t *keyname) {
   1039 	const cfg_listelt_t *elt, *elt2;
   1040 	const cfg_obj_t *keylist;
   1041 	isc_result_t result;
   1042 	dns_keytable_t *secroots = NULL;
   1043 
   1044 	CHECK(dns_view_getsecroots(view, &secroots));
   1045 
   1046 	for (elt = cfg_list_first(keys); elt != NULL; elt = cfg_list_next(elt))
   1047 	{
   1048 		keylist = cfg_listelt_value(elt);
   1049 
   1050 		for (elt2 = cfg_list_first(keylist); elt2 != NULL;
   1051 		     elt2 = cfg_list_next(elt2))
   1052 		{
   1053 			CHECK(process_key(cfg_listelt_value(elt2), secroots,
   1054 					  keyname, view, managed));
   1055 		}
   1056 	}
   1057 
   1058 cleanup:
   1059 	if (secroots != NULL) {
   1060 		dns_keytable_detach(&secroots);
   1061 	}
   1062 	if (result == DST_R_NOCRYPTO) {
   1063 		result = ISC_R_SUCCESS;
   1064 	}
   1065 	return result;
   1066 }
   1067 
   1068 /*%
   1069  * Check whether a key has been successfully loaded.
   1070  */
   1071 static bool
   1072 keyloaded(dns_view_t *view, const dns_name_t *name) {
   1073 	isc_result_t result;
   1074 	dns_keytable_t *secroots = NULL;
   1075 	dns_keynode_t *keynode = NULL;
   1076 
   1077 	result = dns_view_getsecroots(view, &secroots);
   1078 	if (result != ISC_R_SUCCESS) {
   1079 		return false;
   1080 	}
   1081 
   1082 	result = dns_keytable_find(secroots, name, &keynode);
   1083 
   1084 	if (keynode != NULL) {
   1085 		dns_keynode_detach(&keynode);
   1086 	}
   1087 	if (secroots != NULL) {
   1088 		dns_keytable_detach(&secroots);
   1089 	}
   1090 
   1091 	return result == ISC_R_SUCCESS;
   1092 }
   1093 
   1094 /*%
   1095  * Configure DNSSEC keys for a view.
   1096  *
   1097  * The per-view configuration values and the server-global defaults are read
   1098  * from 'vconfig' and 'config'.
   1099  */
   1100 static isc_result_t
   1101 configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
   1102 			  const cfg_obj_t *config, const cfg_obj_t *bindkeys,
   1103 			  bool auto_root) {
   1104 	isc_result_t result = ISC_R_SUCCESS;
   1105 	const cfg_obj_t *view_keys = NULL;
   1106 	const cfg_obj_t *global_keys = NULL;
   1107 	const cfg_obj_t *view_managed_keys = NULL;
   1108 	const cfg_obj_t *view_trust_anchors = NULL;
   1109 	const cfg_obj_t *global_managed_keys = NULL;
   1110 	const cfg_obj_t *global_trust_anchors = NULL;
   1111 	const cfg_obj_t *maps[4];
   1112 	const cfg_obj_t *voptions = NULL;
   1113 	const cfg_obj_t *options = NULL;
   1114 	const cfg_obj_t *obj = NULL;
   1115 	const char *directory;
   1116 	int i = 0;
   1117 
   1118 	/* We don't need trust anchors for the _bind view */
   1119 	if (strcmp(view->name, "_bind") == 0 &&
   1120 	    view->rdclass == dns_rdataclass_chaos)
   1121 	{
   1122 		return ISC_R_SUCCESS;
   1123 	}
   1124 
   1125 	if (vconfig != NULL) {
   1126 		voptions = cfg_tuple_get(vconfig, "options");
   1127 		if (voptions != NULL) {
   1128 			(void)cfg_map_get(voptions, "trusted-keys", &view_keys);
   1129 
   1130 			/* managed-keys and trust-anchors are synonyms. */
   1131 			(void)cfg_map_get(voptions, "managed-keys",
   1132 					  &view_managed_keys);
   1133 			(void)cfg_map_get(voptions, "trust-anchors",
   1134 					  &view_trust_anchors);
   1135 
   1136 			maps[i++] = voptions;
   1137 		}
   1138 	}
   1139 
   1140 	if (config != NULL) {
   1141 		(void)cfg_map_get(config, "trusted-keys", &global_keys);
   1142 
   1143 		/* managed-keys and trust-anchors are synonyms. */
   1144 		(void)cfg_map_get(config, "managed-keys", &global_managed_keys);
   1145 		(void)cfg_map_get(config, "trust-anchors",
   1146 				  &global_trust_anchors);
   1147 
   1148 		(void)cfg_map_get(config, "options", &options);
   1149 		if (options != NULL) {
   1150 			maps[i++] = options;
   1151 		}
   1152 	}
   1153 
   1154 	maps[i++] = named_g_defaults;
   1155 	maps[i] = NULL;
   1156 
   1157 	dns_view_initsecroots(view);
   1158 	dns_view_initntatable(view, named_g_loopmgr);
   1159 
   1160 	if (auto_root && view->rdclass == dns_rdataclass_in) {
   1161 		const cfg_obj_t *builtin_keys = NULL;
   1162 
   1163 		/*
   1164 		 * If bind.keys exists and is populated, it overrides
   1165 		 * the trust-anchors clause hard-coded in named_g_config.
   1166 		 */
   1167 		if (bindkeys != NULL) {
   1168 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
   1169 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   1170 				      "obtaining root key for view %s "
   1171 				      "from '%s'",
   1172 				      view->name, named_g_server->bindkeysfile);
   1173 
   1174 			(void)cfg_map_get(bindkeys, "trust-anchors",
   1175 					  &builtin_keys);
   1176 
   1177 			if (builtin_keys == NULL) {
   1178 				isc_log_write(
   1179 					named_g_lctx, DNS_LOGCATEGORY_SECURITY,
   1180 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   1181 					"dnssec-validation auto: "
   1182 					"WARNING: root zone key "
   1183 					"not found");
   1184 			}
   1185 		}
   1186 
   1187 		if (builtin_keys == NULL) {
   1188 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
   1189 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   1190 				      "using built-in root key for view %s",
   1191 				      view->name);
   1192 
   1193 			(void)cfg_map_get(named_g_config, "trust-anchors",
   1194 					  &builtin_keys);
   1195 		}
   1196 
   1197 		if (builtin_keys != NULL) {
   1198 			CHECK(load_view_keys(builtin_keys, view, true,
   1199 					     dns_rootname));
   1200 		}
   1201 
   1202 		if (!keyloaded(view, dns_rootname)) {
   1203 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
   1204 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   1205 				      "root key not loaded");
   1206 			result = ISC_R_FAILURE;
   1207 			goto cleanup;
   1208 		}
   1209 	}
   1210 
   1211 	if (view->rdclass == dns_rdataclass_in) {
   1212 		CHECK(load_view_keys(view_keys, view, false, NULL));
   1213 		CHECK(load_view_keys(view_trust_anchors, view, true, NULL));
   1214 		CHECK(load_view_keys(view_managed_keys, view, true, NULL));
   1215 
   1216 		CHECK(load_view_keys(global_keys, view, false, NULL));
   1217 		CHECK(load_view_keys(global_trust_anchors, view, true, NULL));
   1218 		CHECK(load_view_keys(global_managed_keys, view, true, NULL));
   1219 	}
   1220 
   1221 	/*
   1222 	 * Add key zone for managed keys.
   1223 	 */
   1224 	obj = NULL;
   1225 	(void)named_config_get(maps, "managed-keys-directory", &obj);
   1226 	directory = (obj != NULL ? cfg_obj_asstring(obj) : NULL);
   1227 	if (directory != NULL) {
   1228 		result = isc_file_isdirectory(directory);
   1229 	}
   1230 	if (result != ISC_R_SUCCESS) {
   1231 		isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
   1232 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   1233 			      "invalid managed-keys-directory %s: %s",
   1234 			      directory, isc_result_totext(result));
   1235 		goto cleanup;
   1236 	} else if (directory != NULL) {
   1237 		if (!isc_file_isdirwritable(directory)) {
   1238 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   1239 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   1240 				      "managed-keys-directory '%s' "
   1241 				      "is not writable",
   1242 				      directory);
   1243 			result = ISC_R_NOPERM;
   1244 			goto cleanup;
   1245 		}
   1246 	}
   1247 
   1248 	if (auto_root) {
   1249 		CHECK(add_keydata_zone(view, directory, named_g_mctx));
   1250 	}
   1251 
   1252 cleanup:
   1253 	return result;
   1254 }
   1255 
   1256 static isc_result_t
   1257 mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
   1258 	const cfg_listelt_t *element;
   1259 	const cfg_obj_t *obj;
   1260 	const char *str;
   1261 	dns_fixedname_t fixed;
   1262 	dns_name_t *name;
   1263 	bool value;
   1264 	isc_result_t result;
   1265 	isc_buffer_t b;
   1266 
   1267 	name = dns_fixedname_initname(&fixed);
   1268 	for (element = cfg_list_first(mbs); element != NULL;
   1269 	     element = cfg_list_next(element))
   1270 	{
   1271 		obj = cfg_listelt_value(element);
   1272 		str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
   1273 		isc_buffer_constinit(&b, str, strlen(str));
   1274 		isc_buffer_add(&b, strlen(str));
   1275 		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
   1276 		value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
   1277 		CHECK(dns_resolver_setmustbesecure(resolver, name, value));
   1278 	}
   1279 
   1280 	result = ISC_R_SUCCESS;
   1281 
   1282 cleanup:
   1283 	return result;
   1284 }
   1285 
   1286 /*%
   1287  * Get a dispatch appropriate for the resolver of a given view.
   1288  */
   1289 static isc_result_t
   1290 get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
   1291 			      dns_dispatch_t **dispatchp, bool is_firstview) {
   1292 	isc_result_t result = ISC_R_FAILURE;
   1293 	dns_dispatch_t *disp = NULL;
   1294 	isc_sockaddr_t sa;
   1295 	const cfg_obj_t *obj = NULL;
   1296 
   1297 	switch (af) {
   1298 	case AF_INET:
   1299 		result = named_config_get(maps, "query-source", &obj);
   1300 		INSIST(result == ISC_R_SUCCESS);
   1301 		break;
   1302 	case AF_INET6:
   1303 		result = named_config_get(maps, "query-source-v6", &obj);
   1304 		INSIST(result == ISC_R_SUCCESS);
   1305 		break;
   1306 	default:
   1307 		UNREACHABLE();
   1308 	}
   1309 
   1310 	if (cfg_obj_isvoid(obj)) {
   1311 		/*
   1312 		 * We don't want to use this address family, let's
   1313 		 * bail now. The dispatch object for this family will
   1314 		 * be null then not used to run queries.
   1315 		 */
   1316 		return ISC_R_SUCCESS;
   1317 	} else {
   1318 		/*
   1319 		 * obj _has_ to be sockaddr here, cfg_obj_assockaddr()
   1320 		 * asserts this internally.
   1321 		 */
   1322 		sa = *(cfg_obj_assockaddr(obj));
   1323 		INSIST(isc_sockaddr_pf(&sa) == af);
   1324 	}
   1325 
   1326 	/*
   1327 	 * If we don't support this address family, we're done!
   1328 	 */
   1329 	switch (af) {
   1330 	case AF_INET:
   1331 		result = isc_net_probeipv4();
   1332 		break;
   1333 	case AF_INET6:
   1334 		result = isc_net_probeipv6();
   1335 		break;
   1336 	default:
   1337 		UNREACHABLE();
   1338 	}
   1339 	if (result != ISC_R_SUCCESS) {
   1340 		return ISC_R_SUCCESS;
   1341 	}
   1342 
   1343 	/*
   1344 	 * Try to find a dispatcher that we can share.
   1345 	 */
   1346 	if (isc_sockaddr_getport(&sa) != 0) {
   1347 		INSIST(obj != NULL);
   1348 		if (is_firstview) {
   1349 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
   1350 				    "using specific query-source port "
   1351 				    "suppresses port randomization and can be "
   1352 				    "insecure.");
   1353 		}
   1354 	}
   1355 
   1356 	result = dns_dispatch_createudp(named_g_dispatchmgr, &sa, &disp);
   1357 	if (result != ISC_R_SUCCESS) {
   1358 		isc_sockaddr_t any;
   1359 		char buf[ISC_SOCKADDR_FORMATSIZE];
   1360 
   1361 		switch (af) {
   1362 		case AF_INET:
   1363 			isc_sockaddr_any(&any);
   1364 			break;
   1365 		case AF_INET6:
   1366 			isc_sockaddr_any6(&any);
   1367 			break;
   1368 		}
   1369 		if (isc_sockaddr_equal(&sa, &any)) {
   1370 			return ISC_R_SUCCESS;
   1371 		}
   1372 		isc_sockaddr_format(&sa, buf, sizeof(buf));
   1373 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   1374 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   1375 			      "could not get query source dispatcher (%s): %s",
   1376 			      buf, isc_result_totext(result));
   1377 		return result;
   1378 	}
   1379 
   1380 	*dispatchp = disp;
   1381 
   1382 	return ISC_R_SUCCESS;
   1383 }
   1384 
   1385 static isc_result_t
   1386 configure_order(dns_order_t *order, const cfg_obj_t *ent) {
   1387 	dns_rdataclass_t rdclass;
   1388 	dns_rdatatype_t rdtype;
   1389 	const cfg_obj_t *obj;
   1390 	dns_fixedname_t fixed;
   1391 	unsigned int mode = 0;
   1392 	const char *str;
   1393 	isc_buffer_t b;
   1394 	isc_result_t result;
   1395 	bool addroot;
   1396 
   1397 	result = named_config_getclass(cfg_tuple_get(ent, "class"),
   1398 				       dns_rdataclass_any, &rdclass);
   1399 	if (result != ISC_R_SUCCESS) {
   1400 		return result;
   1401 	}
   1402 
   1403 	result = named_config_gettype(cfg_tuple_get(ent, "type"),
   1404 				      dns_rdatatype_any, &rdtype);
   1405 	if (result != ISC_R_SUCCESS) {
   1406 		return result;
   1407 	}
   1408 
   1409 	obj = cfg_tuple_get(ent, "name");
   1410 	if (cfg_obj_isstring(obj)) {
   1411 		str = cfg_obj_asstring(obj);
   1412 	} else {
   1413 		str = "*";
   1414 	}
   1415 	addroot = (strcmp(str, "*") == 0);
   1416 	isc_buffer_constinit(&b, str, strlen(str));
   1417 	isc_buffer_add(&b, strlen(str));
   1418 	dns_fixedname_init(&fixed);
   1419 	result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, dns_rootname,
   1420 				   0, NULL);
   1421 	if (result != ISC_R_SUCCESS) {
   1422 		return result;
   1423 	}
   1424 
   1425 	obj = cfg_tuple_get(ent, "ordering");
   1426 	INSIST(cfg_obj_isstring(obj));
   1427 	str = cfg_obj_asstring(obj);
   1428 	if (!strcasecmp(str, "fixed")) {
   1429 #if DNS_RDATASET_FIXED
   1430 		mode = DNS_RDATASETATTR_FIXEDORDER;
   1431 #else  /* if DNS_RDATASET_FIXED */
   1432 		mode = DNS_RDATASETATTR_CYCLIC;
   1433 #endif /* DNS_RDATASET_FIXED */
   1434 	} else if (!strcasecmp(str, "random")) {
   1435 		mode = DNS_RDATASETATTR_RANDOMIZE;
   1436 	} else if (!strcasecmp(str, "cyclic")) {
   1437 		mode = DNS_RDATASETATTR_CYCLIC;
   1438 	} else if (!strcasecmp(str, "none")) {
   1439 		mode = DNS_RDATASETATTR_NONE;
   1440 	} else {
   1441 		UNREACHABLE();
   1442 	}
   1443 
   1444 	/*
   1445 	 * "*" should match everything including the root (BIND 8 compat).
   1446 	 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
   1447 	 * explicit entry for "." when the name is "*".
   1448 	 */
   1449 	if (addroot) {
   1450 		result = dns_order_add(order, dns_rootname, rdtype, rdclass,
   1451 				       mode);
   1452 		if (result != ISC_R_SUCCESS) {
   1453 			return result;
   1454 		}
   1455 	}
   1456 
   1457 	return dns_order_add(order, dns_fixedname_name(&fixed), rdtype, rdclass,
   1458 			     mode);
   1459 }
   1460 
   1461 static isc_result_t
   1462 configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
   1463 	isc_netaddr_t na;
   1464 	dns_peer_t *peer;
   1465 	const cfg_obj_t *obj;
   1466 	const char *str;
   1467 	isc_result_t result;
   1468 	unsigned int prefixlen;
   1469 
   1470 	cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
   1471 
   1472 	peer = NULL;
   1473 	result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
   1474 	if (result != ISC_R_SUCCESS) {
   1475 		return result;
   1476 	}
   1477 
   1478 	obj = NULL;
   1479 	(void)cfg_map_get(cpeer, "bogus", &obj);
   1480 	if (obj != NULL) {
   1481 		CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
   1482 	}
   1483 
   1484 	obj = NULL;
   1485 	(void)cfg_map_get(cpeer, "provide-ixfr", &obj);
   1486 	if (obj != NULL) {
   1487 		CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
   1488 	}
   1489 
   1490 	obj = NULL;
   1491 	(void)cfg_map_get(cpeer, "request-expire", &obj);
   1492 	if (obj != NULL) {
   1493 		CHECK(dns_peer_setrequestexpire(peer, cfg_obj_asboolean(obj)));
   1494 	}
   1495 
   1496 	obj = NULL;
   1497 	(void)cfg_map_get(cpeer, "request-ixfr", &obj);
   1498 	if (obj != NULL) {
   1499 		CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
   1500 	}
   1501 
   1502 	obj = NULL;
   1503 	(void)cfg_map_get(cpeer, "request-nsid", &obj);
   1504 	if (obj != NULL) {
   1505 		CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
   1506 	}
   1507 
   1508 	obj = NULL;
   1509 	(void)cfg_map_get(cpeer, "send-cookie", &obj);
   1510 	if (obj != NULL) {
   1511 		CHECK(dns_peer_setsendcookie(peer, cfg_obj_asboolean(obj)));
   1512 	}
   1513 
   1514 	obj = NULL;
   1515 	(void)cfg_map_get(cpeer, "require-cookie", &obj);
   1516 	if (obj != NULL) {
   1517 		CHECK(dns_peer_setrequirecookie(peer, cfg_obj_asboolean(obj)));
   1518 	}
   1519 
   1520 	obj = NULL;
   1521 	(void)cfg_map_get(cpeer, "edns", &obj);
   1522 	if (obj != NULL) {
   1523 		CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
   1524 	}
   1525 
   1526 	obj = NULL;
   1527 	(void)cfg_map_get(cpeer, "edns-udp-size", &obj);
   1528 	if (obj != NULL) {
   1529 		uint32_t udpsize = cfg_obj_asuint32(obj);
   1530 		if (udpsize < 512U) {
   1531 			udpsize = 512U;
   1532 		}
   1533 		if (udpsize > 4096U) {
   1534 			udpsize = 4096U;
   1535 		}
   1536 		CHECK(dns_peer_setudpsize(peer, (uint16_t)udpsize));
   1537 	}
   1538 
   1539 	obj = NULL;
   1540 	(void)cfg_map_get(cpeer, "edns-version", &obj);
   1541 	if (obj != NULL) {
   1542 		uint32_t ednsversion = cfg_obj_asuint32(obj);
   1543 		if (ednsversion > 255U) {
   1544 			ednsversion = 255U;
   1545 		}
   1546 		CHECK(dns_peer_setednsversion(peer, (uint8_t)ednsversion));
   1547 	}
   1548 
   1549 	obj = NULL;
   1550 	(void)cfg_map_get(cpeer, "max-udp-size", &obj);
   1551 	if (obj != NULL) {
   1552 		uint32_t udpsize = cfg_obj_asuint32(obj);
   1553 		if (udpsize < 512U) {
   1554 			udpsize = 512U;
   1555 		}
   1556 		if (udpsize > 4096U) {
   1557 			udpsize = 4096U;
   1558 		}
   1559 		CHECK(dns_peer_setmaxudp(peer, (uint16_t)udpsize));
   1560 	}
   1561 
   1562 	obj = NULL;
   1563 	(void)cfg_map_get(cpeer, "padding", &obj);
   1564 	if (obj != NULL) {
   1565 		uint32_t padding = cfg_obj_asuint32(obj);
   1566 		if (padding > 512U) {
   1567 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   1568 				    "server padding value cannot "
   1569 				    "exceed 512: lowering");
   1570 			padding = 512U;
   1571 		}
   1572 		CHECK(dns_peer_setpadding(peer, (uint16_t)padding));
   1573 	}
   1574 
   1575 	obj = NULL;
   1576 	(void)cfg_map_get(cpeer, "tcp-only", &obj);
   1577 	if (obj != NULL) {
   1578 		CHECK(dns_peer_setforcetcp(peer, cfg_obj_asboolean(obj)));
   1579 	}
   1580 
   1581 	obj = NULL;
   1582 	(void)cfg_map_get(cpeer, "tcp-keepalive", &obj);
   1583 	if (obj != NULL) {
   1584 		CHECK(dns_peer_settcpkeepalive(peer, cfg_obj_asboolean(obj)));
   1585 	}
   1586 
   1587 	obj = NULL;
   1588 	(void)cfg_map_get(cpeer, "transfers", &obj);
   1589 	if (obj != NULL) {
   1590 		CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
   1591 	}
   1592 
   1593 	obj = NULL;
   1594 	(void)cfg_map_get(cpeer, "transfer-format", &obj);
   1595 	if (obj != NULL) {
   1596 		str = cfg_obj_asstring(obj);
   1597 		if (strcasecmp(str, "many-answers") == 0) {
   1598 			CHECK(dns_peer_settransferformat(peer,
   1599 							 dns_many_answers));
   1600 		} else if (strcasecmp(str, "one-answer") == 0) {
   1601 			CHECK(dns_peer_settransferformat(peer, dns_one_answer));
   1602 		} else {
   1603 			UNREACHABLE();
   1604 		}
   1605 	}
   1606 
   1607 	obj = NULL;
   1608 	(void)cfg_map_get(cpeer, "keys", &obj);
   1609 	if (obj != NULL) {
   1610 		result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
   1611 		if (result != ISC_R_SUCCESS) {
   1612 			goto cleanup;
   1613 		}
   1614 	}
   1615 
   1616 	obj = NULL;
   1617 	if (na.family == AF_INET) {
   1618 		(void)cfg_map_get(cpeer, "transfer-source", &obj);
   1619 	} else {
   1620 		(void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
   1621 	}
   1622 	if (obj != NULL) {
   1623 		result = dns_peer_settransfersource(peer,
   1624 						    cfg_obj_assockaddr(obj));
   1625 		if (result != ISC_R_SUCCESS) {
   1626 			goto cleanup;
   1627 		}
   1628 	}
   1629 
   1630 	obj = NULL;
   1631 	if (na.family == AF_INET) {
   1632 		(void)cfg_map_get(cpeer, "notify-source", &obj);
   1633 	} else {
   1634 		(void)cfg_map_get(cpeer, "notify-source-v6", &obj);
   1635 	}
   1636 	if (obj != NULL) {
   1637 		result = dns_peer_setnotifysource(peer,
   1638 						  cfg_obj_assockaddr(obj));
   1639 		if (result != ISC_R_SUCCESS) {
   1640 			goto cleanup;
   1641 		}
   1642 	}
   1643 
   1644 	obj = NULL;
   1645 	if (na.family == AF_INET) {
   1646 		(void)cfg_map_get(cpeer, "query-source", &obj);
   1647 	} else {
   1648 		(void)cfg_map_get(cpeer, "query-source-v6", &obj);
   1649 	}
   1650 	if (obj != NULL) {
   1651 		INSIST(cfg_obj_issockaddr(obj));
   1652 		result = dns_peer_setquerysource(peer, cfg_obj_assockaddr(obj));
   1653 		if (result != ISC_R_SUCCESS) {
   1654 			goto cleanup;
   1655 		}
   1656 	}
   1657 
   1658 	*peerp = peer;
   1659 	return ISC_R_SUCCESS;
   1660 
   1661 cleanup:
   1662 	dns_peer_detach(&peer);
   1663 	return result;
   1664 }
   1665 
   1666 static isc_result_t
   1667 configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx,
   1668 		const dns_dyndbctx_t *dctx) {
   1669 	isc_result_t result = ISC_R_SUCCESS;
   1670 	const cfg_obj_t *obj;
   1671 	const char *name, *library;
   1672 
   1673 	/* Get the name of the dyndb instance and the library path . */
   1674 	name = cfg_obj_asstring(cfg_tuple_get(dyndb, "name"));
   1675 	library = cfg_obj_asstring(cfg_tuple_get(dyndb, "library"));
   1676 
   1677 	obj = cfg_tuple_get(dyndb, "parameters");
   1678 	if (obj != NULL) {
   1679 		result = dns_dyndb_load(library, name, cfg_obj_asstring(obj),
   1680 					cfg_obj_file(obj), cfg_obj_line(obj),
   1681 					mctx, dctx);
   1682 	}
   1683 
   1684 	if (result != ISC_R_SUCCESS) {
   1685 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   1686 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   1687 			      "dynamic database '%s' configuration failed: %s",
   1688 			      name, isc_result_totext(result));
   1689 	}
   1690 	return result;
   1691 }
   1692 
   1693 static isc_result_t
   1694 disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
   1695 	isc_result_t result;
   1696 	const cfg_obj_t *algorithms;
   1697 	const cfg_listelt_t *element;
   1698 	const char *str;
   1699 	dns_fixedname_t fixed;
   1700 	dns_name_t *name;
   1701 	isc_buffer_t b;
   1702 
   1703 	name = dns_fixedname_initname(&fixed);
   1704 	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
   1705 	isc_buffer_constinit(&b, str, strlen(str));
   1706 	isc_buffer_add(&b, strlen(str));
   1707 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
   1708 
   1709 	algorithms = cfg_tuple_get(disabled, "algorithms");
   1710 	for (element = cfg_list_first(algorithms); element != NULL;
   1711 	     element = cfg_list_next(element))
   1712 	{
   1713 		isc_textregion_t r;
   1714 		dns_secalg_t alg;
   1715 
   1716 		r.base = UNCONST(cfg_obj_asstring(cfg_listelt_value(element)));
   1717 		r.length = strlen(r.base);
   1718 
   1719 		result = dns_secalg_fromtext(&alg, &r);
   1720 		if (result != ISC_R_SUCCESS) {
   1721 			uint8_t ui;
   1722 			result = isc_parse_uint8(&ui, r.base, 10);
   1723 			alg = ui;
   1724 		}
   1725 		if (result != ISC_R_SUCCESS) {
   1726 			cfg_obj_log(cfg_listelt_value(element), named_g_lctx,
   1727 				    ISC_LOG_ERROR, "invalid algorithm");
   1728 			CHECK(result);
   1729 		}
   1730 		CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
   1731 	}
   1732 cleanup:
   1733 	return result;
   1734 }
   1735 
   1736 static isc_result_t
   1737 disable_ds_digests(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
   1738 	isc_result_t result;
   1739 	const cfg_obj_t *digests;
   1740 	const cfg_listelt_t *element;
   1741 	const char *str;
   1742 	dns_fixedname_t fixed;
   1743 	dns_name_t *name;
   1744 	isc_buffer_t b;
   1745 
   1746 	name = dns_fixedname_initname(&fixed);
   1747 	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
   1748 	isc_buffer_constinit(&b, str, strlen(str));
   1749 	isc_buffer_add(&b, strlen(str));
   1750 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
   1751 
   1752 	digests = cfg_tuple_get(disabled, "digests");
   1753 	for (element = cfg_list_first(digests); element != NULL;
   1754 	     element = cfg_list_next(element))
   1755 	{
   1756 		isc_textregion_t r;
   1757 		dns_dsdigest_t digest;
   1758 
   1759 		r.base = UNCONST(cfg_obj_asstring(cfg_listelt_value(element)));
   1760 		r.length = strlen(r.base);
   1761 
   1762 		/* disable_ds_digests handles numeric values. */
   1763 		result = dns_dsdigest_fromtext(&digest, &r);
   1764 		if (result != ISC_R_SUCCESS) {
   1765 			cfg_obj_log(cfg_listelt_value(element), named_g_lctx,
   1766 				    ISC_LOG_ERROR, "invalid algorithm");
   1767 			CHECK(result);
   1768 		}
   1769 		CHECK(dns_resolver_disable_ds_digest(resolver, name, digest));
   1770 	}
   1771 cleanup:
   1772 	return result;
   1773 }
   1774 
   1775 static bool
   1776 on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
   1777 	const cfg_listelt_t *element;
   1778 	dns_fixedname_t fixed;
   1779 	dns_name_t *name;
   1780 	isc_result_t result;
   1781 	const cfg_obj_t *value;
   1782 	const char *str;
   1783 	isc_buffer_t b;
   1784 
   1785 	name = dns_fixedname_initname(&fixed);
   1786 
   1787 	for (element = cfg_list_first(disablelist); element != NULL;
   1788 	     element = cfg_list_next(element))
   1789 	{
   1790 		value = cfg_listelt_value(element);
   1791 		str = cfg_obj_asstring(value);
   1792 		isc_buffer_constinit(&b, str, strlen(str));
   1793 		isc_buffer_add(&b, strlen(str));
   1794 		result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
   1795 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1796 		if (dns_name_equal(name, zonename)) {
   1797 			return true;
   1798 		}
   1799 	}
   1800 	return false;
   1801 }
   1802 
   1803 static isc_result_t
   1804 check_dbtype(dns_zone_t *zone, unsigned int dbtypec, const char **dbargv,
   1805 	     isc_mem_t *mctx) {
   1806 	char **argv = NULL;
   1807 	unsigned int i;
   1808 	isc_result_t result = ISC_R_SUCCESS;
   1809 
   1810 	CHECK(dns_zone_getdbtype(zone, &argv, mctx));
   1811 
   1812 	/*
   1813 	 * Check that all the arguments match.
   1814 	 */
   1815 	for (i = 0; i < dbtypec; i++) {
   1816 		if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) {
   1817 			CHECK(ISC_R_FAILURE);
   1818 		}
   1819 	}
   1820 
   1821 	/*
   1822 	 * Check that there are not extra arguments.
   1823 	 */
   1824 	if (i == dbtypec && argv[i] != NULL) {
   1825 		result = ISC_R_FAILURE;
   1826 	}
   1827 
   1828 cleanup:
   1829 	isc_mem_free(mctx, argv);
   1830 	return result;
   1831 }
   1832 
   1833 static void
   1834 setquerystats(dns_zone_t *zone, isc_mem_t *mctx, dns_zonestat_level_t level) {
   1835 	isc_stats_t *zoneqrystats;
   1836 
   1837 	dns_zone_setstatlevel(zone, level);
   1838 
   1839 	zoneqrystats = NULL;
   1840 	if (level == dns_zonestat_full) {
   1841 		isc_stats_create(mctx, &zoneqrystats, ns_statscounter_max);
   1842 	}
   1843 	dns_zone_setrequeststats(zone, zoneqrystats);
   1844 	if (zoneqrystats != NULL) {
   1845 		isc_stats_detach(&zoneqrystats);
   1846 	}
   1847 }
   1848 
   1849 static named_cache_t *
   1850 cachelist_find(named_cachelist_t *cachelist, const char *cachename,
   1851 	       dns_rdataclass_t rdclass) {
   1852 	for (named_cache_t *nsc = ISC_LIST_HEAD(*cachelist); nsc != NULL;
   1853 	     nsc = ISC_LIST_NEXT(nsc, link))
   1854 	{
   1855 		if (nsc->rdclass == rdclass &&
   1856 		    strcmp(dns_cache_getname(nsc->cache), cachename) == 0)
   1857 		{
   1858 			return nsc;
   1859 		}
   1860 	}
   1861 
   1862 	return NULL;
   1863 }
   1864 
   1865 static bool
   1866 cache_reusable(dns_view_t *originview, dns_view_t *view,
   1867 	       bool new_zero_no_soattl) {
   1868 	if (originview->rdclass != view->rdclass ||
   1869 	    originview->checknames != view->checknames ||
   1870 	    originview->acceptexpired != view->acceptexpired ||
   1871 	    originview->enablevalidation != view->enablevalidation ||
   1872 	    originview->maxcachettl != view->maxcachettl ||
   1873 	    originview->maxncachettl != view->maxncachettl ||
   1874 	    originview->resolver == NULL ||
   1875 	    dns_resolver_getzeronosoattl(originview->resolver) !=
   1876 		    new_zero_no_soattl)
   1877 	{
   1878 		return false;
   1879 	}
   1880 
   1881 	return true;
   1882 }
   1883 
   1884 static bool
   1885 cache_sharable(dns_view_t *originview, dns_view_t *view,
   1886 	       bool new_zero_no_soattl, uint64_t new_max_cache_size,
   1887 	       uint32_t new_stale_ttl, uint32_t new_stale_refresh_time) {
   1888 	/*
   1889 	 * If the cache cannot even reused for the same view, it cannot be
   1890 	 * shared with other views.
   1891 	 */
   1892 	if (!cache_reusable(originview, view, new_zero_no_soattl)) {
   1893 		return false;
   1894 	}
   1895 
   1896 	/*
   1897 	 * Check other cache related parameters that must be consistent among
   1898 	 * the sharing views.
   1899 	 */
   1900 	if (dns_cache_getservestalettl(originview->cache) != new_stale_ttl ||
   1901 	    dns_cache_getservestalerefresh(originview->cache) !=
   1902 		    new_stale_refresh_time ||
   1903 	    dns_cache_getcachesize(originview->cache) != new_max_cache_size)
   1904 	{
   1905 		return false;
   1906 	}
   1907 
   1908 	return true;
   1909 }
   1910 
   1911 /*
   1912  * Callback from DLZ configure when the driver sets up a writeable zone
   1913  */
   1914 static isc_result_t
   1915 dlzconfigure_callback(dns_view_t *view, dns_dlzdb_t *dlzdb, dns_zone_t *zone) {
   1916 	dns_name_t *origin = dns_zone_getorigin(zone);
   1917 	dns_rdataclass_t zclass = view->rdclass;
   1918 	isc_result_t result;
   1919 
   1920 	result = dns_zonemgr_managezone(named_g_server->zonemgr, zone);
   1921 	if (result != ISC_R_SUCCESS) {
   1922 		return result;
   1923 	}
   1924 	dns_zone_setstats(zone, named_g_server->zonestats);
   1925 
   1926 	return named_zone_configure_writeable_dlz(dlzdb, zone, zclass, origin);
   1927 }
   1928 
   1929 static isc_result_t
   1930 dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na,
   1931 	      unsigned int prefixlen, const char *server, const char *contact) {
   1932 	char reverse[48 + sizeof("ip6.arpa.")] = { 0 };
   1933 	char buf[sizeof("x.x.")];
   1934 	const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." };
   1935 	const char *sep = ": view ";
   1936 	const char *viewname = view->name;
   1937 	const unsigned char *s6;
   1938 	dns_fixedname_t fixed;
   1939 	dns_name_t *name;
   1940 	dns_zone_t *zone = NULL;
   1941 	int dns64_dbtypec = 4;
   1942 	isc_buffer_t b;
   1943 	isc_result_t result;
   1944 
   1945 	REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
   1946 		prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
   1947 
   1948 	if (!strcmp(viewname, "_default")) {
   1949 		sep = "";
   1950 		viewname = "";
   1951 	}
   1952 
   1953 	/*
   1954 	 * Construct the reverse name of the zone.
   1955 	 */
   1956 	s6 = na->type.in6.s6_addr;
   1957 	while (prefixlen > 0) {
   1958 		prefixlen -= 8;
   1959 		snprintf(buf, sizeof(buf), "%x.%x.", s6[prefixlen / 8] & 0xf,
   1960 			 (s6[prefixlen / 8] >> 4) & 0xf);
   1961 		strlcat(reverse, buf, sizeof(reverse));
   1962 	}
   1963 	strlcat(reverse, "ip6.arpa.", sizeof(reverse));
   1964 
   1965 	/*
   1966 	 * Create the actual zone.
   1967 	 */
   1968 	if (server != NULL) {
   1969 		dns64_dbtype[2] = server;
   1970 	}
   1971 	if (contact != NULL) {
   1972 		dns64_dbtype[3] = contact;
   1973 	}
   1974 	name = dns_fixedname_initname(&fixed);
   1975 	isc_buffer_constinit(&b, reverse, strlen(reverse));
   1976 	isc_buffer_add(&b, strlen(reverse));
   1977 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
   1978 	dns_zone_create(&zone, mctx, 0);
   1979 	CHECK(dns_zone_setorigin(zone, name));
   1980 	dns_zone_setview(zone, view);
   1981 	CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
   1982 	dns_zone_setclass(zone, view->rdclass);
   1983 	dns_zone_settype(zone, dns_zone_primary);
   1984 	dns_zone_setstats(zone, named_g_server->zonestats);
   1985 	dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype);
   1986 	if (view->queryacl != NULL) {
   1987 		dns_zone_setqueryacl(zone, view->queryacl);
   1988 	}
   1989 	if (view->queryonacl != NULL) {
   1990 		dns_zone_setqueryonacl(zone, view->queryonacl);
   1991 	}
   1992 	dns_zone_setdialup(zone, dns_dialuptype_no);
   1993 	dns_zone_setcheckdstype(zone, dns_checkdstype_no);
   1994 	dns_zone_setnotifytype(zone, dns_notifytype_no);
   1995 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
   1996 	setquerystats(zone, mctx, dns_zonestat_none);
   1997 	CHECK(dns_view_addzone(view, zone));
   1998 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   1999 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   2000 		      "dns64 reverse zone%s%s: %s", sep, viewname, reverse);
   2001 
   2002 cleanup:
   2003 	if (zone != NULL) {
   2004 		dns_zone_detach(&zone);
   2005 	}
   2006 	return result;
   2007 }
   2008 
   2009 #ifdef USE_DNSRPS
   2010 typedef struct conf_dnsrps_ctx conf_dnsrps_ctx_t;
   2011 struct conf_dnsrps_ctx {
   2012 	isc_result_t result;
   2013 	char *cstr;
   2014 	size_t cstr_size;
   2015 	isc_mem_t *mctx;
   2016 };
   2017 
   2018 /*
   2019  * Add to the DNSRPS configuration string.
   2020  */
   2021 static bool
   2022 conf_dnsrps_sadd(conf_dnsrps_ctx_t *ctx, const char *p, ...) {
   2023 	size_t new_len, cur_len, new_cstr_size;
   2024 	char *new_cstr;
   2025 	va_list args;
   2026 
   2027 	if (ctx->cstr == NULL) {
   2028 		ctx->cstr = isc_mem_get(ctx->mctx, 256);
   2029 		ctx->cstr[0] = '\0';
   2030 		ctx->cstr_size = 256;
   2031 	}
   2032 
   2033 	cur_len = strlen(ctx->cstr);
   2034 	va_start(args, p);
   2035 	new_len = vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p,
   2036 			    args) +
   2037 		  1;
   2038 	va_end(args);
   2039 
   2040 	if (cur_len + new_len <= ctx->cstr_size) {
   2041 		return true;
   2042 	}
   2043 
   2044 	new_cstr_size = ((cur_len + new_len) / 256 + 1) * 256;
   2045 	new_cstr = isc_mem_get(ctx->mctx, new_cstr_size);
   2046 
   2047 	memmove(new_cstr, ctx->cstr, cur_len);
   2048 	isc_mem_put(ctx->mctx, ctx->cstr, ctx->cstr_size);
   2049 	ctx->cstr_size = new_cstr_size;
   2050 	ctx->cstr = new_cstr;
   2051 
   2052 	/* cannot use args twice after a single va_start()on some systems */
   2053 	va_start(args, p);
   2054 	vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p, args);
   2055 	va_end(args);
   2056 	return true;
   2057 }
   2058 
   2059 /*
   2060  * Get a DNSRPS configuration value using the global and view options
   2061  * for the default.  Return false upon failure.
   2062  */
   2063 static bool
   2064 conf_dnsrps_get(const cfg_obj_t **sub_obj, const cfg_obj_t **maps,
   2065 		const cfg_obj_t *obj, const char *name,
   2066 		conf_dnsrps_ctx_t *ctx) {
   2067 	if (ctx != NULL && ctx->result != ISC_R_SUCCESS) {
   2068 		*sub_obj = NULL;
   2069 		return false;
   2070 	}
   2071 
   2072 	*sub_obj = cfg_tuple_get(obj, name);
   2073 	if (cfg_obj_isvoid(*sub_obj)) {
   2074 		*sub_obj = NULL;
   2075 		if (maps != NULL &&
   2076 		    ISC_R_SUCCESS != named_config_get(maps, name, sub_obj))
   2077 		{
   2078 			*sub_obj = NULL;
   2079 		}
   2080 	}
   2081 	return true;
   2082 }
   2083 
   2084 /*
   2085  * Handle a DNSRPS boolean configuration value with the global and view
   2086  * options providing the default.
   2087  */
   2088 static void
   2089 conf_dnsrps_yes_no(const cfg_obj_t *obj, const char *name,
   2090 		   conf_dnsrps_ctx_t *ctx) {
   2091 	const cfg_obj_t *sub_obj;
   2092 
   2093 	if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) {
   2094 		return;
   2095 	}
   2096 	if (sub_obj == NULL) {
   2097 		return;
   2098 	}
   2099 	if (ctx == NULL) {
   2100 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
   2101 			    "\"%s\" without \"dnsrps-enable yes\"", name);
   2102 		return;
   2103 	}
   2104 
   2105 	conf_dnsrps_sadd(ctx, " %s %s", name,
   2106 			 cfg_obj_asboolean(sub_obj) ? "yes" : "no");
   2107 }
   2108 
   2109 static void
   2110 conf_dnsrps_num(const cfg_obj_t *obj, const char *name,
   2111 		conf_dnsrps_ctx_t *ctx) {
   2112 	const cfg_obj_t *sub_obj;
   2113 
   2114 	if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) {
   2115 		return;
   2116 	}
   2117 	if (sub_obj == NULL) {
   2118 		return;
   2119 	}
   2120 	if (ctx == NULL) {
   2121 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
   2122 			    "\"%s\" without \"dnsrps-enable yes\"", name);
   2123 		return;
   2124 	}
   2125 
   2126 	if (cfg_obj_isduration(sub_obj)) {
   2127 		conf_dnsrps_sadd(ctx, " %s %d", name,
   2128 				 cfg_obj_asduration(sub_obj));
   2129 	} else {
   2130 		conf_dnsrps_sadd(ctx, " %s %d", name,
   2131 				 cfg_obj_asuint32(sub_obj));
   2132 	}
   2133 }
   2134 
   2135 /*
   2136  * Convert the parsed RPZ configuration statement to a string for
   2137  * dns_rpz_new_zones().
   2138  */
   2139 static isc_result_t
   2140 conf_dnsrps(dns_view_t *view, const cfg_obj_t **maps, bool nsip_enabled,
   2141 	    bool nsdname_enabled, dns_rpz_zbits_t *nsip_on,
   2142 	    dns_rpz_zbits_t *nsdname_on, char **rps_cstr, size_t *rps_cstr_size,
   2143 	    const cfg_obj_t *rpz_obj, const cfg_listelt_t *zone_element) {
   2144 	conf_dnsrps_ctx_t ctx;
   2145 	const cfg_obj_t *zone_obj, *obj;
   2146 	dns_rpz_num_t rpz_num;
   2147 	bool on;
   2148 	const char *s;
   2149 
   2150 	memset(&ctx, 0, sizeof(ctx));
   2151 	ctx.result = ISC_R_SUCCESS;
   2152 	ctx.mctx = view->mctx;
   2153 
   2154 	for (rpz_num = 0; zone_element != NULL && ctx.result == ISC_R_SUCCESS;
   2155 	     ++rpz_num)
   2156 	{
   2157 		zone_obj = cfg_listelt_value(zone_element);
   2158 
   2159 		s = cfg_obj_asstring(cfg_tuple_get(zone_obj, "zone name"));
   2160 		conf_dnsrps_sadd(&ctx, "zone \"%s\"", s);
   2161 
   2162 		obj = cfg_tuple_get(zone_obj, "policy");
   2163 		if (!cfg_obj_isvoid(obj)) {
   2164 			s = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
   2165 			conf_dnsrps_sadd(&ctx, " policy %s", s);
   2166 			if (strcasecmp(s, "cname") == 0) {
   2167 				s = cfg_obj_asstring(
   2168 					cfg_tuple_get(obj, "cname"));
   2169 				conf_dnsrps_sadd(&ctx, " %s", s);
   2170 			}
   2171 		}
   2172 
   2173 		conf_dnsrps_yes_no(zone_obj, "recursive-only", &ctx);
   2174 		conf_dnsrps_yes_no(zone_obj, "log", &ctx);
   2175 		conf_dnsrps_num(zone_obj, "max-policy-ttl", &ctx);
   2176 		obj = cfg_tuple_get(rpz_obj, "nsip-enable");
   2177 		if (!cfg_obj_isvoid(obj)) {
   2178 			if (cfg_obj_asboolean(obj)) {
   2179 				*nsip_on |= DNS_RPZ_ZBIT(rpz_num);
   2180 			} else {
   2181 				*nsip_on &= ~DNS_RPZ_ZBIT(rpz_num);
   2182 			}
   2183 		}
   2184 		on = ((*nsip_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
   2185 		if (nsip_enabled != on) {
   2186 			conf_dnsrps_sadd(&ctx, on ? " nsip-enable yes "
   2187 						  : " nsip-enable no ");
   2188 		}
   2189 		obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
   2190 		if (!cfg_obj_isvoid(obj)) {
   2191 			if (cfg_obj_asboolean(obj)) {
   2192 				*nsdname_on |= DNS_RPZ_ZBIT(rpz_num);
   2193 			} else {
   2194 				*nsdname_on &= ~DNS_RPZ_ZBIT(rpz_num);
   2195 			}
   2196 		}
   2197 		on = ((*nsdname_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
   2198 		if (nsdname_enabled != on) {
   2199 			conf_dnsrps_sadd(&ctx, on ? " nsdname-enable yes "
   2200 						  : " nsdname-enable no ");
   2201 		}
   2202 		conf_dnsrps_sadd(&ctx, ";\n");
   2203 		zone_element = cfg_list_next(zone_element);
   2204 	}
   2205 
   2206 	conf_dnsrps_yes_no(rpz_obj, "recursive-only", &ctx);
   2207 	conf_dnsrps_num(rpz_obj, "max-policy-ttl", &ctx);
   2208 	conf_dnsrps_num(rpz_obj, "min-ns-dots", &ctx);
   2209 	conf_dnsrps_yes_no(rpz_obj, "qname-wait-recurse", &ctx);
   2210 	conf_dnsrps_yes_no(rpz_obj, "break-dnssec", &ctx);
   2211 	if (!nsip_enabled) {
   2212 		conf_dnsrps_sadd(&ctx, " nsip-enable no ");
   2213 	}
   2214 	if (!nsdname_enabled) {
   2215 		conf_dnsrps_sadd(&ctx, " nsdname-enable no ");
   2216 	}
   2217 
   2218 	/*
   2219 	 * Get the general dnsrpzd parameters from the response-policy
   2220 	 * statement in the view and the general options.
   2221 	 */
   2222 	if (conf_dnsrps_get(&obj, maps, rpz_obj, "dnsrps-options", &ctx) &&
   2223 	    obj != NULL)
   2224 	{
   2225 		conf_dnsrps_sadd(&ctx, " %s\n", cfg_obj_asstring(obj));
   2226 	}
   2227 
   2228 	if (ctx.result == ISC_R_SUCCESS) {
   2229 		*rps_cstr = ctx.cstr;
   2230 		*rps_cstr_size = ctx.cstr_size;
   2231 	} else {
   2232 		if (ctx.cstr != NULL) {
   2233 			isc_mem_put(ctx.mctx, ctx.cstr, ctx.cstr_size);
   2234 		}
   2235 		*rps_cstr = NULL;
   2236 		*rps_cstr_size = 0;
   2237 	}
   2238 	return ctx.result;
   2239 }
   2240 #endif /* ifdef USE_DNSRPS */
   2241 
   2242 static isc_result_t
   2243 configure_rpz_name(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
   2244 		   const char *str, const char *msg) {
   2245 	isc_result_t result;
   2246 
   2247 	result = dns_name_fromstring(name, str, dns_rootname, DNS_NAME_DOWNCASE,
   2248 				     view->mctx);
   2249 	if (result != ISC_R_SUCCESS) {
   2250 		cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
   2251 			    "invalid %s '%s'", msg, str);
   2252 	}
   2253 	return result;
   2254 }
   2255 
   2256 static isc_result_t
   2257 configure_rpz_name2(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
   2258 		    const char *str, const dns_name_t *origin) {
   2259 	isc_result_t result;
   2260 
   2261 	result = dns_name_fromstring(name, str, origin, DNS_NAME_DOWNCASE,
   2262 				     view->mctx);
   2263 	if (result != ISC_R_SUCCESS) {
   2264 		cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
   2265 			    "invalid zone '%s'", str);
   2266 	}
   2267 	return result;
   2268 }
   2269 
   2270 static isc_result_t
   2271 configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element,
   2272 		   bool recursive_only_default, bool add_soa_default,
   2273 		   dns_ttl_t ttl_default, uint32_t minupdateinterval_default,
   2274 		   const dns_rpz_zone_t *old, bool *old_rpz_okp) {
   2275 	const cfg_obj_t *rpz_obj, *obj;
   2276 	const char *str;
   2277 	dns_rpz_zone_t *zone = NULL;
   2278 	isc_result_t result;
   2279 	dns_rpz_num_t rpz_num;
   2280 
   2281 	REQUIRE(old != NULL || !*old_rpz_okp);
   2282 
   2283 	rpz_obj = cfg_listelt_value(element);
   2284 
   2285 	if (view->rpzs->p.num_zones >= DNS_RPZ_MAX_ZONES) {
   2286 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
   2287 			    "limit of %d response policy zones exceeded",
   2288 			    DNS_RPZ_MAX_ZONES);
   2289 		return ISC_R_FAILURE;
   2290 	}
   2291 
   2292 	result = dns_rpz_new_zone(view->rpzs, &zone);
   2293 	if (result != ISC_R_SUCCESS) {
   2294 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
   2295 			    "Error creating new RPZ zone : %s",
   2296 			    isc_result_totext(result));
   2297 		return result;
   2298 	}
   2299 
   2300 	obj = cfg_tuple_get(rpz_obj, "recursive-only");
   2301 	if (cfg_obj_isvoid(obj) ? recursive_only_default
   2302 				: cfg_obj_asboolean(obj))
   2303 	{
   2304 		view->rpzs->p.no_rd_ok &= ~DNS_RPZ_ZBIT(zone->num);
   2305 	} else {
   2306 		view->rpzs->p.no_rd_ok |= DNS_RPZ_ZBIT(zone->num);
   2307 	}
   2308 
   2309 	obj = cfg_tuple_get(rpz_obj, "log");
   2310 	if (!cfg_obj_isvoid(obj) && !cfg_obj_asboolean(obj)) {
   2311 		view->rpzs->p.no_log |= DNS_RPZ_ZBIT(zone->num);
   2312 	} else {
   2313 		view->rpzs->p.no_log &= ~DNS_RPZ_ZBIT(zone->num);
   2314 	}
   2315 
   2316 	obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
   2317 	if (cfg_obj_isduration(obj)) {
   2318 		zone->max_policy_ttl = cfg_obj_asduration(obj);
   2319 	} else {
   2320 		zone->max_policy_ttl = ttl_default;
   2321 	}
   2322 	if (*old_rpz_okp && zone->max_policy_ttl != old->max_policy_ttl) {
   2323 		*old_rpz_okp = false;
   2324 	}
   2325 
   2326 	obj = cfg_tuple_get(rpz_obj, "min-update-interval");
   2327 	if (cfg_obj_isduration(obj)) {
   2328 		zone->min_update_interval = cfg_obj_asduration(obj);
   2329 	} else {
   2330 		zone->min_update_interval = minupdateinterval_default;
   2331 	}
   2332 	if (*old_rpz_okp &&
   2333 	    zone->min_update_interval != old->min_update_interval)
   2334 	{
   2335 		*old_rpz_okp = false;
   2336 	}
   2337 
   2338 	str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name"));
   2339 	result = configure_rpz_name(view, rpz_obj, &zone->origin, str, "zone");
   2340 	if (result != ISC_R_SUCCESS) {
   2341 		return result;
   2342 	}
   2343 	if (dns_name_equal(&zone->origin, dns_rootname)) {
   2344 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
   2345 			    "invalid zone name '%s'", str);
   2346 		return DNS_R_EMPTYLABEL;
   2347 	}
   2348 	if (!view->rpzs->p.dnsrps_enabled) {
   2349 		for (rpz_num = 0; rpz_num < view->rpzs->p.num_zones - 1;
   2350 		     ++rpz_num)
   2351 		{
   2352 			if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin,
   2353 					   &zone->origin))
   2354 			{
   2355 				cfg_obj_log(rpz_obj, named_g_lctx,
   2356 					    DNS_RPZ_ERROR_LEVEL,
   2357 					    "duplicate '%s'", str);
   2358 				result = DNS_R_DUPLICATE;
   2359 				return result;
   2360 			}
   2361 		}
   2362 	}
   2363 	if (*old_rpz_okp && !dns_name_equal(&old->origin, &zone->origin)) {
   2364 		*old_rpz_okp = false;
   2365 	}
   2366 
   2367 	result = configure_rpz_name2(view, rpz_obj, &zone->client_ip,
   2368 				     DNS_RPZ_CLIENT_IP_ZONE, &zone->origin);
   2369 	if (result != ISC_R_SUCCESS) {
   2370 		return result;
   2371 	}
   2372 
   2373 	result = configure_rpz_name2(view, rpz_obj, &zone->ip, DNS_RPZ_IP_ZONE,
   2374 				     &zone->origin);
   2375 	if (result != ISC_R_SUCCESS) {
   2376 		return result;
   2377 	}
   2378 
   2379 	result = configure_rpz_name2(view, rpz_obj, &zone->nsdname,
   2380 				     DNS_RPZ_NSDNAME_ZONE, &zone->origin);
   2381 	if (result != ISC_R_SUCCESS) {
   2382 		return result;
   2383 	}
   2384 
   2385 	result = configure_rpz_name2(view, rpz_obj, &zone->nsip,
   2386 				     DNS_RPZ_NSIP_ZONE, &zone->origin);
   2387 	if (result != ISC_R_SUCCESS) {
   2388 		return result;
   2389 	}
   2390 
   2391 	result = configure_rpz_name(view, rpz_obj, &zone->passthru,
   2392 				    DNS_RPZ_PASSTHRU_NAME, "name");
   2393 	if (result != ISC_R_SUCCESS) {
   2394 		return result;
   2395 	}
   2396 
   2397 	result = configure_rpz_name(view, rpz_obj, &zone->drop,
   2398 				    DNS_RPZ_DROP_NAME, "name");
   2399 	if (result != ISC_R_SUCCESS) {
   2400 		return result;
   2401 	}
   2402 
   2403 	result = configure_rpz_name(view, rpz_obj, &zone->tcp_only,
   2404 				    DNS_RPZ_TCP_ONLY_NAME, "name");
   2405 	if (result != ISC_R_SUCCESS) {
   2406 		return result;
   2407 	}
   2408 
   2409 	obj = cfg_tuple_get(rpz_obj, "policy");
   2410 	if (cfg_obj_isvoid(obj)) {
   2411 		zone->policy = DNS_RPZ_POLICY_GIVEN;
   2412 	} else {
   2413 		str = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
   2414 		zone->policy = dns_rpz_str2policy(str);
   2415 		INSIST(zone->policy != DNS_RPZ_POLICY_ERROR);
   2416 		if (zone->policy == DNS_RPZ_POLICY_CNAME) {
   2417 			str = cfg_obj_asstring(cfg_tuple_get(obj, "cname"));
   2418 			result = configure_rpz_name(view, rpz_obj, &zone->cname,
   2419 						    str, "cname");
   2420 			if (result != ISC_R_SUCCESS) {
   2421 				return result;
   2422 			}
   2423 		}
   2424 	}
   2425 	if (*old_rpz_okp && (zone->policy != old->policy ||
   2426 			     !dns_name_equal(&old->cname, &zone->cname)))
   2427 	{
   2428 		*old_rpz_okp = false;
   2429 	}
   2430 
   2431 	obj = cfg_tuple_get(rpz_obj, "ede");
   2432 	if (!cfg_obj_isstring(obj)) {
   2433 		zone->ede = 0;
   2434 	} else {
   2435 		str = cfg_obj_asstring(obj);
   2436 		zone->ede = dns_rpz_str2ede(str);
   2437 		INSIST(zone->ede != UINT16_MAX);
   2438 	}
   2439 	if (*old_rpz_okp && zone->ede != old->ede) {
   2440 		*old_rpz_okp = false;
   2441 	}
   2442 
   2443 	obj = cfg_tuple_get(rpz_obj, "add-soa");
   2444 	if (cfg_obj_isvoid(obj)) {
   2445 		zone->addsoa = add_soa_default;
   2446 	} else {
   2447 		zone->addsoa = cfg_obj_asboolean(obj);
   2448 	}
   2449 	if (*old_rpz_okp && zone->addsoa != old->addsoa) {
   2450 		*old_rpz_okp = false;
   2451 	}
   2452 
   2453 	return ISC_R_SUCCESS;
   2454 }
   2455 
   2456 static isc_result_t
   2457 configure_rpz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t **maps,
   2458 	      const cfg_obj_t *rpz_obj, bool *old_rpz_okp, bool first_time) {
   2459 	bool dnsrps_enabled;
   2460 	const cfg_listelt_t *zone_element;
   2461 	char *rps_cstr;
   2462 	size_t rps_cstr_size;
   2463 	const cfg_obj_t *sub_obj;
   2464 	bool recursive_only_default, add_soa_default;
   2465 	bool nsip_enabled, nsdname_enabled;
   2466 	dns_rpz_zbits_t nsip_on, nsdname_on;
   2467 	dns_ttl_t ttl_default;
   2468 	uint32_t minupdateinterval_default;
   2469 	dns_rpz_zones_t *zones;
   2470 	const dns_rpz_zones_t *old;
   2471 	bool pview_must_detach = false;
   2472 	const dns_rpz_zone_t *old_zone;
   2473 	isc_result_t result;
   2474 	int i;
   2475 
   2476 	*old_rpz_okp = false;
   2477 
   2478 	zone_element = cfg_list_first(cfg_tuple_get(rpz_obj, "zone list"));
   2479 	if (zone_element == NULL) {
   2480 		return ISC_R_SUCCESS;
   2481 	}
   2482 
   2483 	nsip_enabled = true;
   2484 	sub_obj = cfg_tuple_get(rpz_obj, "nsip-enable");
   2485 	if (!cfg_obj_isvoid(sub_obj)) {
   2486 		nsip_enabled = cfg_obj_asboolean(sub_obj);
   2487 	}
   2488 	nsip_on = nsip_enabled ? DNS_RPZ_ALL_ZBITS : 0;
   2489 
   2490 	nsdname_enabled = true;
   2491 	sub_obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
   2492 	if (!cfg_obj_isvoid(sub_obj)) {
   2493 		nsdname_enabled = cfg_obj_asboolean(sub_obj);
   2494 	}
   2495 	nsdname_on = nsdname_enabled ? DNS_RPZ_ALL_ZBITS : 0;
   2496 
   2497 	/*
   2498 	 * "dnsrps-enable yes|no" can be either a global or response-policy
   2499 	 * clause.
   2500 	 */
   2501 	dnsrps_enabled = false;
   2502 	rps_cstr = NULL;
   2503 	rps_cstr_size = 0;
   2504 	sub_obj = NULL;
   2505 	(void)named_config_get(maps, "dnsrps-enable", &sub_obj);
   2506 	if (sub_obj != NULL) {
   2507 		dnsrps_enabled = cfg_obj_asboolean(sub_obj);
   2508 	}
   2509 	sub_obj = cfg_tuple_get(rpz_obj, "dnsrps-enable");
   2510 	if (!cfg_obj_isvoid(sub_obj)) {
   2511 		dnsrps_enabled = cfg_obj_asboolean(sub_obj);
   2512 	}
   2513 #ifndef USE_DNSRPS
   2514 	if (dnsrps_enabled) {
   2515 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
   2516 			    "\"dnsrps-enable yes\" but"
   2517 			    " without `./configure --enable-dnsrps`");
   2518 		return ISC_R_FAILURE;
   2519 	}
   2520 #else  /* ifndef USE_DNSRPS */
   2521 	if (dnsrps_enabled) {
   2522 		if (librpz == NULL) {
   2523 			cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
   2524 				    "\"dnsrps-enable yes\" but %s",
   2525 				    librpz_lib_open_emsg.c);
   2526 			return ISC_R_FAILURE;
   2527 		}
   2528 
   2529 		/*
   2530 		 * Generate the DNS Response Policy Service
   2531 		 * configuration string.
   2532 		 */
   2533 		result = conf_dnsrps(view, maps, nsip_enabled, nsdname_enabled,
   2534 				     &nsip_on, &nsdname_on, &rps_cstr,
   2535 				     &rps_cstr_size, rpz_obj, zone_element);
   2536 		if (result != ISC_R_SUCCESS) {
   2537 			return result;
   2538 		}
   2539 	}
   2540 #endif /* ifndef USE_DNSRPS */
   2541 
   2542 	result = dns_rpz_new_zones(view, named_g_loopmgr, rps_cstr,
   2543 				   rps_cstr_size, &view->rpzs, first_time);
   2544 	if (result != ISC_R_SUCCESS) {
   2545 		return result;
   2546 	}
   2547 
   2548 	zones = view->rpzs;
   2549 
   2550 	zones->p.nsip_on = nsip_on;
   2551 	zones->p.nsdname_on = nsdname_on;
   2552 	zones->p.slow_mode = ns_server_getoption(named_g_server->sctx,
   2553 						 NS_SERVER_RPZSLOW);
   2554 
   2555 	sub_obj = cfg_tuple_get(rpz_obj, "recursive-only");
   2556 	if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
   2557 		recursive_only_default = false;
   2558 	} else {
   2559 		recursive_only_default = true;
   2560 	}
   2561 
   2562 	sub_obj = cfg_tuple_get(rpz_obj, "add-soa");
   2563 	if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
   2564 		add_soa_default = false;
   2565 	} else {
   2566 		add_soa_default = true;
   2567 	}
   2568 
   2569 	sub_obj = cfg_tuple_get(rpz_obj, "break-dnssec");
   2570 	if (!cfg_obj_isvoid(sub_obj) && cfg_obj_asboolean(sub_obj)) {
   2571 		zones->p.break_dnssec = true;
   2572 	} else {
   2573 		zones->p.break_dnssec = false;
   2574 	}
   2575 
   2576 	sub_obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
   2577 	if (cfg_obj_isduration(sub_obj)) {
   2578 		ttl_default = cfg_obj_asduration(sub_obj);
   2579 	} else {
   2580 		ttl_default = DNS_RPZ_MAX_TTL_DEFAULT;
   2581 	}
   2582 
   2583 	sub_obj = cfg_tuple_get(rpz_obj, "min-update-interval");
   2584 	if (cfg_obj_isduration(sub_obj)) {
   2585 		minupdateinterval_default = cfg_obj_asduration(sub_obj);
   2586 	} else {
   2587 		minupdateinterval_default = DNS_RPZ_MINUPDATEINTERVAL_DEFAULT;
   2588 	}
   2589 
   2590 	sub_obj = cfg_tuple_get(rpz_obj, "min-ns-dots");
   2591 	if (cfg_obj_isuint32(sub_obj)) {
   2592 		zones->p.min_ns_labels = cfg_obj_asuint32(sub_obj) + 1;
   2593 	} else {
   2594 		zones->p.min_ns_labels = 2;
   2595 	}
   2596 
   2597 	sub_obj = cfg_tuple_get(rpz_obj, "qname-wait-recurse");
   2598 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
   2599 		zones->p.qname_wait_recurse = true;
   2600 	} else {
   2601 		zones->p.qname_wait_recurse = false;
   2602 	}
   2603 
   2604 	sub_obj = cfg_tuple_get(rpz_obj, "nsdname-wait-recurse");
   2605 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
   2606 		zones->p.nsdname_wait_recurse = true;
   2607 	} else {
   2608 		zones->p.nsdname_wait_recurse = false;
   2609 	}
   2610 
   2611 	sub_obj = cfg_tuple_get(rpz_obj, "nsip-wait-recurse");
   2612 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
   2613 		zones->p.nsip_wait_recurse = true;
   2614 	} else {
   2615 		zones->p.nsip_wait_recurse = false;
   2616 	}
   2617 
   2618 	sub_obj = cfg_tuple_get(rpz_obj, "servfail-until-ready");
   2619 	if (!cfg_obj_isvoid(sub_obj) && cfg_obj_asboolean(sub_obj)) {
   2620 		zones->p.servfail_until_ready = true;
   2621 	} else {
   2622 		zones->p.servfail_until_ready = false;
   2623 	}
   2624 
   2625 	if (dnsrps_enabled && zones->p.servfail_until_ready) {
   2626 		zones->p.servfail_until_ready = false;
   2627 		cfg_obj_log(rpz_obj, named_g_lctx, ISC_LOG_WARNING,
   2628 			    "\"servfail-until-ready yes\" has no effect when "
   2629 			    "used with \"dnsrps-enable yes\"");
   2630 	}
   2631 
   2632 	if (pview != NULL) {
   2633 		old = pview->rpzs;
   2634 	} else {
   2635 		result = dns_viewlist_find(&named_g_server->viewlist,
   2636 					   view->name, view->rdclass, &pview);
   2637 		if (result == ISC_R_SUCCESS) {
   2638 			pview_must_detach = true;
   2639 			old = pview->rpzs;
   2640 		} else {
   2641 			old = NULL;
   2642 		}
   2643 	}
   2644 
   2645 	if (old == NULL) {
   2646 		*old_rpz_okp = false;
   2647 	} else {
   2648 		*old_rpz_okp = true;
   2649 	}
   2650 
   2651 	for (i = 0; zone_element != NULL;
   2652 	     ++i, zone_element = cfg_list_next(zone_element))
   2653 	{
   2654 		INSIST(!*old_rpz_okp || old != NULL);
   2655 		if (*old_rpz_okp && i < old->p.num_zones) {
   2656 			old_zone = old->zones[i];
   2657 		} else {
   2658 			*old_rpz_okp = false;
   2659 			old_zone = NULL;
   2660 		}
   2661 		result = configure_rpz_zone(
   2662 			view, zone_element, recursive_only_default,
   2663 			add_soa_default, ttl_default, minupdateinterval_default,
   2664 			old_zone, old_rpz_okp);
   2665 		if (result != ISC_R_SUCCESS) {
   2666 			if (pview_must_detach) {
   2667 				dns_view_detach(&pview);
   2668 			}
   2669 			return result;
   2670 		}
   2671 	}
   2672 
   2673 	/*
   2674 	 * If this is a reloading and the parameters and list of policy
   2675 	 * zones are unchanged, then use the same policy data.
   2676 	 * Data for individual zones that must be reloaded will be merged.
   2677 	 */
   2678 	if (*old_rpz_okp) {
   2679 		if (old != NULL &&
   2680 		    memcmp(&old->p, &zones->p, sizeof(zones->p)) != 0)
   2681 		{
   2682 			*old_rpz_okp = false;
   2683 		} else if ((old == NULL || old->rps_cstr == NULL) !=
   2684 			   (zones->rps_cstr == NULL))
   2685 		{
   2686 			*old_rpz_okp = false;
   2687 		} else if (old != NULL && zones->rps_cstr != NULL &&
   2688 			   strcmp(old->rps_cstr, zones->rps_cstr) != 0)
   2689 		{
   2690 			*old_rpz_okp = false;
   2691 		}
   2692 	}
   2693 
   2694 	if (*old_rpz_okp) {
   2695 		INSIST(pview->rpzs != NULL);
   2696 
   2697 		/* Discard the newly created rpzs. */
   2698 		dns_rpz_zones_shutdown(view->rpzs);
   2699 		dns_rpz_zones_detach(&view->rpzs);
   2700 
   2701 		/*
   2702 		 * We are reusing the old rpzs, so it can no longer be its
   2703 		 * first time.
   2704 		 */
   2705 		pview->rpzs->first_time = false;
   2706 
   2707 		/* Reuse rpzs from the old view. */
   2708 		dns_rpz_zones_attach(pview->rpzs, &view->rpzs);
   2709 		dns_rpz_zones_detach(&pview->rpzs);
   2710 	} else if (old != NULL && pview != NULL) {
   2711 		INSIST(pview->rpzs != NULL);
   2712 
   2713 		++pview->rpzs->rpz_ver;
   2714 		view->rpzs->rpz_ver = pview->rpzs->rpz_ver;
   2715 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_DEBUG_LEVEL1,
   2716 			    "updated RPZ policy: version %d",
   2717 			    view->rpzs->rpz_ver);
   2718 	}
   2719 
   2720 	if (pview_must_detach) {
   2721 		dns_view_detach(&pview);
   2722 	}
   2723 
   2724 	return ISC_R_SUCCESS;
   2725 }
   2726 
   2727 static void
   2728 catz_addmodzone_cb(void *arg) {
   2729 	catz_chgzone_t *cz = (catz_chgzone_t *)arg;
   2730 	isc_result_t result;
   2731 	dns_forwarders_t *dnsforwarders = NULL;
   2732 	dns_name_t *name = NULL;
   2733 	isc_buffer_t namebuf;
   2734 	isc_buffer_t *confbuf = NULL;
   2735 	char nameb[DNS_NAME_FORMATSIZE];
   2736 	const cfg_obj_t *zlist = NULL;
   2737 	cfg_obj_t *zoneconf = NULL;
   2738 	cfg_obj_t *zoneobj = NULL;
   2739 	ns_cfgctx_t *cfg = NULL;
   2740 	dns_zone_t *zone = NULL;
   2741 
   2742 	if (isc_loop_shuttingdown(isc_loop_get(named_g_loopmgr, isc_tid()))) {
   2743 		goto cleanup;
   2744 	}
   2745 
   2746 	/*
   2747 	 * A non-empty 'catalog-zones' statement implies that 'allow-new-zones'
   2748 	 * is true, so this is expected to be non-NULL.
   2749 	 */
   2750 	cfg = (ns_cfgctx_t *)cz->view->new_zone_config;
   2751 	if (cfg == NULL) {
   2752 		CHECK(ISC_R_FAILURE);
   2753 	}
   2754 
   2755 	name = dns_catz_entry_getname(cz->entry);
   2756 
   2757 	isc_buffer_init(&namebuf, nameb, DNS_NAME_FORMATSIZE);
   2758 	dns_name_totext(name, DNS_NAME_OMITFINALDOT, &namebuf);
   2759 	isc_buffer_putuint8(&namebuf, 0);
   2760 
   2761 	result = dns_fwdtable_find(cz->view->fwdtable, name, &dnsforwarders);
   2762 	if (result == ISC_R_SUCCESS &&
   2763 	    dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
   2764 	{
   2765 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2766 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2767 			      "catz: catz_addmodzone_cb: "
   2768 			      "zone '%s' will not be processed because of the "
   2769 			      "explicitly configured forwarding for that zone",
   2770 			      nameb);
   2771 		goto cleanup;
   2772 	}
   2773 
   2774 	result = dns_view_findzone(cz->view, name, DNS_ZTFIND_EXACT, &zone);
   2775 
   2776 	if (cz->mod) {
   2777 		dns_catz_zone_t *parentcatz;
   2778 
   2779 		if (result != ISC_R_SUCCESS) {
   2780 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2781 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2782 				      "catz: error \"%s\" while trying to "
   2783 				      "modify zone '%s'",
   2784 				      isc_result_totext(result), nameb);
   2785 			goto cleanup;
   2786 		}
   2787 
   2788 		if (!dns_zone_getadded(zone)) {
   2789 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2790 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2791 				      "catz: catz_addmodzone_cb: "
   2792 				      "zone '%s' is not a dynamically "
   2793 				      "added zone",
   2794 				      nameb);
   2795 			goto cleanup;
   2796 		}
   2797 
   2798 		parentcatz = dns_zone_get_parentcatz(zone);
   2799 
   2800 		if (parentcatz == NULL) {
   2801 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2802 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2803 				      "catz: catz_addmodzone_cb: "
   2804 				      "zone '%s' exists and is not added by "
   2805 				      "a catalog zone, so won't be modified",
   2806 				      nameb);
   2807 			goto cleanup;
   2808 		}
   2809 		if (parentcatz != cz->origin) {
   2810 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2811 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2812 				      "catz: catz_addmodzone_cb: "
   2813 				      "zone '%s' exists in multiple "
   2814 				      "catalog zones",
   2815 				      nameb);
   2816 			goto cleanup;
   2817 		}
   2818 
   2819 		dns_zone_detach(&zone);
   2820 	} else {
   2821 		/* Zone shouldn't already exist when adding */
   2822 		if (result == ISC_R_SUCCESS) {
   2823 			if (dns_zone_get_parentcatz(zone) == NULL) {
   2824 				isc_log_write(
   2825 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2826 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2827 					"catz: "
   2828 					"catz_addmodzone_cb: "
   2829 					"zone '%s' will not be added "
   2830 					"because it is an explicitly "
   2831 					"configured zone",
   2832 					nameb);
   2833 			} else {
   2834 				isc_log_write(
   2835 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2836 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2837 					"catz: "
   2838 					"catz_addmodzone_cb: "
   2839 					"zone '%s' will not be added "
   2840 					"because another catalog zone "
   2841 					"already contains an entry with "
   2842 					"that zone",
   2843 					nameb);
   2844 			}
   2845 			goto cleanup;
   2846 		} else {
   2847 			RUNTIME_CHECK(result == ISC_R_NOTFOUND);
   2848 		}
   2849 	}
   2850 	RUNTIME_CHECK(zone == NULL);
   2851 	/* Create a config for new zone */
   2852 	confbuf = NULL;
   2853 	result = dns_catz_generate_zonecfg(cz->origin, cz->entry, &confbuf);
   2854 	if (result == ISC_R_SUCCESS) {
   2855 		cfg_parser_reset(cfg->add_parser);
   2856 		result = cfg_parse_buffer(cfg->add_parser, confbuf, "catz", 0,
   2857 					  &cfg_type_addzoneconf, 0, &zoneconf);
   2858 	}
   2859 	/*
   2860 	 * Fail if either dns_catz_generate_zonecfg() or cfg_parse_buffer()
   2861 	 * failed.
   2862 	 */
   2863 	if (result != ISC_R_SUCCESS) {
   2864 		isc_log_write(
   2865 			named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2866 			NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   2867 			"catz: error \"%s\" while trying to generate "
   2868 			"config for zone '%s'%s%.*s%s",
   2869 			isc_result_totext(result), nameb,
   2870 			confbuf != NULL ? " buffer '" : "",
   2871 			confbuf != NULL ? (int)isc_buffer_usedlength(confbuf)
   2872 					: 0,
   2873 			confbuf != NULL ? (char *)isc_buffer_base(confbuf) : "",
   2874 			confbuf != NULL ? "'" : "");
   2875 		goto cleanup;
   2876 	}
   2877 	isc_buffer_free(&confbuf);
   2878 	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
   2879 	if (!cfg_obj_islist(zlist)) {
   2880 		CHECK(ISC_R_FAILURE);
   2881 	}
   2882 
   2883 	/* For now we only support adding one zone at a time */
   2884 	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
   2885 
   2886 	/* Mark view unfrozen so that zone can be added */
   2887 	isc_loopmgr_pause(named_g_loopmgr);
   2888 	dns_view_thaw(cz->view);
   2889 	result = configure_zone(cfg->config, zoneobj, cfg->vconfig, cz->view,
   2890 				&cz->cbd->server->viewlist,
   2891 				&cz->cbd->server->kasplist,
   2892 				&cz->cbd->server->keystorelist, cfg->actx, true,
   2893 				false, true, cz->mod);
   2894 	dns_view_freeze(cz->view);
   2895 	isc_loopmgr_resume(named_g_loopmgr);
   2896 
   2897 	if (result != ISC_R_SUCCESS) {
   2898 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2899 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2900 			      "catz: failed to configure zone '%s' - %d", nameb,
   2901 			      result);
   2902 		goto cleanup;
   2903 	}
   2904 
   2905 	/* Is it there yet? */
   2906 	CHECK(dns_view_findzone(cz->view, name, DNS_ZTFIND_EXACT, &zone));
   2907 
   2908 	/*
   2909 	 * Load the zone from the master file.	If this fails, we'll
   2910 	 * need to undo the configuration we've done already.
   2911 	 */
   2912 	result = dns_zone_load(zone, true);
   2913 	if (result != ISC_R_SUCCESS) {
   2914 		dns_db_t *dbp = NULL;
   2915 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2916 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   2917 			      "catz: dns_zone_load() failed "
   2918 			      "with %s; reverting.",
   2919 			      isc_result_totext(result));
   2920 
   2921 		/* If the zone loaded partially, unload it */
   2922 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
   2923 			dns_db_detach(&dbp);
   2924 			dns_zone_unload(zone);
   2925 		}
   2926 
   2927 		/* Remove the zone from the zone table */
   2928 		dns_view_delzone(cz->view, zone);
   2929 		goto cleanup;
   2930 	}
   2931 
   2932 	/* Flag the zone as having been added at runtime */
   2933 	dns_zone_setadded(zone, true);
   2934 	dns_zone_set_parentcatz(zone, cz->origin);
   2935 
   2936 cleanup:
   2937 	if (confbuf != NULL) {
   2938 		isc_buffer_free(&confbuf);
   2939 	}
   2940 	if (zone != NULL) {
   2941 		dns_zone_detach(&zone);
   2942 	}
   2943 	if (zoneconf != NULL) {
   2944 		cfg_obj_destroy(cfg->add_parser, &zoneconf);
   2945 	}
   2946 	if (dnsforwarders != NULL) {
   2947 		dns_forwarders_detach(&dnsforwarders);
   2948 	}
   2949 	dns_catz_entry_detach(cz->origin, &cz->entry);
   2950 	dns_catz_zone_detach(&cz->origin);
   2951 	dns_view_weakdetach(&cz->view);
   2952 	isc_mem_putanddetach(&cz->mctx, cz, sizeof(*cz));
   2953 }
   2954 
   2955 static void
   2956 catz_delzone_cb(void *arg) {
   2957 	catz_chgzone_t *cz = (catz_chgzone_t *)arg;
   2958 	isc_result_t result;
   2959 	dns_zone_t *zone = NULL;
   2960 	dns_db_t *dbp = NULL;
   2961 	char cname[DNS_NAME_FORMATSIZE];
   2962 	const char *file = NULL;
   2963 
   2964 	if (isc_loop_shuttingdown(isc_loop_get(named_g_loopmgr, isc_tid()))) {
   2965 		goto cleanup;
   2966 	}
   2967 
   2968 	isc_loopmgr_pause(named_g_loopmgr);
   2969 
   2970 	dns_name_format(dns_catz_entry_getname(cz->entry), cname,
   2971 			DNS_NAME_FORMATSIZE);
   2972 	result = dns_view_findzone(cz->view, dns_catz_entry_getname(cz->entry),
   2973 				   DNS_ZTFIND_EXACT, &zone);
   2974 	if (result != ISC_R_SUCCESS) {
   2975 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2976 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2977 			      "catz: catz_delzone_cb: "
   2978 			      "zone '%s' not found",
   2979 			      cname);
   2980 		goto resume;
   2981 	}
   2982 
   2983 	if (!dns_zone_getadded(zone)) {
   2984 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2985 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2986 			      "catz: catz_delzone_cb: "
   2987 			      "zone '%s' is not a dynamically added zone",
   2988 			      cname);
   2989 		goto resume;
   2990 	}
   2991 
   2992 	if (dns_zone_get_parentcatz(zone) != cz->origin) {
   2993 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   2994 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   2995 			      "catz: catz_delzone_cb: zone "
   2996 			      "'%s' exists in multiple catalog zones",
   2997 			      cname);
   2998 		goto resume;
   2999 	}
   3000 
   3001 	/* Stop answering for this zone */
   3002 	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
   3003 		dns_db_detach(&dbp);
   3004 		dns_zone_unload(zone);
   3005 	}
   3006 
   3007 	if (dns_view_delzone(cz->view, zone) != ISC_R_SUCCESS) {
   3008 		goto resume;
   3009 	}
   3010 	file = dns_zone_getfile(zone);
   3011 	if (file != NULL) {
   3012 		isc_file_remove(file);
   3013 		file = dns_zone_getjournal(zone);
   3014 		if (file != NULL) {
   3015 			isc_file_remove(file);
   3016 		}
   3017 	}
   3018 
   3019 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   3020 		      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   3021 		      "catz: catz_delzone_cb: "
   3022 		      "zone '%s' deleted",
   3023 		      cname);
   3024 resume:
   3025 	isc_loopmgr_resume(named_g_loopmgr);
   3026 cleanup:
   3027 	if (zone != NULL) {
   3028 		dns_zone_detach(&zone);
   3029 	}
   3030 	dns_catz_entry_detach(cz->origin, &cz->entry);
   3031 	dns_catz_zone_detach(&cz->origin);
   3032 	dns_view_weakdetach(&cz->view);
   3033 	isc_mem_putanddetach(&cz->mctx, cz, sizeof(*cz));
   3034 }
   3035 
   3036 static isc_result_t
   3037 catz_run(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
   3038 	 void *udata, catz_type_t type) {
   3039 	catz_chgzone_t *cz = NULL;
   3040 	isc_job_cb action = NULL;
   3041 
   3042 	switch (type) {
   3043 	case CATZ_ADDZONE:
   3044 	case CATZ_MODZONE:
   3045 		action = catz_addmodzone_cb;
   3046 		break;
   3047 	case CATZ_DELZONE:
   3048 		action = catz_delzone_cb;
   3049 		break;
   3050 	default:
   3051 		REQUIRE(0);
   3052 		UNREACHABLE();
   3053 	}
   3054 
   3055 	cz = isc_mem_get(view->mctx, sizeof(*cz));
   3056 	*cz = (catz_chgzone_t){
   3057 		.cbd = (catz_cb_data_t *)udata,
   3058 		.mod = (type == CATZ_MODZONE),
   3059 	};
   3060 	isc_mem_attach(view->mctx, &cz->mctx);
   3061 
   3062 	dns_catz_entry_attach(entry, &cz->entry);
   3063 	dns_catz_zone_attach(origin, &cz->origin);
   3064 	dns_view_weakattach(view, &cz->view);
   3065 
   3066 	isc_async_run(named_g_mainloop, action, cz);
   3067 
   3068 	return ISC_R_SUCCESS;
   3069 }
   3070 
   3071 static isc_result_t
   3072 catz_addzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
   3073 	     void *udata) {
   3074 	return catz_run(entry, origin, view, udata, CATZ_ADDZONE);
   3075 }
   3076 
   3077 static isc_result_t
   3078 catz_delzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
   3079 	     void *udata) {
   3080 	return catz_run(entry, origin, view, udata, CATZ_DELZONE);
   3081 }
   3082 
   3083 static isc_result_t
   3084 catz_modzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
   3085 	     void *udata) {
   3086 	return catz_run(entry, origin, view, udata, CATZ_MODZONE);
   3087 }
   3088 
   3089 static void
   3090 catz_changeview(dns_catz_entry_t *entry, void *arg1, void *arg2) {
   3091 	dns_view_t *pview = arg1;
   3092 	dns_view_t *view = arg2;
   3093 
   3094 	dns_zone_t *zone = NULL;
   3095 	isc_result_t result = dns_view_findzone(
   3096 		pview, dns_catz_entry_getname(entry), DNS_ZTFIND_EXACT, &zone);
   3097 
   3098 	if (result != ISC_R_SUCCESS) {
   3099 		return;
   3100 	}
   3101 
   3102 	dns_zone_setview(zone, view);
   3103 	dns_view_addzone(view, zone);
   3104 
   3105 	dns_zone_detach(&zone);
   3106 }
   3107 
   3108 static void
   3109 catz_reconfigure(dns_catz_entry_t *entry, void *arg1, void *arg2) {
   3110 	dns_view_t *view = arg1;
   3111 	catz_reconfig_data_t *data = arg2;
   3112 	isc_buffer_t namebuf;
   3113 	isc_buffer_t *confbuf = NULL;
   3114 	const cfg_obj_t *zlist = NULL;
   3115 	char nameb[DNS_NAME_FORMATSIZE];
   3116 	cfg_obj_t *zoneconf = NULL;
   3117 	cfg_obj_t *zoneobj = NULL;
   3118 	ns_cfgctx_t *cfg = NULL;
   3119 	dns_zone_t *zone = NULL;
   3120 	isc_result_t result;
   3121 
   3122 	isc_buffer_init(&namebuf, nameb, DNS_NAME_FORMATSIZE);
   3123 	dns_name_totext(dns_catz_entry_getname(entry), DNS_NAME_OMITFINALDOT,
   3124 			&namebuf);
   3125 	isc_buffer_putuint8(&namebuf, 0);
   3126 
   3127 	result = dns_view_findzone(view, dns_catz_entry_getname(entry),
   3128 				   DNS_ZTFIND_EXACT, &zone);
   3129 	if (result != ISC_R_SUCCESS) {
   3130 		return;
   3131 	}
   3132 
   3133 	/*
   3134 	 * A non-empty 'catalog-zones' statement implies that 'allow-new-zones'
   3135 	 * is true, so this is expected to be non-NULL.
   3136 	 */
   3137 	cfg = (ns_cfgctx_t *)view->new_zone_config;
   3138 	if (cfg == NULL) {
   3139 		CHECK(ISC_R_FAILURE);
   3140 	}
   3141 
   3142 	result = dns_catz_generate_zonecfg(data->catz, entry, &confbuf);
   3143 	if (result == ISC_R_SUCCESS) {
   3144 		cfg_parser_reset(cfg->add_parser);
   3145 		result = cfg_parse_buffer(cfg->add_parser, confbuf, "catz", 0,
   3146 					  &cfg_type_addzoneconf, 0, &zoneconf);
   3147 		isc_buffer_free(&confbuf);
   3148 	}
   3149 	/*
   3150 	 * Fail if either dns_catz_generate_zonecfg() or cfg_parse_buffer()
   3151 	 * failed.
   3152 	 */
   3153 	if (result != ISC_R_SUCCESS) {
   3154 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   3155 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   3156 			      "catz_reconfigure: error \"%s\" while trying to "
   3157 			      "generate config for member zone '%s'",
   3158 			      isc_result_totext(result), nameb);
   3159 		goto cleanup;
   3160 	}
   3161 
   3162 	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
   3163 	if (!cfg_obj_islist(zlist)) {
   3164 		CHECK(ISC_R_FAILURE);
   3165 	}
   3166 	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
   3167 
   3168 	result = configure_zone(data->config, zoneobj, cfg->vconfig, view,
   3169 				&data->cbd->server->viewlist,
   3170 				&data->cbd->server->kasplist,
   3171 				&data->cbd->server->keystorelist, cfg->actx,
   3172 				true, false, true, true);
   3173 	if (result != ISC_R_SUCCESS) {
   3174 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   3175 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   3176 			      "catz_reconfigure : error \"%s\" while trying to "
   3177 			      "reconfigure member zone '%s'",
   3178 			      isc_result_totext(result), nameb);
   3179 		goto cleanup;
   3180 	}
   3181 
   3182 cleanup:
   3183 	if (zoneconf != NULL) {
   3184 		cfg_obj_destroy(cfg->add_parser, &zoneconf);
   3185 	}
   3186 
   3187 	dns_zone_detach(&zone);
   3188 }
   3189 
   3190 static isc_result_t
   3191 configure_catz_zone(dns_view_t *view, dns_view_t *pview,
   3192 		    const cfg_obj_t *config, const cfg_listelt_t *element) {
   3193 	const cfg_obj_t *catz_obj, *obj;
   3194 	dns_catz_zone_t *zone = NULL;
   3195 	const char *str;
   3196 	isc_result_t result;
   3197 	dns_name_t origin;
   3198 	dns_ipkeylist_t ipkl;
   3199 	dns_catz_options_t *opts;
   3200 
   3201 	dns_name_init(&origin, NULL);
   3202 	dns_ipkeylist_init(&ipkl);
   3203 	catz_obj = cfg_listelt_value(element);
   3204 
   3205 	str = cfg_obj_asstring(cfg_tuple_get(catz_obj, "zone name"));
   3206 
   3207 	result = dns_name_fromstring(&origin, str, dns_rootname,
   3208 				     DNS_NAME_DOWNCASE, view->mctx);
   3209 	if (result == ISC_R_SUCCESS && dns_name_equal(&origin, dns_rootname)) {
   3210 		result = DNS_R_EMPTYLABEL;
   3211 	}
   3212 
   3213 	if (result != ISC_R_SUCCESS) {
   3214 		cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
   3215 			    "catz: invalid zone name '%s'", str);
   3216 		goto cleanup;
   3217 	}
   3218 
   3219 	obj = cfg_tuple_get(catz_obj, "default-masters");
   3220 	if (obj == NULL || !cfg_obj_istuple(obj)) {
   3221 		obj = cfg_tuple_get(catz_obj, "default-primaries");
   3222 	}
   3223 	if (obj != NULL && cfg_obj_istuple(obj)) {
   3224 		result = named_config_getipandkeylist(config, obj, view->mctx,
   3225 						      &ipkl);
   3226 		if (result != ISC_R_SUCCESS) {
   3227 			cfg_obj_log(catz_obj, named_g_lctx,
   3228 				    DNS_CATZ_ERROR_LEVEL,
   3229 				    "catz: default-primaries parse error: %s",
   3230 				    isc_result_totext(result));
   3231 			goto cleanup;
   3232 		}
   3233 	}
   3234 
   3235 	result = dns_catz_zone_add(view->catzs, &origin, &zone);
   3236 	if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
   3237 		cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
   3238 			    "catz: dns_catz_zone_add failed: %s",
   3239 			    isc_result_totext(result));
   3240 		goto cleanup;
   3241 	}
   3242 
   3243 	dns_catz_zone_prereconfig(zone);
   3244 
   3245 	if (result == ISC_R_EXISTS) {
   3246 		catz_reconfig_data_t data = {
   3247 			.catz = zone,
   3248 			.config = config,
   3249 			.cbd = (catz_cb_data_t *)dns_catz_zones_get_udata(
   3250 				view->catzs),
   3251 		};
   3252 
   3253 		/*
   3254 		 * We have to walk through all the member zones, re-attach
   3255 		 * them to the current view and reconfigure
   3256 		 */
   3257 		dns_catz_zone_for_each_entry2(zone, catz_changeview, pview,
   3258 					      view);
   3259 		dns_catz_zone_for_each_entry2(zone, catz_reconfigure, view,
   3260 					      &data);
   3261 
   3262 		result = ISC_R_SUCCESS;
   3263 	}
   3264 
   3265 	dns_catz_zone_resetdefoptions(zone);
   3266 	opts = dns_catz_zone_getdefoptions(zone);
   3267 	if (ipkl.count != 0) {
   3268 		/*
   3269 		 * Transfer the ownership of the pointers inside 'ipkl' and
   3270 		 * set its count to 0 in order to not cleanup it later below.
   3271 		 */
   3272 		opts->masters = ipkl;
   3273 		ipkl.count = 0;
   3274 	}
   3275 
   3276 	obj = cfg_tuple_get(catz_obj, "in-memory");
   3277 	if (obj != NULL && cfg_obj_isboolean(obj)) {
   3278 		opts->in_memory = cfg_obj_asboolean(obj);
   3279 	}
   3280 
   3281 	obj = cfg_tuple_get(catz_obj, "zone-directory");
   3282 	if (!opts->in_memory && obj != NULL && cfg_obj_isstring(obj)) {
   3283 		opts->zonedir = isc_mem_strdup(view->mctx,
   3284 					       cfg_obj_asstring(obj));
   3285 		if (isc_file_isdirectory(opts->zonedir) != ISC_R_SUCCESS) {
   3286 			cfg_obj_log(obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
   3287 				    "catz: zone-directory '%s' "
   3288 				    "not found; zone files will not be "
   3289 				    "saved",
   3290 				    opts->zonedir);
   3291 			opts->in_memory = true;
   3292 		}
   3293 	}
   3294 
   3295 	obj = cfg_tuple_get(catz_obj, "min-update-interval");
   3296 	if (obj != NULL && cfg_obj_isduration(obj)) {
   3297 		opts->min_update_interval = cfg_obj_asduration(obj);
   3298 	}
   3299 
   3300 	dns_catz_zone_postreconfig(zone);
   3301 
   3302 cleanup:
   3303 	dns_name_free(&origin, view->mctx);
   3304 	if (ipkl.count != 0) {
   3305 		dns_ipkeylist_clear(view->mctx, &ipkl);
   3306 	}
   3307 
   3308 	return result;
   3309 }
   3310 
   3311 static catz_cb_data_t ns_catz_cbdata;
   3312 static dns_catz_zonemodmethods_t ns_catz_zonemodmethods = {
   3313 	catz_addzone, catz_modzone, catz_delzone, &ns_catz_cbdata
   3314 };
   3315 
   3316 static isc_result_t
   3317 configure_catz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t *config,
   3318 	       const cfg_obj_t *catz_obj) {
   3319 	const cfg_listelt_t *zone_element = NULL;
   3320 	const dns_catz_zones_t *old = NULL;
   3321 	bool pview_must_detach = false;
   3322 	isc_result_t result;
   3323 
   3324 	/* xxxwpk TODO do it cleaner, once, somewhere */
   3325 	ns_catz_cbdata.server = named_g_server;
   3326 
   3327 	zone_element = cfg_list_first(cfg_tuple_get(catz_obj, "zone list"));
   3328 	if (zone_element == NULL) {
   3329 		return ISC_R_SUCCESS;
   3330 	}
   3331 
   3332 	if (pview != NULL) {
   3333 		old = pview->catzs;
   3334 	} else {
   3335 		result = dns_viewlist_find(&named_g_server->viewlist,
   3336 					   view->name, view->rdclass, &pview);
   3337 		if (result == ISC_R_SUCCESS) {
   3338 			pview_must_detach = true;
   3339 			old = pview->catzs;
   3340 		}
   3341 	}
   3342 
   3343 	if (old != NULL) {
   3344 		dns_catz_zones_attach(pview->catzs, &view->catzs);
   3345 		dns_catz_zones_detach(&pview->catzs);
   3346 		dns_catz_prereconfig(view->catzs);
   3347 	} else {
   3348 		view->catzs = dns_catz_zones_new(view->mctx, named_g_loopmgr,
   3349 						 &ns_catz_zonemodmethods);
   3350 	}
   3351 
   3352 	while (zone_element != NULL) {
   3353 		CHECK(configure_catz_zone(view, pview, config, zone_element));
   3354 		zone_element = cfg_list_next(zone_element);
   3355 	}
   3356 
   3357 	if (old != NULL) {
   3358 		dns_catz_postreconfig(view->catzs);
   3359 	}
   3360 
   3361 	result = ISC_R_SUCCESS;
   3362 
   3363 cleanup:
   3364 	if (pview_must_detach) {
   3365 		dns_view_detach(&pview);
   3366 	}
   3367 
   3368 	return result;
   3369 }
   3370 
   3371 #define CHECK_RRL(cond, pat, val1, val2)                                   \
   3372 	do {                                                               \
   3373 		if (!(cond)) {                                             \
   3374 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, pat, \
   3375 				    val1, val2);                           \
   3376 			result = ISC_R_RANGE;                              \
   3377 			goto cleanup;                                      \
   3378 		}                                                          \
   3379 	} while (0)
   3380 
   3381 #define CHECK_RRL_RATE(rate, def, max_rate, name)                           \
   3382 	do {                                                                \
   3383 		obj = NULL;                                                 \
   3384 		rrl->rate.str = name;                                       \
   3385 		result = cfg_map_get(map, name, &obj);                      \
   3386 		if (result == ISC_R_SUCCESS) {                              \
   3387 			rrl->rate.r = cfg_obj_asuint32(obj);                \
   3388 			CHECK_RRL(rrl->rate.r <= max_rate, name " %d > %d", \
   3389 				  rrl->rate.r, max_rate);                   \
   3390 		} else {                                                    \
   3391 			rrl->rate.r = def;                                  \
   3392 		}                                                           \
   3393 		rrl->rate.scaled = rrl->rate.r;                             \
   3394 	} while (0)
   3395 
   3396 static isc_result_t
   3397 configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
   3398 	const cfg_obj_t *obj;
   3399 	dns_rrl_t *rrl;
   3400 	isc_result_t result;
   3401 	int min_entries, i, j;
   3402 
   3403 	/*
   3404 	 * Most DNS servers have few clients, but intentinally open
   3405 	 * recursive and authoritative servers often have many.
   3406 	 * So start with a small number of entries unless told otherwise
   3407 	 * to reduce cold-start costs.
   3408 	 */
   3409 	min_entries = 500;
   3410 	obj = NULL;
   3411 	result = cfg_map_get(map, "min-table-size", &obj);
   3412 	if (result == ISC_R_SUCCESS) {
   3413 		min_entries = cfg_obj_asuint32(obj);
   3414 		if (min_entries < 1) {
   3415 			min_entries = 1;
   3416 		}
   3417 	}
   3418 	result = dns_rrl_init(&rrl, view, min_entries);
   3419 	if (result != ISC_R_SUCCESS) {
   3420 		return result;
   3421 	}
   3422 
   3423 	i = ISC_MAX(20000, min_entries);
   3424 	obj = NULL;
   3425 	result = cfg_map_get(map, "max-table-size", &obj);
   3426 	if (result == ISC_R_SUCCESS) {
   3427 		i = cfg_obj_asuint32(obj);
   3428 		CHECK_RRL(i >= min_entries,
   3429 			  "max-table-size %d < min-table-size %d", i,
   3430 			  min_entries);
   3431 	}
   3432 	rrl->max_entries = i;
   3433 
   3434 	CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE,
   3435 		       "responses-per-second");
   3436 	CHECK_RRL_RATE(referrals_per_second, rrl->responses_per_second.r,
   3437 		       DNS_RRL_MAX_RATE, "referrals-per-second");
   3438 	CHECK_RRL_RATE(nodata_per_second, rrl->responses_per_second.r,
   3439 		       DNS_RRL_MAX_RATE, "nodata-per-second");
   3440 	CHECK_RRL_RATE(nxdomains_per_second, rrl->responses_per_second.r,
   3441 		       DNS_RRL_MAX_RATE, "nxdomains-per-second");
   3442 	CHECK_RRL_RATE(errors_per_second, rrl->responses_per_second.r,
   3443 		       DNS_RRL_MAX_RATE, "errors-per-second");
   3444 
   3445 	CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE, "all-per-second");
   3446 
   3447 	CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP, "slip");
   3448 
   3449 	i = 15;
   3450 	obj = NULL;
   3451 	result = cfg_map_get(map, "window", &obj);
   3452 	if (result == ISC_R_SUCCESS) {
   3453 		i = cfg_obj_asuint32(obj);
   3454 		CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW,
   3455 			  "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW);
   3456 	}
   3457 	rrl->window = i;
   3458 
   3459 	i = 0;
   3460 	obj = NULL;
   3461 	result = cfg_map_get(map, "qps-scale", &obj);
   3462 	if (result == ISC_R_SUCCESS) {
   3463 		i = cfg_obj_asuint32(obj);
   3464 		CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, "");
   3465 	}
   3466 	rrl->qps_scale = i;
   3467 	rrl->qps = 1.0;
   3468 
   3469 	i = 24;
   3470 	obj = NULL;
   3471 	result = cfg_map_get(map, "ipv4-prefix-length", &obj);
   3472 	if (result == ISC_R_SUCCESS) {
   3473 		i = cfg_obj_asuint32(obj);
   3474 		CHECK_RRL(i >= 8 && i <= 32,
   3475 			  "invalid 'ipv4-prefix-length %d'%s", i, "");
   3476 	}
   3477 	rrl->ipv4_prefixlen = i;
   3478 	if (i == 32) {
   3479 		rrl->ipv4_mask = 0xffffffff;
   3480 	} else {
   3481 		rrl->ipv4_mask = htonl(0xffffffff << (32 - i));
   3482 	}
   3483 
   3484 	i = 56;
   3485 	obj = NULL;
   3486 	result = cfg_map_get(map, "ipv6-prefix-length", &obj);
   3487 	if (result == ISC_R_SUCCESS) {
   3488 		i = cfg_obj_asuint32(obj);
   3489 		CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX,
   3490 			  "ipv6-prefix-length %d < 16 or > %d", i,
   3491 			  DNS_RRL_MAX_PREFIX);
   3492 	}
   3493 	rrl->ipv6_prefixlen = i;
   3494 	for (j = 0; j < 4; ++j) {
   3495 		if (i <= 0) {
   3496 			rrl->ipv6_mask[j] = 0;
   3497 		} else if (i < 32) {
   3498 			rrl->ipv6_mask[j] = htonl(0xffffffff << (32 - i));
   3499 		} else {
   3500 			rrl->ipv6_mask[j] = 0xffffffff;
   3501 		}
   3502 		i -= 32;
   3503 	}
   3504 
   3505 	obj = NULL;
   3506 	result = cfg_map_get(map, "exempt-clients", &obj);
   3507 	if (result == ISC_R_SUCCESS) {
   3508 		result = cfg_acl_fromconfig(obj, config, named_g_lctx,
   3509 					    named_g_aclconfctx, named_g_mctx, 0,
   3510 					    &rrl->exempt);
   3511 		CHECK_RRL(result == ISC_R_SUCCESS, "invalid %s%s",
   3512 			  "address match list", "");
   3513 	}
   3514 
   3515 	obj = NULL;
   3516 	result = cfg_map_get(map, "log-only", &obj);
   3517 	if (result == ISC_R_SUCCESS && cfg_obj_asboolean(obj)) {
   3518 		rrl->log_only = true;
   3519 	} else {
   3520 		rrl->log_only = false;
   3521 	}
   3522 
   3523 	return ISC_R_SUCCESS;
   3524 
   3525 cleanup:
   3526 	dns_rrl_view_destroy(view);
   3527 	return result;
   3528 }
   3529 
   3530 static isc_result_t
   3531 add_soa(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
   3532 	const dns_name_t *origin, const dns_name_t *contact) {
   3533 	dns_dbnode_t *node = NULL;
   3534 	dns_rdata_t rdata = DNS_RDATA_INIT;
   3535 	dns_rdatalist_t rdatalist;
   3536 	dns_rdataset_t rdataset;
   3537 	isc_result_t result;
   3538 	unsigned char buf[DNS_SOA_BUFFERSIZE];
   3539 
   3540 	CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db), 0, 28800,
   3541 				 7200, 604800, 86400, buf, &rdata));
   3542 
   3543 	dns_rdatalist_init(&rdatalist);
   3544 	rdatalist.type = rdata.type;
   3545 	rdatalist.rdclass = rdata.rdclass;
   3546 	rdatalist.ttl = 86400;
   3547 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
   3548 
   3549 	dns_rdataset_init(&rdataset);
   3550 	dns_rdatalist_tordataset(&rdatalist, &rdataset);
   3551 	CHECK(dns_db_findnode(db, name, true, &node));
   3552 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
   3553 
   3554 cleanup:
   3555 	if (node != NULL) {
   3556 		dns_db_detachnode(db, &node);
   3557 	}
   3558 	return result;
   3559 }
   3560 
   3561 static isc_result_t
   3562 add_ns(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
   3563        const dns_name_t *nsname) {
   3564 	dns_dbnode_t *node = NULL;
   3565 	dns_rdata_ns_t ns;
   3566 	dns_rdata_t rdata = DNS_RDATA_INIT;
   3567 	dns_rdatalist_t rdatalist;
   3568 	dns_rdataset_t rdataset;
   3569 	isc_result_t result;
   3570 	isc_buffer_t b;
   3571 	unsigned char buf[DNS_NAME_MAXWIRE];
   3572 
   3573 	isc_buffer_init(&b, buf, sizeof(buf));
   3574 
   3575 	ns.common.rdtype = dns_rdatatype_ns;
   3576 	ns.common.rdclass = dns_db_class(db);
   3577 	ns.mctx = NULL;
   3578 	dns_name_init(&ns.name, NULL);
   3579 	dns_name_clone(nsname, &ns.name);
   3580 	CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns,
   3581 				   &ns, &b));
   3582 
   3583 	dns_rdatalist_init(&rdatalist);
   3584 	rdatalist.type = rdata.type;
   3585 	rdatalist.rdclass = rdata.rdclass;
   3586 	rdatalist.ttl = 86400;
   3587 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
   3588 
   3589 	dns_rdataset_init(&rdataset);
   3590 	dns_rdatalist_tordataset(&rdatalist, &rdataset);
   3591 	CHECK(dns_db_findnode(db, name, true, &node));
   3592 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
   3593 
   3594 cleanup:
   3595 	if (node != NULL) {
   3596 		dns_db_detachnode(db, &node);
   3597 	}
   3598 	return result;
   3599 }
   3600 
   3601 static isc_result_t
   3602 create_empty_zone(dns_zone_t *pzone, dns_name_t *name, dns_view_t *view,
   3603 		  const cfg_obj_t *zonelist, const char **empty_dbtype,
   3604 		  int empty_dbtypec, dns_zonestat_level_t statlevel) {
   3605 	char namebuf[DNS_NAME_FORMATSIZE];
   3606 	const cfg_listelt_t *element;
   3607 	const cfg_obj_t *obj;
   3608 	const cfg_obj_t *zconfig;
   3609 	const cfg_obj_t *zoptions;
   3610 	const char *default_dbtype[4] = { ZONEDB_DEFAULT };
   3611 	const char *sep = ": view ";
   3612 	const char *str;
   3613 	const char *viewname = view->name;
   3614 	dns_db_t *db = NULL;
   3615 	dns_dbversion_t *version = NULL;
   3616 	dns_fixedname_t cfixed;
   3617 	dns_fixedname_t fixed;
   3618 	dns_fixedname_t nsfixed;
   3619 	dns_name_t *contact;
   3620 	dns_name_t *ns;
   3621 	dns_name_t *zname;
   3622 	dns_zone_t *zone = NULL;
   3623 	int default_dbtypec = 1;
   3624 	isc_result_t result;
   3625 	dns_namereln_t namereln;
   3626 	int order;
   3627 	unsigned int nlabels;
   3628 
   3629 	zname = dns_fixedname_initname(&fixed);
   3630 	ns = dns_fixedname_initname(&nsfixed);
   3631 	contact = dns_fixedname_initname(&cfixed);
   3632 
   3633 	/*
   3634 	 * Look for forward "zones" beneath this empty zone and if so
   3635 	 * create a custom db for the empty zone.
   3636 	 */
   3637 	for (element = cfg_list_first(zonelist); element != NULL;
   3638 	     element = cfg_list_next(element))
   3639 	{
   3640 		zconfig = cfg_listelt_value(element);
   3641 		str = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
   3642 		CHECK(dns_name_fromstring(zname, str, dns_rootname, 0, NULL));
   3643 		namereln = dns_name_fullcompare(zname, name, &order, &nlabels);
   3644 		if (namereln != dns_namereln_subdomain) {
   3645 			continue;
   3646 		}
   3647 
   3648 		zoptions = cfg_tuple_get(zconfig, "options");
   3649 
   3650 		obj = NULL;
   3651 		(void)cfg_map_get(zoptions, "type", &obj);
   3652 		if (obj != NULL &&
   3653 		    strcasecmp(cfg_obj_asstring(obj), "forward") == 0)
   3654 		{
   3655 			obj = NULL;
   3656 			(void)cfg_map_get(zoptions, "forward", &obj);
   3657 			if (obj == NULL) {
   3658 				continue;
   3659 			}
   3660 			if (strcasecmp(cfg_obj_asstring(obj), "only") != 0) {
   3661 				continue;
   3662 			}
   3663 		}
   3664 		if (db == NULL) {
   3665 			CHECK(dns_db_create(view->mctx, ZONEDB_DEFAULT, name,
   3666 					    dns_dbtype_zone, view->rdclass, 0,
   3667 					    NULL, &db));
   3668 			CHECK(dns_db_newversion(db, &version));
   3669 			if (strcmp(empty_dbtype[2], "@") == 0) {
   3670 				dns_name_clone(name, ns);
   3671 			} else {
   3672 				CHECK(dns_name_fromstring(ns, empty_dbtype[2],
   3673 							  dns_rootname, 0,
   3674 							  NULL));
   3675 			}
   3676 			CHECK(dns_name_fromstring(contact, empty_dbtype[3],
   3677 						  dns_rootname, 0, NULL));
   3678 			CHECK(add_soa(db, version, name, ns, contact));
   3679 			CHECK(add_ns(db, version, name, ns));
   3680 		}
   3681 		CHECK(add_ns(db, version, zname, dns_rootname));
   3682 	}
   3683 
   3684 	/*
   3685 	 * Is the existing zone ok to use?
   3686 	 */
   3687 	if (pzone != NULL) {
   3688 		unsigned int typec;
   3689 		const char **dbargv = NULL;
   3690 
   3691 		if (db != NULL) {
   3692 			typec = default_dbtypec;
   3693 			dbargv = default_dbtype;
   3694 		} else {
   3695 			typec = empty_dbtypec;
   3696 			dbargv = empty_dbtype;
   3697 		}
   3698 
   3699 		result = check_dbtype(pzone, typec, dbargv, view->mctx);
   3700 		if (result != ISC_R_SUCCESS) {
   3701 			pzone = NULL;
   3702 		}
   3703 
   3704 		if (pzone != NULL &&
   3705 		    dns_zone_gettype(pzone) != dns_zone_primary)
   3706 		{
   3707 			pzone = NULL;
   3708 		}
   3709 		if (pzone != NULL && dns_zone_getfile(pzone) != NULL) {
   3710 			pzone = NULL;
   3711 		}
   3712 		if (pzone != NULL) {
   3713 			dns_zone_getraw(pzone, &zone);
   3714 			if (zone != NULL) {
   3715 				dns_zone_detach(&zone);
   3716 				pzone = NULL;
   3717 			}
   3718 		}
   3719 	}
   3720 
   3721 	if (pzone == NULL) {
   3722 		CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
   3723 		CHECK(dns_zone_setorigin(zone, name));
   3724 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
   3725 		if (db == NULL) {
   3726 			dns_zone_setdbtype(zone, empty_dbtypec, empty_dbtype);
   3727 		}
   3728 		dns_zone_setclass(zone, view->rdclass);
   3729 		dns_zone_settype(zone, dns_zone_primary);
   3730 		dns_zone_setstats(zone, named_g_server->zonestats);
   3731 	} else {
   3732 		dns_zone_attach(pzone, &zone);
   3733 	}
   3734 
   3735 	dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, false);
   3736 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
   3737 	dns_zone_setcheckdstype(zone, dns_checkdstype_no);
   3738 	dns_zone_setnotifytype(zone, dns_notifytype_no);
   3739 	dns_zone_setdialup(zone, dns_dialuptype_no);
   3740 	dns_zone_setautomatic(zone, true);
   3741 	if (view->queryacl != NULL) {
   3742 		dns_zone_setqueryacl(zone, view->queryacl);
   3743 	} else {
   3744 		dns_zone_clearqueryacl(zone);
   3745 	}
   3746 	if (view->queryonacl != NULL) {
   3747 		dns_zone_setqueryonacl(zone, view->queryonacl);
   3748 	} else {
   3749 		dns_zone_clearqueryonacl(zone);
   3750 	}
   3751 	dns_zone_clearupdateacl(zone);
   3752 	if (view->transferacl != NULL) {
   3753 		dns_zone_setxfracl(zone, view->transferacl);
   3754 	} else {
   3755 		dns_zone_clearxfracl(zone);
   3756 	}
   3757 
   3758 	setquerystats(zone, view->mctx, statlevel);
   3759 	if (db != NULL) {
   3760 		dns_db_closeversion(db, &version, true);
   3761 		CHECK(dns_zone_replacedb(zone, db, false));
   3762 	}
   3763 	dns_zone_setoption(zone, DNS_ZONEOPT_AUTOEMPTY, true);
   3764 	dns_zone_setview(zone, view);
   3765 	CHECK(dns_view_addzone(view, zone));
   3766 
   3767 	if (!strcmp(viewname, "_default")) {
   3768 		sep = "";
   3769 		viewname = "";
   3770 	}
   3771 	dns_name_format(name, namebuf, sizeof(namebuf));
   3772 	isc_log_write(named_g_lctx, DNS_LOGCATEGORY_ZONELOAD,
   3773 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   3774 		      "automatic empty zone%s%s: %s", sep, viewname, namebuf);
   3775 
   3776 cleanup:
   3777 	if (zone != NULL) {
   3778 		dns_zone_detach(&zone);
   3779 	}
   3780 	if (version != NULL) {
   3781 		dns_db_closeversion(db, &version, false);
   3782 	}
   3783 	if (db != NULL) {
   3784 		dns_db_detach(&db);
   3785 	}
   3786 
   3787 	INSIST(version == NULL);
   3788 
   3789 	return result;
   3790 }
   3791 
   3792 static isc_result_t
   3793 create_ipv4only_zone(dns_zone_t *pzone, dns_view_t *view,
   3794 		     const dns_name_t *name, const char *type, isc_mem_t *mctx,
   3795 		     const char *server, const char *contact) {
   3796 	char namebuf[DNS_NAME_FORMATSIZE];
   3797 	const char *dbtype[4] = { "_builtin", NULL, "@", "." };
   3798 	const char *sep = ": view ";
   3799 	const char *viewname = view->name;
   3800 	dns_zone_t *zone = NULL;
   3801 	int dbtypec = 4;
   3802 	isc_result_t result;
   3803 
   3804 	REQUIRE(type != NULL);
   3805 
   3806 	if (!strcmp(viewname, "_default")) {
   3807 		sep = "";
   3808 		viewname = "";
   3809 	}
   3810 
   3811 	dbtype[1] = type;
   3812 	if (server != NULL) {
   3813 		dbtype[2] = server;
   3814 	}
   3815 	if (contact != NULL) {
   3816 		dbtype[3] = contact;
   3817 	}
   3818 
   3819 	if (pzone != NULL) {
   3820 		result = check_dbtype(pzone, dbtypec, dbtype, view->mctx);
   3821 		if (result != ISC_R_SUCCESS) {
   3822 			pzone = NULL;
   3823 		}
   3824 	}
   3825 
   3826 	if (pzone == NULL) {
   3827 		/*
   3828 		 * Create the actual zone.
   3829 		 */
   3830 		dns_zone_create(&zone, mctx, 0);
   3831 		CHECK(dns_zone_setorigin(zone, name));
   3832 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
   3833 		dns_zone_setclass(zone, view->rdclass);
   3834 		dns_zone_settype(zone, dns_zone_primary);
   3835 		dns_zone_setstats(zone, named_g_server->zonestats);
   3836 		dns_zone_setdbtype(zone, dbtypec, dbtype);
   3837 		dns_zone_setdialup(zone, dns_dialuptype_no);
   3838 		dns_zone_setcheckdstype(zone, dns_checkdstype_no);
   3839 		dns_zone_setnotifytype(zone, dns_notifytype_no);
   3840 		dns_zone_setautomatic(zone, true);
   3841 		dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
   3842 	} else {
   3843 		dns_zone_attach(pzone, &zone);
   3844 	}
   3845 	if (view->queryacl != NULL) {
   3846 		dns_zone_setqueryacl(zone, view->queryacl);
   3847 	} else {
   3848 		dns_zone_clearqueryacl(zone);
   3849 	}
   3850 	if (view->queryonacl != NULL) {
   3851 		dns_zone_setqueryonacl(zone, view->queryonacl);
   3852 	} else {
   3853 		dns_zone_clearqueryonacl(zone);
   3854 	}
   3855 	dns_zone_setview(zone, view);
   3856 	CHECK(dns_view_addzone(view, zone));
   3857 
   3858 	dns_name_format(name, namebuf, sizeof(namebuf));
   3859 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   3860 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   3861 		      "automatic ipv4only zone%s%s: %s", sep, viewname,
   3862 		      namebuf);
   3863 
   3864 cleanup:
   3865 	if (zone != NULL) {
   3866 		dns_zone_detach(&zone);
   3867 	}
   3868 	return result;
   3869 }
   3870 
   3871 #ifdef HAVE_DNSTAP
   3872 static isc_result_t
   3873 configure_dnstap(const cfg_obj_t **maps, dns_view_t *view) {
   3874 	isc_result_t result;
   3875 	const cfg_obj_t *obj, *obj2;
   3876 	const cfg_listelt_t *element;
   3877 	const char *dpath;
   3878 	const cfg_obj_t *dlist = NULL;
   3879 	dns_dtmsgtype_t dttypes = 0;
   3880 	unsigned int i;
   3881 	struct fstrm_iothr_options *fopt = NULL;
   3882 
   3883 	result = named_config_get(maps, "dnstap", &dlist);
   3884 	if (result != ISC_R_SUCCESS) {
   3885 		return ISC_R_SUCCESS;
   3886 	}
   3887 
   3888 	for (element = cfg_list_first(dlist); element != NULL;
   3889 	     element = cfg_list_next(element))
   3890 	{
   3891 		const char *str;
   3892 		dns_dtmsgtype_t dt = 0;
   3893 
   3894 		obj = cfg_listelt_value(element);
   3895 		obj2 = cfg_tuple_get(obj, "type");
   3896 		str = cfg_obj_asstring(obj2);
   3897 		if (strcasecmp(str, "client") == 0) {
   3898 			dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR;
   3899 		} else if (strcasecmp(str, "auth") == 0) {
   3900 			dt |= DNS_DTTYPE_AQ | DNS_DTTYPE_AR;
   3901 		} else if (strcasecmp(str, "resolver") == 0) {
   3902 			dt |= DNS_DTTYPE_RQ | DNS_DTTYPE_RR;
   3903 		} else if (strcasecmp(str, "forwarder") == 0) {
   3904 			dt |= DNS_DTTYPE_FQ | DNS_DTTYPE_FR;
   3905 		} else if (strcasecmp(str, "update") == 0) {
   3906 			dt |= DNS_DTTYPE_UQ | DNS_DTTYPE_UR;
   3907 		} else if (strcasecmp(str, "all") == 0) {
   3908 			dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR | DNS_DTTYPE_AQ |
   3909 			      DNS_DTTYPE_AR | DNS_DTTYPE_RQ | DNS_DTTYPE_RR |
   3910 			      DNS_DTTYPE_FQ | DNS_DTTYPE_FR | DNS_DTTYPE_UQ |
   3911 			      DNS_DTTYPE_UR;
   3912 		}
   3913 
   3914 		obj2 = cfg_tuple_get(obj, "mode");
   3915 		if (obj2 == NULL || cfg_obj_isvoid(obj2)) {
   3916 			dttypes |= dt;
   3917 			continue;
   3918 		}
   3919 
   3920 		str = cfg_obj_asstring(obj2);
   3921 		if (strcasecmp(str, "query") == 0) {
   3922 			dt &= ~DNS_DTTYPE_RESPONSE;
   3923 		} else if (strcasecmp(str, "response") == 0) {
   3924 			dt &= ~DNS_DTTYPE_QUERY;
   3925 		}
   3926 
   3927 		dttypes |= dt;
   3928 	}
   3929 
   3930 	if (named_g_server->dtenv == NULL && dttypes != 0) {
   3931 		dns_dtmode_t dmode;
   3932 		uint64_t max_size = 0;
   3933 		uint32_t rolls = 0;
   3934 		isc_log_rollsuffix_t suffix = isc_log_rollsuffix_increment;
   3935 
   3936 		obj = NULL;
   3937 		CHECKM(named_config_get(maps, "dnstap-output", &obj),
   3938 		       "'dnstap-output' must be set if 'dnstap' is set");
   3939 
   3940 		obj2 = cfg_tuple_get(obj, "mode");
   3941 		if (obj2 == NULL) {
   3942 			CHECKM(ISC_R_FAILURE, "dnstap-output mode not found");
   3943 		}
   3944 		if (strcasecmp(cfg_obj_asstring(obj2), "file") == 0) {
   3945 			dmode = dns_dtmode_file;
   3946 		} else {
   3947 			dmode = dns_dtmode_unix;
   3948 		}
   3949 
   3950 		obj2 = cfg_tuple_get(obj, "path");
   3951 		if (obj2 == NULL) {
   3952 			CHECKM(ISC_R_FAILURE, "dnstap-output path not found");
   3953 		}
   3954 
   3955 		dpath = cfg_obj_asstring(obj2);
   3956 
   3957 		obj2 = cfg_tuple_get(obj, "size");
   3958 		if (obj2 != NULL && cfg_obj_isuint64(obj2)) {
   3959 			max_size = cfg_obj_asuint64(obj2);
   3960 			if (max_size > SIZE_MAX) {
   3961 				cfg_obj_log(obj2, named_g_lctx, ISC_LOG_WARNING,
   3962 					    "'dnstap-output size "
   3963 					    "%" PRIu64 "' "
   3964 					    "is too large for this "
   3965 					    "system; reducing to %lu",
   3966 					    max_size, (unsigned long)SIZE_MAX);
   3967 				max_size = SIZE_MAX;
   3968 			}
   3969 		}
   3970 
   3971 		obj2 = cfg_tuple_get(obj, "versions");
   3972 		if (obj2 != NULL && cfg_obj_isuint32(obj2)) {
   3973 			rolls = cfg_obj_asuint32(obj2);
   3974 		} else {
   3975 			rolls = ISC_LOG_ROLLINFINITE;
   3976 		}
   3977 
   3978 		obj2 = cfg_tuple_get(obj, "suffix");
   3979 		if (obj2 != NULL && cfg_obj_isstring(obj2) &&
   3980 		    strcasecmp(cfg_obj_asstring(obj2), "timestamp") == 0)
   3981 		{
   3982 			suffix = isc_log_rollsuffix_timestamp;
   3983 		}
   3984 
   3985 		fopt = fstrm_iothr_options_init();
   3986 		/*
   3987 		 * Both network threads and worker threads may log dnstap data.
   3988 		 */
   3989 		fstrm_iothr_options_set_num_input_queues(fopt,
   3990 							 2 * named_g_cpus);
   3991 		fstrm_iothr_options_set_queue_model(
   3992 			fopt, FSTRM_IOTHR_QUEUE_MODEL_MPSC);
   3993 
   3994 		obj = NULL;
   3995 		result = named_config_get(maps, "fstrm-set-buffer-hint", &obj);
   3996 		if (result == ISC_R_SUCCESS) {
   3997 			i = cfg_obj_asuint32(obj);
   3998 			fstrm_iothr_options_set_buffer_hint(fopt, i);
   3999 		}
   4000 
   4001 		obj = NULL;
   4002 		result = named_config_get(maps, "fstrm-set-flush-timeout",
   4003 					  &obj);
   4004 		if (result == ISC_R_SUCCESS) {
   4005 			i = cfg_obj_asuint32(obj);
   4006 			fstrm_iothr_options_set_flush_timeout(fopt, i);
   4007 		}
   4008 
   4009 		obj = NULL;
   4010 		result = named_config_get(maps, "fstrm-set-input-queue-size",
   4011 					  &obj);
   4012 		if (result == ISC_R_SUCCESS) {
   4013 			i = cfg_obj_asuint32(obj);
   4014 			fstrm_iothr_options_set_input_queue_size(fopt, i);
   4015 		}
   4016 
   4017 		obj = NULL;
   4018 		result = named_config_get(
   4019 			maps, "fstrm-set-output-notify-threshold", &obj);
   4020 		if (result == ISC_R_SUCCESS) {
   4021 			i = cfg_obj_asuint32(obj);
   4022 			fstrm_iothr_options_set_queue_notify_threshold(fopt, i);
   4023 		}
   4024 
   4025 		obj = NULL;
   4026 		result = named_config_get(maps, "fstrm-set-output-queue-model",
   4027 					  &obj);
   4028 		if (result == ISC_R_SUCCESS) {
   4029 			if (strcasecmp(cfg_obj_asstring(obj), "spsc") == 0) {
   4030 				i = FSTRM_IOTHR_QUEUE_MODEL_SPSC;
   4031 			} else {
   4032 				i = FSTRM_IOTHR_QUEUE_MODEL_MPSC;
   4033 			}
   4034 			fstrm_iothr_options_set_queue_model(fopt, i);
   4035 		}
   4036 
   4037 		obj = NULL;
   4038 		result = named_config_get(maps, "fstrm-set-output-queue-size",
   4039 					  &obj);
   4040 		if (result == ISC_R_SUCCESS) {
   4041 			i = cfg_obj_asuint32(obj);
   4042 			fstrm_iothr_options_set_output_queue_size(fopt, i);
   4043 		}
   4044 
   4045 		obj = NULL;
   4046 		result = named_config_get(maps, "fstrm-set-reopen-interval",
   4047 					  &obj);
   4048 		if (result == ISC_R_SUCCESS) {
   4049 			i = cfg_obj_asduration(obj);
   4050 			fstrm_iothr_options_set_reopen_interval(fopt, i);
   4051 		}
   4052 
   4053 		CHECKM(dns_dt_create(named_g_mctx, dmode, dpath, &fopt,
   4054 				     named_g_mainloop, &named_g_server->dtenv),
   4055 		       "unable to create dnstap environment");
   4056 
   4057 		CHECKM(dns_dt_setupfile(named_g_server->dtenv, max_size, rolls,
   4058 					suffix),
   4059 		       "unable to set up dnstap logfile");
   4060 	}
   4061 
   4062 	if (named_g_server->dtenv == NULL) {
   4063 		return ISC_R_SUCCESS;
   4064 	}
   4065 
   4066 	obj = NULL;
   4067 	result = named_config_get(maps, "dnstap-version", &obj);
   4068 	if (result != ISC_R_SUCCESS) {
   4069 		/* not specified; use the product and version */
   4070 		dns_dt_setversion(named_g_server->dtenv, PACKAGE_STRING);
   4071 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
   4072 		/* Quoted string */
   4073 		dns_dt_setversion(named_g_server->dtenv, cfg_obj_asstring(obj));
   4074 	}
   4075 
   4076 	obj = NULL;
   4077 	result = named_config_get(maps, "dnstap-identity", &obj);
   4078 	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
   4079 		/* "hostname" is interpreted as boolean true */
   4080 		char buf[256];
   4081 		if (gethostname(buf, sizeof(buf)) == 0) {
   4082 			dns_dt_setidentity(named_g_server->dtenv, buf);
   4083 		}
   4084 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
   4085 		/* Quoted string */
   4086 		dns_dt_setidentity(named_g_server->dtenv,
   4087 				   cfg_obj_asstring(obj));
   4088 	}
   4089 
   4090 	dns_dt_attach(named_g_server->dtenv, &view->dtenv);
   4091 	view->dttypes = dttypes;
   4092 
   4093 	result = ISC_R_SUCCESS;
   4094 
   4095 cleanup:
   4096 	if (fopt != NULL) {
   4097 		fstrm_iothr_options_destroy(&fopt);
   4098 	}
   4099 
   4100 	return result;
   4101 }
   4102 #endif /* HAVE_DNSTAP */
   4103 
   4104 static isc_result_t
   4105 create_mapped_acl(void) {
   4106 	isc_result_t result;
   4107 	dns_acl_t *acl = NULL;
   4108 	struct in6_addr in6 = IN6ADDR_V4MAPPED_INIT;
   4109 	isc_netaddr_t addr;
   4110 
   4111 	isc_netaddr_fromin6(&addr, &in6);
   4112 
   4113 	dns_acl_create(named_g_mctx, 1, &acl);
   4114 
   4115 	result = dns_iptable_addprefix(acl->iptable, &addr, 96, true);
   4116 	if (result == ISC_R_SUCCESS) {
   4117 		dns_acl_attach(acl, &named_g_mapped);
   4118 	}
   4119 	dns_acl_detach(&acl);
   4120 	return result;
   4121 }
   4122 
   4123 /*%
   4124  * A callback for the cfg_pluginlist_foreach() call in configure_view() below.
   4125  * If registering any plugin fails, registering subsequent ones is not
   4126  * attempted.
   4127  */
   4128 static isc_result_t
   4129 register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj,
   4130 		    const char *plugin_path, const char *parameters,
   4131 		    void *callback_data) {
   4132 	dns_view_t *view = callback_data;
   4133 	char full_path[PATH_MAX];
   4134 	isc_result_t result;
   4135 
   4136 	result = ns_plugin_expandpath(plugin_path, full_path,
   4137 				      sizeof(full_path));
   4138 	if (result != ISC_R_SUCCESS) {
   4139 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   4140 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   4141 			      "%s: plugin configuration failed: "
   4142 			      "unable to get full plugin path: %s",
   4143 			      plugin_path, isc_result_totext(result));
   4144 		return result;
   4145 	}
   4146 
   4147 	result = ns_plugin_register(full_path, parameters, config,
   4148 				    cfg_obj_file(obj), cfg_obj_line(obj),
   4149 				    named_g_mctx, named_g_lctx,
   4150 				    named_g_aclconfctx, view);
   4151 	if (result != ISC_R_SUCCESS) {
   4152 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   4153 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   4154 			      "%s: plugin configuration failed: %s", full_path,
   4155 			      isc_result_totext(result));
   4156 	}
   4157 
   4158 	return result;
   4159 }
   4160 
   4161 static const char *const response_synonyms[] = { "response", NULL };
   4162 
   4163 /*
   4164  * Configure 'view' according to 'vconfig', taking defaults from
   4165  * 'config' where values are missing in 'vconfig'.
   4166  *
   4167  * When configuring the default view, 'vconfig' will be NULL and the
   4168  * global defaults in 'config' used exclusively.
   4169  */
   4170 static isc_result_t
   4171 configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
   4172 	       cfg_obj_t *vconfig, named_cachelist_t *cachelist,
   4173 	       named_cachelist_t *oldcachelist, dns_kasplist_t *kasplist,
   4174 	       dns_keystorelist_t *keystores, const cfg_obj_t *bindkeys,
   4175 	       isc_mem_t *mctx, cfg_aclconfctx_t *actx, bool need_hints,
   4176 	       bool first_time) {
   4177 	const cfg_obj_t *maps[4] = { 0 };
   4178 	const cfg_obj_t *cfgmaps[3] = { 0 };
   4179 	const cfg_obj_t *options = NULL;
   4180 	const cfg_obj_t *voptions = NULL;
   4181 	const cfg_obj_t *forwardtype;
   4182 	const cfg_obj_t *forwarders;
   4183 	const cfg_obj_t *alternates;
   4184 	const cfg_obj_t *zonelist;
   4185 	const cfg_obj_t *dlzlist;
   4186 	const cfg_obj_t *dlz;
   4187 	const cfg_obj_t *prefetch_trigger;
   4188 	const cfg_obj_t *prefetch_eligible;
   4189 	unsigned int dlzargc;
   4190 	char **dlzargv;
   4191 	const cfg_obj_t *dyndb_list, *plugin_list;
   4192 	const cfg_obj_t *disabled;
   4193 	const cfg_obj_t *obj, *obj2;
   4194 	const cfg_listelt_t *element = NULL;
   4195 	const cfg_listelt_t *zone_element_latest = NULL;
   4196 	in_port_t port;
   4197 	dns_cache_t *cache = NULL;
   4198 	isc_result_t result;
   4199 	size_t max_cache_size;
   4200 	uint32_t max_cache_size_percent = 0;
   4201 	size_t max_adb_size;
   4202 	uint32_t lame_ttl, fail_ttl;
   4203 	uint32_t max_stale_ttl = 0;
   4204 	uint32_t stale_refresh_time = 0;
   4205 	dns_tsigkeyring_t *ring = NULL;
   4206 	dns_transport_list_t *transports = NULL;
   4207 	dns_view_t *pview = NULL; /* Production view */
   4208 	dns_dispatch_t *dispatch4 = NULL;
   4209 	dns_dispatch_t *dispatch6 = NULL;
   4210 	bool rpz_configured = false;
   4211 	bool catz_configured = false;
   4212 	bool shared_cache = false;
   4213 	int i = 0, j = 0;
   4214 	const char *str = NULL;
   4215 	const char *cachename = NULL;
   4216 	dns_order_t *order = NULL;
   4217 	uint32_t udpsize;
   4218 	uint32_t maxbits;
   4219 	unsigned int resopts = 0;
   4220 	dns_zone_t *zone = NULL;
   4221 	uint32_t clients_per_query, max_clients_per_query;
   4222 	bool empty_zones_enable;
   4223 	const cfg_obj_t *disablelist = NULL;
   4224 	isc_stats_t *resstats = NULL;
   4225 	dns_stats_t *resquerystats = NULL;
   4226 	bool auto_root = false;
   4227 	named_cache_t *nsc = NULL;
   4228 	bool zero_no_soattl;
   4229 	dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
   4230 	unsigned int query_timeout;
   4231 	bool old_rpz_ok = false;
   4232 	dns_dyndbctx_t *dctx = NULL;
   4233 	dns_ntatable_t *ntatable = NULL;
   4234 	const char *qminmode = NULL;
   4235 	dns_adb_t *adb = NULL;
   4236 	bool oldcache = false;
   4237 	uint32_t padding;
   4238 
   4239 	REQUIRE(DNS_VIEW_VALID(view));
   4240 
   4241 	if (config != NULL) {
   4242 		(void)cfg_map_get(config, "options", &options);
   4243 	}
   4244 
   4245 	/*
   4246 	 * maps: view options, options, defaults
   4247 	 * cfgmaps: view options, top-level config
   4248 	 */
   4249 	if (vconfig != NULL) {
   4250 		voptions = cfg_tuple_get(vconfig, "options");
   4251 		maps[i++] = voptions;
   4252 		cfgmaps[j++] = voptions;
   4253 	}
   4254 	if (options != NULL) {
   4255 		maps[i++] = options;
   4256 	}
   4257 	maps[i++] = named_g_defaults;
   4258 
   4259 	if (config != NULL) {
   4260 		cfgmaps[j++] = config;
   4261 	}
   4262 
   4263 	/*
   4264 	 * Set the view's port number for outgoing queries.
   4265 	 */
   4266 	CHECKM(named_config_getport(config, "port", &port), "port");
   4267 	dns_view_setdstport(view, port);
   4268 
   4269 	/*
   4270 	 * Make the list of response policy zone names for a view that
   4271 	 * is used for real lookups and so cares about hints.
   4272 	 */
   4273 	obj = NULL;
   4274 	if (view->rdclass == dns_rdataclass_in && need_hints &&
   4275 	    named_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS)
   4276 	{
   4277 		CHECK(configure_rpz(view, NULL, maps, obj, &old_rpz_ok,
   4278 				    first_time));
   4279 		rpz_configured = true;
   4280 	}
   4281 
   4282 	obj = NULL;
   4283 	if (view->rdclass != dns_rdataclass_in && need_hints &&
   4284 	    named_config_get(maps, "catalog-zones", &obj) == ISC_R_SUCCESS)
   4285 	{
   4286 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   4287 			    "'catalog-zones' option is only supported "
   4288 			    "for views with class IN");
   4289 	}
   4290 
   4291 	obj = NULL;
   4292 	if (view->rdclass == dns_rdataclass_in && need_hints &&
   4293 	    named_config_get(maps, "catalog-zones", &obj) == ISC_R_SUCCESS)
   4294 	{
   4295 		CHECK(configure_catz(view, NULL, config, obj));
   4296 		catz_configured = true;
   4297 	}
   4298 
   4299 	/*
   4300 	 * Configure the zones.
   4301 	 */
   4302 	zonelist = NULL;
   4303 	if (voptions != NULL) {
   4304 		(void)cfg_map_get(voptions, "zone", &zonelist);
   4305 	} else {
   4306 		(void)cfg_map_get(config, "zone", &zonelist);
   4307 	}
   4308 
   4309 	/*
   4310 	 * Load zone configuration
   4311 	 */
   4312 	for (element = cfg_list_first(zonelist); element != NULL;
   4313 	     element = cfg_list_next(element))
   4314 	{
   4315 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
   4316 		CHECK(configure_zone(config, zconfig, vconfig, view, viewlist,
   4317 				     kasplist, keystores, actx, false,
   4318 				     old_rpz_ok, false, false));
   4319 		zone_element_latest = element;
   4320 	}
   4321 
   4322 	/*
   4323 	 * Check that a primary or secondary zone was found for each
   4324 	 * zone named in the response policy statement, unless we are
   4325 	 * using RPZ service interface.
   4326 	 */
   4327 	if (view->rpzs != NULL && !view->rpzs->p.dnsrps_enabled) {
   4328 		dns_rpz_num_t n;
   4329 
   4330 		for (n = 0; n < view->rpzs->p.num_zones; ++n) {
   4331 			if ((view->rpzs->defined & DNS_RPZ_ZBIT(n)) == 0) {
   4332 				char namebuf[DNS_NAME_FORMATSIZE];
   4333 
   4334 				dns_name_format(&view->rpzs->zones[n]->origin,
   4335 						namebuf, sizeof(namebuf));
   4336 				isc_log_write(named_g_lctx,
   4337 					      NAMED_LOGCATEGORY_GENERAL,
   4338 					      NAMED_LOGMODULE_SERVER,
   4339 					      DNS_RPZ_ERROR_LEVEL,
   4340 					      "rpz '%s' is not a primary or a "
   4341 					      "secondary zone",
   4342 					      namebuf);
   4343 				result = ISC_R_NOTFOUND;
   4344 				goto cleanup;
   4345 			}
   4346 		}
   4347 	}
   4348 
   4349 	/*
   4350 	 * If we're allowing added zones, then load zone configuration
   4351 	 * from the newzone file for zones that were added during previous
   4352 	 * runs.
   4353 	 */
   4354 	CHECK(configure_newzones(view, config, vconfig, actx));
   4355 
   4356 	/*
   4357 	 * Create Dynamically Loadable Zone driver.
   4358 	 */
   4359 	dlzlist = NULL;
   4360 	if (voptions != NULL) {
   4361 		(void)cfg_map_get(voptions, "dlz", &dlzlist);
   4362 	} else {
   4363 		(void)cfg_map_get(config, "dlz", &dlzlist);
   4364 	}
   4365 
   4366 	for (element = cfg_list_first(dlzlist); element != NULL;
   4367 	     element = cfg_list_next(element))
   4368 	{
   4369 		dlz = cfg_listelt_value(element);
   4370 
   4371 		obj = NULL;
   4372 		(void)cfg_map_get(dlz, "database", &obj);
   4373 		if (obj != NULL) {
   4374 			dns_dlzdb_t *dlzdb = NULL;
   4375 			const cfg_obj_t *name, *search = NULL;
   4376 			char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
   4377 
   4378 			if (s == NULL) {
   4379 				result = ISC_R_NOMEMORY;
   4380 				goto cleanup;
   4381 			}
   4382 
   4383 			result = isc_commandline_strtoargv(mctx, s, &dlzargc,
   4384 							   &dlzargv, 0);
   4385 			if (result != ISC_R_SUCCESS) {
   4386 				isc_mem_free(mctx, s);
   4387 				goto cleanup;
   4388 			}
   4389 
   4390 			name = cfg_map_getname(dlz);
   4391 			result = dns_dlzcreate(mctx, cfg_obj_asstring(name),
   4392 					       dlzargv[0], dlzargc, dlzargv,
   4393 					       &dlzdb);
   4394 			isc_mem_free(mctx, s);
   4395 			isc_mem_cput(mctx, dlzargv, dlzargc, sizeof(*dlzargv));
   4396 			if (result != ISC_R_SUCCESS) {
   4397 				goto cleanup;
   4398 			}
   4399 
   4400 			/*
   4401 			 * If the DLZ backend supports configuration,
   4402 			 * and is searchable, then call its configure
   4403 			 * method now.  If not searchable, we'll take
   4404 			 * care of it when we process the zone statement.
   4405 			 */
   4406 			(void)cfg_map_get(dlz, "search", &search);
   4407 			if (search == NULL || cfg_obj_asboolean(search)) {
   4408 				dlzdb->search = true;
   4409 				result = dns_dlzconfigure(
   4410 					view, dlzdb, dlzconfigure_callback);
   4411 				if (result != ISC_R_SUCCESS) {
   4412 					goto cleanup;
   4413 				}
   4414 				ISC_LIST_APPEND(view->dlz_searched, dlzdb,
   4415 						link);
   4416 			} else {
   4417 				dlzdb->search = false;
   4418 				ISC_LIST_APPEND(view->dlz_unsearched, dlzdb,
   4419 						link);
   4420 			}
   4421 		}
   4422 	}
   4423 
   4424 	/*
   4425 	 * Obtain configuration parameters that affect the decision of whether
   4426 	 * we can reuse/share an existing cache.
   4427 	 */
   4428 	obj = NULL;
   4429 	result = named_config_get(maps, "recursion", &obj);
   4430 	INSIST(result == ISC_R_SUCCESS);
   4431 	view->recursion = cfg_obj_asboolean(obj);
   4432 
   4433 	if (named_g_maxcachesize != 0) {
   4434 		/*
   4435 		 * If "-T maxcachesize=..." is in effect, it overrides any
   4436 		 * other "max-cache-size" setting found in configuration,
   4437 		 * either implicit or explicit.  For simplicity, the value
   4438 		 * passed to that command line option is always treated as
   4439 		 * the number of bytes to set "max-cache-size" to.
   4440 		 */
   4441 		max_cache_size = named_g_maxcachesize;
   4442 	} else {
   4443 		obj = NULL;
   4444 		result = named_config_get(maps, "max-cache-size", &obj);
   4445 		INSIST(result == ISC_R_SUCCESS);
   4446 		if (cfg_obj_isstring(obj) &&
   4447 		    strcasecmp(cfg_obj_asstring(obj), "default") == 0)
   4448 		{
   4449 			/*
   4450 			 * The default for a view with recursion
   4451 			 * is 90% of memory. With no recursion,
   4452 			 * it's the minimum cache size allowed by
   4453 			 * dns_cache_setcachesize().
   4454 			 */
   4455 			if (view->recursion) {
   4456 				max_cache_size = SIZE_AS_PERCENT;
   4457 				max_cache_size_percent = 90;
   4458 			} else {
   4459 				max_cache_size = 1;
   4460 			}
   4461 		} else if (cfg_obj_isstring(obj)) {
   4462 			str = cfg_obj_asstring(obj);
   4463 			INSIST(strcasecmp(str, "unlimited") == 0);
   4464 			max_cache_size = 0;
   4465 		} else if (cfg_obj_ispercentage(obj)) {
   4466 			max_cache_size = SIZE_AS_PERCENT;
   4467 			max_cache_size_percent = cfg_obj_aspercentage(obj);
   4468 		} else if (cfg_obj_isuint64(obj)) {
   4469 			uint64_t value = cfg_obj_asuint64(obj);
   4470 			if (value > SIZE_MAX) {
   4471 				cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   4472 					    "'max-cache-size "
   4473 					    "%" PRIu64 "' "
   4474 					    "is too large for this "
   4475 					    "system; reducing to %lu",
   4476 					    value, (unsigned long)SIZE_MAX);
   4477 				value = SIZE_MAX;
   4478 			}
   4479 			max_cache_size = (size_t)value;
   4480 		} else {
   4481 			UNREACHABLE();
   4482 		}
   4483 	}
   4484 
   4485 	if (max_cache_size == SIZE_AS_PERCENT) {
   4486 		uint64_t totalphys = isc_meminfo_totalphys();
   4487 
   4488 		max_cache_size =
   4489 			(size_t)(totalphys * max_cache_size_percent / 100);
   4490 		if (totalphys == 0) {
   4491 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   4492 				    "Unable to determine amount of physical "
   4493 				    "memory, setting 'max-cache-size' to "
   4494 				    "unlimited");
   4495 		} else {
   4496 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
   4497 				    "'max-cache-size %d%%' "
   4498 				    "- setting to %" PRIu64 "MB "
   4499 				    "(out of %" PRIu64 "MB)",
   4500 				    max_cache_size_percent,
   4501 				    (uint64_t)(max_cache_size / (1024 * 1024)),
   4502 				    totalphys / (1024 * 1024));
   4503 		}
   4504 	}
   4505 
   4506 	/* Check-names. */
   4507 	obj = NULL;
   4508 	result = named_checknames_get(maps, response_synonyms, &obj);
   4509 	INSIST(result == ISC_R_SUCCESS);
   4510 
   4511 	str = cfg_obj_asstring(obj);
   4512 	if (strcasecmp(str, "fail") == 0) {
   4513 		resopts |= DNS_RESOLVER_CHECKNAMES |
   4514 			   DNS_RESOLVER_CHECKNAMESFAIL;
   4515 		view->checknames = true;
   4516 	} else if (strcasecmp(str, "warn") == 0) {
   4517 		resopts |= DNS_RESOLVER_CHECKNAMES;
   4518 		view->checknames = false;
   4519 	} else if (strcasecmp(str, "ignore") == 0) {
   4520 		view->checknames = false;
   4521 	} else {
   4522 		UNREACHABLE();
   4523 	}
   4524 
   4525 	obj = NULL;
   4526 	result = named_config_get(maps, "zero-no-soa-ttl-cache", &obj);
   4527 	INSIST(result == ISC_R_SUCCESS);
   4528 	zero_no_soattl = cfg_obj_asboolean(obj);
   4529 
   4530 	obj = NULL;
   4531 	result = named_config_get(maps, "resolver-use-dns64", &obj);
   4532 	INSIST(result == ISC_R_SUCCESS);
   4533 	view->usedns64 = cfg_obj_asboolean(obj);
   4534 
   4535 	obj = NULL;
   4536 	result = named_config_get(maps, "dns64", &obj);
   4537 	if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") &&
   4538 	    strcmp(view->name, "_meta"))
   4539 	{
   4540 		isc_netaddr_t na, suffix, *sp;
   4541 		unsigned int prefixlen;
   4542 		const char *server, *contact;
   4543 		const cfg_obj_t *myobj;
   4544 
   4545 		myobj = NULL;
   4546 		result = named_config_get(maps, "dns64-server", &myobj);
   4547 		if (result == ISC_R_SUCCESS) {
   4548 			server = cfg_obj_asstring(myobj);
   4549 		} else {
   4550 			server = NULL;
   4551 		}
   4552 
   4553 		myobj = NULL;
   4554 		result = named_config_get(maps, "dns64-contact", &myobj);
   4555 		if (result == ISC_R_SUCCESS) {
   4556 			contact = cfg_obj_asstring(myobj);
   4557 		} else {
   4558 			contact = NULL;
   4559 		}
   4560 
   4561 		for (element = cfg_list_first(obj); element != NULL;
   4562 		     element = cfg_list_next(element))
   4563 		{
   4564 			const cfg_obj_t *map = cfg_listelt_value(element);
   4565 			dns_dns64_t *dns64 = NULL;
   4566 			unsigned int dns64options = 0;
   4567 
   4568 			cfg_obj_asnetprefix(cfg_map_getname(map), &na,
   4569 					    &prefixlen);
   4570 
   4571 			obj = NULL;
   4572 			(void)cfg_map_get(map, "suffix", &obj);
   4573 			if (obj != NULL) {
   4574 				sp = &suffix;
   4575 				isc_netaddr_fromsockaddr(
   4576 					sp, cfg_obj_assockaddr(obj));
   4577 			} else {
   4578 				sp = NULL;
   4579 			}
   4580 
   4581 			clients = mapped = excluded = NULL;
   4582 			obj = NULL;
   4583 			(void)cfg_map_get(map, "clients", &obj);
   4584 			if (obj != NULL) {
   4585 				result = cfg_acl_fromconfig(obj, config,
   4586 							    named_g_lctx, actx,
   4587 							    mctx, 0, &clients);
   4588 				if (result != ISC_R_SUCCESS) {
   4589 					goto cleanup;
   4590 				}
   4591 			}
   4592 			obj = NULL;
   4593 			(void)cfg_map_get(map, "mapped", &obj);
   4594 			if (obj != NULL) {
   4595 				result = cfg_acl_fromconfig(obj, config,
   4596 							    named_g_lctx, actx,
   4597 							    mctx, 0, &mapped);
   4598 				if (result != ISC_R_SUCCESS) {
   4599 					goto cleanup;
   4600 				}
   4601 			}
   4602 			obj = NULL;
   4603 			(void)cfg_map_get(map, "exclude", &obj);
   4604 			if (obj != NULL) {
   4605 				result = cfg_acl_fromconfig(obj, config,
   4606 							    named_g_lctx, actx,
   4607 							    mctx, 0, &excluded);
   4608 				if (result != ISC_R_SUCCESS) {
   4609 					goto cleanup;
   4610 				}
   4611 			} else {
   4612 				if (named_g_mapped == NULL) {
   4613 					result = create_mapped_acl();
   4614 					if (result != ISC_R_SUCCESS) {
   4615 						goto cleanup;
   4616 					}
   4617 				}
   4618 				dns_acl_attach(named_g_mapped, &excluded);
   4619 			}
   4620 
   4621 			obj = NULL;
   4622 			(void)cfg_map_get(map, "recursive-only", &obj);
   4623 			if (obj != NULL && cfg_obj_asboolean(obj)) {
   4624 				dns64options |= DNS_DNS64_RECURSIVE_ONLY;
   4625 			}
   4626 
   4627 			obj = NULL;
   4628 			(void)cfg_map_get(map, "break-dnssec", &obj);
   4629 			if (obj != NULL && cfg_obj_asboolean(obj)) {
   4630 				dns64options |= DNS_DNS64_BREAK_DNSSEC;
   4631 			}
   4632 
   4633 			result = dns_dns64_create(mctx, &na, prefixlen, sp,
   4634 						  clients, mapped, excluded,
   4635 						  dns64options, &dns64);
   4636 			if (result != ISC_R_SUCCESS) {
   4637 				goto cleanup;
   4638 			}
   4639 			dns_dns64_append(&view->dns64, dns64);
   4640 			view->dns64cnt++;
   4641 			result = dns64_reverse(view, mctx, &na, prefixlen,
   4642 					       server, contact);
   4643 			if (result != ISC_R_SUCCESS) {
   4644 				goto cleanup;
   4645 			}
   4646 			if (clients != NULL) {
   4647 				dns_acl_detach(&clients);
   4648 			}
   4649 			if (mapped != NULL) {
   4650 				dns_acl_detach(&mapped);
   4651 			}
   4652 			if (excluded != NULL) {
   4653 				dns_acl_detach(&excluded);
   4654 			}
   4655 		}
   4656 	}
   4657 
   4658 	obj = NULL;
   4659 	result = named_config_get(maps, "dnssec-accept-expired", &obj);
   4660 	INSIST(result == ISC_R_SUCCESS);
   4661 	view->acceptexpired = cfg_obj_asboolean(obj);
   4662 
   4663 	obj = NULL;
   4664 	result = named_config_get(maps, "dnssec-validation", &obj);
   4665 	INSIST(result == ISC_R_SUCCESS);
   4666 	if (cfg_obj_isboolean(obj)) {
   4667 		view->enablevalidation = cfg_obj_asboolean(obj);
   4668 	} else {
   4669 		/*
   4670 		 * If dnssec-validation is set but not boolean,
   4671 		 * then it must be "auto"
   4672 		 */
   4673 		view->enablevalidation = true;
   4674 		auto_root = true;
   4675 	}
   4676 
   4677 	obj = NULL;
   4678 	result = named_config_get(maps, "max-cache-ttl", &obj);
   4679 	INSIST(result == ISC_R_SUCCESS);
   4680 	view->maxcachettl = cfg_obj_asduration(obj);
   4681 
   4682 	obj = NULL;
   4683 	result = named_config_get(maps, "max-ncache-ttl", &obj);
   4684 	INSIST(result == ISC_R_SUCCESS);
   4685 	view->maxncachettl = cfg_obj_asduration(obj);
   4686 
   4687 	obj = NULL;
   4688 	result = named_config_get(maps, "min-cache-ttl", &obj);
   4689 	INSIST(result == ISC_R_SUCCESS);
   4690 	view->mincachettl = cfg_obj_asduration(obj);
   4691 
   4692 	obj = NULL;
   4693 	result = named_config_get(maps, "min-ncache-ttl", &obj);
   4694 	INSIST(result == ISC_R_SUCCESS);
   4695 	view->minncachettl = cfg_obj_asduration(obj);
   4696 
   4697 	obj = NULL;
   4698 	result = named_config_get(maps, "synth-from-dnssec", &obj);
   4699 	INSIST(result == ISC_R_SUCCESS);
   4700 	view->synthfromdnssec = cfg_obj_asboolean(obj);
   4701 
   4702 	obj = NULL;
   4703 	result = named_config_get(maps, "stale-cache-enable", &obj);
   4704 	INSIST(result == ISC_R_SUCCESS);
   4705 	if (cfg_obj_asboolean(obj)) {
   4706 		obj = NULL;
   4707 		result = named_config_get(maps, "max-stale-ttl", &obj);
   4708 		INSIST(result == ISC_R_SUCCESS);
   4709 		max_stale_ttl = ISC_MAX(cfg_obj_asduration(obj), 1);
   4710 	}
   4711 	/*
   4712 	 * If 'stale-cache-enable' is false, max_stale_ttl is set to 0,
   4713 	 * meaning keeping stale RRsets in cache is disabled.
   4714 	 */
   4715 
   4716 	obj = NULL;
   4717 	result = named_config_get(maps, "stale-answer-enable", &obj);
   4718 	INSIST(result == ISC_R_SUCCESS);
   4719 	view->staleanswersenable = cfg_obj_asboolean(obj);
   4720 
   4721 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
   4722 				   view->rdclass, &pview);
   4723 	if (result == ISC_R_SUCCESS) {
   4724 		view->staleanswersok = pview->staleanswersok;
   4725 		dns_view_detach(&pview);
   4726 	} else {
   4727 		view->staleanswersok = dns_stale_answer_conf;
   4728 	}
   4729 
   4730 	obj = NULL;
   4731 	result = named_config_get(maps, "stale-answer-client-timeout", &obj);
   4732 	INSIST(result == ISC_R_SUCCESS);
   4733 	if (cfg_obj_isstring(obj)) {
   4734 		/*
   4735 		 * The only string values available for this option
   4736 		 * are "disabled" and "off".
   4737 		 * We use (uint32_t) -1 to represent disabled since
   4738 		 * a value of zero means that stale data can be used
   4739 		 * to promptly answer the query, while an attempt to
   4740 		 * refresh the RRset will still be made in background.
   4741 		 */
   4742 		view->staleanswerclienttimeout = (uint32_t)-1;
   4743 	} else {
   4744 		view->staleanswerclienttimeout = cfg_obj_asuint32(obj);
   4745 
   4746 		/*
   4747 		 * BIND 9 no longer supports non-zero values of
   4748 		 * stale-answer-client-timeout.
   4749 		 */
   4750 		if (view->staleanswerclienttimeout != 0) {
   4751 			view->staleanswerclienttimeout = 0;
   4752 			isc_log_write(
   4753 				named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   4754 				NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   4755 				"BIND 9 no longer supports non-zero values of "
   4756 				"stale-answer-client-timeout, adjusted to 0");
   4757 		}
   4758 	}
   4759 
   4760 	obj = NULL;
   4761 	result = named_config_get(maps, "stale-refresh-time", &obj);
   4762 	INSIST(result == ISC_R_SUCCESS);
   4763 	stale_refresh_time = cfg_obj_asduration(obj);
   4764 
   4765 	/*
   4766 	 * Configure the view's cache.
   4767 	 *
   4768 	 * First, check to see if there are any attach-cache options.  If yes,
   4769 	 * attempt to lookup an existing cache at attach it to the view.  If
   4770 	 * there is not one, then try to reuse an existing cache if possible;
   4771 	 * otherwise create a new cache.
   4772 	 *
   4773 	 * Note that the ADB is not preserved or shared in either case.
   4774 	 *
   4775 	 * When a matching view is found, the associated statistics are also
   4776 	 * retrieved and reused.
   4777 	 *
   4778 	 * XXX Determining when it is safe to reuse or share a cache is tricky.
   4779 	 * When the view's configuration changes, the cached data may become
   4780 	 * invalid because it reflects our old view of the world.  We check
   4781 	 * some of the configuration parameters that could invalidate the cache
   4782 	 * or otherwise make it unshareable, but there are other configuration
   4783 	 * options that should be checked.  For example, if a view uses a
   4784 	 * forwarder, changes in the forwarder configuration may invalidate
   4785 	 * the cache.  At the moment, it's the administrator's responsibility to
   4786 	 * ensure these configuration options don't invalidate reusing/sharing.
   4787 	 */
   4788 	obj = NULL;
   4789 	result = named_config_get(maps, "attach-cache", &obj);
   4790 	if (result == ISC_R_SUCCESS) {
   4791 		cachename = cfg_obj_asstring(obj);
   4792 	} else {
   4793 		cachename = view->name;
   4794 	}
   4795 
   4796 	nsc = cachelist_find(cachelist, cachename, view->rdclass);
   4797 	if (result == ISC_R_SUCCESS && nsc == NULL) {
   4798 		/*
   4799 		 * If we're using 'attach-cache' but didn't find the
   4800 		 * specified cache in the cache list already, check
   4801 		 * the old list.
   4802 		 */
   4803 		nsc = cachelist_find(oldcachelist, cachename, view->rdclass);
   4804 		oldcache = true;
   4805 	}
   4806 	if (nsc != NULL) {
   4807 		if (!cache_sharable(nsc->primaryview, view, zero_no_soattl,
   4808 				    max_cache_size, max_stale_ttl,
   4809 				    stale_refresh_time))
   4810 		{
   4811 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   4812 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   4813 				      "view %s can't use existing cache %s due "
   4814 				      "to configuration parameter mismatch",
   4815 				      view->name,
   4816 				      dns_cache_getname(nsc->cache));
   4817 			nsc = NULL;
   4818 		} else {
   4819 			shared_cache = true;
   4820 			dns_cache_attach(nsc->cache, &cache);
   4821 			if (oldcache) {
   4822 				/*
   4823 				 * We need to re-use the cache, but we don't
   4824 				 * want to mutate the old production list.
   4825 				 */
   4826 				nsc = NULL;
   4827 			}
   4828 		}
   4829 	} else if (strcmp(cachename, view->name) == 0) {
   4830 		result = dns_viewlist_find(&named_g_server->viewlist, cachename,
   4831 					   view->rdclass, &pview);
   4832 		if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
   4833 			goto cleanup;
   4834 		}
   4835 		if (pview != NULL) {
   4836 			if (!cache_reusable(pview, view, zero_no_soattl)) {
   4837 				isc_log_write(named_g_lctx,
   4838 					      NAMED_LOGCATEGORY_GENERAL,
   4839 					      NAMED_LOGMODULE_SERVER,
   4840 					      ISC_LOG_DEBUG(1),
   4841 					      "cache cannot be reused "
   4842 					      "for view %s due to "
   4843 					      "configuration parameter "
   4844 					      "mismatch",
   4845 					      view->name);
   4846 			} else {
   4847 				INSIST(pview->cache != NULL);
   4848 				isc_log_write(named_g_lctx,
   4849 					      NAMED_LOGCATEGORY_GENERAL,
   4850 					      NAMED_LOGMODULE_SERVER,
   4851 					      ISC_LOG_DEBUG(3),
   4852 					      "reusing existing cache");
   4853 				dns_cache_attach(pview->cache, &cache);
   4854 			}
   4855 			dns_resolver_getstats(pview->resolver, &resstats);
   4856 			dns_resolver_getquerystats(pview->resolver,
   4857 						   &resquerystats);
   4858 			dns_view_detach(&pview);
   4859 		}
   4860 	}
   4861 
   4862 	if (nsc == NULL) {
   4863 		/*
   4864 		 * Create a cache with the desired name.  This normally
   4865 		 * equals the view name, but may also be a forward
   4866 		 * reference to a view that share the cache with this
   4867 		 * view but is not yet configured.  If it is not the
   4868 		 * view name but not a forward reference either, then it
   4869 		 * is simply a named cache that is not shared.
   4870 		 */
   4871 		if (cache == NULL) {
   4872 			CHECK(dns_cache_create(named_g_loopmgr, view->rdclass,
   4873 					       cachename, mctx, &cache));
   4874 		}
   4875 
   4876 		nsc = isc_mem_get(mctx, sizeof(*nsc));
   4877 		*nsc = (named_cache_t){
   4878 			.primaryview = view,
   4879 			.rdclass = view->rdclass,
   4880 			.link = ISC_LINK_INITIALIZER,
   4881 		};
   4882 
   4883 		dns_cache_attach(cache, &nsc->cache);
   4884 		ISC_LIST_APPEND(*cachelist, nsc, link);
   4885 	}
   4886 
   4887 	dns_view_setcache(view, cache, shared_cache);
   4888 
   4889 	dns_cache_setcachesize(cache, max_cache_size);
   4890 	dns_cache_setservestalettl(cache, max_stale_ttl);
   4891 	dns_cache_setservestalerefresh(cache, stale_refresh_time);
   4892 
   4893 	dns_cache_detach(&cache);
   4894 
   4895 	obj = NULL;
   4896 	result = named_config_get(maps, "stale-answer-ttl", &obj);
   4897 	INSIST(result == ISC_R_SUCCESS);
   4898 	view->staleanswerttl = ISC_MAX(cfg_obj_asduration(obj), 1);
   4899 
   4900 	/*
   4901 	 * Resolver.
   4902 	 */
   4903 	CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4,
   4904 					    ISC_LIST_PREV(view, link) == NULL));
   4905 	CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6,
   4906 					    ISC_LIST_PREV(view, link) == NULL));
   4907 	if (dispatch4 == NULL && dispatch6 == NULL) {
   4908 		UNEXPECTED_ERROR("unable to obtain either an IPv4 or"
   4909 				 " an IPv6 dispatch");
   4910 		result = ISC_R_UNEXPECTED;
   4911 		goto cleanup;
   4912 	}
   4913 
   4914 	CHECK(dns_view_createresolver(view, named_g_netmgr, resopts,
   4915 				      named_g_server->tlsctx_client_cache,
   4916 				      dispatch4, dispatch6));
   4917 
   4918 	if (resstats == NULL) {
   4919 		isc_stats_create(mctx, &resstats, dns_resstatscounter_max);
   4920 	}
   4921 	dns_resolver_setstats(view->resolver, resstats);
   4922 	if (resquerystats == NULL) {
   4923 		dns_rdatatypestats_create(mctx, &resquerystats);
   4924 	}
   4925 	dns_resolver_setquerystats(view->resolver, resquerystats);
   4926 
   4927 	/*
   4928 	 * Set the ADB cache size to 1/8th of the max-cache-size or
   4929 	 * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
   4930 	 */
   4931 	max_adb_size = 0;
   4932 	if (max_cache_size != 0U) {
   4933 		max_adb_size = max_cache_size / 8;
   4934 		if (max_adb_size == 0U) {
   4935 			max_adb_size = 1; /* Force minimum. */
   4936 		}
   4937 		if (view != nsc->primaryview &&
   4938 		    max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE)
   4939 		{
   4940 			max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE;
   4941 			if (!nsc->adbsizeadjusted) {
   4942 				dns_view_getadb(nsc->primaryview, &adb);
   4943 				if (adb != NULL) {
   4944 					dns_adb_setadbsize(
   4945 						adb,
   4946 						MAX_ADB_SIZE_FOR_CACHESHARE);
   4947 					nsc->adbsizeadjusted = true;
   4948 					dns_adb_detach(&adb);
   4949 				}
   4950 			}
   4951 		}
   4952 	}
   4953 	dns_view_getadb(view, &adb);
   4954 	if (adb != NULL) {
   4955 		dns_adb_setadbsize(adb, max_adb_size);
   4956 		dns_adb_detach(&adb);
   4957 	}
   4958 
   4959 	/*
   4960 	 * Set up ADB quotas
   4961 	 */
   4962 	{
   4963 		uint32_t fps, freq;
   4964 		double low, high, discount;
   4965 
   4966 		obj = NULL;
   4967 		result = named_config_get(maps, "fetches-per-server", &obj);
   4968 		INSIST(result == ISC_R_SUCCESS);
   4969 		obj2 = cfg_tuple_get(obj, "fetches");
   4970 		fps = cfg_obj_asuint32(obj2);
   4971 		obj2 = cfg_tuple_get(obj, "response");
   4972 		if (!cfg_obj_isvoid(obj2)) {
   4973 			const char *resp = cfg_obj_asstring(obj2);
   4974 			isc_result_t r = DNS_R_SERVFAIL;
   4975 
   4976 			if (strcasecmp(resp, "drop") == 0) {
   4977 				r = DNS_R_DROP;
   4978 			} else if (strcasecmp(resp, "fail") == 0) {
   4979 				r = DNS_R_SERVFAIL;
   4980 			} else {
   4981 				UNREACHABLE();
   4982 			}
   4983 
   4984 			dns_resolver_setquotaresponse(view->resolver,
   4985 						      dns_quotatype_server, r);
   4986 		}
   4987 
   4988 		obj = NULL;
   4989 		result = named_config_get(maps, "fetch-quota-params", &obj);
   4990 		INSIST(result == ISC_R_SUCCESS);
   4991 
   4992 		obj2 = cfg_tuple_get(obj, "frequency");
   4993 		freq = cfg_obj_asuint32(obj2);
   4994 
   4995 		obj2 = cfg_tuple_get(obj, "low");
   4996 		low = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
   4997 
   4998 		obj2 = cfg_tuple_get(obj, "high");
   4999 		high = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
   5000 
   5001 		obj2 = cfg_tuple_get(obj, "discount");
   5002 		discount = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
   5003 
   5004 		dns_view_getadb(view, &adb);
   5005 		if (adb != NULL) {
   5006 			dns_adb_setquota(adb, fps, freq, low, high, discount);
   5007 			dns_adb_detach(&adb);
   5008 		}
   5009 	}
   5010 
   5011 	/*
   5012 	 * Set resolver's lame-ttl.
   5013 	 */
   5014 	obj = NULL;
   5015 	result = named_config_get(maps, "lame-ttl", &obj);
   5016 	INSIST(result == ISC_R_SUCCESS);
   5017 	lame_ttl = cfg_obj_asduration(obj);
   5018 	if (lame_ttl > 0) {
   5019 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   5020 			    "disabling lame cache despite lame-ttl > 0 as it "
   5021 			    "may cause performance issues");
   5022 	}
   5023 
   5024 	/*
   5025 	 * Set the resolver's query timeout.
   5026 	 */
   5027 	obj = NULL;
   5028 	result = named_config_get(maps, "resolver-query-timeout", &obj);
   5029 	INSIST(result == ISC_R_SUCCESS);
   5030 	query_timeout = cfg_obj_asuint32(obj);
   5031 	dns_resolver_settimeout(view->resolver, query_timeout);
   5032 
   5033 	/* Specify whether to use 0-TTL for negative response for SOA query */
   5034 	dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl);
   5035 
   5036 	/*
   5037 	 * Set the resolver's EDNS UDP size.
   5038 	 */
   5039 	obj = NULL;
   5040 	result = named_config_get(maps, "edns-udp-size", &obj);
   5041 	INSIST(result == ISC_R_SUCCESS);
   5042 	udpsize = cfg_obj_asuint32(obj);
   5043 	if (udpsize < 512) {
   5044 		udpsize = 512;
   5045 	}
   5046 	if (udpsize > 4096) {
   5047 		udpsize = 4096;
   5048 	}
   5049 	dns_view_setudpsize(view, (uint16_t)udpsize);
   5050 
   5051 	/*
   5052 	 * Set the maximum UDP response size.
   5053 	 */
   5054 	obj = NULL;
   5055 	result = named_config_get(maps, "max-udp-size", &obj);
   5056 	INSIST(result == ISC_R_SUCCESS);
   5057 	udpsize = cfg_obj_asuint32(obj);
   5058 	if (udpsize < 512) {
   5059 		udpsize = 512;
   5060 	}
   5061 	if (udpsize > 4096) {
   5062 		udpsize = 4096;
   5063 	}
   5064 	view->maxudp = udpsize;
   5065 
   5066 	/*
   5067 	 * Set the maximum UDP when a COOKIE is not provided.
   5068 	 */
   5069 	obj = NULL;
   5070 	result = named_config_get(maps, "nocookie-udp-size", &obj);
   5071 	INSIST(result == ISC_R_SUCCESS);
   5072 	udpsize = cfg_obj_asuint32(obj);
   5073 	if (udpsize < 128) {
   5074 		udpsize = 128;
   5075 	}
   5076 	if (udpsize > view->maxudp) {
   5077 		udpsize = view->maxudp;
   5078 	}
   5079 	view->nocookieudp = udpsize;
   5080 
   5081 	/*
   5082 	 * Set the maximum rsa exponent bits.
   5083 	 */
   5084 	obj = NULL;
   5085 	result = named_config_get(maps, "max-rsa-exponent-size", &obj);
   5086 	INSIST(result == ISC_R_SUCCESS);
   5087 	maxbits = cfg_obj_asuint32(obj);
   5088 	if (maxbits != 0 && maxbits < 35) {
   5089 		maxbits = 35;
   5090 	}
   5091 	if (maxbits > 4096) {
   5092 		maxbits = 4096;
   5093 	}
   5094 	view->maxbits = maxbits;
   5095 
   5096 	/*
   5097 	 * Set supported DNSSEC algorithms.
   5098 	 */
   5099 	disabled = NULL;
   5100 	(void)named_config_get(maps, "disable-algorithms", &disabled);
   5101 	if (disabled != NULL) {
   5102 		for (element = cfg_list_first(disabled); element != NULL;
   5103 		     element = cfg_list_next(element))
   5104 		{
   5105 			CHECK(disable_algorithms(cfg_listelt_value(element),
   5106 						 view->resolver));
   5107 		}
   5108 	}
   5109 
   5110 	/*
   5111 	 * Set supported DS digest types.
   5112 	 */
   5113 	disabled = NULL;
   5114 	(void)named_config_get(maps, "disable-ds-digests", &disabled);
   5115 	if (disabled != NULL) {
   5116 		for (element = cfg_list_first(disabled); element != NULL;
   5117 		     element = cfg_list_next(element))
   5118 		{
   5119 			CHECK(disable_ds_digests(cfg_listelt_value(element),
   5120 						 view->resolver));
   5121 		}
   5122 	}
   5123 
   5124 	/*
   5125 	 * A global or view "forwarders" option, if present,
   5126 	 * creates an entry for "." in the forwarding table.
   5127 	 */
   5128 	forwardtype = NULL;
   5129 	forwarders = NULL;
   5130 	(void)named_config_get(maps, "forward", &forwardtype);
   5131 	(void)named_config_get(maps, "forwarders", &forwarders);
   5132 	if (forwarders != NULL) {
   5133 		CHECK(configure_forward(config, view, dns_rootname, forwarders,
   5134 					forwardtype));
   5135 	}
   5136 
   5137 	/*
   5138 	 * Dual Stack Servers.
   5139 	 */
   5140 	alternates = NULL;
   5141 	(void)named_config_get(maps, "dual-stack-servers", &alternates);
   5142 	if (alternates != NULL) {
   5143 		CHECK(configure_alternates(config, view, alternates));
   5144 	}
   5145 
   5146 	/*
   5147 	 * We have default hints for class IN if we need them.
   5148 	 */
   5149 	if (view->rdclass == dns_rdataclass_in && view->hints == NULL) {
   5150 		dns_view_sethints(view, named_g_server->in_roothints);
   5151 	}
   5152 
   5153 	/*
   5154 	 * If we still have no hints, this is a non-IN view with no
   5155 	 * "hints zone" configured.  Issue a warning, except if this
   5156 	 * is a root server.  Root servers never need to consult
   5157 	 * their hints, so it's no point requiring users to configure
   5158 	 * them.
   5159 	 */
   5160 	if (view->hints == NULL) {
   5161 		dns_zone_t *rootzone = NULL;
   5162 		(void)dns_view_findzone(view, dns_rootname, DNS_ZTFIND_EXACT,
   5163 					&rootzone);
   5164 		if (rootzone != NULL) {
   5165 			dns_zone_detach(&rootzone);
   5166 			need_hints = false;
   5167 		}
   5168 		if (need_hints) {
   5169 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   5170 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   5171 				      "no root hints for view '%s'",
   5172 				      view->name);
   5173 		}
   5174 	}
   5175 
   5176 	/*
   5177 	 * Configure the view's transports (DoT/DoH)
   5178 	 */
   5179 	CHECK(named_transports_fromconfig(config, vconfig, view->mctx,
   5180 					  &transports));
   5181 	dns_view_settransports(view, transports);
   5182 	dns_transport_list_detach(&transports);
   5183 
   5184 	/*
   5185 	 * Configure SIG(0) check limits when matching a DNS message to a view.
   5186 	 */
   5187 	obj = NULL;
   5188 	result = named_config_get(maps, "sig0key-checks-limit", &obj);
   5189 	INSIST(result == ISC_R_SUCCESS);
   5190 	view->sig0key_checks_limit = cfg_obj_asuint32(obj);
   5191 
   5192 	obj = NULL;
   5193 	result = named_config_get(maps, "sig0message-checks-limit", &obj);
   5194 	INSIST(result == ISC_R_SUCCESS);
   5195 	view->sig0message_checks_limit = cfg_obj_asuint32(obj);
   5196 
   5197 	/*
   5198 	 * Configure the view's TSIG keys.
   5199 	 */
   5200 	CHECK(named_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
   5201 	if (named_g_server->sessionkey != NULL) {
   5202 		dns_tsigkey_t *tsigkey = NULL;
   5203 		result = dns_tsigkey_createfromkey(
   5204 			named_g_server->session_keyname,
   5205 			named_g_server->session_keyalg,
   5206 			named_g_server->sessionkey, false, false, NULL, 0, 0,
   5207 			mctx, &tsigkey);
   5208 		if (result == ISC_R_SUCCESS) {
   5209 			result = dns_tsigkeyring_add(ring, tsigkey);
   5210 			dns_tsigkey_detach(&tsigkey);
   5211 		}
   5212 		CHECK(result);
   5213 	}
   5214 	dns_view_setkeyring(view, ring);
   5215 	dns_tsigkeyring_detach(&ring);
   5216 
   5217 	/*
   5218 	 * See if we can re-use a dynamic key ring.
   5219 	 */
   5220 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
   5221 				   view->rdclass, &pview);
   5222 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
   5223 		goto cleanup;
   5224 	}
   5225 	if (pview != NULL) {
   5226 		dns_view_getdynamickeyring(pview, &ring);
   5227 		if (ring != NULL) {
   5228 			dns_view_setdynamickeyring(view, ring);
   5229 		}
   5230 		dns_tsigkeyring_detach(&ring);
   5231 		dns_view_detach(&pview);
   5232 	} else {
   5233 		dns_view_restorekeyring(view);
   5234 	}
   5235 
   5236 	/*
   5237 	 * Configure the view's peer list.
   5238 	 */
   5239 	{
   5240 		const cfg_obj_t *peers = NULL;
   5241 		dns_peerlist_t *newpeers = NULL;
   5242 
   5243 		(void)named_config_get(cfgmaps, "server", &peers);
   5244 		CHECK(dns_peerlist_new(mctx, &newpeers));
   5245 		for (element = cfg_list_first(peers); element != NULL;
   5246 		     element = cfg_list_next(element))
   5247 		{
   5248 			const cfg_obj_t *cpeer = cfg_listelt_value(element);
   5249 			dns_peer_t *peer;
   5250 
   5251 			CHECK(configure_peer(cpeer, mctx, &peer));
   5252 			dns_peerlist_addpeer(newpeers, peer);
   5253 			dns_peer_detach(&peer);
   5254 		}
   5255 		dns_peerlist_detach(&view->peers);
   5256 		view->peers = newpeers; /* Transfer ownership. */
   5257 	}
   5258 
   5259 	/*
   5260 	 *	Configure the views rrset-order.
   5261 	 */
   5262 	{
   5263 		const cfg_obj_t *rrsetorder = NULL;
   5264 
   5265 		(void)named_config_get(maps, "rrset-order", &rrsetorder);
   5266 		CHECK(dns_order_create(mctx, &order));
   5267 		for (element = cfg_list_first(rrsetorder); element != NULL;
   5268 		     element = cfg_list_next(element))
   5269 		{
   5270 			const cfg_obj_t *ent = cfg_listelt_value(element);
   5271 
   5272 			CHECK(configure_order(order, ent));
   5273 		}
   5274 		if (view->order != NULL) {
   5275 			dns_order_detach(&view->order);
   5276 		}
   5277 		dns_order_attach(order, &view->order);
   5278 		dns_order_detach(&order);
   5279 	}
   5280 	/*
   5281 	 * Copy the aclenv object.
   5282 	 */
   5283 	dns_aclenv_copy(view->aclenv, ns_interfacemgr_getaclenv(
   5284 					      named_g_server->interfacemgr));
   5285 
   5286 	/*
   5287 	 * Configure the "match-clients" and "match-destinations" ACL.
   5288 	 * (These are only meaningful at the view level, but 'config'
   5289 	 * must be passed so that named ACLs defined at the global level
   5290 	 * can be retrieved.)
   5291 	 */
   5292 	CHECK(configure_view_acl(vconfig, config, NULL, "match-clients", NULL,
   5293 				 actx, named_g_mctx, &view->matchclients));
   5294 	CHECK(configure_view_acl(vconfig, config, NULL, "match-destinations",
   5295 				 NULL, actx, named_g_mctx,
   5296 				 &view->matchdestinations));
   5297 
   5298 	/*
   5299 	 * Configure the "match-recursive-only" option.
   5300 	 */
   5301 	obj = NULL;
   5302 	(void)named_config_get(maps, "match-recursive-only", &obj);
   5303 	if (obj != NULL && cfg_obj_asboolean(obj)) {
   5304 		view->matchrecursiveonly = true;
   5305 	} else {
   5306 		view->matchrecursiveonly = false;
   5307 	}
   5308 
   5309 	/*
   5310 	 * Configure other configurable data.
   5311 	 */
   5312 	obj = NULL;
   5313 	result = named_config_get(maps, "qname-minimization", &obj);
   5314 	INSIST(result == ISC_R_SUCCESS);
   5315 	qminmode = cfg_obj_asstring(obj);
   5316 	INSIST(qminmode != NULL);
   5317 	if (!strcmp(qminmode, "strict")) {
   5318 		view->qminimization = true;
   5319 		view->qmin_strict = true;
   5320 	} else if (!strcmp(qminmode, "relaxed")) {
   5321 		view->qminimization = true;
   5322 		view->qmin_strict = false;
   5323 	} else { /* "disabled" or "off" */
   5324 		view->qminimization = false;
   5325 		view->qmin_strict = false;
   5326 	}
   5327 
   5328 	obj = NULL;
   5329 	result = named_config_get(maps, "auth-nxdomain", &obj);
   5330 	INSIST(result == ISC_R_SUCCESS);
   5331 	view->auth_nxdomain = cfg_obj_asboolean(obj);
   5332 
   5333 	obj = NULL;
   5334 	result = named_config_get(maps, "minimal-any", &obj);
   5335 	INSIST(result == ISC_R_SUCCESS);
   5336 	view->minimal_any = cfg_obj_asboolean(obj);
   5337 
   5338 	obj = NULL;
   5339 	result = named_config_get(maps, "minimal-responses", &obj);
   5340 	INSIST(result == ISC_R_SUCCESS);
   5341 	if (cfg_obj_isboolean(obj)) {
   5342 		if (cfg_obj_asboolean(obj)) {
   5343 			view->minimalresponses = dns_minimal_yes;
   5344 		} else {
   5345 			view->minimalresponses = dns_minimal_no;
   5346 		}
   5347 	} else {
   5348 		str = cfg_obj_asstring(obj);
   5349 		if (strcasecmp(str, "no-auth") == 0) {
   5350 			view->minimalresponses = dns_minimal_noauth;
   5351 		} else if (strcasecmp(str, "no-auth-recursive") == 0) {
   5352 			view->minimalresponses = dns_minimal_noauthrec;
   5353 		} else {
   5354 			UNREACHABLE();
   5355 		}
   5356 	}
   5357 
   5358 	obj = NULL;
   5359 	result = named_config_get(maps, "transfer-format", &obj);
   5360 	INSIST(result == ISC_R_SUCCESS);
   5361 	str = cfg_obj_asstring(obj);
   5362 	if (strcasecmp(str, "many-answers") == 0) {
   5363 		view->transfer_format = dns_many_answers;
   5364 	} else if (strcasecmp(str, "one-answer") == 0) {
   5365 		view->transfer_format = dns_one_answer;
   5366 	} else {
   5367 		UNREACHABLE();
   5368 	}
   5369 
   5370 	obj = NULL;
   5371 	result = named_config_get(maps, "trust-anchor-telemetry", &obj);
   5372 	INSIST(result == ISC_R_SUCCESS);
   5373 	view->trust_anchor_telemetry = cfg_obj_asboolean(obj);
   5374 
   5375 	obj = NULL;
   5376 	result = named_config_get(maps, "root-key-sentinel", &obj);
   5377 	INSIST(result == ISC_R_SUCCESS);
   5378 	view->root_key_sentinel = cfg_obj_asboolean(obj);
   5379 
   5380 	/*
   5381 	 * Set the "allow-query", "allow-query-cache", "allow-recursion",
   5382 	 * "allow-recursion-on" and "allow-query-cache-on" ACLs if
   5383 	 * configured in named.conf, but NOT from the global defaults.
   5384 	 * This is done by leaving the third argument to configure_view_acl()
   5385 	 * NULL.
   5386 	 *
   5387 	 * We ignore the global defaults here because these ACLs
   5388 	 * can inherit from each other.  If any are still unset after
   5389 	 * applying the inheritance rules, we'll look up the defaults at
   5390 	 * that time.
   5391 	 */
   5392 
   5393 	/* named.conf only */
   5394 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query", NULL,
   5395 				 actx, named_g_mctx, &view->queryacl));
   5396 
   5397 	/* named.conf only */
   5398 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache",
   5399 				 NULL, actx, named_g_mctx, &view->cacheacl));
   5400 	/* named.conf only */
   5401 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache-on",
   5402 				 NULL, actx, named_g_mctx, &view->cacheonacl));
   5403 
   5404 	CHECK(configure_view_acl(vconfig, config, named_g_config, "allow-proxy",
   5405 				 NULL, actx, named_g_mctx, &view->proxyacl));
   5406 
   5407 	CHECK(configure_view_acl(vconfig, config, named_g_config,
   5408 				 "allow-proxy-on", NULL, actx, named_g_mctx,
   5409 				 &view->proxyonacl));
   5410 
   5411 	if (strcmp(view->name, "_bind") != 0 &&
   5412 	    view->rdclass != dns_rdataclass_chaos)
   5413 	{
   5414 		/* named.conf only */
   5415 		CHECK(configure_view_acl(vconfig, config, NULL,
   5416 					 "allow-recursion", NULL, actx,
   5417 					 named_g_mctx, &view->recursionacl));
   5418 		/* named.conf only */
   5419 		CHECK(configure_view_acl(vconfig, config, NULL,
   5420 					 "allow-recursion-on", NULL, actx,
   5421 					 named_g_mctx, &view->recursiononacl));
   5422 	}
   5423 
   5424 	if (view->recursion) {
   5425 		/*
   5426 		 * "allow-query-cache" inherits from "allow-recursion" if set,
   5427 		 * otherwise from "allow-query" if set.
   5428 		 */
   5429 		if (view->cacheacl == NULL) {
   5430 			if (view->recursionacl != NULL) {
   5431 				dns_acl_attach(view->recursionacl,
   5432 					       &view->cacheacl);
   5433 			} else if (view->queryacl != NULL) {
   5434 				dns_acl_attach(view->queryacl, &view->cacheacl);
   5435 			}
   5436 		}
   5437 
   5438 		/*
   5439 		 * "allow-recursion" inherits from "allow-query-cache" if set,
   5440 		 * otherwise from "allow-query" if set.
   5441 		 */
   5442 		if (view->recursionacl == NULL) {
   5443 			if (view->cacheacl != NULL) {
   5444 				dns_acl_attach(view->cacheacl,
   5445 					       &view->recursionacl);
   5446 			} else if (view->queryacl != NULL) {
   5447 				dns_acl_attach(view->queryacl,
   5448 					       &view->recursionacl);
   5449 			}
   5450 		}
   5451 
   5452 		/*
   5453 		 * "allow-query-cache-on" inherits from "allow-recursion-on"
   5454 		 * if set.
   5455 		 */
   5456 		if (view->cacheonacl == NULL) {
   5457 			if (view->recursiononacl != NULL) {
   5458 				dns_acl_attach(view->recursiononacl,
   5459 					       &view->cacheonacl);
   5460 			}
   5461 		}
   5462 
   5463 		/*
   5464 		 * "allow-recursion-on" inherits from "allow-query-cache-on"
   5465 		 * if set.
   5466 		 */
   5467 		if (view->recursiononacl == NULL) {
   5468 			if (view->cacheonacl != NULL) {
   5469 				dns_acl_attach(view->cacheonacl,
   5470 					       &view->recursiononacl);
   5471 			}
   5472 		}
   5473 
   5474 		/*
   5475 		 * If any are still unset at this point, we now get default
   5476 		 * values for from the global config.
   5477 		 */
   5478 
   5479 		if (view->recursionacl == NULL) {
   5480 			/* global default only */
   5481 			CHECK(configure_view_acl(
   5482 				NULL, NULL, named_g_config, "allow-recursion",
   5483 				NULL, actx, named_g_mctx, &view->recursionacl));
   5484 		}
   5485 		if (view->recursiononacl == NULL) {
   5486 			/* global default only */
   5487 			CHECK(configure_view_acl(NULL, NULL, named_g_config,
   5488 						 "allow-recursion-on", NULL,
   5489 						 actx, named_g_mctx,
   5490 						 &view->recursiononacl));
   5491 		}
   5492 		if (view->cacheacl == NULL) {
   5493 			/* global default only */
   5494 			CHECK(configure_view_acl(
   5495 				NULL, NULL, named_g_config, "allow-query-cache",
   5496 				NULL, actx, named_g_mctx, &view->cacheacl));
   5497 		}
   5498 		if (view->cacheonacl == NULL) {
   5499 			/* global default only */
   5500 			CHECK(configure_view_acl(NULL, NULL, named_g_config,
   5501 						 "allow-query-cache-on", NULL,
   5502 						 actx, named_g_mctx,
   5503 						 &view->cacheonacl));
   5504 		}
   5505 	} else {
   5506 		/*
   5507 		 * We're not recursive; if the query-cache ACLs haven't
   5508 		 * been set at the options/view level, set them to none.
   5509 		 */
   5510 		if (view->cacheacl == NULL) {
   5511 			CHECK(dns_acl_none(mctx, &view->cacheacl));
   5512 		}
   5513 		if (view->cacheonacl == NULL) {
   5514 			CHECK(dns_acl_none(mctx, &view->cacheonacl));
   5515 		}
   5516 	}
   5517 
   5518 	/*
   5519 	 * Finished setting recursion and query-cache ACLs, so now we
   5520 	 * can get the allow-query default if it wasn't set in named.conf
   5521 	 */
   5522 	if (view->queryacl == NULL) {
   5523 		/* global default only */
   5524 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
   5525 					 "allow-query", NULL, actx,
   5526 					 named_g_mctx, &view->queryacl));
   5527 	}
   5528 
   5529 	/*
   5530 	 * Ignore case when compressing responses to the specified
   5531 	 * clients. This causes case not always to be preserved,
   5532 	 * and is needed by some broken clients.
   5533 	 */
   5534 	CHECK(configure_view_acl(vconfig, config, named_g_config,
   5535 				 "no-case-compress", NULL, actx, named_g_mctx,
   5536 				 &view->nocasecompress));
   5537 
   5538 	/*
   5539 	 * Disable name compression completely, this is a tradeoff
   5540 	 * between CPU and network usage.
   5541 	 */
   5542 	obj = NULL;
   5543 	result = named_config_get(maps, "message-compression", &obj);
   5544 	INSIST(result == ISC_R_SUCCESS);
   5545 	view->msgcompression = cfg_obj_asboolean(obj);
   5546 
   5547 	/*
   5548 	 * Filter setting on addresses in the answer section.
   5549 	 */
   5550 	CHECK(configure_view_acl(vconfig, config, named_g_config,
   5551 				 "deny-answer-addresses", "acl", actx,
   5552 				 named_g_mctx, &view->denyansweracl));
   5553 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses",
   5554 				       "except-from", named_g_mctx,
   5555 				       &view->answeracl_exclude));
   5556 
   5557 	/*
   5558 	 * Filter setting on names (CNAME/DNAME targets) in the answer section.
   5559 	 */
   5560 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
   5561 				       "name", named_g_mctx,
   5562 				       &view->denyanswernames));
   5563 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
   5564 				       "except-from", named_g_mctx,
   5565 				       &view->answernames_exclude));
   5566 
   5567 	/*
   5568 	 * Configure sortlist, if set
   5569 	 */
   5570 	CHECK(configure_view_sortlist(vconfig, config, actx, named_g_mctx,
   5571 				      &view->sortlist));
   5572 
   5573 	/*
   5574 	 * Configure default allow-update and allow-update-forwarding ACLs,
   5575 	 * so they can be inherited by zones. (XXX: These are not
   5576 	 * read from the options/view level here. However, they may be
   5577 	 * read from there in zoneconf.c:configure_zone_acl() later.)
   5578 	 */
   5579 	if (view->updateacl == NULL) {
   5580 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
   5581 					 "allow-update", NULL, actx,
   5582 					 named_g_mctx, &view->updateacl));
   5583 	}
   5584 	if (view->upfwdacl == NULL) {
   5585 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
   5586 					 "allow-update-forwarding", NULL, actx,
   5587 					 named_g_mctx, &view->upfwdacl));
   5588 	}
   5589 
   5590 	/*
   5591 	 * Configure default allow-transfer and allow-notify ACLs so they
   5592 	 * can be inherited by zones.
   5593 	 */
   5594 	if (view->transferacl == NULL) {
   5595 		CHECK(configure_view_acl(vconfig, config, named_g_config,
   5596 					 "allow-transfer", NULL, actx,
   5597 					 named_g_mctx, &view->transferacl));
   5598 	}
   5599 	if (view->notifyacl == NULL) {
   5600 		CHECK(configure_view_acl(vconfig, config, named_g_config,
   5601 					 "allow-notify", NULL, actx,
   5602 					 named_g_mctx, &view->notifyacl));
   5603 	}
   5604 
   5605 	obj = NULL;
   5606 	result = named_config_get(maps, "provide-ixfr", &obj);
   5607 	INSIST(result == ISC_R_SUCCESS);
   5608 	view->provideixfr = cfg_obj_asboolean(obj);
   5609 
   5610 	obj = NULL;
   5611 	result = named_config_get(maps, "request-nsid", &obj);
   5612 	INSIST(result == ISC_R_SUCCESS);
   5613 	view->requestnsid = cfg_obj_asboolean(obj);
   5614 
   5615 	obj = NULL;
   5616 	result = named_config_get(maps, "send-cookie", &obj);
   5617 	INSIST(result == ISC_R_SUCCESS);
   5618 	view->sendcookie = cfg_obj_asboolean(obj);
   5619 
   5620 	obj = NULL;
   5621 	if (view->pad_acl != NULL) {
   5622 		dns_acl_detach(&view->pad_acl);
   5623 	}
   5624 	result = named_config_get(maps, "response-padding", &obj);
   5625 	INSIST(result == ISC_R_SUCCESS);
   5626 	padding = cfg_obj_asuint32(cfg_tuple_get(obj, "block-size"));
   5627 	if (padding > 512U) {
   5628 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   5629 			    "response-padding block-size cannot "
   5630 			    "exceed 512: lowering");
   5631 		padding = 512U;
   5632 	}
   5633 	view->padding = (uint16_t)padding;
   5634 	CHECK(cfg_acl_fromconfig(cfg_tuple_get(obj, "acl"), config,
   5635 				 named_g_lctx, actx, named_g_mctx, 0,
   5636 				 &view->pad_acl));
   5637 
   5638 	obj = NULL;
   5639 	result = named_config_get(maps, "require-server-cookie", &obj);
   5640 	INSIST(result == ISC_R_SUCCESS);
   5641 	view->requireservercookie = cfg_obj_asboolean(obj);
   5642 
   5643 	obj = NULL;
   5644 	result = named_config_get(maps, "v6-bias", &obj);
   5645 	INSIST(result == ISC_R_SUCCESS);
   5646 	view->v6bias = cfg_obj_asuint32(obj) * 1000;
   5647 
   5648 	obj = NULL;
   5649 	result = named_config_get(maps, "clients-per-query", &obj);
   5650 	INSIST(result == ISC_R_SUCCESS);
   5651 	clients_per_query = cfg_obj_asuint32(obj);
   5652 
   5653 	obj = NULL;
   5654 	result = named_config_get(maps, "max-clients-per-query", &obj);
   5655 	INSIST(result == ISC_R_SUCCESS);
   5656 	max_clients_per_query = cfg_obj_asuint32(obj);
   5657 
   5658 	if (max_clients_per_query < clients_per_query) {
   5659 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   5660 			    "configured clients-per-query (%u) exceeds "
   5661 			    "max-clients-per-query (%u); automatically "
   5662 			    "adjusting max-clients-per-query to (%u)",
   5663 			    clients_per_query, max_clients_per_query,
   5664 			    clients_per_query);
   5665 		max_clients_per_query = clients_per_query;
   5666 	}
   5667 	dns_resolver_setclientsperquery(view->resolver, clients_per_query,
   5668 					max_clients_per_query);
   5669 
   5670 	/*
   5671 	 * This is used for the cache and also as a default value
   5672 	 * for zone databases.
   5673 	 */
   5674 	obj = NULL;
   5675 	result = named_config_get(maps, "max-records-per-type", &obj);
   5676 	INSIST(result == ISC_R_SUCCESS);
   5677 	dns_view_setmaxrrperset(view, cfg_obj_asuint32(obj));
   5678 
   5679 	/*
   5680 	 * This is used for the cache and also as a default value
   5681 	 * for zone databases.
   5682 	 */
   5683 	obj = NULL;
   5684 	result = named_config_get(maps, "max-types-per-name", &obj);
   5685 	INSIST(result == ISC_R_SUCCESS);
   5686 	dns_view_setmaxtypepername(view, cfg_obj_asuint32(obj));
   5687 
   5688 	obj = NULL;
   5689 	result = named_config_get(maps, "max-recursion-depth", &obj);
   5690 	INSIST(result == ISC_R_SUCCESS);
   5691 	dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj));
   5692 
   5693 	obj = NULL;
   5694 	result = named_config_get(maps, "max-recursion-queries", &obj);
   5695 	INSIST(result == ISC_R_SUCCESS);
   5696 	dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
   5697 
   5698 	obj = NULL;
   5699 	result = named_config_get(maps, "max-query-restarts", &obj);
   5700 	INSIST(result == ISC_R_SUCCESS);
   5701 	dns_view_setmaxrestarts(view, cfg_obj_asuint32(obj));
   5702 
   5703 	obj = NULL;
   5704 	result = named_config_get(maps, "max-query-count", &obj);
   5705 	INSIST(result == ISC_R_SUCCESS);
   5706 	dns_view_setmaxqueries(view, cfg_obj_asuint32(obj));
   5707 
   5708 	obj = NULL;
   5709 	result = named_config_get(maps, "max-validations-per-fetch", &obj);
   5710 	if (result == ISC_R_SUCCESS) {
   5711 		dns_resolver_setmaxvalidations(view->resolver,
   5712 					       cfg_obj_asuint32(obj));
   5713 	}
   5714 
   5715 	obj = NULL;
   5716 	result = named_config_get(maps, "max-validation-failures-per-fetch",
   5717 				  &obj);
   5718 	if (result == ISC_R_SUCCESS) {
   5719 		dns_resolver_setmaxvalidationfails(view->resolver,
   5720 						   cfg_obj_asuint32(obj));
   5721 	}
   5722 
   5723 	obj = NULL;
   5724 	result = named_config_get(maps, "fetches-per-zone", &obj);
   5725 	INSIST(result == ISC_R_SUCCESS);
   5726 	obj2 = cfg_tuple_get(obj, "fetches");
   5727 	dns_resolver_setfetchesperzone(view->resolver, cfg_obj_asuint32(obj2));
   5728 	obj2 = cfg_tuple_get(obj, "response");
   5729 	if (!cfg_obj_isvoid(obj2)) {
   5730 		const char *resp = cfg_obj_asstring(obj2);
   5731 		isc_result_t r = DNS_R_SERVFAIL;
   5732 
   5733 		if (strcasecmp(resp, "drop") == 0) {
   5734 			r = DNS_R_DROP;
   5735 		} else if (strcasecmp(resp, "fail") == 0) {
   5736 			r = DNS_R_SERVFAIL;
   5737 		} else {
   5738 			UNREACHABLE();
   5739 		}
   5740 
   5741 		dns_resolver_setquotaresponse(view->resolver,
   5742 					      dns_quotatype_zone, r);
   5743 	}
   5744 
   5745 	obj = NULL;
   5746 	result = named_config_get(maps, "prefetch", &obj);
   5747 	INSIST(result == ISC_R_SUCCESS);
   5748 	prefetch_trigger = cfg_tuple_get(obj, "trigger");
   5749 	view->prefetch_trigger = cfg_obj_asuint32(prefetch_trigger);
   5750 	if (view->prefetch_trigger > 10) {
   5751 		view->prefetch_trigger = 10;
   5752 	}
   5753 	prefetch_eligible = cfg_tuple_get(obj, "eligible");
   5754 	if (cfg_obj_isvoid(prefetch_eligible)) {
   5755 		int m;
   5756 		for (m = 1; maps[m] != NULL; m++) {
   5757 			obj = NULL;
   5758 			result = named_config_get(&maps[m], "prefetch", &obj);
   5759 			INSIST(result == ISC_R_SUCCESS);
   5760 			prefetch_eligible = cfg_tuple_get(obj, "eligible");
   5761 			if (cfg_obj_isuint32(prefetch_eligible)) {
   5762 				break;
   5763 			}
   5764 		}
   5765 		INSIST(cfg_obj_isuint32(prefetch_eligible));
   5766 	}
   5767 	view->prefetch_eligible = cfg_obj_asuint32(prefetch_eligible);
   5768 	if (view->prefetch_eligible < view->prefetch_trigger + 6) {
   5769 		view->prefetch_eligible = view->prefetch_trigger + 6;
   5770 	}
   5771 
   5772 	/*
   5773 	 * For now, there is only one kind of trusted keys, the
   5774 	 * "security roots".
   5775 	 */
   5776 	CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys,
   5777 					auto_root));
   5778 
   5779 	obj = NULL;
   5780 	result = named_config_get(maps, "dnssec-must-be-secure", &obj);
   5781 	if (result == ISC_R_SUCCESS) {
   5782 		CHECK(mustbesecure(obj, view->resolver));
   5783 	}
   5784 
   5785 	obj = NULL;
   5786 	result = named_config_get(maps, "nta-recheck", &obj);
   5787 	INSIST(result == ISC_R_SUCCESS);
   5788 	view->nta_recheck = cfg_obj_asduration(obj);
   5789 
   5790 	obj = NULL;
   5791 	result = named_config_get(maps, "nta-lifetime", &obj);
   5792 	INSIST(result == ISC_R_SUCCESS);
   5793 	view->nta_lifetime = cfg_obj_asduration(obj);
   5794 
   5795 	obj = NULL;
   5796 	result = named_config_get(maps, "preferred-glue", &obj);
   5797 	if (result == ISC_R_SUCCESS) {
   5798 		str = cfg_obj_asstring(obj);
   5799 		if (strcasecmp(str, "a") == 0) {
   5800 			view->preferred_glue = dns_rdatatype_a;
   5801 		} else if (strcasecmp(str, "aaaa") == 0) {
   5802 			view->preferred_glue = dns_rdatatype_aaaa;
   5803 		} else {
   5804 			view->preferred_glue = 0;
   5805 		}
   5806 	} else {
   5807 		view->preferred_glue = 0;
   5808 	}
   5809 
   5810 	/*
   5811 	 * Load DynDB modules.
   5812 	 */
   5813 	dyndb_list = NULL;
   5814 	if (voptions != NULL) {
   5815 		(void)cfg_map_get(voptions, "dyndb", &dyndb_list);
   5816 	} else {
   5817 		(void)cfg_map_get(config, "dyndb", &dyndb_list);
   5818 	}
   5819 
   5820 	for (element = cfg_list_first(dyndb_list); element != NULL;
   5821 	     element = cfg_list_next(element))
   5822 	{
   5823 		const cfg_obj_t *dyndb = cfg_listelt_value(element);
   5824 
   5825 		if (dctx == NULL) {
   5826 			const void *hashinit = isc_hash_get_initializer();
   5827 			CHECK(dns_dyndb_createctx(mctx, hashinit, named_g_lctx,
   5828 						  view, named_g_server->zonemgr,
   5829 						  named_g_loopmgr, &dctx));
   5830 		}
   5831 
   5832 		CHECK(configure_dyndb(dyndb, mctx, dctx));
   5833 	}
   5834 
   5835 	/*
   5836 	 * Load plugins.
   5837 	 */
   5838 	plugin_list = NULL;
   5839 	if (voptions != NULL) {
   5840 		(void)cfg_map_get(voptions, "plugin", &plugin_list);
   5841 	} else {
   5842 		(void)cfg_map_get(config, "plugin", &plugin_list);
   5843 	}
   5844 
   5845 	if (plugin_list != NULL) {
   5846 		INSIST(view->hooktable == NULL);
   5847 		CHECK(ns_hooktable_create(view->mctx,
   5848 					  (ns_hooktable_t **)&view->hooktable));
   5849 		view->hooktable_free = ns_hooktable_free;
   5850 
   5851 		ns_plugins_create(view->mctx, (ns_plugins_t **)&view->plugins);
   5852 		view->plugins_free = ns_plugins_free;
   5853 
   5854 		CHECK(cfg_pluginlist_foreach(config, plugin_list, named_g_lctx,
   5855 					     register_one_plugin, view));
   5856 	}
   5857 
   5858 	/*
   5859 	 * Setup automatic empty zones.  If recursion is off then
   5860 	 * they are disabled by default.
   5861 	 */
   5862 	obj = NULL;
   5863 	(void)named_config_get(maps, "empty-zones-enable", &obj);
   5864 	(void)named_config_get(maps, "disable-empty-zone", &disablelist);
   5865 	if (obj == NULL && disablelist == NULL &&
   5866 	    view->rdclass == dns_rdataclass_in)
   5867 	{
   5868 		empty_zones_enable = view->recursion;
   5869 	} else if (view->rdclass == dns_rdataclass_in) {
   5870 		if (obj != NULL) {
   5871 			empty_zones_enable = cfg_obj_asboolean(obj);
   5872 		} else {
   5873 			empty_zones_enable = view->recursion;
   5874 		}
   5875 	} else {
   5876 		empty_zones_enable = false;
   5877 	}
   5878 
   5879 	if (empty_zones_enable) {
   5880 		const char *empty;
   5881 		int empty_zone = 0;
   5882 		dns_fixedname_t fixed;
   5883 		dns_name_t *name;
   5884 		isc_buffer_t buffer;
   5885 		char server[DNS_NAME_FORMATSIZE + 1];
   5886 		char contact[DNS_NAME_FORMATSIZE + 1];
   5887 		const char *empty_dbtype[4] = { "_builtin", "empty", NULL,
   5888 						NULL };
   5889 		int empty_dbtypec = 4;
   5890 		dns_zonestat_level_t statlevel = dns_zonestat_none;
   5891 
   5892 		name = dns_fixedname_initname(&fixed);
   5893 
   5894 		obj = NULL;
   5895 		result = named_config_get(maps, "empty-server", &obj);
   5896 		if (result == ISC_R_SUCCESS) {
   5897 			CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
   5898 						  dns_rootname, 0, NULL));
   5899 			isc_buffer_init(&buffer, server, sizeof(server) - 1);
   5900 			CHECK(dns_name_totext(name, 0, &buffer));
   5901 			server[isc_buffer_usedlength(&buffer)] = 0;
   5902 			empty_dbtype[2] = server;
   5903 		} else {
   5904 			empty_dbtype[2] = "@";
   5905 		}
   5906 
   5907 		obj = NULL;
   5908 		result = named_config_get(maps, "empty-contact", &obj);
   5909 		if (result == ISC_R_SUCCESS) {
   5910 			CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
   5911 						  dns_rootname, 0, NULL));
   5912 			isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
   5913 			CHECK(dns_name_totext(name, 0, &buffer));
   5914 			contact[isc_buffer_usedlength(&buffer)] = 0;
   5915 			empty_dbtype[3] = contact;
   5916 		} else {
   5917 			empty_dbtype[3] = ".";
   5918 		}
   5919 
   5920 		obj = NULL;
   5921 		result = named_config_get(maps, "zone-statistics", &obj);
   5922 		INSIST(result == ISC_R_SUCCESS);
   5923 		if (cfg_obj_isboolean(obj)) {
   5924 			if (cfg_obj_asboolean(obj)) {
   5925 				statlevel = dns_zonestat_full;
   5926 			} else {
   5927 				statlevel = dns_zonestat_none;
   5928 			}
   5929 		} else {
   5930 			const char *levelstr = cfg_obj_asstring(obj);
   5931 			if (strcasecmp(levelstr, "full") == 0) {
   5932 				statlevel = dns_zonestat_full;
   5933 			} else if (strcasecmp(levelstr, "terse") == 0) {
   5934 				statlevel = dns_zonestat_terse;
   5935 			} else if (strcasecmp(levelstr, "none") == 0) {
   5936 				statlevel = dns_zonestat_none;
   5937 			} else {
   5938 				UNREACHABLE();
   5939 			}
   5940 		}
   5941 
   5942 		for (empty = empty_zones[empty_zone]; empty != NULL;
   5943 		     empty = empty_zones[++empty_zone])
   5944 		{
   5945 			dns_forwarders_t *dnsforwarders = NULL;
   5946 			dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
   5947 
   5948 			/*
   5949 			 * Look for zone on drop list.
   5950 			 */
   5951 			CHECK(dns_name_fromstring(name, empty, dns_rootname, 0,
   5952 						  NULL));
   5953 			if (disablelist != NULL &&
   5954 			    on_disable_list(disablelist, name))
   5955 			{
   5956 				continue;
   5957 			}
   5958 
   5959 			/*
   5960 			 * This zone already exists.
   5961 			 */
   5962 			(void)dns_view_findzone(view, name, DNS_ZTFIND_EXACT,
   5963 						&zone);
   5964 			if (zone != NULL) {
   5965 				dns_zone_detach(&zone);
   5966 				continue;
   5967 			}
   5968 
   5969 			/*
   5970 			 * If we would forward this name don't add a
   5971 			 * empty zone for it.
   5972 			 */
   5973 			result = dns_fwdtable_find(view->fwdtable, name,
   5974 						   &dnsforwarders);
   5975 			if (result == ISC_R_SUCCESS ||
   5976 			    result == DNS_R_PARTIALMATCH)
   5977 			{
   5978 				fwdpolicy = dnsforwarders->fwdpolicy;
   5979 				dns_forwarders_detach(&dnsforwarders);
   5980 			}
   5981 			if (fwdpolicy == dns_fwdpolicy_only) {
   5982 				continue;
   5983 			}
   5984 
   5985 			/*
   5986 			 * See if we can re-use a existing zone.
   5987 			 */
   5988 			result = dns_viewlist_find(&named_g_server->viewlist,
   5989 						   view->name, view->rdclass,
   5990 						   &pview);
   5991 			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
   5992 			{
   5993 				goto cleanup;
   5994 			}
   5995 
   5996 			if (pview != NULL) {
   5997 				(void)dns_view_findzone(
   5998 					pview, name, DNS_ZTFIND_EXACT, &zone);
   5999 				dns_view_detach(&pview);
   6000 			}
   6001 
   6002 			CHECK(create_empty_zone(zone, name, view, zonelist,
   6003 						empty_dbtype, empty_dbtypec,
   6004 						statlevel));
   6005 			if (zone != NULL) {
   6006 				dns_zone_detach(&zone);
   6007 			}
   6008 		}
   6009 	}
   6010 
   6011 	obj = NULL;
   6012 	if (view->rdclass == dns_rdataclass_in) {
   6013 		(void)named_config_get(maps, "ipv4only-enable", &obj);
   6014 	}
   6015 	if (view->rdclass == dns_rdataclass_in && (obj != NULL)
   6016 		    ? cfg_obj_asboolean(obj)
   6017 		    : !ISC_LIST_EMPTY(view->dns64))
   6018 	{
   6019 		const char *server, *contact;
   6020 		dns_fixedname_t fixed;
   6021 		dns_name_t *name;
   6022 		struct {
   6023 			const char *name;
   6024 			const char *type;
   6025 		} zones[] = {
   6026 			{ "ipv4only.arpa", "ipv4only" },
   6027 			{ "170.0.0.192.in-addr.arpa", "ipv4reverse" },
   6028 			{ "171.0.0.192.in-addr.arpa", "ipv4reverse" },
   6029 		};
   6030 		size_t ipv4only_zone;
   6031 
   6032 		obj = NULL;
   6033 		result = named_config_get(maps, "ipv4only-server", &obj);
   6034 		if (result == ISC_R_SUCCESS) {
   6035 			server = cfg_obj_asstring(obj);
   6036 		} else {
   6037 			server = NULL;
   6038 		}
   6039 
   6040 		obj = NULL;
   6041 		result = named_config_get(maps, "ipv4only-contact", &obj);
   6042 		if (result == ISC_R_SUCCESS) {
   6043 			contact = cfg_obj_asstring(obj);
   6044 		} else {
   6045 			contact = NULL;
   6046 		}
   6047 
   6048 		name = dns_fixedname_initname(&fixed);
   6049 		for (ipv4only_zone = 0; ipv4only_zone < ARRAY_SIZE(zones);
   6050 		     ipv4only_zone++)
   6051 		{
   6052 			dns_forwarders_t *dnsforwarders = NULL;
   6053 			dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
   6054 
   6055 			CHECK(dns_name_fromstring(name,
   6056 						  zones[ipv4only_zone].name,
   6057 						  dns_rootname, 0, NULL));
   6058 
   6059 			(void)dns_view_findzone(view, name, DNS_ZTFIND_EXACT,
   6060 						&zone);
   6061 			if (zone != NULL) {
   6062 				dns_zone_detach(&zone);
   6063 				continue;
   6064 			}
   6065 
   6066 			/*
   6067 			 * If we would forward this name don't add it.
   6068 			 */
   6069 			result = dns_fwdtable_find(view->fwdtable, name,
   6070 						   &dnsforwarders);
   6071 			if (result == ISC_R_SUCCESS ||
   6072 			    result == DNS_R_PARTIALMATCH)
   6073 			{
   6074 				fwdpolicy = dnsforwarders->fwdpolicy;
   6075 				dns_forwarders_detach(&dnsforwarders);
   6076 			}
   6077 			if (fwdpolicy == dns_fwdpolicy_only) {
   6078 				continue;
   6079 			}
   6080 
   6081 			/*
   6082 			 * See if we can re-use a existing zone.
   6083 			 */
   6084 			result = dns_viewlist_find(&named_g_server->viewlist,
   6085 						   view->name, view->rdclass,
   6086 						   &pview);
   6087 			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
   6088 			{
   6089 				goto cleanup;
   6090 			}
   6091 
   6092 			if (pview != NULL) {
   6093 				(void)dns_view_findzone(
   6094 					pview, name, DNS_ZTFIND_EXACT, &zone);
   6095 				dns_view_detach(&pview);
   6096 			}
   6097 
   6098 			CHECK(create_ipv4only_zone(zone, view, name,
   6099 						   zones[ipv4only_zone].type,
   6100 						   mctx, server, contact));
   6101 			if (zone != NULL) {
   6102 				dns_zone_detach(&zone);
   6103 			}
   6104 		}
   6105 	}
   6106 
   6107 	obj = NULL;
   6108 	result = named_config_get(maps, "rate-limit", &obj);
   6109 	if (result == ISC_R_SUCCESS) {
   6110 		result = configure_rrl(view, config, obj);
   6111 		if (result != ISC_R_SUCCESS) {
   6112 			goto cleanup;
   6113 		}
   6114 	}
   6115 
   6116 	/*
   6117 	 * Set the servfail-ttl.
   6118 	 */
   6119 	obj = NULL;
   6120 	result = named_config_get(maps, "servfail-ttl", &obj);
   6121 	INSIST(result == ISC_R_SUCCESS);
   6122 	fail_ttl = cfg_obj_asduration(obj);
   6123 	if (fail_ttl > 30) {
   6124 		fail_ttl = 30;
   6125 	}
   6126 	dns_view_setfailttl(view, fail_ttl);
   6127 
   6128 	/*
   6129 	 * Name space to look up redirect information in.
   6130 	 */
   6131 	obj = NULL;
   6132 	result = named_config_get(maps, "nxdomain-redirect", &obj);
   6133 	if (result == ISC_R_SUCCESS) {
   6134 		dns_name_t *name = dns_fixedname_name(&view->redirectfixed);
   6135 		CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
   6136 					  dns_rootname, 0, NULL));
   6137 		view->redirectzone = name;
   6138 	} else {
   6139 		view->redirectzone = NULL;
   6140 	}
   6141 
   6142 	/*
   6143 	 * Exceptions to DNSSEC validation.
   6144 	 */
   6145 	obj = NULL;
   6146 	result = named_config_get(maps, "validate-except", &obj);
   6147 	if (result == ISC_R_SUCCESS) {
   6148 		result = dns_view_getntatable(view, &ntatable);
   6149 	}
   6150 	if (result == ISC_R_SUCCESS) {
   6151 		for (element = cfg_list_first(obj); element != NULL;
   6152 		     element = cfg_list_next(element))
   6153 		{
   6154 			dns_fixedname_t fntaname;
   6155 			dns_name_t *ntaname;
   6156 
   6157 			ntaname = dns_fixedname_initname(&fntaname);
   6158 			obj = cfg_listelt_value(element);
   6159 			CHECK(dns_name_fromstring(ntaname,
   6160 						  cfg_obj_asstring(obj),
   6161 						  dns_rootname, 0, NULL));
   6162 			CHECK(dns_ntatable_add(ntatable, ntaname, true, 0,
   6163 					       0xffffffffU));
   6164 		}
   6165 	}
   6166 
   6167 #ifdef HAVE_DNSTAP
   6168 	/*
   6169 	 * Set up the dnstap environment and configure message
   6170 	 * types to log.
   6171 	 */
   6172 	CHECK(configure_dnstap(maps, view));
   6173 #endif /* HAVE_DNSTAP */
   6174 
   6175 	result = ISC_R_SUCCESS;
   6176 
   6177 cleanup:
   6178 	/*
   6179 	 * Revert to the old view if there was an error.
   6180 	 */
   6181 	if (result != ISC_R_SUCCESS) {
   6182 		isc_result_t result2;
   6183 
   6184 		result2 = dns_viewlist_find(&named_g_server->viewlist,
   6185 					    view->name, view->rdclass, &pview);
   6186 		if (result2 == ISC_R_SUCCESS) {
   6187 			dns_view_thaw(pview);
   6188 
   6189 			obj = NULL;
   6190 			if (rpz_configured &&
   6191 			    pview->rdclass == dns_rdataclass_in && need_hints &&
   6192 			    named_config_get(maps, "response-policy", &obj) ==
   6193 				    ISC_R_SUCCESS)
   6194 			{
   6195 				/*
   6196 				 * We are swapping the places of the `view` and
   6197 				 * `pview` in the function's parameters list
   6198 				 * because we are reverting the same operation
   6199 				 * done previously in the "correct" order.
   6200 				 */
   6201 				result2 = configure_rpz(pview, view, maps, obj,
   6202 							&old_rpz_ok,
   6203 							first_time);
   6204 				if (result2 != ISC_R_SUCCESS) {
   6205 					isc_log_write(named_g_lctx,
   6206 						      NAMED_LOGCATEGORY_GENERAL,
   6207 						      NAMED_LOGMODULE_SERVER,
   6208 						      ISC_LOG_ERROR,
   6209 						      "rpz configuration "
   6210 						      "revert failed for view "
   6211 						      "'%s'",
   6212 						      pview->name);
   6213 				}
   6214 			}
   6215 
   6216 			obj = NULL;
   6217 			if (catz_configured &&
   6218 			    pview->rdclass == dns_rdataclass_in && need_hints &&
   6219 			    named_config_get(maps, "catalog-zones", &obj) ==
   6220 				    ISC_R_SUCCESS)
   6221 			{
   6222 				/*
   6223 				 * We are swapping the places of the `view` and
   6224 				 * `pview` in the function's parameters list
   6225 				 * because we are reverting the same operation
   6226 				 * done previously in the "correct" order.
   6227 				 */
   6228 				result2 = configure_catz(pview, view, config,
   6229 							 obj);
   6230 				if (result2 != ISC_R_SUCCESS) {
   6231 					isc_log_write(named_g_lctx,
   6232 						      NAMED_LOGCATEGORY_GENERAL,
   6233 						      NAMED_LOGMODULE_SERVER,
   6234 						      ISC_LOG_ERROR,
   6235 						      "catz configuration "
   6236 						      "revert failed for view "
   6237 						      "'%s'",
   6238 						      pview->name);
   6239 				}
   6240 			}
   6241 
   6242 			dns_view_freeze(pview);
   6243 		}
   6244 
   6245 		if (pview != NULL) {
   6246 			dns_view_detach(&pview);
   6247 		}
   6248 
   6249 		if (zone_element_latest != NULL) {
   6250 			for (element = cfg_list_first(zonelist);
   6251 			     element != NULL; element = cfg_list_next(element))
   6252 			{
   6253 				const cfg_obj_t *zconfig =
   6254 					cfg_listelt_value(element);
   6255 				configure_zone_setviewcommit(result, zconfig,
   6256 							     view);
   6257 				if (element == zone_element_latest) {
   6258 					/*
   6259 					 * This was the latest element that was
   6260 					 * successfully configured earlier.
   6261 					 */
   6262 					break;
   6263 				}
   6264 			}
   6265 		}
   6266 	}
   6267 
   6268 	if (ntatable != NULL) {
   6269 		dns_ntatable_detach(&ntatable);
   6270 	}
   6271 	if (clients != NULL) {
   6272 		dns_acl_detach(&clients);
   6273 	}
   6274 	if (mapped != NULL) {
   6275 		dns_acl_detach(&mapped);
   6276 	}
   6277 	if (excluded != NULL) {
   6278 		dns_acl_detach(&excluded);
   6279 	}
   6280 	if (ring != NULL) {
   6281 		dns_tsigkeyring_detach(&ring);
   6282 	}
   6283 	if (zone != NULL) {
   6284 		dns_zone_detach(&zone);
   6285 	}
   6286 	if (dispatch4 != NULL) {
   6287 		dns_dispatch_detach(&dispatch4);
   6288 	}
   6289 	if (dispatch6 != NULL) {
   6290 		dns_dispatch_detach(&dispatch6);
   6291 	}
   6292 	if (resstats != NULL) {
   6293 		isc_stats_detach(&resstats);
   6294 	}
   6295 	if (resquerystats != NULL) {
   6296 		dns_stats_detach(&resquerystats);
   6297 	}
   6298 	if (order != NULL) {
   6299 		dns_order_detach(&order);
   6300 	}
   6301 	if (cache != NULL) {
   6302 		dns_cache_detach(&cache);
   6303 	}
   6304 	if (dctx != NULL) {
   6305 		dns_dyndb_destroyctx(&dctx);
   6306 	}
   6307 
   6308 	return result;
   6309 }
   6310 
   6311 static isc_result_t
   6312 configure_hints(dns_view_t *view, const char *filename) {
   6313 	isc_result_t result;
   6314 	dns_db_t *db;
   6315 
   6316 	db = NULL;
   6317 	result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
   6318 	if (result == ISC_R_SUCCESS) {
   6319 		dns_view_sethints(view, db);
   6320 		dns_db_detach(&db);
   6321 	}
   6322 
   6323 	return result;
   6324 }
   6325 
   6326 static isc_result_t
   6327 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
   6328 		     const cfg_obj_t *alternates) {
   6329 	const cfg_obj_t *portobj;
   6330 	const cfg_obj_t *addresses;
   6331 	const cfg_listelt_t *element;
   6332 	isc_result_t result = ISC_R_SUCCESS;
   6333 	in_port_t port;
   6334 
   6335 	/*
   6336 	 * Determine which port to send requests to.
   6337 	 */
   6338 	CHECKM(named_config_getport(config, "port", &port), "port");
   6339 
   6340 	if (alternates != NULL) {
   6341 		portobj = cfg_tuple_get(alternates, "port");
   6342 		if (cfg_obj_isuint32(portobj)) {
   6343 			uint32_t val = cfg_obj_asuint32(portobj);
   6344 			if (val > UINT16_MAX) {
   6345 				cfg_obj_log(portobj, named_g_lctx,
   6346 					    ISC_LOG_ERROR,
   6347 					    "port '%u' out of range", val);
   6348 				return ISC_R_RANGE;
   6349 			}
   6350 			port = (in_port_t)val;
   6351 		}
   6352 	}
   6353 
   6354 	addresses = NULL;
   6355 	if (alternates != NULL) {
   6356 		addresses = cfg_tuple_get(alternates, "addresses");
   6357 	}
   6358 
   6359 	for (element = cfg_list_first(addresses); element != NULL;
   6360 	     element = cfg_list_next(element))
   6361 	{
   6362 		const cfg_obj_t *alternate = cfg_listelt_value(element);
   6363 		isc_sockaddr_t sa;
   6364 
   6365 		if (!cfg_obj_issockaddr(alternate)) {
   6366 			dns_fixedname_t fixed;
   6367 			dns_name_t *name;
   6368 			const char *str = cfg_obj_asstring(
   6369 				cfg_tuple_get(alternate, "name"));
   6370 			isc_buffer_t buffer;
   6371 			in_port_t myport = port;
   6372 
   6373 			isc_buffer_constinit(&buffer, str, strlen(str));
   6374 			isc_buffer_add(&buffer, strlen(str));
   6375 			name = dns_fixedname_initname(&fixed);
   6376 			CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
   6377 						NULL));
   6378 
   6379 			portobj = cfg_tuple_get(alternate, "port");
   6380 			if (cfg_obj_isuint32(portobj)) {
   6381 				uint32_t val = cfg_obj_asuint32(portobj);
   6382 				if (val > UINT16_MAX) {
   6383 					cfg_obj_log(portobj, named_g_lctx,
   6384 						    ISC_LOG_ERROR,
   6385 						    "port '%u' out of range",
   6386 						    val);
   6387 					return ISC_R_RANGE;
   6388 				}
   6389 				myport = (in_port_t)val;
   6390 			}
   6391 			dns_resolver_addalternate(view->resolver, NULL, name,
   6392 						  myport);
   6393 			continue;
   6394 		}
   6395 
   6396 		sa = *cfg_obj_assockaddr(alternate);
   6397 		if (isc_sockaddr_getport(&sa) == 0) {
   6398 			isc_sockaddr_setport(&sa, port);
   6399 		}
   6400 		dns_resolver_addalternate(view->resolver, &sa, NULL, 0);
   6401 	}
   6402 
   6403 cleanup:
   6404 	return result;
   6405 }
   6406 
   6407 static isc_result_t
   6408 validate_tls(const cfg_obj_t *config, dns_view_t *view, const cfg_obj_t *obj,
   6409 	     isc_log_t *logctx, const char *str, dns_name_t **name) {
   6410 	dns_fixedname_t fname;
   6411 	dns_name_t *nm = dns_fixedname_initname(&fname);
   6412 	isc_result_t result = dns_name_fromstring(nm, str, dns_rootname, 0,
   6413 						  NULL);
   6414 
   6415 	if (result != ISC_R_SUCCESS) {
   6416 		cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
   6417 			    "'%s' is not a valid name", str);
   6418 		return result;
   6419 	}
   6420 
   6421 	if (strcasecmp(str, "ephemeral") != 0) {
   6422 		const cfg_obj_t *tlsmap = find_maplist(config, "tls", str);
   6423 
   6424 		if (tlsmap == NULL) {
   6425 			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
   6426 				    "tls '%s' is not defined", str);
   6427 			return ISC_R_FAILURE;
   6428 		}
   6429 	}
   6430 
   6431 	if (name != NULL && *name == NULL) {
   6432 		*name = isc_mem_get(view->mctx, sizeof(dns_name_t));
   6433 		dns_name_init(*name, NULL);
   6434 		dns_name_dup(nm, view->mctx, *name);
   6435 	}
   6436 
   6437 	return ISC_R_SUCCESS;
   6438 }
   6439 
   6440 static isc_result_t
   6441 configure_forward(const cfg_obj_t *config, dns_view_t *view,
   6442 		  const dns_name_t *origin, const cfg_obj_t *forwarders,
   6443 		  const cfg_obj_t *forwardtype) {
   6444 	const cfg_obj_t *portobj = NULL;
   6445 	const cfg_obj_t *tlspobj = NULL;
   6446 	const cfg_obj_t *faddresses = NULL;
   6447 	const cfg_listelt_t *element = NULL;
   6448 	dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
   6449 	dns_forwarderlist_t fwdlist;
   6450 	dns_forwarder_t *fwd = NULL;
   6451 	isc_result_t result;
   6452 	in_port_t port;
   6453 	in_port_t tls_port;
   6454 	const char *tls = NULL;
   6455 
   6456 	ISC_LIST_INIT(fwdlist);
   6457 
   6458 	/*
   6459 	 * Determine which port to send forwarded requests to.
   6460 	 */
   6461 	CHECKM(named_config_getport(config, "port", &port), "port");
   6462 	CHECKM(named_config_getport(config, "tls-port", &tls_port), "tls-port");
   6463 
   6464 	if (forwarders != NULL) {
   6465 		portobj = cfg_tuple_get(forwarders, "port");
   6466 		if (cfg_obj_isuint32(portobj)) {
   6467 			uint32_t val = cfg_obj_asuint32(portobj);
   6468 			if (val > UINT16_MAX) {
   6469 				cfg_obj_log(portobj, named_g_lctx,
   6470 					    ISC_LOG_ERROR,
   6471 					    "port '%u' out of range", val);
   6472 				return ISC_R_RANGE;
   6473 			}
   6474 			port = tls_port = (in_port_t)val;
   6475 		}
   6476 	}
   6477 
   6478 	/*
   6479 	 * TLS value for forwarded requests.
   6480 	 */
   6481 	if (forwarders != NULL) {
   6482 		tlspobj = cfg_tuple_get(forwarders, "tls");
   6483 		if (cfg_obj_isstring(tlspobj)) {
   6484 			tls = cfg_obj_asstring(tlspobj);
   6485 			if (tls != NULL) {
   6486 				result = validate_tls(config, view, tlspobj,
   6487 						      named_g_lctx, tls, NULL);
   6488 				if (result != ISC_R_SUCCESS) {
   6489 					return result;
   6490 				}
   6491 			}
   6492 		}
   6493 	}
   6494 
   6495 	faddresses = NULL;
   6496 	if (forwarders != NULL) {
   6497 		faddresses = cfg_tuple_get(forwarders, "addresses");
   6498 	}
   6499 
   6500 	for (element = cfg_list_first(faddresses); element != NULL;
   6501 	     element = cfg_list_next(element))
   6502 	{
   6503 		const cfg_obj_t *forwarder = cfg_listelt_value(element);
   6504 		const char *cur_tls = NULL;
   6505 
   6506 		fwd = isc_mem_get(view->mctx, sizeof(dns_forwarder_t));
   6507 		fwd->tlsname = NULL;
   6508 		cur_tls = cfg_obj_getsockaddrtls(forwarder);
   6509 		if (cur_tls == NULL) {
   6510 			cur_tls = tls;
   6511 		}
   6512 		if (cur_tls != NULL) {
   6513 			result = validate_tls(config, view, faddresses,
   6514 					      named_g_lctx, cur_tls,
   6515 					      &fwd->tlsname);
   6516 			if (result != ISC_R_SUCCESS) {
   6517 				isc_mem_put(view->mctx, fwd,
   6518 					    sizeof(dns_forwarder_t));
   6519 				goto cleanup;
   6520 			}
   6521 		}
   6522 		fwd->addr = *cfg_obj_assockaddr(forwarder);
   6523 		if (isc_sockaddr_getport(&fwd->addr) == 0) {
   6524 			isc_sockaddr_setport(&fwd->addr,
   6525 					     cur_tls != NULL ? tls_port : port);
   6526 		}
   6527 		ISC_LINK_INIT(fwd, link);
   6528 		ISC_LIST_APPEND(fwdlist, fwd, link);
   6529 	}
   6530 
   6531 	if (ISC_LIST_EMPTY(fwdlist)) {
   6532 		if (forwardtype != NULL) {
   6533 			cfg_obj_log(forwardtype, named_g_lctx, ISC_LOG_WARNING,
   6534 				    "no forwarders seen; disabling "
   6535 				    "forwarding");
   6536 		}
   6537 		fwdpolicy = dns_fwdpolicy_none;
   6538 	} else {
   6539 		if (forwardtype == NULL) {
   6540 			fwdpolicy = dns_fwdpolicy_first;
   6541 		} else {
   6542 			const char *forwardstr = cfg_obj_asstring(forwardtype);
   6543 			if (strcasecmp(forwardstr, "first") == 0) {
   6544 				fwdpolicy = dns_fwdpolicy_first;
   6545 			} else if (strcasecmp(forwardstr, "only") == 0) {
   6546 				fwdpolicy = dns_fwdpolicy_only;
   6547 			} else {
   6548 				UNREACHABLE();
   6549 			}
   6550 		}
   6551 	}
   6552 
   6553 	result = dns_fwdtable_addfwd(view->fwdtable, origin, &fwdlist,
   6554 				     fwdpolicy);
   6555 	if (result != ISC_R_SUCCESS) {
   6556 		char namebuf[DNS_NAME_FORMATSIZE];
   6557 		dns_name_format(origin, namebuf, sizeof(namebuf));
   6558 		cfg_obj_log(forwarders, named_g_lctx, ISC_LOG_WARNING,
   6559 			    "could not set up forwarding for domain '%s': %s",
   6560 			    namebuf, isc_result_totext(result));
   6561 		goto cleanup;
   6562 	}
   6563 
   6564 	if (fwdpolicy == dns_fwdpolicy_only) {
   6565 		dns_view_sfd_add(view, origin);
   6566 	}
   6567 
   6568 	result = ISC_R_SUCCESS;
   6569 
   6570 cleanup:
   6571 
   6572 	while (!ISC_LIST_EMPTY(fwdlist)) {
   6573 		fwd = ISC_LIST_HEAD(fwdlist);
   6574 		ISC_LIST_UNLINK(fwdlist, fwd, link);
   6575 		if (fwd->tlsname != NULL) {
   6576 			dns_name_free(fwd->tlsname, view->mctx);
   6577 			isc_mem_put(view->mctx, fwd->tlsname,
   6578 				    sizeof(dns_name_t));
   6579 		}
   6580 		isc_mem_put(view->mctx, fwd, sizeof(dns_forwarder_t));
   6581 	}
   6582 
   6583 	return result;
   6584 }
   6585 
   6586 static isc_result_t
   6587 get_viewinfo(const cfg_obj_t *vconfig, const char **namep,
   6588 	     dns_rdataclass_t *classp) {
   6589 	isc_result_t result = ISC_R_SUCCESS;
   6590 	const char *viewname;
   6591 	dns_rdataclass_t viewclass;
   6592 
   6593 	REQUIRE(namep != NULL && *namep == NULL);
   6594 	REQUIRE(classp != NULL);
   6595 
   6596 	if (vconfig != NULL) {
   6597 		const cfg_obj_t *classobj = NULL;
   6598 
   6599 		viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
   6600 		classobj = cfg_tuple_get(vconfig, "class");
   6601 		CHECK(named_config_getclass(classobj, dns_rdataclass_in,
   6602 					    &viewclass));
   6603 		if (dns_rdataclass_ismeta(viewclass)) {
   6604 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   6605 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   6606 				      "view '%s': class must not be meta",
   6607 				      viewname);
   6608 			CHECK(ISC_R_FAILURE);
   6609 		}
   6610 	} else {
   6611 		viewname = "_default";
   6612 		viewclass = dns_rdataclass_in;
   6613 	}
   6614 
   6615 	*namep = viewname;
   6616 	*classp = viewclass;
   6617 
   6618 cleanup:
   6619 	return result;
   6620 }
   6621 
   6622 /*
   6623  * Find a view based on its configuration info and attach to it.
   6624  *
   6625  * If 'vconfig' is NULL, attach to the default view.
   6626  */
   6627 static isc_result_t
   6628 find_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
   6629 	  dns_view_t **viewp) {
   6630 	isc_result_t result;
   6631 	const char *viewname = NULL;
   6632 	dns_rdataclass_t viewclass;
   6633 	dns_view_t *view = NULL;
   6634 
   6635 	result = get_viewinfo(vconfig, &viewname, &viewclass);
   6636 	if (result != ISC_R_SUCCESS) {
   6637 		return result;
   6638 	}
   6639 
   6640 	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
   6641 	if (result != ISC_R_SUCCESS) {
   6642 		return result;
   6643 	}
   6644 
   6645 	*viewp = view;
   6646 	return ISC_R_SUCCESS;
   6647 }
   6648 
   6649 /*
   6650  * Create a new view and add it to the list.
   6651  *
   6652  * If 'vconfig' is NULL, create the default view.
   6653  *
   6654  * The view created is attached to '*viewp'.
   6655  */
   6656 static isc_result_t
   6657 create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
   6658 	    dns_view_t **viewp) {
   6659 	isc_result_t result;
   6660 	const char *viewname = NULL;
   6661 	dns_rdataclass_t viewclass;
   6662 	dns_view_t *view = NULL;
   6663 
   6664 	result = get_viewinfo(vconfig, &viewname, &viewclass);
   6665 	if (result != ISC_R_SUCCESS) {
   6666 		return result;
   6667 	}
   6668 
   6669 	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
   6670 	if (result == ISC_R_SUCCESS) {
   6671 		return ISC_R_EXISTS;
   6672 	}
   6673 	if (result != ISC_R_NOTFOUND) {
   6674 		return result;
   6675 	}
   6676 	INSIST(view == NULL);
   6677 
   6678 	result = dns_view_create(named_g_mctx, named_g_loopmgr,
   6679 				 named_g_dispatchmgr, viewclass, viewname,
   6680 				 &view);
   6681 	if (result != ISC_R_SUCCESS) {
   6682 		return result;
   6683 	}
   6684 
   6685 	isc_nonce_buf(view->secret, sizeof(view->secret));
   6686 
   6687 	ISC_LIST_APPEND(*viewlist, view, link);
   6688 	dns_view_attach(view, viewp);
   6689 	return ISC_R_SUCCESS;
   6690 }
   6691 
   6692 /*
   6693  * Configure or reconfigure a zone.
   6694  */
   6695 static isc_result_t
   6696 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
   6697 	       const cfg_obj_t *vconfig, dns_view_t *view,
   6698 	       dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
   6699 	       dns_keystorelist_t *keystores, cfg_aclconfctx_t *aclconf,
   6700 	       bool added, bool old_rpz_ok, bool is_catz_member, bool modify) {
   6701 	dns_view_t *pview = NULL; /* Production view */
   6702 	dns_zone_t *zone = NULL;  /* New or reused zone */
   6703 	dns_zone_t *raw = NULL;	  /* New or reused raw zone */
   6704 	dns_zone_t *dupzone = NULL;
   6705 	const cfg_obj_t *options = NULL;
   6706 	const cfg_obj_t *zoptions = NULL;
   6707 	const cfg_obj_t *typeobj = NULL;
   6708 	const cfg_obj_t *forwarders = NULL;
   6709 	const cfg_obj_t *forwardtype = NULL;
   6710 	const cfg_obj_t *ixfrfromdiffs = NULL;
   6711 	const cfg_obj_t *viewobj = NULL;
   6712 	isc_result_t result = ISC_R_SUCCESS;
   6713 	isc_result_t tresult;
   6714 	isc_buffer_t buffer;
   6715 	dns_fixedname_t fixorigin;
   6716 	dns_name_t *origin;
   6717 	const char *zname;
   6718 	dns_rdataclass_t zclass;
   6719 	const char *ztypestr;
   6720 	dns_rpz_num_t rpz_num;
   6721 	bool zone_is_catz = false;
   6722 	bool zone_maybe_inline = false;
   6723 	bool inline_signing = false;
   6724 	bool fullsign = false;
   6725 
   6726 	options = NULL;
   6727 	(void)cfg_map_get(config, "options", &options);
   6728 
   6729 	zoptions = cfg_tuple_get(zconfig, "options");
   6730 
   6731 	/*
   6732 	 * Get the zone origin as a dns_name_t.
   6733 	 */
   6734 	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
   6735 	isc_buffer_constinit(&buffer, zname, strlen(zname));
   6736 	isc_buffer_add(&buffer, strlen(zname));
   6737 	dns_fixedname_init(&fixorigin);
   6738 	CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), &buffer,
   6739 				dns_rootname, 0, NULL));
   6740 	origin = dns_fixedname_name(&fixorigin);
   6741 
   6742 	CHECK(named_config_getclass(cfg_tuple_get(zconfig, "class"),
   6743 				    view->rdclass, &zclass));
   6744 	if (zclass != view->rdclass) {
   6745 		const char *vname = NULL;
   6746 		if (vconfig != NULL) {
   6747 			vname = cfg_obj_asstring(
   6748 				cfg_tuple_get(vconfig, "name"));
   6749 		} else {
   6750 			vname = "<default view>";
   6751 		}
   6752 
   6753 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   6754 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   6755 			      "zone '%s': wrong class for view '%s'", zname,
   6756 			      vname);
   6757 		result = ISC_R_FAILURE;
   6758 		goto cleanup;
   6759 	}
   6760 
   6761 	(void)cfg_map_get(zoptions, "in-view", &viewobj);
   6762 	if (viewobj != NULL) {
   6763 		const char *inview = cfg_obj_asstring(viewobj);
   6764 		dns_view_t *otherview = NULL;
   6765 
   6766 		if (viewlist == NULL) {
   6767 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
   6768 				    "'in-view' option is not permitted in "
   6769 				    "dynamically added zones");
   6770 			result = ISC_R_FAILURE;
   6771 			goto cleanup;
   6772 		}
   6773 
   6774 		result = dns_viewlist_find(viewlist, inview, view->rdclass,
   6775 					   &otherview);
   6776 		if (result != ISC_R_SUCCESS) {
   6777 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
   6778 				    "view '%s' is not yet defined.", inview);
   6779 			result = ISC_R_FAILURE;
   6780 			goto cleanup;
   6781 		}
   6782 
   6783 		result = dns_view_findzone(otherview, origin, DNS_ZTFIND_EXACT,
   6784 					   &zone);
   6785 		dns_view_detach(&otherview);
   6786 		if (result != ISC_R_SUCCESS) {
   6787 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
   6788 				    "zone '%s' not defined in view '%s'", zname,
   6789 				    inview);
   6790 			result = ISC_R_FAILURE;
   6791 			goto cleanup;
   6792 		}
   6793 
   6794 		CHECK(dns_view_addzone(view, zone));
   6795 		dns_zone_detach(&zone);
   6796 
   6797 		/*
   6798 		 * If the zone contains a 'forwarders' statement, configure
   6799 		 * selective forwarding.  Note: this is not inherited from the
   6800 		 * other view.
   6801 		 */
   6802 		forwarders = NULL;
   6803 		result = cfg_map_get(zoptions, "forwarders", &forwarders);
   6804 		if (result == ISC_R_SUCCESS) {
   6805 			forwardtype = NULL;
   6806 			(void)cfg_map_get(zoptions, "forward", &forwardtype);
   6807 			CHECK(configure_forward(config, view, origin,
   6808 						forwarders, forwardtype));
   6809 		}
   6810 		result = ISC_R_SUCCESS;
   6811 		goto cleanup;
   6812 	}
   6813 
   6814 	(void)cfg_map_get(zoptions, "type", &typeobj);
   6815 	if (typeobj == NULL) {
   6816 		cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
   6817 			    "zone '%s' 'type' not specified", zname);
   6818 		result = ISC_R_FAILURE;
   6819 		goto cleanup;
   6820 	}
   6821 	ztypestr = cfg_obj_asstring(typeobj);
   6822 
   6823 	/*
   6824 	 * "hints zones" aren't zones.	If we've got one,
   6825 	 * configure it and return.
   6826 	 */
   6827 	if (strcasecmp(ztypestr, "hint") == 0) {
   6828 		const cfg_obj_t *fileobj = NULL;
   6829 		if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
   6830 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   6831 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   6832 				      "zone '%s': 'file' not specified", zname);
   6833 			result = ISC_R_FAILURE;
   6834 			goto cleanup;
   6835 		}
   6836 		if (dns_name_equal(origin, dns_rootname)) {
   6837 			const char *hintsfile = cfg_obj_asstring(fileobj);
   6838 
   6839 			CHECK(configure_hints(view, hintsfile));
   6840 		} else {
   6841 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   6842 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   6843 				      "ignoring non-root hint zone '%s'",
   6844 				      zname);
   6845 			result = ISC_R_SUCCESS;
   6846 		}
   6847 		/* Skip ordinary zone processing. */
   6848 		goto cleanup;
   6849 	}
   6850 
   6851 	/*
   6852 	 * "forward zones" aren't zones either.  Translate this syntax into
   6853 	 * the appropriate selective forwarding configuration and return.
   6854 	 */
   6855 	if (strcasecmp(ztypestr, "forward") == 0) {
   6856 		forwardtype = NULL;
   6857 		forwarders = NULL;
   6858 
   6859 		(void)cfg_map_get(zoptions, "forward", &forwardtype);
   6860 		(void)cfg_map_get(zoptions, "forwarders", &forwarders);
   6861 		CHECK(configure_forward(config, view, origin, forwarders,
   6862 					forwardtype));
   6863 		goto cleanup;
   6864 	}
   6865 
   6866 	/*
   6867 	 * Redirect zones only require minimal configuration.
   6868 	 */
   6869 	if (strcasecmp(ztypestr, "redirect") == 0) {
   6870 		if (view->redirect != NULL) {
   6871 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
   6872 				    "redirect zone already exists");
   6873 			result = ISC_R_EXISTS;
   6874 			goto cleanup;
   6875 		}
   6876 		result = dns_viewlist_find(viewlist, view->name, view->rdclass,
   6877 					   &pview);
   6878 		if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
   6879 			goto cleanup;
   6880 		}
   6881 		if (pview != NULL && pview->redirect != NULL) {
   6882 			dns_zone_attach(pview->redirect, &zone);
   6883 			dns_zone_setview(zone, view);
   6884 		} else {
   6885 			CHECK(dns_zonemgr_createzone(named_g_server->zonemgr,
   6886 						     &zone));
   6887 			CHECK(dns_zone_setorigin(zone, origin));
   6888 			dns_zone_setview(zone, view);
   6889 			CHECK(dns_zonemgr_managezone(named_g_server->zonemgr,
   6890 						     zone));
   6891 			dns_zone_setstats(zone, named_g_server->zonestats);
   6892 		}
   6893 		CHECK(named_zone_configure(config, vconfig, zconfig, aclconf,
   6894 					   kasplist, keystores, zone, NULL));
   6895 		dns_zone_attach(zone, &view->redirect);
   6896 		goto cleanup;
   6897 	}
   6898 
   6899 	if (!modify) {
   6900 		/*
   6901 		 * Check for duplicates in the new zone table.
   6902 		 */
   6903 		result = dns_view_findzone(view, origin, DNS_ZTFIND_EXACT,
   6904 					   &dupzone);
   6905 		if (result == ISC_R_SUCCESS) {
   6906 			/*
   6907 			 * We already have this zone!
   6908 			 */
   6909 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
   6910 				    "zone '%s' already exists", zname);
   6911 			dns_zone_detach(&dupzone);
   6912 			result = ISC_R_EXISTS;
   6913 			goto cleanup;
   6914 		}
   6915 		INSIST(dupzone == NULL);
   6916 	}
   6917 
   6918 	/*
   6919 	 * Note whether this is a response policy zone and which one if so,
   6920 	 * unless we are using RPZ service interface.  In that case, the
   6921 	 * BIND zone database has nothing to do with rpz and so we don't care.
   6922 	 */
   6923 	for (rpz_num = 0;; ++rpz_num) {
   6924 		if (view->rpzs == NULL || rpz_num >= view->rpzs->p.num_zones ||
   6925 		    view->rpzs->p.dnsrps_enabled)
   6926 		{
   6927 			rpz_num = DNS_RPZ_INVALID_NUM;
   6928 			break;
   6929 		}
   6930 		if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin, origin))
   6931 		{
   6932 			break;
   6933 		}
   6934 	}
   6935 
   6936 	if (!is_catz_member && view->catzs != NULL &&
   6937 	    dns_catz_zone_get(view->catzs, origin) != NULL)
   6938 	{
   6939 		zone_is_catz = true;
   6940 	}
   6941 
   6942 	/*
   6943 	 * See if we can reuse an existing zone.  This is
   6944 	 * only possible if all of these are true:
   6945 	 *   - The zone's view exists
   6946 	 *   - A zone with the right name exists in the view
   6947 	 *   - The zone is compatible with the config
   6948 	 *     options (e.g., an existing primary zone cannot
   6949 	 *     be reused if the options specify a secondary zone)
   6950 	 *   - The zone was not and is still not a response policy zone
   6951 	 *     or the zone is a policy zone with an unchanged number
   6952 	 *     and we are using the old policy zone summary data.
   6953 	 */
   6954 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
   6955 				   view->rdclass, &pview);
   6956 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
   6957 		goto cleanup;
   6958 	}
   6959 	if (pview != NULL) {
   6960 		result = dns_view_findzone(pview, origin, DNS_ZTFIND_EXACT,
   6961 					   &zone);
   6962 	}
   6963 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
   6964 		goto cleanup;
   6965 	}
   6966 
   6967 	if (zone != NULL &&
   6968 	    !named_zone_reusable(zone, zconfig, vconfig, config, kasplist))
   6969 	{
   6970 		dns_zone_detach(&zone);
   6971 		fullsign = true;
   6972 	}
   6973 
   6974 	if (zone != NULL && (rpz_num != dns_zone_get_rpz_num(zone) ||
   6975 			     (rpz_num != DNS_RPZ_INVALID_NUM && !old_rpz_ok)))
   6976 	{
   6977 		dns_zone_detach(&zone);
   6978 	}
   6979 
   6980 	if (zone != NULL) {
   6981 		/*
   6982 		 * We found a reusable zone.  Make it use the
   6983 		 * new view.
   6984 		 */
   6985 		dns_zone_setview(zone, view);
   6986 	} else {
   6987 		/*
   6988 		 * We cannot reuse an existing zone, we have
   6989 		 * to create a new one.
   6990 		 */
   6991 		CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
   6992 		CHECK(dns_zone_setorigin(zone, origin));
   6993 		dns_zone_setview(zone, view);
   6994 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
   6995 		dns_zone_setstats(zone, named_g_server->zonestats);
   6996 	}
   6997 	if (rpz_num != DNS_RPZ_INVALID_NUM) {
   6998 		result = dns_zone_rpz_enable(zone, view->rpzs, rpz_num);
   6999 		if (result != ISC_R_SUCCESS) {
   7000 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7001 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   7002 				      "zone '%s': incompatible"
   7003 				      " masterfile-format or database"
   7004 				      " for a response policy zone",
   7005 				      zname);
   7006 			goto cleanup;
   7007 		}
   7008 	}
   7009 
   7010 	if (zone_is_catz) {
   7011 		dns_zone_catz_enable(zone, view->catzs);
   7012 	} else if (dns_zone_catz_is_enabled(zone)) {
   7013 		dns_zone_catz_disable(zone);
   7014 	}
   7015 
   7016 	/*
   7017 	 * If the zone contains a 'forwarders' statement, configure
   7018 	 * selective forwarding.
   7019 	 */
   7020 	forwarders = NULL;
   7021 	if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) {
   7022 		forwardtype = NULL;
   7023 		(void)cfg_map_get(zoptions, "forward", &forwardtype);
   7024 		CHECK(configure_forward(config, view, origin, forwarders,
   7025 					forwardtype));
   7026 	}
   7027 
   7028 	/*
   7029 	 * Mark whether the zone was originally added at runtime or not
   7030 	 */
   7031 	dns_zone_setadded(zone, added);
   7032 
   7033 	/*
   7034 	 * Determine if we need to set up inline signing.
   7035 	 */
   7036 	zone_maybe_inline = (strcasecmp(ztypestr, "primary") == 0 ||
   7037 			     strcasecmp(ztypestr, "master") == 0 ||
   7038 			     strcasecmp(ztypestr, "secondary") == 0 ||
   7039 			     strcasecmp(ztypestr, "slave") == 0);
   7040 
   7041 	if (zone_maybe_inline) {
   7042 		inline_signing = named_zone_inlinesigning(zconfig, vconfig,
   7043 							  config, kasplist);
   7044 	}
   7045 	if (inline_signing) {
   7046 		dns_zone_getraw(zone, &raw);
   7047 		if (raw == NULL) {
   7048 			dns_zone_create(&raw, dns_zone_getmem(zone),
   7049 					dns_zone_gettid(zone));
   7050 			CHECK(dns_zone_setorigin(raw, origin));
   7051 			dns_zone_setview(raw, view);
   7052 			dns_zone_setstats(raw, named_g_server->zonestats);
   7053 			CHECK(dns_zone_link(zone, raw));
   7054 		}
   7055 		if (cfg_map_get(zoptions, "ixfr-from-differences",
   7056 				&ixfrfromdiffs) == ISC_R_SUCCESS)
   7057 		{
   7058 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7059 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   7060 				      "zone '%s': 'ixfr-from-differences' is "
   7061 				      "ignored for inline-signed zones",
   7062 				      zname);
   7063 		}
   7064 	}
   7065 
   7066 	/*
   7067 	 * Configure the zone.
   7068 	 */
   7069 	CHECK(named_zone_configure(config, vconfig, zconfig, aclconf, kasplist,
   7070 				   keystores, zone, raw));
   7071 
   7072 	/*
   7073 	 * Add the zone to its view in the new view list.
   7074 	 */
   7075 	if (!modify) {
   7076 		CHECK(dns_view_addzone(view, zone));
   7077 	}
   7078 
   7079 	if (zone_is_catz) {
   7080 		/*
   7081 		 * force catz reload if the zone is loaded;
   7082 		 * if it's not it'll get reloaded on zone load
   7083 		 */
   7084 		dns_db_t *db = NULL;
   7085 
   7086 		tresult = dns_zone_getdb(zone, &db);
   7087 		if (tresult == ISC_R_SUCCESS) {
   7088 			dns_catz_dbupdate_callback(db, view->catzs);
   7089 			dns_db_detach(&db);
   7090 		}
   7091 	}
   7092 
   7093 	/*
   7094 	 * Ensure that zone keys are reloaded on reconfig
   7095 	 */
   7096 	if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0) {
   7097 		dns_zone_rekey(zone, fullsign, false);
   7098 	}
   7099 
   7100 cleanup:
   7101 	if (zone != NULL) {
   7102 		dns_zone_detach(&zone);
   7103 	}
   7104 	if (raw != NULL) {
   7105 		dns_zone_detach(&raw);
   7106 	}
   7107 	if (pview != NULL) {
   7108 		dns_view_detach(&pview);
   7109 	}
   7110 
   7111 	return result;
   7112 }
   7113 
   7114 /*
   7115  * Configure built-in zone for storing managed-key data.
   7116  */
   7117 static isc_result_t
   7118 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
   7119 	isc_result_t result;
   7120 	dns_view_t *pview = NULL;
   7121 	dns_zone_t *zone = NULL;
   7122 	dns_acl_t *none = NULL;
   7123 	char filename[PATH_MAX];
   7124 	bool defaultview;
   7125 
   7126 	REQUIRE(view != NULL);
   7127 
   7128 	/* See if we can re-use an existing keydata zone. */
   7129 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
   7130 				   view->rdclass, &pview);
   7131 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
   7132 		return result;
   7133 	}
   7134 
   7135 	if (pview != NULL) {
   7136 		if (pview->managed_keys != NULL) {
   7137 			dns_zone_attach(pview->managed_keys,
   7138 					&view->managed_keys);
   7139 			dns_zone_setview(pview->managed_keys, view);
   7140 			dns_zone_setviewcommit(pview->managed_keys);
   7141 			dns_view_detach(&pview);
   7142 			dns_zone_synckeyzone(view->managed_keys);
   7143 			return ISC_R_SUCCESS;
   7144 		}
   7145 
   7146 		dns_view_detach(&pview);
   7147 	}
   7148 
   7149 	/* No existing keydata zone was found; create one */
   7150 	CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
   7151 	CHECK(dns_zone_setorigin(zone, dns_rootname));
   7152 
   7153 	defaultview = (strcmp(view->name, "_default") == 0);
   7154 	CHECK(isc_file_sanitize(
   7155 		directory, defaultview ? "managed-keys" : view->name,
   7156 		defaultview ? "bind" : "mkeys", filename, sizeof(filename)));
   7157 	CHECK(dns_zone_setfile(zone, filename, dns_masterformat_text,
   7158 			       &dns_master_style_default));
   7159 
   7160 	dns_zone_setview(zone, view);
   7161 	dns_zone_settype(zone, dns_zone_key);
   7162 	dns_zone_setclass(zone, view->rdclass);
   7163 
   7164 	CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
   7165 
   7166 	CHECK(dns_acl_none(mctx, &none));
   7167 	dns_zone_setqueryacl(zone, none);
   7168 	dns_zone_setqueryonacl(zone, none);
   7169 	dns_acl_detach(&none);
   7170 
   7171 	dns_zone_setdialup(zone, dns_dialuptype_no);
   7172 	dns_zone_setcheckdstype(zone, dns_checkdstype_no);
   7173 	dns_zone_setnotifytype(zone, dns_notifytype_no);
   7174 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
   7175 	dns_zone_setjournalsize(zone, 0);
   7176 
   7177 	dns_zone_setstats(zone, named_g_server->zonestats);
   7178 	setquerystats(zone, mctx, dns_zonestat_none);
   7179 
   7180 	if (view->managed_keys != NULL) {
   7181 		dns_zone_detach(&view->managed_keys);
   7182 	}
   7183 	dns_zone_attach(zone, &view->managed_keys);
   7184 
   7185 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7186 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   7187 		      "set up managed keys zone for view %s, file '%s'",
   7188 		      view->name, filename);
   7189 
   7190 cleanup:
   7191 	if (zone != NULL) {
   7192 		dns_zone_detach(&zone);
   7193 	}
   7194 	if (none != NULL) {
   7195 		dns_acl_detach(&none);
   7196 	}
   7197 
   7198 	return result;
   7199 }
   7200 
   7201 /*
   7202  * Configure a single server quota.
   7203  */
   7204 static void
   7205 configure_server_quota(const cfg_obj_t **maps, const char *name,
   7206 		       isc_quota_t *quota) {
   7207 	const cfg_obj_t *obj = NULL;
   7208 	isc_result_t result;
   7209 
   7210 	result = named_config_get(maps, name, &obj);
   7211 	INSIST(result == ISC_R_SUCCESS);
   7212 	isc_quota_max(quota, cfg_obj_asuint32(obj));
   7213 }
   7214 
   7215 /*
   7216  * This function is called as soon as the 'directory' statement has been
   7217  * parsed.  This can be extended to support other options if necessary.
   7218  */
   7219 static isc_result_t
   7220 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
   7221 	isc_result_t result;
   7222 	const char *directory;
   7223 
   7224 	REQUIRE(strcasecmp("directory", clausename) == 0);
   7225 
   7226 	UNUSED(arg);
   7227 	UNUSED(clausename);
   7228 
   7229 	/*
   7230 	 * Change directory.
   7231 	 */
   7232 	directory = cfg_obj_asstring(obj);
   7233 
   7234 	if (!isc_file_ischdiridempotent(directory)) {
   7235 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   7236 			    "option 'directory' contains relative path '%s'",
   7237 			    directory);
   7238 	}
   7239 
   7240 	if (!isc_file_isdirwritable(directory)) {
   7241 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7242 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   7243 			      "directory '%s' is not writable", directory);
   7244 		return ISC_R_NOPERM;
   7245 	}
   7246 
   7247 	result = isc_dir_chdir(directory);
   7248 	if (result != ISC_R_SUCCESS) {
   7249 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
   7250 			    "change directory to '%s' failed: %s", directory,
   7251 			    isc_result_totext(result));
   7252 		return result;
   7253 	}
   7254 
   7255 	char cwd[PATH_MAX];
   7256 	if (getcwd(cwd, sizeof(cwd)) == cwd) {
   7257 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7258 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   7259 			      "the working directory is now '%s'", cwd);
   7260 	}
   7261 
   7262 	return ISC_R_SUCCESS;
   7263 }
   7264 
   7265 /*
   7266  * This event callback is invoked to do periodic network interface
   7267  * scanning.
   7268  */
   7269 
   7270 static void
   7271 interface_timer_tick(void *arg) {
   7272 	named_server_t *server = (named_server_t *)arg;
   7273 
   7274 	(void)ns_interfacemgr_scan(server->interfacemgr, false, false);
   7275 }
   7276 
   7277 static void
   7278 heartbeat_timer_tick(void *arg) {
   7279 	named_server_t *server = (named_server_t *)arg;
   7280 	dns_view_t *view = NULL;
   7281 
   7282 	view = ISC_LIST_HEAD(server->viewlist);
   7283 	while (view != NULL) {
   7284 		dns_view_dialup(view);
   7285 		view = ISC_LIST_NEXT(view, link);
   7286 	}
   7287 }
   7288 
   7289 typedef struct {
   7290 	isc_mem_t *mctx;
   7291 	isc_loop_t *loop;
   7292 	dns_fetch_t *fetch;
   7293 	dns_view_t *view;
   7294 	dns_fixedname_t tatname;
   7295 	dns_fixedname_t keyname;
   7296 	dns_rdataset_t rdataset;
   7297 	dns_rdataset_t sigrdataset;
   7298 } ns_tat_t;
   7299 
   7300 static int
   7301 cid(const void *a, const void *b) {
   7302 	const uint16_t ida = *(const uint16_t *)a;
   7303 	const uint16_t idb = *(const uint16_t *)b;
   7304 	if (ida < idb) {
   7305 		return -1;
   7306 	} else if (ida > idb) {
   7307 		return 1;
   7308 	} else {
   7309 		return 0;
   7310 	}
   7311 }
   7312 
   7313 static void
   7314 tat_done(void *arg) {
   7315 	dns_fetchresponse_t *resp = (dns_fetchresponse_t *)arg;
   7316 	ns_tat_t *tat = NULL;
   7317 
   7318 	INSIST(resp != NULL);
   7319 
   7320 	tat = resp->arg;
   7321 
   7322 	INSIST(tat != NULL);
   7323 
   7324 	/* Free resources which are not of interest */
   7325 	if (resp->node != NULL) {
   7326 		dns_db_detachnode(resp->db, &resp->node);
   7327 	}
   7328 	if (resp->db != NULL) {
   7329 		dns_db_detach(&resp->db);
   7330 	}
   7331 
   7332 	dns_resolver_freefresp(&resp);
   7333 	dns_resolver_destroyfetch(&tat->fetch);
   7334 	if (dns_rdataset_isassociated(&tat->rdataset)) {
   7335 		dns_rdataset_disassociate(&tat->rdataset);
   7336 	}
   7337 	if (dns_rdataset_isassociated(&tat->sigrdataset)) {
   7338 		dns_rdataset_disassociate(&tat->sigrdataset);
   7339 	}
   7340 	dns_view_detach(&tat->view);
   7341 	isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
   7342 }
   7343 
   7344 struct dotat_arg {
   7345 	dns_view_t *view;
   7346 	isc_loop_t *loop;
   7347 };
   7348 
   7349 /*%
   7350  * Prepare the QNAME for the TAT query to be sent by processing the trust
   7351  * anchors present at 'keynode' of 'keytable'.  Store the result in 'dst' and
   7352  * the domain name which 'keynode' is associated with in 'origin'.
   7353  *
   7354  * A maximum of 12 key IDs can be reported in a single TAT query due to the
   7355  * 63-octet length limit for any single label in a domain name.  If there are
   7356  * more than 12 keys configured at 'keynode', only the first 12 will be
   7357  * reported in the TAT query.
   7358  */
   7359 static isc_result_t
   7360 get_tat_qname(dns_name_t *target, dns_name_t *keyname, dns_keynode_t *keynode) {
   7361 	dns_rdataset_t dsset;
   7362 	unsigned int i, n = 0;
   7363 	uint16_t ids[12];
   7364 	isc_textregion_t r;
   7365 	char label[64];
   7366 	int m;
   7367 
   7368 	dns_rdataset_init(&dsset);
   7369 	if (dns_keynode_dsset(keynode, &dsset)) {
   7370 		isc_result_t result;
   7371 
   7372 		for (result = dns_rdataset_first(&dsset);
   7373 		     result == ISC_R_SUCCESS;
   7374 		     result = dns_rdataset_next(&dsset))
   7375 		{
   7376 			dns_rdata_t rdata = DNS_RDATA_INIT;
   7377 			dns_rdata_ds_t ds;
   7378 
   7379 			dns_rdata_reset(&rdata);
   7380 			dns_rdataset_current(&dsset, &rdata);
   7381 			result = dns_rdata_tostruct(&rdata, &ds, NULL);
   7382 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7383 			if (n < (sizeof(ids) / sizeof(ids[0]))) {
   7384 				ids[n] = ds.key_tag;
   7385 				n++;
   7386 			}
   7387 		}
   7388 		dns_rdataset_disassociate(&dsset);
   7389 	}
   7390 
   7391 	if (n == 0) {
   7392 		return DNS_R_EMPTYNAME;
   7393 	}
   7394 
   7395 	if (n > 1) {
   7396 		qsort(ids, n, sizeof(ids[0]), cid);
   7397 	}
   7398 
   7399 	/*
   7400 	 * Encoded as "_ta-xxxx\(-xxxx\)*" where xxxx is the hex version of
   7401 	 * of the keyid.
   7402 	 */
   7403 	label[0] = 0;
   7404 	r.base = label;
   7405 	r.length = sizeof(label);
   7406 	m = snprintf(r.base, r.length, "_ta");
   7407 	if (m < 0 || (unsigned int)m > r.length) {
   7408 		return ISC_R_FAILURE;
   7409 	}
   7410 	isc_textregion_consume(&r, m);
   7411 	for (i = 0; i < n; i++) {
   7412 		m = snprintf(r.base, r.length, "-%04x", ids[i]);
   7413 		if (m < 0 || (unsigned int)m > r.length) {
   7414 			return ISC_R_FAILURE;
   7415 		}
   7416 		isc_textregion_consume(&r, m);
   7417 	}
   7418 
   7419 	return dns_name_fromstring(target, label, keyname, 0, NULL);
   7420 }
   7421 
   7422 static void
   7423 tat_send(void *arg) {
   7424 	ns_tat_t *tat = (ns_tat_t *)arg;
   7425 	char namebuf[DNS_NAME_FORMATSIZE];
   7426 	dns_fixedname_t fdomain;
   7427 	dns_name_t *domain = NULL;
   7428 	dns_rdataset_t nameservers;
   7429 	isc_result_t result;
   7430 	dns_name_t *keyname = NULL;
   7431 	dns_name_t *tatname = NULL;
   7432 
   7433 	keyname = dns_fixedname_name(&tat->keyname);
   7434 	tatname = dns_fixedname_name(&tat->tatname);
   7435 
   7436 	dns_name_format(tatname, namebuf, sizeof(namebuf));
   7437 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7438 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   7439 		      "%s: sending trust-anchor-telemetry query '%s/NULL'",
   7440 		      tat->view->name, namebuf);
   7441 
   7442 	/*
   7443 	 * TAT queries should be sent to the authoritative servers for a given
   7444 	 * zone.  If this function is called for a keytable node corresponding
   7445 	 * to a locally served zone, calling dns_resolver_createfetch() with
   7446 	 * NULL 'domain' and 'nameservers' arguments will cause 'tatname' to be
   7447 	 * resolved locally, without sending any TAT queries upstream.
   7448 	 *
   7449 	 * Work around this issue by calling dns_view_findzonecut() first.  If
   7450 	 * the zone is served locally, the NS RRset for the given domain name
   7451 	 * will be retrieved from local data; if it is not, the deepest zone
   7452 	 * cut we have for it will be retrieved from cache.  In either case,
   7453 	 * passing the results to dns_resolver_createfetch() will prevent it
   7454 	 * from returning NXDOMAIN for 'tatname' while still allowing it to
   7455 	 * chase down any potential delegations returned by upstream servers in
   7456 	 * order to eventually find the destination host to send the TAT query
   7457 	 * to.
   7458 	 *
   7459 	 * After the dns_view_findzonecut() call, 'domain' will hold the
   7460 	 * deepest zone cut we can find for 'keyname' while 'nameservers' will
   7461 	 * hold the NS RRset at that zone cut.
   7462 	 */
   7463 	domain = dns_fixedname_initname(&fdomain);
   7464 	dns_rdataset_init(&nameservers);
   7465 	result = dns_view_findzonecut(tat->view, keyname, domain, NULL, 0, 0,
   7466 				      true, true, &nameservers, NULL);
   7467 	if (result == ISC_R_SUCCESS) {
   7468 		result = dns_resolver_createfetch(
   7469 			tat->view->resolver, tatname, dns_rdatatype_null,
   7470 			domain, &nameservers, NULL, NULL, 0, 0, 0, NULL, NULL,
   7471 			NULL, tat->loop, tat_done, tat, NULL, &tat->rdataset,
   7472 			&tat->sigrdataset, &tat->fetch);
   7473 	}
   7474 
   7475 	/*
   7476 	 * 'domain' holds the dns_name_t pointer inside a dst_key_t structure.
   7477 	 * dns_resolver_createfetch() creates its own copy of 'domain' if it
   7478 	 * succeeds.  Thus, 'domain' is not freed here.
   7479 	 *
   7480 	 * Even if dns_view_findzonecut() returned something else than
   7481 	 * ISC_R_SUCCESS, it still could have associated 'nameservers'.
   7482 	 * dns_resolver_createfetch() creates its own copy of 'nameservers' if
   7483 	 * it succeeds.  Thus, we need to check whether 'nameservers' is
   7484 	 * associated and release it if it is.
   7485 	 */
   7486 	if (dns_rdataset_isassociated(&nameservers)) {
   7487 		dns_rdataset_disassociate(&nameservers);
   7488 	}
   7489 
   7490 	if (result != ISC_R_SUCCESS) {
   7491 		dns_view_detach(&tat->view);
   7492 		isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
   7493 	}
   7494 }
   7495 
   7496 static void
   7497 dotat(dns_keytable_t *keytable, dns_keynode_t *keynode, dns_name_t *keyname,
   7498       void *arg) {
   7499 	struct dotat_arg *dotat_arg = (struct dotat_arg *)arg;
   7500 	isc_result_t result;
   7501 	dns_view_t *view = NULL;
   7502 	ns_tat_t *tat = NULL;
   7503 
   7504 	REQUIRE(keytable != NULL);
   7505 	REQUIRE(keynode != NULL);
   7506 	REQUIRE(dotat_arg != NULL);
   7507 
   7508 	view = dotat_arg->view;
   7509 
   7510 	tat = isc_mem_get(view->mctx, sizeof(*tat));
   7511 	*tat = (ns_tat_t){ 0 };
   7512 
   7513 	dns_rdataset_init(&tat->rdataset);
   7514 	dns_rdataset_init(&tat->sigrdataset);
   7515 	dns_name_copy(keyname, dns_fixedname_initname(&tat->keyname));
   7516 	result = get_tat_qname(dns_fixedname_initname(&tat->tatname), keyname,
   7517 			       keynode);
   7518 	if (result != ISC_R_SUCCESS) {
   7519 		isc_mem_put(view->mctx, tat, sizeof(*tat));
   7520 		return;
   7521 	}
   7522 	isc_mem_attach(view->mctx, &tat->mctx);
   7523 	tat->loop = dotat_arg->loop;
   7524 	dns_view_attach(view, &tat->view);
   7525 
   7526 	/*
   7527 	 * We don't want to be holding the keytable lock when calling
   7528 	 * dns_view_findzonecut() as it creates a lock order loop so
   7529 	 * call dns_view_findzonecut() in a event handler.
   7530 	 *
   7531 	 * zone->lock (dns_zone_setviewcommit) while holding view->lock
   7532 	 * (dns_view_setviewcommit)
   7533 	 *
   7534 	 * keytable->lock (dns_keytable_find) while holding zone->lock
   7535 	 * (zone_asyncload)
   7536 	 *
   7537 	 * view->lock (dns_view_findzonecut) while holding keytable->lock
   7538 	 * (dns_keytable_forall)
   7539 	 */
   7540 	isc_async_run(named_g_mainloop, tat_send, tat);
   7541 }
   7542 
   7543 static void
   7544 tat_timer_tick(void *arg) {
   7545 	isc_result_t result;
   7546 	named_server_t *server = (named_server_t *)arg;
   7547 	struct dotat_arg dotat_arg = { 0 };
   7548 	dns_view_t *view = NULL;
   7549 	dns_keytable_t *secroots = NULL;
   7550 
   7551 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   7552 	     view = ISC_LIST_NEXT(view, link))
   7553 	{
   7554 		if (!view->trust_anchor_telemetry || !view->enablevalidation) {
   7555 			continue;
   7556 		}
   7557 
   7558 		result = dns_view_getsecroots(view, &secroots);
   7559 		if (result != ISC_R_SUCCESS) {
   7560 			continue;
   7561 		}
   7562 
   7563 		dotat_arg.view = view;
   7564 		dotat_arg.loop = named_g_mainloop;
   7565 		dns_keytable_forall(secroots, dotat, &dotat_arg);
   7566 		dns_keytable_detach(&secroots);
   7567 	}
   7568 }
   7569 
   7570 static void
   7571 pps_timer_tick(void *arg) {
   7572 	static unsigned int oldrequests = 0;
   7573 	unsigned int requests = atomic_load_relaxed(&ns_client_requests);
   7574 
   7575 	UNUSED(arg);
   7576 
   7577 	/*
   7578 	 * Don't worry about wrapping as the overflow result will be right.
   7579 	 */
   7580 	dns_pps = (requests - oldrequests) / 1200;
   7581 	oldrequests = requests;
   7582 }
   7583 
   7584 /*
   7585  * Replace the current value of '*field', a dynamically allocated
   7586  * string or NULL, with a dynamically allocated copy of the
   7587  * null-terminated string pointed to by 'value', or NULL.
   7588  */
   7589 static void
   7590 setstring(named_server_t *server, char **field, const char *value) {
   7591 	char *copy;
   7592 
   7593 	if (value != NULL) {
   7594 		copy = isc_mem_strdup(server->mctx, value);
   7595 	} else {
   7596 		copy = NULL;
   7597 	}
   7598 
   7599 	if (*field != NULL) {
   7600 		isc_mem_free(server->mctx, *field);
   7601 	}
   7602 
   7603 	*field = copy;
   7604 }
   7605 
   7606 /*
   7607  * Replace the current value of '*field', a dynamically allocated
   7608  * string or NULL, with another dynamically allocated string
   7609  * or NULL if whether 'obj' is a string or void value, respectively.
   7610  */
   7611 static void
   7612 setoptstring(named_server_t *server, char **field, const cfg_obj_t *obj) {
   7613 	if (cfg_obj_isvoid(obj)) {
   7614 		setstring(server, field, NULL);
   7615 	} else {
   7616 		setstring(server, field, cfg_obj_asstring(obj));
   7617 	}
   7618 }
   7619 
   7620 static void
   7621 portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
   7622 		 bool positive) {
   7623 	const cfg_listelt_t *element;
   7624 
   7625 	for (element = cfg_list_first(ports); element != NULL;
   7626 	     element = cfg_list_next(element))
   7627 	{
   7628 		const cfg_obj_t *obj = cfg_listelt_value(element);
   7629 
   7630 		if (cfg_obj_isuint32(obj)) {
   7631 			in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
   7632 
   7633 			if (positive) {
   7634 				isc_portset_add(portset, port);
   7635 			} else {
   7636 				isc_portset_remove(portset, port);
   7637 			}
   7638 		} else {
   7639 			const cfg_obj_t *obj_loport, *obj_hiport;
   7640 			in_port_t loport, hiport;
   7641 
   7642 			obj_loport = cfg_tuple_get(obj, "loport");
   7643 			loport = (in_port_t)cfg_obj_asuint32(obj_loport);
   7644 			obj_hiport = cfg_tuple_get(obj, "hiport");
   7645 			hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
   7646 
   7647 			if (positive) {
   7648 				isc_portset_addrange(portset, loport, hiport);
   7649 			} else {
   7650 				isc_portset_removerange(portset, loport,
   7651 							hiport);
   7652 			}
   7653 		}
   7654 	}
   7655 }
   7656 
   7657 static isc_result_t
   7658 removed(dns_zone_t *zone, void *uap) {
   7659 	if (dns_zone_getview(zone) != uap) {
   7660 		return ISC_R_SUCCESS;
   7661 	}
   7662 
   7663 	dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed",
   7664 		     dns_zonetype_name(dns_zone_gettype(zone)));
   7665 	return ISC_R_SUCCESS;
   7666 }
   7667 
   7668 static void
   7669 cleanup_session_key(named_server_t *server, isc_mem_t *mctx) {
   7670 	if (server->session_keyfile != NULL) {
   7671 		isc_file_remove(server->session_keyfile);
   7672 		isc_mem_free(mctx, server->session_keyfile);
   7673 		server->session_keyfile = NULL;
   7674 	}
   7675 
   7676 	if (server->session_keyname != NULL) {
   7677 		if (dns_name_dynamic(server->session_keyname)) {
   7678 			dns_name_free(server->session_keyname, mctx);
   7679 		}
   7680 		isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t));
   7681 		server->session_keyname = NULL;
   7682 	}
   7683 
   7684 	if (server->sessionkey != NULL) {
   7685 		dst_key_free(&server->sessionkey);
   7686 	}
   7687 
   7688 	server->session_keyalg = DST_ALG_UNKNOWN;
   7689 	server->session_keybits = 0;
   7690 }
   7691 
   7692 static isc_result_t
   7693 generate_session_key(const char *filename, const char *keynamestr,
   7694 		     const dns_name_t *keyname, dst_algorithm_t alg,
   7695 		     uint16_t bits, isc_mem_t *mctx, bool first_time,
   7696 		     dst_key_t **keyp) {
   7697 	isc_result_t result = ISC_R_SUCCESS;
   7698 	dst_key_t *key = NULL;
   7699 	isc_buffer_t key_txtbuffer;
   7700 	isc_buffer_t key_rawbuffer;
   7701 	char key_txtsecret[256];
   7702 	char key_rawsecret[64];
   7703 	isc_region_t key_rawregion;
   7704 	FILE *fp = NULL;
   7705 
   7706 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7707 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   7708 		      "generating session key for dynamic DNS");
   7709 
   7710 	/* generate key */
   7711 	result = dst_key_generate(keyname, alg, bits, 1, 0, DNS_KEYPROTO_ANY,
   7712 				  dns_rdataclass_in, NULL, mctx, &key, NULL);
   7713 	if (result != ISC_R_SUCCESS) {
   7714 		return result;
   7715 	}
   7716 
   7717 	/*
   7718 	 * Dump the key to the buffer for later use.
   7719 	 */
   7720 	isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
   7721 	CHECK(dst_key_tobuffer(key, &key_rawbuffer));
   7722 
   7723 	isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
   7724 	isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
   7725 	CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer));
   7726 
   7727 	/* Dump the key to the key file. */
   7728 	fp = named_os_openfile(filename, S_IRUSR | S_IWUSR, first_time);
   7729 	if (fp == NULL) {
   7730 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7731 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   7732 			      "could not create %s", filename);
   7733 		result = ISC_R_NOPERM;
   7734 		goto cleanup;
   7735 	}
   7736 
   7737 	fprintf(fp,
   7738 		"key \"%s\" {\n"
   7739 		"\talgorithm %s;\n"
   7740 		"\tsecret \"%.*s\";\n};\n",
   7741 		keynamestr, dst_hmac_algorithm_totext(alg),
   7742 		(int)isc_buffer_usedlength(&key_txtbuffer),
   7743 		(char *)isc_buffer_base(&key_txtbuffer));
   7744 
   7745 	CHECK(isc_stdio_flush(fp));
   7746 	result = isc_stdio_close(fp);
   7747 	if (result != ISC_R_SUCCESS) {
   7748 		goto cleanup;
   7749 	}
   7750 
   7751 	*keyp = key;
   7752 	return ISC_R_SUCCESS;
   7753 
   7754 cleanup:
   7755 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7756 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   7757 		      "failed to generate session key "
   7758 		      "for dynamic DNS: %s",
   7759 		      isc_result_totext(result));
   7760 	if (fp != NULL) {
   7761 		(void)isc_stdio_close(fp);
   7762 		(void)isc_file_remove(filename);
   7763 	}
   7764 	if (key != NULL) {
   7765 		dst_key_free(&key);
   7766 	}
   7767 
   7768 	return result;
   7769 }
   7770 
   7771 static isc_result_t
   7772 configure_session_key(const cfg_obj_t **maps, named_server_t *server,
   7773 		      isc_mem_t *mctx, bool first_time) {
   7774 	const char *keyfile = NULL, *keynamestr = NULL, *algstr = NULL;
   7775 	unsigned int algtype;
   7776 	dns_fixedname_t fname;
   7777 	dns_name_t *keyname = NULL;
   7778 	isc_buffer_t buffer;
   7779 	uint16_t bits;
   7780 	const cfg_obj_t *obj = NULL;
   7781 	bool need_deleteold = false;
   7782 	bool need_createnew = false;
   7783 	isc_result_t result;
   7784 
   7785 	obj = NULL;
   7786 	result = named_config_get(maps, "session-keyfile", &obj);
   7787 	if (result == ISC_R_SUCCESS) {
   7788 		if (cfg_obj_isvoid(obj)) {
   7789 			keyfile = NULL; /* disable it */
   7790 		} else {
   7791 			keyfile = cfg_obj_asstring(obj);
   7792 		}
   7793 	} else {
   7794 		keyfile = named_g_defaultsessionkeyfile;
   7795 	}
   7796 
   7797 	obj = NULL;
   7798 	result = named_config_get(maps, "session-keyname", &obj);
   7799 	INSIST(result == ISC_R_SUCCESS);
   7800 	keynamestr = cfg_obj_asstring(obj);
   7801 	isc_buffer_constinit(&buffer, keynamestr, strlen(keynamestr));
   7802 	isc_buffer_add(&buffer, strlen(keynamestr));
   7803 	keyname = dns_fixedname_initname(&fname);
   7804 	result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL);
   7805 	if (result != ISC_R_SUCCESS) {
   7806 		return result;
   7807 	}
   7808 
   7809 	obj = NULL;
   7810 	result = named_config_get(maps, "session-keyalg", &obj);
   7811 	INSIST(result == ISC_R_SUCCESS);
   7812 	algstr = cfg_obj_asstring(obj);
   7813 	result = named_config_getkeyalgorithm(algstr, &algtype, &bits);
   7814 	if (result != ISC_R_SUCCESS) {
   7815 		const char *s = " (keeping current key)";
   7816 
   7817 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
   7818 			    "session-keyalg: "
   7819 			    "unsupported or unknown algorithm '%s'%s",
   7820 			    algstr, server->session_keyfile != NULL ? s : "");
   7821 		return result;
   7822 	}
   7823 
   7824 	/* See if we need to (re)generate a new key. */
   7825 	if (keyfile == NULL) {
   7826 		if (server->session_keyfile != NULL) {
   7827 			need_deleteold = true;
   7828 		}
   7829 	} else if (server->session_keyfile == NULL) {
   7830 		need_createnew = true;
   7831 	} else if (strcmp(keyfile, server->session_keyfile) != 0 ||
   7832 		   !dns_name_equal(server->session_keyname, keyname) ||
   7833 		   server->session_keyalg != algtype ||
   7834 		   server->session_keybits != bits)
   7835 	{
   7836 		need_deleteold = true;
   7837 		need_createnew = true;
   7838 	}
   7839 
   7840 	if (need_deleteold) {
   7841 		INSIST(server->session_keyfile != NULL);
   7842 		INSIST(server->session_keyname != NULL);
   7843 		INSIST(server->sessionkey != NULL);
   7844 
   7845 		cleanup_session_key(server, mctx);
   7846 	}
   7847 
   7848 	if (need_createnew) {
   7849 		INSIST(server->sessionkey == NULL);
   7850 		INSIST(server->session_keyfile == NULL);
   7851 		INSIST(server->session_keyname == NULL);
   7852 		INSIST(server->session_keyalg == DST_ALG_UNKNOWN);
   7853 		INSIST(server->session_keybits == 0);
   7854 
   7855 		server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t));
   7856 		dns_name_init(server->session_keyname, NULL);
   7857 		dns_name_dup(keyname, mctx, server->session_keyname);
   7858 
   7859 		server->session_keyfile = isc_mem_strdup(mctx, keyfile);
   7860 
   7861 		server->session_keyalg = algtype;
   7862 		server->session_keybits = bits;
   7863 
   7864 		CHECK(generate_session_key(keyfile, keynamestr, keyname,
   7865 					   algtype, bits, mctx, first_time,
   7866 					   &server->sessionkey));
   7867 	}
   7868 
   7869 	return result;
   7870 
   7871 cleanup:
   7872 	cleanup_session_key(server, mctx);
   7873 	return result;
   7874 }
   7875 
   7876 static isc_result_t
   7877 setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
   7878 	       cfg_parser_t *conf_parser, cfg_aclconfctx_t *actx) {
   7879 	isc_result_t result = ISC_R_SUCCESS;
   7880 	bool allow = false;
   7881 	ns_cfgctx_t *nzcfg = NULL;
   7882 	const cfg_obj_t *maps[4];
   7883 	const cfg_obj_t *options = NULL, *voptions = NULL;
   7884 	const cfg_obj_t *nz = NULL;
   7885 	const cfg_obj_t *nzdir = NULL;
   7886 	const char *dir = NULL;
   7887 	const cfg_obj_t *obj = NULL;
   7888 	int i = 0;
   7889 	uint64_t mapsize = 0ULL;
   7890 
   7891 	REQUIRE(config != NULL);
   7892 
   7893 	if (vconfig != NULL) {
   7894 		voptions = cfg_tuple_get(vconfig, "options");
   7895 	}
   7896 	if (voptions != NULL) {
   7897 		maps[i++] = voptions;
   7898 	}
   7899 	result = cfg_map_get(config, "options", &options);
   7900 	if (result == ISC_R_SUCCESS) {
   7901 		maps[i++] = options;
   7902 	}
   7903 	maps[i++] = named_g_defaults;
   7904 	maps[i] = NULL;
   7905 
   7906 	result = named_config_get(maps, "allow-new-zones", &nz);
   7907 	if (result == ISC_R_SUCCESS) {
   7908 		allow = cfg_obj_asboolean(nz);
   7909 	}
   7910 	result = named_config_get(maps, "new-zones-directory", &nzdir);
   7911 	if (result == ISC_R_SUCCESS) {
   7912 		dir = cfg_obj_asstring(nzdir);
   7913 		result = isc_file_isdirectory(dir);
   7914 		if (result != ISC_R_SUCCESS) {
   7915 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
   7916 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   7917 				      "invalid new-zones-directory %s: %s", dir,
   7918 				      isc_result_totext(result));
   7919 			return result;
   7920 		}
   7921 		if (!isc_file_isdirwritable(dir)) {
   7922 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   7923 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   7924 				      "new-zones-directory '%s' "
   7925 				      "is not writable",
   7926 				      dir);
   7927 			return ISC_R_NOPERM;
   7928 		}
   7929 
   7930 		dns_view_setnewzonedir(view, dir);
   7931 	}
   7932 
   7933 #ifdef HAVE_LMDB
   7934 	result = named_config_get(maps, "lmdb-mapsize", &obj);
   7935 	if (result == ISC_R_SUCCESS && obj != NULL) {
   7936 		mapsize = cfg_obj_asuint64(obj);
   7937 		if (mapsize < (1ULL << 20)) { /* 1 megabyte */
   7938 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
   7939 				    "'lmdb-mapsize "
   7940 				    "%" PRId64 "' "
   7941 				    "is too small",
   7942 				    mapsize);
   7943 			return ISC_R_FAILURE;
   7944 		} else if (mapsize > (1ULL << 40)) { /* 1 terabyte */
   7945 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
   7946 				    "'lmdb-mapsize "
   7947 				    "%" PRId64 "' "
   7948 				    "is too large",
   7949 				    mapsize);
   7950 			return ISC_R_FAILURE;
   7951 		}
   7952 	}
   7953 #else  /* ifdef HAVE_LMDB */
   7954 	UNUSED(obj);
   7955 #endif /* HAVE_LMDB */
   7956 
   7957 	/*
   7958 	 * A non-empty catalog-zones statement implies allow-new-zones
   7959 	 */
   7960 	if (!allow) {
   7961 		const cfg_obj_t *cz = NULL;
   7962 		result = named_config_get(maps, "catalog-zones", &cz);
   7963 		if (result == ISC_R_SUCCESS) {
   7964 			const cfg_listelt_t *e =
   7965 				cfg_list_first(cfg_tuple_get(cz, "zone list"));
   7966 			if (e != NULL) {
   7967 				allow = true;
   7968 			}
   7969 		}
   7970 	}
   7971 
   7972 	if (!allow) {
   7973 		dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
   7974 		return ISC_R_SUCCESS;
   7975 	}
   7976 
   7977 	nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg));
   7978 	*nzcfg = (ns_cfgctx_t){ 0 };
   7979 
   7980 	/*
   7981 	 * We attach the parser that was used for config as well
   7982 	 * as the one that will be used for added zones, to avoid
   7983 	 * a shutdown race later.
   7984 	 */
   7985 	isc_mem_attach(view->mctx, &nzcfg->mctx);
   7986 	cfg_parser_attach(conf_parser, &nzcfg->conf_parser);
   7987 	cfg_parser_attach(named_g_addparser, &nzcfg->add_parser);
   7988 	cfg_aclconfctx_attach(actx, &nzcfg->actx);
   7989 
   7990 	result = dns_view_setnewzones(view, true, nzcfg, newzone_cfgctx_destroy,
   7991 				      mapsize);
   7992 	if (result != ISC_R_SUCCESS) {
   7993 		cfg_aclconfctx_detach(&nzcfg->actx);
   7994 		cfg_parser_destroy(&nzcfg->add_parser);
   7995 		cfg_parser_destroy(&nzcfg->conf_parser);
   7996 		isc_mem_putanddetach(&nzcfg->mctx, nzcfg, sizeof(*nzcfg));
   7997 		dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
   7998 		return result;
   7999 	}
   8000 
   8001 	cfg_obj_attach(config, &nzcfg->config);
   8002 	if (vconfig != NULL) {
   8003 		cfg_obj_attach(vconfig, &nzcfg->vconfig);
   8004 	}
   8005 
   8006 	result = load_nzf(view, nzcfg);
   8007 	return result;
   8008 }
   8009 
   8010 static void
   8011 configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
   8012 			     dns_view_t *view) {
   8013 	const char *zname;
   8014 	dns_fixedname_t fixorigin;
   8015 	dns_name_t *origin;
   8016 	isc_result_t result2;
   8017 	dns_view_t *pview = NULL;
   8018 	dns_zone_t *zone = NULL;
   8019 
   8020 	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
   8021 	origin = dns_fixedname_initname(&fixorigin);
   8022 
   8023 	result2 = dns_name_fromstring(origin, zname, dns_rootname, 0, NULL);
   8024 	if (result2 != ISC_R_SUCCESS) {
   8025 		return;
   8026 	}
   8027 
   8028 	result2 = dns_viewlist_find(&named_g_server->viewlist, view->name,
   8029 				    view->rdclass, &pview);
   8030 	if (result2 != ISC_R_SUCCESS) {
   8031 		return;
   8032 	}
   8033 
   8034 	result2 = dns_view_findzone(pview, origin, DNS_ZTFIND_EXACT, &zone);
   8035 	if (result2 != ISC_R_SUCCESS) {
   8036 		dns_view_detach(&pview);
   8037 		return;
   8038 	}
   8039 
   8040 	if (result == ISC_R_SUCCESS) {
   8041 		dns_zone_setviewcommit(zone);
   8042 	} else {
   8043 		dns_zone_setviewrevert(zone);
   8044 	}
   8045 
   8046 	dns_zone_detach(&zone);
   8047 	dns_view_detach(&pview);
   8048 }
   8049 
   8050 #ifndef HAVE_LMDB
   8051 
   8052 static isc_result_t
   8053 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
   8054 		   cfg_aclconfctx_t *actx) {
   8055 	isc_result_t result;
   8056 	ns_cfgctx_t *nzctx;
   8057 	const cfg_obj_t *zonelist;
   8058 	const cfg_listelt_t *element;
   8059 
   8060 	nzctx = view->new_zone_config;
   8061 	if (nzctx == NULL || nzctx->nzf_config == NULL) {
   8062 		return ISC_R_SUCCESS;
   8063 	}
   8064 
   8065 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8066 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8067 		      "loading additional zones for view '%s'", view->name);
   8068 
   8069 	zonelist = NULL;
   8070 	cfg_map_get(nzctx->nzf_config, "zone", &zonelist);
   8071 
   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 		CHECK(configure_zone(config, zconfig, vconfig, view,
   8077 				     &named_g_server->viewlist,
   8078 				     &named_g_server->kasplist,
   8079 				     &named_g_server->keystorelist, actx, true,
   8080 				     false, false, false));
   8081 	}
   8082 
   8083 	result = ISC_R_SUCCESS;
   8084 
   8085 cleanup:
   8086 	for (element = cfg_list_first(zonelist); element != NULL;
   8087 	     element = cfg_list_next(element))
   8088 	{
   8089 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
   8090 		configure_zone_setviewcommit(result, zconfig, view);
   8091 	}
   8092 
   8093 	return result;
   8094 }
   8095 
   8096 #else /* HAVE_LMDB */
   8097 
   8098 static isc_result_t
   8099 data_to_cfg(dns_view_t *view, MDB_val *key, MDB_val *data, isc_buffer_t **text,
   8100 	    cfg_obj_t **zoneconfig) {
   8101 	isc_result_t result;
   8102 	const char *zone_name;
   8103 	size_t zone_name_len;
   8104 	const char *zone_config;
   8105 	size_t zone_config_len;
   8106 	cfg_obj_t *zoneconf = NULL;
   8107 	char bufname[DNS_NAME_FORMATSIZE];
   8108 
   8109 	REQUIRE(view != NULL);
   8110 	REQUIRE(key != NULL);
   8111 	REQUIRE(data != NULL);
   8112 	REQUIRE(text != NULL);
   8113 	REQUIRE(zoneconfig != NULL && *zoneconfig == NULL);
   8114 
   8115 	if (*text == NULL) {
   8116 		isc_buffer_allocate(view->mctx, text, 256);
   8117 	} else {
   8118 		isc_buffer_clear(*text);
   8119 	}
   8120 
   8121 	zone_name = (const char *)key->mv_data;
   8122 	zone_name_len = key->mv_size;
   8123 	INSIST(zone_name != NULL && zone_name_len > 0);
   8124 
   8125 	zone_config = (const char *)data->mv_data;
   8126 	zone_config_len = data->mv_size;
   8127 	INSIST(zone_config != NULL && zone_config_len > 0);
   8128 
   8129 	/* zone zonename { config; }; */
   8130 	result = isc_buffer_reserve(*text, 6 + zone_name_len + 2 +
   8131 						   zone_config_len + 2);
   8132 	if (result != ISC_R_SUCCESS) {
   8133 		goto cleanup;
   8134 	}
   8135 
   8136 	CHECK(putstr(text, "zone \""));
   8137 	CHECK(putmem(text, (const void *)zone_name, zone_name_len));
   8138 	CHECK(putstr(text, "\" "));
   8139 	CHECK(putmem(text, (const void *)zone_config, zone_config_len));
   8140 	CHECK(putstr(text, ";\n"));
   8141 
   8142 	snprintf(bufname, sizeof(bufname), "%.*s", (int)zone_name_len,
   8143 		 zone_name);
   8144 
   8145 	cfg_parser_reset(named_g_addparser);
   8146 	result = cfg_parse_buffer(named_g_addparser, *text, bufname, 0,
   8147 				  &cfg_type_addzoneconf, 0, &zoneconf);
   8148 	if (result != ISC_R_SUCCESS) {
   8149 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8150 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   8151 			      "parsing config for zone '%.*s' in "
   8152 			      "NZD database '%s' failed",
   8153 			      (int)zone_name_len, zone_name, view->new_zone_db);
   8154 		goto cleanup;
   8155 	}
   8156 
   8157 	*zoneconfig = zoneconf;
   8158 	zoneconf = NULL;
   8159 	result = ISC_R_SUCCESS;
   8160 
   8161 cleanup:
   8162 	if (zoneconf != NULL) {
   8163 		cfg_obj_destroy(named_g_addparser, &zoneconf);
   8164 	}
   8165 
   8166 	return result;
   8167 }
   8168 
   8169 /*%
   8170  * Prototype for a callback which can be used with for_all_newzone_cfgs().
   8171  */
   8172 typedef isc_result_t (*newzone_cfg_cb_t)(const cfg_obj_t *zconfig,
   8173 					 cfg_obj_t *config, cfg_obj_t *vconfig,
   8174 					 dns_view_t *view,
   8175 					 cfg_aclconfctx_t *actx);
   8176 
   8177 /*%
   8178  * For each zone found in a NZD opened by the caller, create an object
   8179  * representing its configuration and invoke "callback" with the created
   8180  * object, "config", "vconfig", "mctx", "view" and "actx" as arguments (all
   8181  * these are non-global variables required to invoke configure_zone()).
   8182  * Immediately interrupt processing if an error is encountered while
   8183  * transforming NZD data into a zone configuration object or if "callback"
   8184  * returns an error.
   8185  *
   8186  * Caller must hold 'view->new_zone_lock'.
   8187  */
   8188 static isc_result_t
   8189 for_all_newzone_cfgs(newzone_cfg_cb_t callback, cfg_obj_t *config,
   8190 		     cfg_obj_t *vconfig, dns_view_t *view,
   8191 		     cfg_aclconfctx_t *actx, MDB_txn *txn, MDB_dbi dbi) {
   8192 	const cfg_obj_t *zconfig, *zlist;
   8193 	isc_result_t result = ISC_R_SUCCESS;
   8194 	cfg_obj_t *zconfigobj = NULL;
   8195 	isc_buffer_t *text = NULL;
   8196 	MDB_cursor *cursor = NULL;
   8197 	MDB_val data, key;
   8198 	int status;
   8199 
   8200 	status = mdb_cursor_open(txn, dbi, &cursor);
   8201 	if (status != MDB_SUCCESS) {
   8202 		return ISC_R_FAILURE;
   8203 	}
   8204 
   8205 	for (status = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
   8206 	     status == MDB_SUCCESS;
   8207 	     status = mdb_cursor_get(cursor, &key, &data, MDB_NEXT))
   8208 	{
   8209 		/*
   8210 		 * Create a configuration object from data fetched from NZD.
   8211 		 */
   8212 		result = data_to_cfg(view, &key, &data, &text, &zconfigobj);
   8213 		if (result != ISC_R_SUCCESS) {
   8214 			break;
   8215 		}
   8216 
   8217 		/*
   8218 		 * Extract zone configuration from configuration object.
   8219 		 */
   8220 		zlist = NULL;
   8221 		result = cfg_map_get(zconfigobj, "zone", &zlist);
   8222 		if (result != ISC_R_SUCCESS) {
   8223 			break;
   8224 		} else if (!cfg_obj_islist(zlist)) {
   8225 			result = ISC_R_FAILURE;
   8226 			break;
   8227 		}
   8228 		zconfig = cfg_listelt_value(cfg_list_first(zlist));
   8229 
   8230 		/*
   8231 		 * Invoke callback.
   8232 		 */
   8233 		result = callback(zconfig, config, vconfig, view, actx);
   8234 		if (result != ISC_R_SUCCESS) {
   8235 			break;
   8236 		}
   8237 
   8238 		/*
   8239 		 * Destroy the configuration object created in this iteration.
   8240 		 */
   8241 		cfg_obj_destroy(named_g_addparser, &zconfigobj);
   8242 	}
   8243 
   8244 	if (text != NULL) {
   8245 		isc_buffer_free(&text);
   8246 	}
   8247 	if (zconfigobj != NULL) {
   8248 		cfg_obj_destroy(named_g_addparser, &zconfigobj);
   8249 	}
   8250 	mdb_cursor_close(cursor);
   8251 
   8252 	return result;
   8253 }
   8254 
   8255 /*%
   8256  * Attempt to configure a zone found in NZD and return the result.
   8257  */
   8258 static isc_result_t
   8259 configure_newzone(const cfg_obj_t *zconfig, cfg_obj_t *config,
   8260 		  cfg_obj_t *vconfig, dns_view_t *view,
   8261 		  cfg_aclconfctx_t *actx) {
   8262 	return configure_zone(
   8263 		config, zconfig, vconfig, view, &named_g_server->viewlist,
   8264 		&named_g_server->kasplist, &named_g_server->keystorelist, actx,
   8265 		true, false, false, false);
   8266 }
   8267 
   8268 /*%
   8269  * Revert new view assignment for a zone found in NZD.
   8270  */
   8271 static isc_result_t
   8272 configure_newzone_revert(const cfg_obj_t *zconfig, cfg_obj_t *config,
   8273 			 cfg_obj_t *vconfig, dns_view_t *view,
   8274 			 cfg_aclconfctx_t *actx) {
   8275 	UNUSED(config);
   8276 	UNUSED(vconfig);
   8277 	UNUSED(actx);
   8278 
   8279 	configure_zone_setviewcommit(ISC_R_FAILURE, zconfig, view);
   8280 
   8281 	return ISC_R_SUCCESS;
   8282 }
   8283 
   8284 static isc_result_t
   8285 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
   8286 		   cfg_aclconfctx_t *actx) {
   8287 	isc_result_t result;
   8288 	MDB_txn *txn = NULL;
   8289 	MDB_dbi dbi;
   8290 
   8291 	if (view->new_zone_config == NULL) {
   8292 		return ISC_R_SUCCESS;
   8293 	}
   8294 
   8295 	LOCK(&view->new_zone_lock);
   8296 
   8297 	result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
   8298 	if (result != ISC_R_SUCCESS) {
   8299 		UNLOCK(&view->new_zone_lock);
   8300 		return ISC_R_SUCCESS;
   8301 	}
   8302 
   8303 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8304 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8305 		      "loading NZD configs from '%s' "
   8306 		      "for view '%s'",
   8307 		      view->new_zone_db, view->name);
   8308 
   8309 	result = for_all_newzone_cfgs(configure_newzone, config, vconfig, view,
   8310 				      actx, txn, dbi);
   8311 	if (result != ISC_R_SUCCESS) {
   8312 		/*
   8313 		 * An error was encountered while attempting to configure zones
   8314 		 * found in NZD.  As this error may have been caused by a
   8315 		 * configure_zone() failure, try restoring a sane configuration
   8316 		 * by reattaching all zones found in NZD to the old view.  If
   8317 		 * this also fails, too bad, there is nothing more we can do in
   8318 		 * terms of trying to make things right.
   8319 		 */
   8320 		(void)for_all_newzone_cfgs(configure_newzone_revert, config,
   8321 					   vconfig, view, actx, txn, dbi);
   8322 	}
   8323 
   8324 	(void)nzd_close(&txn, false);
   8325 
   8326 	UNLOCK(&view->new_zone_lock);
   8327 
   8328 	return result;
   8329 }
   8330 
   8331 static isc_result_t
   8332 get_newzone_config(dns_view_t *view, const char *zonename,
   8333 		   cfg_obj_t **zoneconfig) {
   8334 	isc_result_t result;
   8335 	int status;
   8336 	cfg_obj_t *zoneconf = NULL;
   8337 	isc_buffer_t *text = NULL;
   8338 	MDB_txn *txn = NULL;
   8339 	MDB_dbi dbi;
   8340 	MDB_val key, data;
   8341 	char zname[DNS_NAME_FORMATSIZE];
   8342 	dns_fixedname_t fname;
   8343 	dns_name_t *name;
   8344 	isc_buffer_t b;
   8345 
   8346 	INSIST(zoneconfig != NULL && *zoneconfig == NULL);
   8347 
   8348 	LOCK(&view->new_zone_lock);
   8349 
   8350 	CHECK(nzd_open(view, MDB_RDONLY, &txn, &dbi));
   8351 
   8352 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8353 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8354 		      "loading NZD config from '%s' "
   8355 		      "for zone '%s'",
   8356 		      view->new_zone_db, zonename);
   8357 
   8358 	/* Normalize zone name */
   8359 	isc_buffer_constinit(&b, zonename, strlen(zonename));
   8360 	isc_buffer_add(&b, strlen(zonename));
   8361 	name = dns_fixedname_initname(&fname);
   8362 	CHECK(dns_name_fromtext(name, &b, dns_rootname, DNS_NAME_DOWNCASE,
   8363 				NULL));
   8364 	dns_name_format(name, zname, sizeof(zname));
   8365 
   8366 	key.mv_data = zname;
   8367 	key.mv_size = strlen(zname);
   8368 
   8369 	status = mdb_get(txn, dbi, &key, &data);
   8370 	if (status != MDB_SUCCESS) {
   8371 		CHECK(ISC_R_FAILURE);
   8372 	}
   8373 
   8374 	CHECK(data_to_cfg(view, &key, &data, &text, &zoneconf));
   8375 
   8376 	*zoneconfig = zoneconf;
   8377 	zoneconf = NULL;
   8378 	result = ISC_R_SUCCESS;
   8379 
   8380 cleanup:
   8381 	(void)nzd_close(&txn, false);
   8382 
   8383 	UNLOCK(&view->new_zone_lock);
   8384 
   8385 	if (zoneconf != NULL) {
   8386 		cfg_obj_destroy(named_g_addparser, &zoneconf);
   8387 	}
   8388 	if (text != NULL) {
   8389 		isc_buffer_free(&text);
   8390 	}
   8391 
   8392 	return result;
   8393 }
   8394 
   8395 #endif /* HAVE_LMDB */
   8396 
   8397 static isc_result_t
   8398 load_configuration(const char *filename, named_server_t *server,
   8399 		   bool first_time) {
   8400 	cfg_obj_t *config = NULL, *bindkeys = NULL;
   8401 	cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL;
   8402 	const cfg_listelt_t *element;
   8403 	const cfg_obj_t *builtin_views;
   8404 	const cfg_obj_t *maps[3];
   8405 	const cfg_obj_t *obj;
   8406 	const cfg_obj_t *options;
   8407 	const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
   8408 	const cfg_obj_t *kasps;
   8409 	const cfg_obj_t *keystores;
   8410 	dns_kasp_t *kasp = NULL;
   8411 	dns_kasp_t *kasp_next = NULL;
   8412 	dns_kasp_t *default_kasp = NULL;
   8413 	dns_kasplist_t tmpkasplist, kasplist;
   8414 	unsigned int kaspopts = (ISCCFG_KASPCONF_CHECK_ALGORITHMS |
   8415 				 ISCCFG_KASPCONF_CHECK_KEYLIST |
   8416 				 ISCCFG_KASPCONF_LOG_ERRORS);
   8417 	dns_keystore_t *keystore = NULL;
   8418 	dns_keystore_t *keystore_next = NULL;
   8419 	dns_keystorelist_t tmpkeystorelist, keystorelist;
   8420 	const cfg_obj_t *views = NULL;
   8421 	dns_view_t *view_next = NULL;
   8422 	dns_viewlist_t tmpviewlist;
   8423 	dns_viewlist_t viewlist, builtin_viewlist;
   8424 	in_port_t listen_port, udpport_low, udpport_high;
   8425 	int i, backlog;
   8426 	isc_interval_t interval;
   8427 	isc_logconfig_t *logc = NULL;
   8428 	isc_portset_t *v4portset = NULL;
   8429 	isc_portset_t *v6portset = NULL;
   8430 	isc_result_t result;
   8431 	uint32_t heartbeat_interval;
   8432 	uint32_t interface_interval;
   8433 	uint32_t udpsize;
   8434 	uint32_t transfer_message_size;
   8435 	uint32_t recv_tcp_buffer_size;
   8436 	uint32_t send_tcp_buffer_size;
   8437 	uint32_t recv_udp_buffer_size;
   8438 	uint32_t send_udp_buffer_size;
   8439 	named_cache_t *nsc = NULL;
   8440 	named_cachelist_t cachelist, tmpcachelist;
   8441 	ns_altsecret_t *altsecret;
   8442 	ns_altsecretlist_t altsecrets, tmpaltsecrets;
   8443 	uint32_t softquota = 0;
   8444 	uint32_t max;
   8445 	uint64_t initial, idle, keepalive, advertised;
   8446 	bool loadbalancesockets;
   8447 	bool exclusive = true;
   8448 	dns_aclenv_t *env =
   8449 		ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
   8450 
   8451 	/*
   8452 	 * Require the reconfiguration to happen always on the main loop
   8453 	 */
   8454 	REQUIRE(isc_loop() == named_g_mainloop);
   8455 
   8456 	ISC_LIST_INIT(kasplist);
   8457 	ISC_LIST_INIT(keystorelist);
   8458 	ISC_LIST_INIT(viewlist);
   8459 	ISC_LIST_INIT(builtin_viewlist);
   8460 	ISC_LIST_INIT(cachelist);
   8461 	ISC_LIST_INIT(altsecrets);
   8462 
   8463 	/* Ensure exclusive access to configuration data. */
   8464 	isc_loopmgr_pause(named_g_loopmgr);
   8465 
   8466 	/* Create the ACL configuration context */
   8467 	if (named_g_aclconfctx != NULL) {
   8468 		cfg_aclconfctx_detach(&named_g_aclconfctx);
   8469 	}
   8470 	result = cfg_aclconfctx_create(named_g_mctx, &named_g_aclconfctx);
   8471 	if (result != ISC_R_SUCCESS) {
   8472 		goto cleanup_exclusive;
   8473 	}
   8474 
   8475 	/*
   8476 	 * Shut down all dyndb instances.
   8477 	 */
   8478 	dns_dyndb_cleanup(false);
   8479 
   8480 	/*
   8481 	 * Parse the global default pseudo-config file.
   8482 	 */
   8483 	if (first_time) {
   8484 		result = named_config_parsedefaults(named_g_parser,
   8485 						    &named_g_config);
   8486 		if (result != ISC_R_SUCCESS) {
   8487 			named_main_earlyfatal("unable to load "
   8488 					      "internal defaults: %s",
   8489 					      isc_result_totext(result));
   8490 		}
   8491 		RUNTIME_CHECK(cfg_map_get(named_g_config, "options",
   8492 					  &named_g_defaults) == ISC_R_SUCCESS);
   8493 	}
   8494 
   8495 	/*
   8496 	 * Log the current working directory.
   8497 	 */
   8498 	if (first_time) {
   8499 		char cwd[PATH_MAX];
   8500 		if (getcwd(cwd, sizeof(cwd)) == cwd) {
   8501 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8502 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8503 				      "the initial working directory is '%s'",
   8504 				      cwd);
   8505 		}
   8506 	}
   8507 
   8508 	/*
   8509 	 * Parse the configuration file using the new config code.
   8510 	 */
   8511 	config = NULL;
   8512 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8513 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8514 		      "loading configuration from '%s'", filename);
   8515 	result = cfg_parser_create(named_g_mctx, named_g_lctx, &conf_parser);
   8516 	if (result != ISC_R_SUCCESS) {
   8517 		goto cleanup_exclusive;
   8518 	}
   8519 
   8520 	cfg_parser_setcallback(conf_parser, directory_callback, NULL);
   8521 	result = cfg_parse_file(conf_parser, filename, &cfg_type_namedconf,
   8522 				&config);
   8523 	if (result != ISC_R_SUCCESS) {
   8524 		goto cleanup_conf_parser;
   8525 	}
   8526 
   8527 	/*
   8528 	 * Check the validity of the configuration.
   8529 	 *
   8530 	 * (Ignore plugin parameters for now; they will be
   8531 	 * checked later when the modules are actually loaded and
   8532 	 * registered.)
   8533 	 */
   8534 	result = isccfg_check_namedconf(config, BIND_CHECK_ALGORITHMS,
   8535 					named_g_lctx, named_g_mctx);
   8536 	if (result != ISC_R_SUCCESS) {
   8537 		goto cleanup_config;
   8538 	}
   8539 
   8540 	/* Let's recreate the TLS context cache */
   8541 	if (server->tlsctx_server_cache != NULL) {
   8542 		isc_tlsctx_cache_detach(&server->tlsctx_server_cache);
   8543 	}
   8544 
   8545 	isc_tlsctx_cache_create(named_g_mctx, &server->tlsctx_server_cache);
   8546 
   8547 	if (server->tlsctx_client_cache != NULL) {
   8548 		isc_tlsctx_cache_detach(&server->tlsctx_client_cache);
   8549 	}
   8550 
   8551 	isc_tlsctx_cache_create(named_g_mctx, &server->tlsctx_client_cache);
   8552 
   8553 	dns_zonemgr_set_tlsctx_cache(server->zonemgr,
   8554 				     server->tlsctx_client_cache);
   8555 
   8556 	/*
   8557 	 * Fill in the maps array, used for resolving defaults.
   8558 	 */
   8559 	i = 0;
   8560 	options = NULL;
   8561 	result = cfg_map_get(config, "options", &options);
   8562 	if (result == ISC_R_SUCCESS) {
   8563 		maps[i++] = options;
   8564 	}
   8565 	maps[i++] = named_g_defaults;
   8566 	maps[i] = NULL;
   8567 
   8568 #if HAVE_LIBNGHTTP2
   8569 	obj = NULL;
   8570 	result = named_config_get(maps, "http-port", &obj);
   8571 	INSIST(result == ISC_R_SUCCESS);
   8572 	named_g_httpport = (in_port_t)cfg_obj_asuint32(obj);
   8573 
   8574 	obj = NULL;
   8575 	result = named_config_get(maps, "https-port", &obj);
   8576 	INSIST(result == ISC_R_SUCCESS);
   8577 	named_g_httpsport = (in_port_t)cfg_obj_asuint32(obj);
   8578 
   8579 	obj = NULL;
   8580 	result = named_config_get(maps, "http-listener-clients", &obj);
   8581 	INSIST(result == ISC_R_SUCCESS);
   8582 	named_g_http_listener_clients = cfg_obj_asuint32(obj);
   8583 
   8584 	obj = NULL;
   8585 	result = named_config_get(maps, "http-streams-per-connection", &obj);
   8586 	INSIST(result == ISC_R_SUCCESS);
   8587 	named_g_http_streams_per_conn = cfg_obj_asuint32(obj);
   8588 #endif
   8589 
   8590 	/*
   8591 	 * If "dnssec-validation auto" is turned on, the root key
   8592 	 * will be used as a default trust anchor. The root key
   8593 	 * is built in, but if bindkeys-file is set, then it will
   8594 	 * be overridden with the key in that file.
   8595 	 */
   8596 	obj = NULL;
   8597 	(void)named_config_get(maps, "bindkeys-file", &obj);
   8598 	if (obj != NULL) {
   8599 		setstring(server, &server->bindkeysfile, cfg_obj_asstring(obj));
   8600 		INSIST(server->bindkeysfile != NULL);
   8601 		if (access(server->bindkeysfile, R_OK) != 0) {
   8602 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8603 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8604 				      "unable to open '%s'; using built-in "
   8605 				      "keys instead",
   8606 				      server->bindkeysfile);
   8607 		} else {
   8608 			result = cfg_parser_create(named_g_mctx, named_g_lctx,
   8609 						   &bindkeys_parser);
   8610 			if (result != ISC_R_SUCCESS) {
   8611 				goto cleanup_config;
   8612 			}
   8613 
   8614 			result = cfg_parse_file(bindkeys_parser,
   8615 						server->bindkeysfile,
   8616 						&cfg_type_bindkeys, &bindkeys);
   8617 			if (result != ISC_R_SUCCESS) {
   8618 				isc_log_write(
   8619 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8620 					NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8621 					"unable to parse '%s' "
   8622 					"error '%s'; using "
   8623 					"built-in keys instead",
   8624 					server->bindkeysfile,
   8625 					isc_result_totext(result));
   8626 			}
   8627 		}
   8628 	} else {
   8629 		setstring(server, &server->bindkeysfile, NULL);
   8630 	}
   8631 
   8632 #if defined(HAVE_GEOIP2)
   8633 	/*
   8634 	 * Release any previously opened GeoIP2 databases.
   8635 	 */
   8636 	named_geoip_unload();
   8637 
   8638 	/*
   8639 	 * Initialize GeoIP databases from the configured location.
   8640 	 * This should happen before configuring any ACLs, so that we
   8641 	 * know what databases are available and can reject any GeoIP
   8642 	 * ACLs that can't work.
   8643 	 */
   8644 	obj = NULL;
   8645 	result = named_config_get(maps, "geoip-directory", &obj);
   8646 	INSIST(result == ISC_R_SUCCESS);
   8647 	if (cfg_obj_isstring(obj)) {
   8648 		char *dir = UNCONST(cfg_obj_asstring(obj));
   8649 		named_geoip_load(dir);
   8650 	}
   8651 	named_g_aclconfctx->geoip = named_g_geoip;
   8652 #endif /* HAVE_GEOIP2 */
   8653 
   8654 	/*
   8655 	 * Configure various server options.
   8656 	 */
   8657 	configure_server_quota(maps, "transfers-out",
   8658 			       &server->sctx->xfroutquota);
   8659 	configure_server_quota(maps, "tcp-clients", &server->sctx->tcpquota);
   8660 	configure_server_quota(maps, "recursive-clients",
   8661 			       &server->sctx->recursionquota);
   8662 	configure_server_quota(maps, "update-quota", &server->sctx->updquota);
   8663 	configure_server_quota(maps, "sig0checks-quota",
   8664 			       &server->sctx->sig0checksquota);
   8665 
   8666 	max = isc_quota_getmax(&server->sctx->recursionquota);
   8667 	if (max > 1000) {
   8668 		unsigned int margin = ISC_MAX(100, named_g_cpus + 1);
   8669 		if (margin + 100 > max) {
   8670 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8671 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   8672 				      "'recursive-clients %d' too low when "
   8673 				      "running with %d worker threads",
   8674 				      max, named_g_cpus);
   8675 			result = ISC_R_RANGE;
   8676 
   8677 			goto cleanup_bindkeys_parser;
   8678 		}
   8679 		softquota = max - margin;
   8680 	} else {
   8681 		softquota = (max * 90) / 100;
   8682 	}
   8683 	isc_quota_soft(&server->sctx->recursionquota, softquota);
   8684 
   8685 	obj = NULL;
   8686 	result = named_config_get(maps, "sig0checks-quota-exempt", &obj);
   8687 	if (result == ISC_R_SUCCESS) {
   8688 		result = cfg_acl_fromconfig(
   8689 			obj, config, named_g_lctx, named_g_aclconfctx,
   8690 			named_g_mctx, 0, &server->sctx->sig0checksquota_exempt);
   8691 		INSIST(result == ISC_R_SUCCESS);
   8692 	}
   8693 
   8694 	/*
   8695 	 * Set "blackhole". Only legal at options level; there is
   8696 	 * no default.
   8697 	 */
   8698 	result = configure_view_acl(NULL, config, NULL, "blackhole", NULL,
   8699 				    named_g_aclconfctx, named_g_mctx,
   8700 				    &server->sctx->blackholeacl);
   8701 	if (result != ISC_R_SUCCESS) {
   8702 		goto cleanup_bindkeys_parser;
   8703 	}
   8704 
   8705 	if (server->sctx->blackholeacl != NULL) {
   8706 		dns_dispatchmgr_setblackhole(named_g_dispatchmgr,
   8707 					     server->sctx->blackholeacl);
   8708 	}
   8709 
   8710 	obj = NULL;
   8711 	result = named_config_get(maps, "match-mapped-addresses", &obj);
   8712 	INSIST(result == ISC_R_SUCCESS);
   8713 	env->match_mapped = cfg_obj_asboolean(obj);
   8714 
   8715 	/*
   8716 	 * Configure the network manager
   8717 	 */
   8718 	obj = NULL;
   8719 	result = named_config_get(maps, "tcp-initial-timeout", &obj);
   8720 	INSIST(result == ISC_R_SUCCESS);
   8721 	initial = cfg_obj_asuint32(obj) * 100;
   8722 	if (initial > MAX_INITIAL_TIMEOUT) {
   8723 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   8724 			    "tcp-initial-timeout value is out of range: "
   8725 			    "lowering to %" PRIu32,
   8726 			    MAX_INITIAL_TIMEOUT / 100);
   8727 		initial = MAX_INITIAL_TIMEOUT;
   8728 	} else if (initial < MIN_INITIAL_TIMEOUT) {
   8729 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   8730 			    "tcp-initial-timeout value is out of range: "
   8731 			    "raising to %" PRIu32,
   8732 			    MIN_INITIAL_TIMEOUT / 100);
   8733 		initial = MIN_INITIAL_TIMEOUT;
   8734 	}
   8735 
   8736 	obj = NULL;
   8737 	result = named_config_get(maps, "tcp-idle-timeout", &obj);
   8738 	INSIST(result == ISC_R_SUCCESS);
   8739 	idle = cfg_obj_asuint32(obj) * 100;
   8740 	if (idle > MAX_IDLE_TIMEOUT) {
   8741 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   8742 			    "tcp-idle-timeout value is out of range: "
   8743 			    "lowering to %" PRIu32,
   8744 			    MAX_IDLE_TIMEOUT / 100);
   8745 		idle = MAX_IDLE_TIMEOUT;
   8746 	} else if (idle < MIN_IDLE_TIMEOUT) {
   8747 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   8748 			    "tcp-idle-timeout value is out of range: "
   8749 			    "raising to %" PRIu32,
   8750 			    MIN_IDLE_TIMEOUT / 100);
   8751 		idle = MIN_IDLE_TIMEOUT;
   8752 	}
   8753 
   8754 	obj = NULL;
   8755 	result = named_config_get(maps, "tcp-keepalive-timeout", &obj);
   8756 	INSIST(result == ISC_R_SUCCESS);
   8757 	keepalive = cfg_obj_asuint32(obj) * 100;
   8758 	if (keepalive > MAX_KEEPALIVE_TIMEOUT) {
   8759 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   8760 			    "tcp-keepalive-timeout value is out of range: "
   8761 			    "lowering to %" PRIu32,
   8762 			    MAX_KEEPALIVE_TIMEOUT / 100);
   8763 		keepalive = MAX_KEEPALIVE_TIMEOUT;
   8764 	} else if (keepalive < MIN_KEEPALIVE_TIMEOUT) {
   8765 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   8766 			    "tcp-keepalive-timeout value is out of range: "
   8767 			    "raising to %" PRIu32,
   8768 			    MIN_KEEPALIVE_TIMEOUT / 100);
   8769 		keepalive = MIN_KEEPALIVE_TIMEOUT;
   8770 	}
   8771 
   8772 	obj = NULL;
   8773 	result = named_config_get(maps, "tcp-advertised-timeout", &obj);
   8774 	INSIST(result == ISC_R_SUCCESS);
   8775 	advertised = cfg_obj_asuint32(obj) * 100;
   8776 	if (advertised > MAX_ADVERTISED_TIMEOUT) {
   8777 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   8778 			    "tcp-advertized-timeout value is out of range: "
   8779 			    "lowering to %" PRIu32,
   8780 			    MAX_ADVERTISED_TIMEOUT / 100);
   8781 		advertised = MAX_ADVERTISED_TIMEOUT;
   8782 	}
   8783 
   8784 	isc_nm_settimeouts(named_g_netmgr, initial, idle, keepalive,
   8785 			   advertised);
   8786 
   8787 #define CAP_IF_NOT_ZERO(v, min, max) \
   8788 	if (v > 0 && v < min) {      \
   8789 		v = min;             \
   8790 	} else if (v > max) {        \
   8791 		v = max;             \
   8792 	}
   8793 
   8794 	/* Set the kernel send and receive buffer sizes */
   8795 	obj = NULL;
   8796 	result = named_config_get(maps, "tcp-receive-buffer", &obj);
   8797 	INSIST(result == ISC_R_SUCCESS);
   8798 	recv_tcp_buffer_size = cfg_obj_asuint32(obj);
   8799 	CAP_IF_NOT_ZERO(recv_tcp_buffer_size, 4096, INT32_MAX);
   8800 
   8801 	obj = NULL;
   8802 	result = named_config_get(maps, "tcp-send-buffer", &obj);
   8803 	INSIST(result == ISC_R_SUCCESS);
   8804 	send_tcp_buffer_size = cfg_obj_asuint32(obj);
   8805 	CAP_IF_NOT_ZERO(send_tcp_buffer_size, 4096, INT32_MAX);
   8806 
   8807 	obj = NULL;
   8808 	result = named_config_get(maps, "udp-receive-buffer", &obj);
   8809 	INSIST(result == ISC_R_SUCCESS);
   8810 	recv_udp_buffer_size = cfg_obj_asuint32(obj);
   8811 	CAP_IF_NOT_ZERO(recv_udp_buffer_size, 4096, INT32_MAX);
   8812 
   8813 	obj = NULL;
   8814 	result = named_config_get(maps, "udp-send-buffer", &obj);
   8815 	INSIST(result == ISC_R_SUCCESS);
   8816 	send_udp_buffer_size = cfg_obj_asuint32(obj);
   8817 	CAP_IF_NOT_ZERO(send_udp_buffer_size, 4096, INT32_MAX);
   8818 
   8819 	isc_nm_setnetbuffers(named_g_netmgr, recv_tcp_buffer_size,
   8820 			     send_tcp_buffer_size, recv_udp_buffer_size,
   8821 			     send_udp_buffer_size);
   8822 
   8823 #undef CAP_IF_NOT_ZERO
   8824 
   8825 	/*
   8826 	 * Configure sets of UDP query source ports.
   8827 	 */
   8828 	result = isc_portset_create(named_g_mctx, &v4portset);
   8829 	if (result != ISC_R_SUCCESS) {
   8830 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8831 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   8832 			      "creating UDP/IPv4 port set: %s",
   8833 			      isc_result_totext(result));
   8834 		goto cleanup_bindkeys_parser;
   8835 	}
   8836 	result = isc_portset_create(named_g_mctx, &v6portset);
   8837 	if (result != ISC_R_SUCCESS) {
   8838 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8839 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   8840 			      "creating UDP/IPv6 port set: %s",
   8841 			      isc_result_totext(result));
   8842 		goto cleanup_v4portset;
   8843 	}
   8844 
   8845 	usev4ports = NULL;
   8846 	usev6ports = NULL;
   8847 	avoidv4ports = NULL;
   8848 	avoidv6ports = NULL;
   8849 
   8850 	(void)named_config_get(maps, "use-v4-udp-ports", &usev4ports);
   8851 	if (usev4ports != NULL) {
   8852 		portset_fromconf(v4portset, usev4ports, true);
   8853 	} else {
   8854 		result = isc_net_getudpportrange(AF_INET, &udpport_low,
   8855 						 &udpport_high);
   8856 		if (result != ISC_R_SUCCESS) {
   8857 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8858 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   8859 				      "get the default UDP/IPv4 port range: %s",
   8860 				      isc_result_totext(result));
   8861 			goto cleanup_v6portset;
   8862 		}
   8863 
   8864 		if (udpport_low == udpport_high) {
   8865 			isc_portset_add(v4portset, udpport_low);
   8866 		} else {
   8867 			isc_portset_addrange(v4portset, udpport_low,
   8868 					     udpport_high);
   8869 		}
   8870 		if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE4)) {
   8871 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8872 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8873 				      "using default UDP/IPv4 port range: "
   8874 				      "[%d, %d]",
   8875 				      udpport_low, udpport_high);
   8876 		}
   8877 	}
   8878 	(void)named_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
   8879 	if (avoidv4ports != NULL) {
   8880 		portset_fromconf(v4portset, avoidv4ports, false);
   8881 	}
   8882 
   8883 	(void)named_config_get(maps, "use-v6-udp-ports", &usev6ports);
   8884 	if (usev6ports != NULL) {
   8885 		portset_fromconf(v6portset, usev6ports, true);
   8886 	} else {
   8887 		result = isc_net_getudpportrange(AF_INET6, &udpport_low,
   8888 						 &udpport_high);
   8889 		if (result != ISC_R_SUCCESS) {
   8890 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8891 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   8892 				      "get the default UDP/IPv6 port range: %s",
   8893 				      isc_result_totext(result));
   8894 			goto cleanup_v6portset;
   8895 		}
   8896 		if (udpport_low == udpport_high) {
   8897 			isc_portset_add(v6portset, udpport_low);
   8898 		} else {
   8899 			isc_portset_addrange(v6portset, udpport_low,
   8900 					     udpport_high);
   8901 		}
   8902 		if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE6)) {
   8903 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   8904 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   8905 				      "using default UDP/IPv6 port range: "
   8906 				      "[%d, %d]",
   8907 				      udpport_low, udpport_high);
   8908 		}
   8909 	}
   8910 	(void)named_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
   8911 	if (avoidv6ports != NULL) {
   8912 		portset_fromconf(v6portset, avoidv6ports, false);
   8913 	}
   8914 
   8915 	dns_dispatchmgr_setavailports(named_g_dispatchmgr, v4portset,
   8916 				      v6portset);
   8917 
   8918 	/*
   8919 	 * Set the EDNS UDP size when we don't match a view.
   8920 	 */
   8921 	obj = NULL;
   8922 	result = named_config_get(maps, "edns-udp-size", &obj);
   8923 	INSIST(result == ISC_R_SUCCESS);
   8924 	udpsize = cfg_obj_asuint32(obj);
   8925 	if (udpsize < 512) {
   8926 		udpsize = 512;
   8927 	}
   8928 	if (udpsize > 4096) {
   8929 		udpsize = 4096;
   8930 	}
   8931 	server->sctx->udpsize = (uint16_t)udpsize;
   8932 
   8933 	/* Set the transfer message size for TCP */
   8934 	obj = NULL;
   8935 	result = named_config_get(maps, "transfer-message-size", &obj);
   8936 	INSIST(result == ISC_R_SUCCESS);
   8937 	transfer_message_size = cfg_obj_asuint32(obj);
   8938 	if (transfer_message_size < 512) {
   8939 		transfer_message_size = 512;
   8940 	} else if (transfer_message_size > 65535) {
   8941 		transfer_message_size = 65535;
   8942 	}
   8943 	server->sctx->transfer_tcp_message_size =
   8944 		(uint16_t)transfer_message_size;
   8945 
   8946 	/*
   8947 	 * Configure the zone manager.
   8948 	 */
   8949 	obj = NULL;
   8950 	result = named_config_get(maps, "transfers-in", &obj);
   8951 	INSIST(result == ISC_R_SUCCESS);
   8952 	dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
   8953 
   8954 	obj = NULL;
   8955 	result = named_config_get(maps, "transfers-per-ns", &obj);
   8956 	INSIST(result == ISC_R_SUCCESS);
   8957 	dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
   8958 
   8959 	obj = NULL;
   8960 	result = named_config_get(maps, "notify-rate", &obj);
   8961 	INSIST(result == ISC_R_SUCCESS);
   8962 	dns_zonemgr_setnotifyrate(server->zonemgr, cfg_obj_asuint32(obj));
   8963 
   8964 	obj = NULL;
   8965 	result = named_config_get(maps, "startup-notify-rate", &obj);
   8966 	INSIST(result == ISC_R_SUCCESS);
   8967 	dns_zonemgr_setstartupnotifyrate(server->zonemgr,
   8968 					 cfg_obj_asuint32(obj));
   8969 
   8970 	obj = NULL;
   8971 	result = named_config_get(maps, "serial-query-rate", &obj);
   8972 	INSIST(result == ISC_R_SUCCESS);
   8973 	dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
   8974 
   8975 	/*
   8976 	 * Determine which port to use for listening for incoming connections.
   8977 	 */
   8978 	if (named_g_port != 0) {
   8979 		listen_port = named_g_port;
   8980 	} else {
   8981 		result = named_config_getport(config, "port", &listen_port);
   8982 		if (result != ISC_R_SUCCESS) {
   8983 			goto cleanup_v6portset;
   8984 		}
   8985 	}
   8986 
   8987 	/*
   8988 	 * Find the listen queue depth.
   8989 	 */
   8990 	obj = NULL;
   8991 	result = named_config_get(maps, "tcp-listen-queue", &obj);
   8992 	INSIST(result == ISC_R_SUCCESS);
   8993 	backlog = cfg_obj_asuint32(obj);
   8994 	if ((backlog > 0) && (backlog < 10)) {
   8995 		backlog = 10;
   8996 	}
   8997 	ns_interfacemgr_setbacklog(server->interfacemgr, backlog);
   8998 
   8999 	obj = NULL;
   9000 	result = named_config_get(maps, "reuseport", &obj);
   9001 	INSIST(result == ISC_R_SUCCESS);
   9002 	loadbalancesockets = cfg_obj_asboolean(obj);
   9003 #if HAVE_SO_REUSEPORT_LB
   9004 	if (first_time) {
   9005 		isc_nm_setloadbalancesockets(named_g_netmgr,
   9006 					     cfg_obj_asboolean(obj));
   9007 	} else if (loadbalancesockets !=
   9008 		   isc_nm_getloadbalancesockets(named_g_netmgr))
   9009 	{
   9010 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   9011 			    "changing reuseport value requires server restart");
   9012 	}
   9013 #else
   9014 	if (loadbalancesockets) {
   9015 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
   9016 			    "reuseport has no effect on this system");
   9017 	}
   9018 #endif
   9019 
   9020 	/*
   9021 	 * Configure the interface manager according to the "listen-on"
   9022 	 * statement.
   9023 	 */
   9024 	{
   9025 		const cfg_obj_t *clistenon = NULL;
   9026 		ns_listenlist_t *listenon = NULL;
   9027 
   9028 		/*
   9029 		 * Even though listen-on is present in the default
   9030 		 * configuration, this way is easier.
   9031 		 */
   9032 		if (options != NULL) {
   9033 			(void)cfg_map_get(options, "listen-on", &clistenon);
   9034 		}
   9035 		if (clistenon != NULL) {
   9036 			result = listenlist_fromconfig(
   9037 				clistenon, config, named_g_aclconfctx,
   9038 				named_g_mctx, AF_INET,
   9039 				server->tlsctx_server_cache, &listenon);
   9040 		} else {
   9041 			/*
   9042 			 * Not specified, use default.
   9043 			 */
   9044 			result = ns_listenlist_default(named_g_mctx,
   9045 						       listen_port, true,
   9046 						       AF_INET, &listenon);
   9047 		}
   9048 		if (result != ISC_R_SUCCESS) {
   9049 			goto cleanup_v6portset;
   9050 		}
   9051 
   9052 		if (listenon != NULL) {
   9053 			ns_interfacemgr_setlistenon4(server->interfacemgr,
   9054 						     listenon);
   9055 			ns_listenlist_detach(&listenon);
   9056 		}
   9057 	}
   9058 
   9059 	/*
   9060 	 * Ditto for IPv6.
   9061 	 */
   9062 	{
   9063 		const cfg_obj_t *clistenon = NULL;
   9064 		ns_listenlist_t *listenon = NULL;
   9065 
   9066 		if (options != NULL) {
   9067 			(void)cfg_map_get(options, "listen-on-v6", &clistenon);
   9068 		}
   9069 		if (clistenon != NULL) {
   9070 			result = listenlist_fromconfig(
   9071 				clistenon, config, named_g_aclconfctx,
   9072 				named_g_mctx, AF_INET6,
   9073 				server->tlsctx_server_cache, &listenon);
   9074 		} else {
   9075 			/*
   9076 			 * Not specified, use default.
   9077 			 */
   9078 			result = ns_listenlist_default(named_g_mctx,
   9079 						       listen_port, true,
   9080 						       AF_INET6, &listenon);
   9081 		}
   9082 		if (result != ISC_R_SUCCESS) {
   9083 			goto cleanup_v6portset;
   9084 		}
   9085 		if (listenon != NULL) {
   9086 			ns_interfacemgr_setlistenon6(server->interfacemgr,
   9087 						     listenon);
   9088 			ns_listenlist_detach(&listenon);
   9089 		}
   9090 	}
   9091 
   9092 	if (first_time) {
   9093 		/*
   9094 		 * Rescan the interface list to pick up changes in the
   9095 		 * listen-on option. This requires the loopmgr to be
   9096 		 * temporarily resumed.
   9097 		 */
   9098 		isc_loopmgr_resume(named_g_loopmgr);
   9099 		result = ns_interfacemgr_scan(server->interfacemgr, true, true);
   9100 		isc_loopmgr_pause(named_g_loopmgr);
   9101 
   9102 		/*
   9103 		 * Check that named is able to TCP listen on at least one
   9104 		 * interface. Otherwise, another named process could be running
   9105 		 * and we should fail.
   9106 		 */
   9107 		if (result == ISC_R_ADDRINUSE) {
   9108 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9109 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9110 				      "unable to listen on any configured "
   9111 				      "interfaces");
   9112 			result = ISC_R_FAILURE;
   9113 			goto cleanup_v6portset;
   9114 		}
   9115 	}
   9116 
   9117 	/*
   9118 	 * Arrange for further interface scanning to occur periodically
   9119 	 * as specified by the "interface-interval" option.
   9120 	 */
   9121 	obj = NULL;
   9122 	result = named_config_get(maps, "interface-interval", &obj);
   9123 	INSIST(result == ISC_R_SUCCESS);
   9124 	interface_interval = cfg_obj_asduration(obj);
   9125 	server->interface_interval = interface_interval;
   9126 
   9127 	/*
   9128 	 * Enable automatic interface scans.
   9129 	 */
   9130 	obj = NULL;
   9131 	result = named_config_get(maps, "automatic-interface-scan", &obj);
   9132 	INSIST(result == ISC_R_SUCCESS);
   9133 	server->sctx->interface_auto = cfg_obj_asboolean(obj);
   9134 
   9135 	if (server->sctx->interface_auto) {
   9136 		if (ns_interfacemgr_dynamic_updates_are_reliable() &&
   9137 		    server->interface_interval != 0)
   9138 		{
   9139 			/*
   9140 			 * In some cases the user might expect a certain
   9141 			 * behaviour from the rescan timer, let's try to deduce
   9142 			 * that from the configuration options.
   9143 			 */
   9144 			isc_log_write(
   9145 				named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9146 				NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   9147 				"Disabling periodic interface re-scans timer");
   9148 			server->interface_interval = 0;
   9149 		}
   9150 
   9151 		ns_interfacemgr_routeconnect(server->interfacemgr);
   9152 	} else {
   9153 		ns_interfacemgr_routedisconnect(server->interfacemgr);
   9154 	}
   9155 
   9156 	if (server->interface_interval == 0) {
   9157 		isc_timer_stop(server->interface_timer);
   9158 	} else {
   9159 		isc_interval_set(&interval, interface_interval, 0);
   9160 		isc_timer_start(server->interface_timer, isc_timertype_ticker,
   9161 				&interval);
   9162 	}
   9163 
   9164 	/*
   9165 	 * Configure the dialup heartbeat timer.
   9166 	 */
   9167 	obj = NULL;
   9168 	result = named_config_get(maps, "heartbeat-interval", &obj);
   9169 	INSIST(result == ISC_R_SUCCESS);
   9170 	heartbeat_interval = cfg_obj_asuint32(obj) * 60;
   9171 	if (heartbeat_interval == 0) {
   9172 		isc_timer_stop(server->heartbeat_timer);
   9173 	} else if (server->heartbeat_interval != heartbeat_interval) {
   9174 		isc_interval_set(&interval, heartbeat_interval, 0);
   9175 		isc_timer_start(server->heartbeat_timer, isc_timertype_ticker,
   9176 				&interval);
   9177 	}
   9178 	server->heartbeat_interval = heartbeat_interval;
   9179 
   9180 	isc_interval_set(&interval, 1200, 0);
   9181 	isc_timer_start(server->pps_timer, isc_timertype_ticker, &interval);
   9182 
   9183 	isc_interval_set(&interval, named_g_tat_interval, 0);
   9184 	isc_timer_start(server->tat_timer, isc_timertype_ticker, &interval);
   9185 
   9186 	/*
   9187 	 * Write the PID file.
   9188 	 */
   9189 	obj = NULL;
   9190 	if (named_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) {
   9191 		if (cfg_obj_isvoid(obj)) {
   9192 			named_os_writepidfile(NULL, first_time);
   9193 		} else {
   9194 			named_os_writepidfile(cfg_obj_asstring(obj),
   9195 					      first_time);
   9196 		}
   9197 	} else {
   9198 		named_os_writepidfile(named_g_defaultpidfile, first_time);
   9199 	}
   9200 
   9201 	/*
   9202 	 * Configure the server-wide session key.  This must be done before
   9203 	 * configure views because zone configuration may need to know
   9204 	 * session-keyname.
   9205 	 *
   9206 	 * Failure of session key generation isn't fatal at this time; if it
   9207 	 * turns out that a session key is really needed but doesn't exist,
   9208 	 * we'll treat it as a fatal error then.
   9209 	 */
   9210 	(void)configure_session_key(maps, server, named_g_mctx, first_time);
   9211 
   9212 	/*
   9213 	 * Create the built-in key store ("key-directory").
   9214 	 */
   9215 	result = cfg_keystore_fromconfig(NULL, named_g_mctx, named_g_lctx,
   9216 					 named_g_engine, &keystorelist, NULL);
   9217 	if (result != ISC_R_SUCCESS) {
   9218 		goto cleanup_keystorelist;
   9219 	}
   9220 
   9221 	/*
   9222 	 * Create the DNSSEC key stores.
   9223 	 */
   9224 	keystores = NULL;
   9225 	(void)cfg_map_get(config, "key-store", &keystores);
   9226 	for (element = cfg_list_first(keystores); element != NULL;
   9227 	     element = cfg_list_next(element))
   9228 	{
   9229 		cfg_obj_t *kconfig = cfg_listelt_value(element);
   9230 		keystore = NULL;
   9231 		result = cfg_keystore_fromconfig(kconfig, named_g_mctx,
   9232 						 named_g_lctx, named_g_engine,
   9233 						 &keystorelist, NULL);
   9234 		if (result != ISC_R_SUCCESS) {
   9235 			goto cleanup_keystorelist;
   9236 		}
   9237 	}
   9238 
   9239 	/*
   9240 	 * Create the built-in kasp policies ("default", "insecure").
   9241 	 */
   9242 	kasps = NULL;
   9243 	(void)cfg_map_get(named_g_config, "dnssec-policy", &kasps);
   9244 	for (element = cfg_list_first(kasps); element != NULL;
   9245 	     element = cfg_list_next(element))
   9246 	{
   9247 		cfg_obj_t *kconfig = cfg_listelt_value(element);
   9248 
   9249 		kasp = NULL;
   9250 		result = cfg_kasp_fromconfig(kconfig, default_kasp, kaspopts,
   9251 					     named_g_mctx, named_g_lctx,
   9252 					     &keystorelist, &kasplist, &kasp);
   9253 		if (result != ISC_R_SUCCESS) {
   9254 			goto cleanup_kasplist;
   9255 		}
   9256 		INSIST(kasp != NULL);
   9257 		dns_kasp_freeze(kasp);
   9258 
   9259 		/* Insist that the first built-in policy is the default one. */
   9260 		if (default_kasp == NULL) {
   9261 			INSIST(strcmp(dns_kasp_getname(kasp), "default") == 0);
   9262 			dns_kasp_attach(kasp, &default_kasp);
   9263 		}
   9264 
   9265 		dns_kasp_detach(&kasp);
   9266 	}
   9267 	INSIST(default_kasp != NULL);
   9268 
   9269 	/*
   9270 	 * Create the DNSSEC key and signing policies (KASP).
   9271 	 */
   9272 	kasps = NULL;
   9273 	(void)cfg_map_get(config, "dnssec-policy", &kasps);
   9274 	for (element = cfg_list_first(kasps); element != NULL;
   9275 	     element = cfg_list_next(element))
   9276 	{
   9277 		cfg_obj_t *kconfig = cfg_listelt_value(element);
   9278 		kasp = NULL;
   9279 		result = cfg_kasp_fromconfig(kconfig, default_kasp, kaspopts,
   9280 					     named_g_mctx, named_g_lctx,
   9281 					     &keystorelist, &kasplist, &kasp);
   9282 		if (result != ISC_R_SUCCESS) {
   9283 			goto cleanup_kasplist;
   9284 		}
   9285 		INSIST(kasp != NULL);
   9286 		dns_kasp_freeze(kasp);
   9287 		dns_kasp_detach(&kasp);
   9288 	}
   9289 	dns_kasp_detach(&default_kasp);
   9290 
   9291 	/*
   9292 	 * Save keystore list and kasp list.
   9293 	 */
   9294 	tmpkeystorelist = server->keystorelist;
   9295 	server->keystorelist = keystorelist;
   9296 	keystorelist = tmpkeystorelist;
   9297 
   9298 	tmpkasplist = server->kasplist;
   9299 	server->kasplist = kasplist;
   9300 	kasplist = tmpkasplist;
   9301 
   9302 #ifdef USE_DNSRPS
   9303 	/*
   9304 	 * Find the path to the DNSRPS implementation library.
   9305 	 */
   9306 	obj = NULL;
   9307 	if (named_config_get(maps, "dnsrps-library", &obj) == ISC_R_SUCCESS) {
   9308 		if (server->dnsrpslib != NULL) {
   9309 			dns_dnsrps_server_destroy();
   9310 			isc_mem_free(server->mctx, server->dnsrpslib);
   9311 			server->dnsrpslib = NULL;
   9312 		}
   9313 		setstring(server, &server->dnsrpslib, cfg_obj_asstring(obj));
   9314 		result = dns_dnsrps_server_create(server->dnsrpslib);
   9315 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9316 			      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
   9317 			      "initializing DNSRPS RPZ provider '%s': %s",
   9318 			      server->dnsrpslib, isc_result_totext(result));
   9319 		/*
   9320 		 * It's okay if librpz isn't available. We'll complain
   9321 		 * later if it turns out to be needed for a view with
   9322 		 * "dnsrps-enable yes".
   9323 		 */
   9324 		if (result == ISC_R_FILENOTFOUND) {
   9325 			result = ISC_R_SUCCESS;
   9326 		}
   9327 		CHECKFATAL(result, "initializing RPZ service interface");
   9328 	}
   9329 #endif /* ifdef USE_DNSRPS */
   9330 
   9331 	/*
   9332 	 * Configure the views.
   9333 	 */
   9334 	views = NULL;
   9335 	(void)cfg_map_get(config, "view", &views);
   9336 
   9337 	/*
   9338 	 * Create the views.
   9339 	 */
   9340 	for (element = cfg_list_first(views); element != NULL;
   9341 	     element = cfg_list_next(element))
   9342 	{
   9343 		cfg_obj_t *vconfig = cfg_listelt_value(element);
   9344 		dns_view_t *view = NULL;
   9345 
   9346 		result = create_view(vconfig, &viewlist, &view);
   9347 		if (result != ISC_R_SUCCESS) {
   9348 			goto cleanup_viewlist;
   9349 		}
   9350 		INSIST(view != NULL);
   9351 
   9352 		result = setup_newzones(view, config, vconfig, conf_parser,
   9353 					named_g_aclconfctx);
   9354 		dns_view_detach(&view);
   9355 
   9356 		if (result != ISC_R_SUCCESS) {
   9357 			goto cleanup_viewlist;
   9358 		}
   9359 	}
   9360 
   9361 	/*
   9362 	 * If there were no explicit views then we do the default
   9363 	 * view here.
   9364 	 */
   9365 	if (views == NULL) {
   9366 		dns_view_t *view = NULL;
   9367 
   9368 		result = create_view(NULL, &viewlist, &view);
   9369 		if (result != ISC_R_SUCCESS) {
   9370 			goto cleanup_viewlist;
   9371 		}
   9372 		INSIST(view != NULL);
   9373 
   9374 		result = setup_newzones(view, config, NULL, conf_parser,
   9375 					named_g_aclconfctx);
   9376 
   9377 		dns_view_detach(&view);
   9378 		if (result != ISC_R_SUCCESS) {
   9379 			goto cleanup_viewlist;
   9380 		}
   9381 	}
   9382 
   9383 	/*
   9384 	 * Configure and freeze all explicit views.  Explicit
   9385 	 * views that have zones were already created at parsing
   9386 	 * time, but views with no zones must be created here.
   9387 	 */
   9388 	for (element = cfg_list_first(views); element != NULL;
   9389 	     element = cfg_list_next(element))
   9390 	{
   9391 		cfg_obj_t *vconfig = cfg_listelt_value(element);
   9392 		dns_view_t *view = NULL;
   9393 
   9394 		view = NULL;
   9395 		result = find_view(vconfig, &viewlist, &view);
   9396 		if (result != ISC_R_SUCCESS) {
   9397 			goto cleanup_cachelist;
   9398 		}
   9399 
   9400 		result = configure_view(
   9401 			view, &viewlist, config, vconfig, &cachelist,
   9402 			&server->cachelist, &server->kasplist,
   9403 			&server->keystorelist, bindkeys, named_g_mctx,
   9404 			named_g_aclconfctx, true, first_time);
   9405 		if (result != ISC_R_SUCCESS) {
   9406 			dns_view_detach(&view);
   9407 			goto cleanup_cachelist;
   9408 		}
   9409 		dns_view_freeze(view);
   9410 		dns_view_detach(&view);
   9411 	}
   9412 
   9413 	/*
   9414 	 * Make sure we have a default view if and only if there
   9415 	 * were no explicit views.
   9416 	 */
   9417 	if (views == NULL) {
   9418 		dns_view_t *view = NULL;
   9419 		result = find_view(NULL, &viewlist, &view);
   9420 		if (result != ISC_R_SUCCESS) {
   9421 			goto cleanup_cachelist;
   9422 		}
   9423 		result = configure_view(
   9424 			view, &viewlist, config, NULL, &cachelist,
   9425 			&server->cachelist, &server->kasplist,
   9426 			&server->keystorelist, bindkeys, named_g_mctx,
   9427 			named_g_aclconfctx, true, first_time);
   9428 		if (result != ISC_R_SUCCESS) {
   9429 			dns_view_detach(&view);
   9430 			goto cleanup_cachelist;
   9431 		}
   9432 		dns_view_freeze(view);
   9433 		dns_view_detach(&view);
   9434 	}
   9435 
   9436 	/*
   9437 	 * Create (or recreate) the built-in views.
   9438 	 */
   9439 	builtin_views = NULL;
   9440 	RUNTIME_CHECK(cfg_map_get(named_g_config, "view", &builtin_views) ==
   9441 		      ISC_R_SUCCESS);
   9442 	for (element = cfg_list_first(builtin_views); element != NULL;
   9443 	     element = cfg_list_next(element))
   9444 	{
   9445 		cfg_obj_t *vconfig = cfg_listelt_value(element);
   9446 		dns_view_t *view = NULL;
   9447 
   9448 		result = create_view(vconfig, &builtin_viewlist, &view);
   9449 		if (result != ISC_R_SUCCESS) {
   9450 			goto cleanup_cachelist;
   9451 		}
   9452 
   9453 		result = configure_view(
   9454 			view, &viewlist, config, vconfig, &cachelist,
   9455 			&server->cachelist, &server->kasplist,
   9456 			&server->keystorelist, bindkeys, named_g_mctx,
   9457 			named_g_aclconfctx, false, first_time);
   9458 		if (result != ISC_R_SUCCESS) {
   9459 			dns_view_detach(&view);
   9460 			goto cleanup_cachelist;
   9461 		}
   9462 		dns_view_freeze(view);
   9463 		dns_view_detach(&view);
   9464 	}
   9465 
   9466 	/* Now combine the two viewlists into one */
   9467 	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
   9468 
   9469 	/*
   9470 	 * Commit any dns_zone_setview() calls on all zones in the new
   9471 	 * view.
   9472 	 */
   9473 	for (dns_view_t *view = ISC_LIST_HEAD(viewlist); view != NULL;
   9474 	     view = ISC_LIST_NEXT(view, link))
   9475 	{
   9476 		dns_view_setviewcommit(view);
   9477 	}
   9478 
   9479 	/* Swap our new view list with the production one. */
   9480 	tmpviewlist = server->viewlist;
   9481 	server->viewlist = viewlist;
   9482 	viewlist = tmpviewlist;
   9483 
   9484 	/* Make the view list available to each of the views */
   9485 	for (dns_view_t *view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   9486 	     view = ISC_LIST_NEXT(view, link))
   9487 	{
   9488 		view->viewlist = &server->viewlist;
   9489 	}
   9490 
   9491 	/* Swap our new cache list with the production one. */
   9492 	tmpcachelist = server->cachelist;
   9493 	server->cachelist = cachelist;
   9494 	cachelist = tmpcachelist;
   9495 
   9496 	/* Load the TKEY information from the configuration. */
   9497 	if (options != NULL) {
   9498 		dns_tkeyctx_t *tkeyctx = NULL;
   9499 
   9500 		result = named_tkeyctx_fromconfig(options, named_g_mctx,
   9501 						  &tkeyctx);
   9502 		if (result != ISC_R_SUCCESS) {
   9503 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9504 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9505 				      "configuring TKEY: %s",
   9506 				      isc_result_totext(result));
   9507 			goto cleanup_cachelist;
   9508 		}
   9509 		if (server->sctx->tkeyctx != NULL) {
   9510 			dns_tkeyctx_destroy(&server->sctx->tkeyctx);
   9511 		}
   9512 		server->sctx->tkeyctx = tkeyctx;
   9513 	}
   9514 
   9515 #ifdef HAVE_LMDB
   9516 	/*
   9517 	 * If we're using LMDB, we may have created newzones databases
   9518 	 * as root, making it impossible to reopen them later after
   9519 	 * switching to a new userid. We close them now, and reopen
   9520 	 * after relinquishing privileges them.
   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_close(view);
   9527 		}
   9528 	}
   9529 #endif /* HAVE_LMDB */
   9530 
   9531 	/*
   9532 	 * Switch to the effective UID for setting up files.
   9533 	 * Later, after configuring all the listening ports,
   9534 	 * we'll relinquish root privileges permanently.
   9535 	 */
   9536 	if (first_time) {
   9537 		named_os_changeuser(false);
   9538 	}
   9539 
   9540 	/*
   9541 	 * Check that the working directory is writable.
   9542 	 */
   9543 	if (!isc_file_isdirwritable(".")) {
   9544 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9545 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9546 			      "the working directory is not writable");
   9547 		result = ISC_R_NOPERM;
   9548 		goto cleanup_cachelist;
   9549 	}
   9550 
   9551 #ifdef HAVE_LMDB
   9552 	/*
   9553 	 * Reopen NZD databases.
   9554 	 */
   9555 	if (first_time) {
   9556 		for (dns_view_t *view = ISC_LIST_HEAD(server->viewlist);
   9557 		     view != NULL; view = ISC_LIST_NEXT(view, link))
   9558 		{
   9559 			nzd_env_reopen(view);
   9560 		}
   9561 	}
   9562 #endif /* HAVE_LMDB */
   9563 
   9564 	/*
   9565 	 * Configure the logging system.
   9566 	 *
   9567 	 * Do this after changing UID to make sure that any log
   9568 	 * files specified in named.conf get created by the
   9569 	 * unprivileged user, not root.
   9570 	 */
   9571 	if (named_g_logstderr) {
   9572 		const cfg_obj_t *logobj = NULL;
   9573 
   9574 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9575 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   9576 			      "not using config file logging "
   9577 			      "statement for logging due to "
   9578 			      "-g option");
   9579 
   9580 		(void)cfg_map_get(config, "logging", &logobj);
   9581 		if (logobj != NULL) {
   9582 			result = named_logconfig(NULL, logobj);
   9583 			if (result != ISC_R_SUCCESS) {
   9584 				isc_log_write(
   9585 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9586 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9587 					"checking logging configuration "
   9588 					"failed: %s",
   9589 					isc_result_totext(result));
   9590 				goto cleanup_cachelist;
   9591 			}
   9592 		}
   9593 	} else {
   9594 		const cfg_obj_t *logobj = NULL;
   9595 
   9596 		isc_logconfig_create(named_g_lctx, &logc);
   9597 
   9598 		logobj = NULL;
   9599 		(void)cfg_map_get(config, "logging", &logobj);
   9600 		if (logobj != NULL) {
   9601 			result = named_logconfig(logc, logobj);
   9602 			if (result != ISC_R_SUCCESS) {
   9603 				isc_log_write(
   9604 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9605 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9606 					"configuring logging: %s",
   9607 					isc_result_totext(result));
   9608 				goto cleanup_logc;
   9609 			}
   9610 		} else {
   9611 			named_log_setdefaultchannels(logc);
   9612 			named_log_setdefaultsslkeylogfile(logc);
   9613 			result = named_log_setunmatchedcategory(logc);
   9614 			if (result != ISC_R_SUCCESS) {
   9615 				isc_log_write(
   9616 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9617 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9618 					"setting up default 'category "
   9619 					"unmatched': %s",
   9620 					isc_result_totext(result));
   9621 				goto cleanup_logc;
   9622 			}
   9623 			result = named_log_setdefaultcategory(logc);
   9624 			if (result != ISC_R_SUCCESS) {
   9625 				isc_log_write(
   9626 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9627 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9628 					"setting up default 'category "
   9629 					"default': %s",
   9630 					isc_result_totext(result));
   9631 				goto cleanup_logc;
   9632 			}
   9633 		}
   9634 
   9635 		isc_logconfig_use(named_g_lctx, logc);
   9636 		logc = NULL;
   9637 
   9638 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9639 			      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
   9640 			      "now using logging configuration from "
   9641 			      "config file");
   9642 	}
   9643 
   9644 	/*
   9645 	 * Set the default value of the query logging flag depending
   9646 	 * whether a "queries" category has been defined.  This is
   9647 	 * a disgusting hack, but we need to do this for BIND 8
   9648 	 * compatibility.
   9649 	 */
   9650 	if (first_time) {
   9651 		const cfg_obj_t *logobj = NULL;
   9652 		const cfg_obj_t *categories = NULL;
   9653 
   9654 		obj = NULL;
   9655 		if (named_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
   9656 			ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES,
   9657 					    cfg_obj_asboolean(obj));
   9658 		} else {
   9659 			(void)cfg_map_get(config, "logging", &logobj);
   9660 			if (logobj != NULL) {
   9661 				(void)cfg_map_get(logobj, "category",
   9662 						  &categories);
   9663 			}
   9664 			if (categories != NULL) {
   9665 				for (element = cfg_list_first(categories);
   9666 				     element != NULL;
   9667 				     element = cfg_list_next(element))
   9668 				{
   9669 					const cfg_obj_t *catobj;
   9670 					const char *str;
   9671 
   9672 					obj = cfg_listelt_value(element);
   9673 					catobj = cfg_tuple_get(obj, "name");
   9674 					str = cfg_obj_asstring(catobj);
   9675 					if (strcasecmp(str, "queries") == 0) {
   9676 						ns_server_setoption(
   9677 							server->sctx,
   9678 							NS_SERVER_LOGQUERIES,
   9679 							true);
   9680 					}
   9681 				}
   9682 			}
   9683 		}
   9684 		obj = NULL;
   9685 		result = named_config_get(maps, "responselog", &obj);
   9686 		if (result == ISC_R_SUCCESS) {
   9687 			ns_server_setoption(server->sctx,
   9688 					    NS_SERVER_LOGRESPONSES,
   9689 					    cfg_obj_asboolean(obj));
   9690 		}
   9691 	}
   9692 
   9693 	obj = NULL;
   9694 	if (options != NULL &&
   9695 	    cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS)
   9696 	{
   9697 		named_g_memstatistics = cfg_obj_asboolean(obj);
   9698 	} else {
   9699 		named_g_memstatistics =
   9700 			((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0);
   9701 	}
   9702 
   9703 	obj = NULL;
   9704 	if (named_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS)
   9705 	{
   9706 		named_main_setmemstats(cfg_obj_asstring(obj));
   9707 	} else if (named_g_memstatistics) {
   9708 		named_main_setmemstats("named.memstats");
   9709 	} else {
   9710 		named_main_setmemstats(NULL);
   9711 	}
   9712 
   9713 	obj = NULL;
   9714 	result = named_config_get(maps, "statistics-file", &obj);
   9715 	INSIST(result == ISC_R_SUCCESS);
   9716 	setstring(server, &server->statsfile, cfg_obj_asstring(obj));
   9717 
   9718 	obj = NULL;
   9719 	result = named_config_get(maps, "dump-file", &obj);
   9720 	INSIST(result == ISC_R_SUCCESS);
   9721 	setstring(server, &server->dumpfile, cfg_obj_asstring(obj));
   9722 
   9723 	obj = NULL;
   9724 	result = named_config_get(maps, "secroots-file", &obj);
   9725 	INSIST(result == ISC_R_SUCCESS);
   9726 	setstring(server, &server->secrootsfile, cfg_obj_asstring(obj));
   9727 
   9728 	obj = NULL;
   9729 	result = named_config_get(maps, "recursing-file", &obj);
   9730 	INSIST(result == ISC_R_SUCCESS);
   9731 	setstring(server, &server->recfile, cfg_obj_asstring(obj));
   9732 
   9733 	obj = NULL;
   9734 	result = named_config_get(maps, "version", &obj);
   9735 	if (result == ISC_R_SUCCESS) {
   9736 		setoptstring(server, &server->version, obj);
   9737 		server->version_set = true;
   9738 	} else {
   9739 		server->version_set = false;
   9740 	}
   9741 
   9742 	obj = NULL;
   9743 	result = named_config_get(maps, "hostname", &obj);
   9744 	if (result == ISC_R_SUCCESS) {
   9745 		setoptstring(server, &server->hostname, obj);
   9746 		server->hostname_set = true;
   9747 	} else {
   9748 		server->hostname_set = false;
   9749 	}
   9750 
   9751 	obj = NULL;
   9752 	result = named_config_get(maps, "server-id", &obj);
   9753 	server->sctx->usehostname = false;
   9754 	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
   9755 		/* The parser translates "hostname" to true */
   9756 		server->sctx->usehostname = true;
   9757 		result = ns_server_setserverid(server->sctx, NULL);
   9758 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
   9759 		/* Found a quoted string */
   9760 		result = ns_server_setserverid(server->sctx,
   9761 					       cfg_obj_asstring(obj));
   9762 	} else {
   9763 		result = ns_server_setserverid(server->sctx, NULL);
   9764 	}
   9765 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   9766 
   9767 	obj = NULL;
   9768 	result = named_config_get(maps, "flush-zones-on-shutdown", &obj);
   9769 	if (result == ISC_R_SUCCESS) {
   9770 		server->flushonshutdown = cfg_obj_asboolean(obj);
   9771 	} else {
   9772 		server->flushonshutdown = false;
   9773 	}
   9774 
   9775 	obj = NULL;
   9776 	result = named_config_get(maps, "answer-cookie", &obj);
   9777 	INSIST(result == ISC_R_SUCCESS);
   9778 	server->sctx->answercookie = cfg_obj_asboolean(obj);
   9779 
   9780 	obj = NULL;
   9781 	result = named_config_get(maps, "cookie-algorithm", &obj);
   9782 	INSIST(result == ISC_R_SUCCESS);
   9783 	if (strcasecmp(cfg_obj_asstring(obj), "siphash24") == 0) {
   9784 		server->sctx->cookiealg = ns_cookiealg_siphash24;
   9785 	} else {
   9786 		UNREACHABLE();
   9787 	}
   9788 
   9789 	obj = NULL;
   9790 	result = named_config_get(maps, "cookie-secret", &obj);
   9791 	if (result == ISC_R_SUCCESS) {
   9792 		const char *str;
   9793 		bool first = true;
   9794 		isc_buffer_t b;
   9795 		unsigned int usedlength;
   9796 		unsigned int expectedlength;
   9797 
   9798 		for (element = cfg_list_first(obj); element != NULL;
   9799 		     element = cfg_list_next(element))
   9800 		{
   9801 			obj = cfg_listelt_value(element);
   9802 			str = cfg_obj_asstring(obj);
   9803 
   9804 			if (first) {
   9805 				memset(server->sctx->secret, 0,
   9806 				       sizeof(server->sctx->secret));
   9807 				isc_buffer_init(&b, server->sctx->secret,
   9808 						sizeof(server->sctx->secret));
   9809 				result = isc_hex_decodestring(str, &b);
   9810 				if (result != ISC_R_SUCCESS &&
   9811 				    result != ISC_R_NOSPACE)
   9812 				{
   9813 					goto cleanup_altsecrets;
   9814 				}
   9815 				first = false;
   9816 			} else {
   9817 				altsecret = isc_mem_get(server->sctx->mctx,
   9818 							sizeof(*altsecret));
   9819 				isc_buffer_init(&b, altsecret->secret,
   9820 						sizeof(altsecret->secret));
   9821 				result = isc_hex_decodestring(str, &b);
   9822 				if (result != ISC_R_SUCCESS &&
   9823 				    result != ISC_R_NOSPACE)
   9824 				{
   9825 					isc_mem_put(server->sctx->mctx,
   9826 						    altsecret,
   9827 						    sizeof(*altsecret));
   9828 					goto cleanup_altsecrets;
   9829 				}
   9830 				ISC_LIST_INITANDAPPEND(altsecrets, altsecret,
   9831 						       link);
   9832 			}
   9833 
   9834 			usedlength = isc_buffer_usedlength(&b);
   9835 			switch (server->sctx->cookiealg) {
   9836 			case ns_cookiealg_siphash24:
   9837 				expectedlength = ISC_SIPHASH24_KEY_LENGTH;
   9838 				if (usedlength != expectedlength) {
   9839 					result = ISC_R_RANGE;
   9840 					isc_log_write(
   9841 						named_g_lctx,
   9842 						NAMED_LOGCATEGORY_GENERAL,
   9843 						NAMED_LOGMODULE_SERVER,
   9844 						ISC_LOG_ERROR,
   9845 						"SipHash-2-4 cookie-secret "
   9846 						"must be 128 bits: %s",
   9847 						isc_result_totext(result));
   9848 					goto cleanup_altsecrets;
   9849 				}
   9850 				break;
   9851 			}
   9852 		}
   9853 	} else {
   9854 		isc_nonce_buf(server->sctx->secret,
   9855 			      sizeof(server->sctx->secret));
   9856 	}
   9857 
   9858 	/*
   9859 	 * Swap altsecrets lists.
   9860 	 */
   9861 	tmpaltsecrets = server->sctx->altsecrets;
   9862 	server->sctx->altsecrets = altsecrets;
   9863 	altsecrets = tmpaltsecrets;
   9864 
   9865 	(void)named_server_loadnta(server);
   9866 
   9867 #ifdef USE_DNSRPS
   9868 	/*
   9869 	 * Start and connect to the DNS Response Policy Service
   9870 	 * daemon, dnsrpzd, for each view that uses DNSRPS.
   9871 	 */
   9872 	for (dns_view_t *view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   9873 	     view = ISC_LIST_NEXT(view, link))
   9874 	{
   9875 		result = dns_dnsrps_connect(view->rpzs);
   9876 		if (result != ISC_R_SUCCESS) {
   9877 			view = NULL;
   9878 			goto cleanup_altsecrets;
   9879 		}
   9880 	}
   9881 #endif /* ifdef USE_DNSRPS */
   9882 
   9883 	/*
   9884 	 * Record the time of most recent configuration
   9885 	 */
   9886 	named_g_configtime = isc_time_now();
   9887 
   9888 	isc_loopmgr_resume(named_g_loopmgr);
   9889 	exclusive = false;
   9890 
   9891 	/* Take back root privileges temporarily */
   9892 	if (first_time) {
   9893 		named_os_restoreuser();
   9894 	}
   9895 
   9896 	/* Configure the statistics channel(s) */
   9897 	result = named_statschannels_configure(named_g_server, config,
   9898 					       named_g_aclconfctx);
   9899 	if (result != ISC_R_SUCCESS) {
   9900 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9901 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9902 			      "configuring statistics server(s): %s",
   9903 			      isc_result_totext(result));
   9904 		goto cleanup_altsecrets;
   9905 	}
   9906 
   9907 	/*
   9908 	 * Bind the control port(s).
   9909 	 */
   9910 	result = named_controls_configure(named_g_server->controls, config,
   9911 					  named_g_aclconfctx);
   9912 	if (result != ISC_R_SUCCESS) {
   9913 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   9914 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   9915 			      "binding control channel(s): %s",
   9916 			      isc_result_totext(result));
   9917 		goto cleanup_altsecrets;
   9918 	}
   9919 
   9920 	(void)ns_interfacemgr_scan(server->interfacemgr, true, true);
   9921 
   9922 	/*
   9923 	 * Permanently drop root privileges now.
   9924 	 */
   9925 	if (first_time) {
   9926 		named_os_changeuser(true);
   9927 	}
   9928 
   9929 	/*
   9930 	 * These cleans up either the old production view list
   9931 	 * or our temporary list depending on whether they
   9932 	 * were swapped above or not.
   9933 	 */
   9934 cleanup_altsecrets:
   9935 	while ((altsecret = ISC_LIST_HEAD(altsecrets)) != NULL) {
   9936 		ISC_LIST_UNLINK(altsecrets, altsecret, link);
   9937 		isc_mem_put(server->sctx->mctx, altsecret, sizeof(*altsecret));
   9938 	}
   9939 
   9940 cleanup_logc:
   9941 	if (logc != NULL) {
   9942 		isc_logconfig_destroy(&logc);
   9943 	}
   9944 
   9945 cleanup_cachelist:
   9946 	while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
   9947 		ISC_LIST_UNLINK(cachelist, nsc, link);
   9948 		dns_cache_detach(&nsc->cache);
   9949 		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
   9950 	}
   9951 
   9952 	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
   9953 
   9954 cleanup_viewlist:
   9955 	for (dns_view_t *view = ISC_LIST_HEAD(viewlist); view != NULL;
   9956 	     view = view_next)
   9957 	{
   9958 		view_next = ISC_LIST_NEXT(view, link);
   9959 		ISC_LIST_UNLINK(viewlist, view, link);
   9960 		if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0)
   9961 		{
   9962 			dns_view_setviewrevert(view);
   9963 			(void)dns_view_apply(view, false, NULL, removed, view);
   9964 		}
   9965 		dns_view_detach(&view);
   9966 	}
   9967 
   9968 cleanup_kasplist:
   9969 	for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) {
   9970 		kasp_next = ISC_LIST_NEXT(kasp, link);
   9971 		ISC_LIST_UNLINK(kasplist, kasp, link);
   9972 		dns_kasp_detach(&kasp);
   9973 	}
   9974 
   9975 cleanup_keystorelist:
   9976 	for (keystore = ISC_LIST_HEAD(keystorelist); keystore != NULL;
   9977 	     keystore = keystore_next)
   9978 	{
   9979 		keystore_next = ISC_LIST_NEXT(keystore, link);
   9980 		ISC_LIST_UNLINK(keystorelist, keystore, link);
   9981 		dns_keystore_detach(&keystore);
   9982 	}
   9983 
   9984 cleanup_v6portset:
   9985 	isc_portset_destroy(named_g_mctx, &v6portset);
   9986 
   9987 cleanup_v4portset:
   9988 	isc_portset_destroy(named_g_mctx, &v4portset);
   9989 
   9990 cleanup_bindkeys_parser:
   9991 
   9992 	if (bindkeys_parser != NULL) {
   9993 		if (bindkeys != NULL) {
   9994 			cfg_obj_destroy(bindkeys_parser, &bindkeys);
   9995 		}
   9996 		cfg_parser_destroy(&bindkeys_parser);
   9997 	}
   9998 
   9999 cleanup_config:
   10000 	cfg_obj_destroy(conf_parser, &config);
   10001 
   10002 cleanup_conf_parser:
   10003 	cfg_parser_destroy(&conf_parser);
   10004 
   10005 cleanup_exclusive:
   10006 	if (exclusive) {
   10007 		isc_loopmgr_resume(named_g_loopmgr);
   10008 	}
   10009 
   10010 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10011 		      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
   10012 		      "load_configuration: %s", isc_result_totext(result));
   10013 
   10014 	return result;
   10015 }
   10016 
   10017 static isc_result_t
   10018 view_loaded(void *arg) {
   10019 	isc_result_t result;
   10020 	ns_zoneload_t *zl = (ns_zoneload_t *)arg;
   10021 
   10022 	/*
   10023 	 * Force zone maintenance.  Do this after loading
   10024 	 * so that we know when we need to force AXFR of
   10025 	 * secondary zones whose master files are missing.
   10026 	 *
   10027 	 * We use the zoneload reference counter to let us
   10028 	 * know when all views are finished.
   10029 	 */
   10030 	if (isc_refcount_decrement(&zl->refs) == 1) {
   10031 		named_server_t *server = zl->server;
   10032 		bool reconfig = zl->reconfig;
   10033 		dns_view_t *view = NULL;
   10034 
   10035 		isc_refcount_destroy(&zl->refs);
   10036 		isc_mem_put(server->mctx, zl, sizeof(*zl));
   10037 
   10038 		/*
   10039 		 * To maintain compatibility with log parsing tools that might
   10040 		 * be looking for this string after "rndc reconfig", we keep it
   10041 		 * as it is
   10042 		 */
   10043 		if (reconfig) {
   10044 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10045 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   10046 				      "any newly configured zones are now "
   10047 				      "loaded");
   10048 		} else {
   10049 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10050 				      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
   10051 				      "all zones loaded");
   10052 		}
   10053 
   10054 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   10055 		     view = ISC_LIST_NEXT(view, link))
   10056 		{
   10057 			if (view->managed_keys != NULL) {
   10058 				result = dns_zone_synckeyzone(
   10059 					view->managed_keys);
   10060 				if (result != ISC_R_SUCCESS) {
   10061 					isc_log_write(
   10062 						named_g_lctx,
   10063 						DNS_LOGCATEGORY_DNSSEC,
   10064 						DNS_LOGMODULE_DNSSEC,
   10065 						ISC_LOG_ERROR,
   10066 						"failed to initialize "
   10067 						"managed-keys for view %s "
   10068 						"(%s): DNSSEC validation is "
   10069 						"at risk",
   10070 						view->name,
   10071 						isc_result_totext(result));
   10072 				}
   10073 			}
   10074 		}
   10075 
   10076 		CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr),
   10077 			   "forcing zone maintenance");
   10078 
   10079 		named_os_started();
   10080 
   10081 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10082 			      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
   10083 			      "FIPS mode is %s",
   10084 			      isc_fips_mode() ? "enabled" : "disabled");
   10085 
   10086 		named_os_notify_systemd("READY=1\n"
   10087 					"STATUS=running\n"
   10088 					"MAINPID=%" PRId64 "\n",
   10089 					(int64_t)getpid());
   10090 
   10091 		atomic_store(&server->reload_status, NAMED_RELOAD_DONE);
   10092 
   10093 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10094 			      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
   10095 			      "running");
   10096 	}
   10097 
   10098 	return ISC_R_SUCCESS;
   10099 }
   10100 
   10101 static isc_result_t
   10102 load_zones(named_server_t *server, bool reconfig) {
   10103 	isc_result_t result = ISC_R_SUCCESS;
   10104 	ns_zoneload_t *zl = NULL;
   10105 	dns_view_t *view = NULL;
   10106 
   10107 	zl = isc_mem_get(server->mctx, sizeof(*zl));
   10108 	zl->server = server;
   10109 	zl->reconfig = reconfig;
   10110 
   10111 	isc_loopmgr_pause(named_g_loopmgr);
   10112 
   10113 	isc_refcount_init(&zl->refs, 1);
   10114 
   10115 	/*
   10116 	 * Schedule zones to be loaded from disk.
   10117 	 */
   10118 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   10119 	     view = ISC_LIST_NEXT(view, link))
   10120 	{
   10121 		if (view->managed_keys != NULL) {
   10122 			result = dns_zone_load(view->managed_keys, false);
   10123 			if (result != ISC_R_SUCCESS &&
   10124 			    result != DNS_R_UPTODATE &&
   10125 			    result != DNS_R_CONTINUE)
   10126 			{
   10127 				goto cleanup;
   10128 			}
   10129 		}
   10130 		if (view->redirect != NULL) {
   10131 			result = dns_zone_load(view->redirect, false);
   10132 			if (result != ISC_R_SUCCESS &&
   10133 			    result != DNS_R_UPTODATE &&
   10134 			    result != DNS_R_CONTINUE)
   10135 			{
   10136 				goto cleanup;
   10137 			}
   10138 		}
   10139 
   10140 		/*
   10141 		 * 'dns_view_asyncload' calls view_loaded if there are no
   10142 		 * zones.
   10143 		 */
   10144 		isc_refcount_increment(&zl->refs);
   10145 		result = dns_view_asyncload(view, reconfig, view_loaded, zl);
   10146 		if (result != ISC_R_SUCCESS) {
   10147 			isc_refcount_decrement1(&zl->refs);
   10148 			goto cleanup;
   10149 		}
   10150 	}
   10151 
   10152 cleanup:
   10153 	if (isc_refcount_decrement(&zl->refs) == 1) {
   10154 		isc_refcount_destroy(&zl->refs);
   10155 		isc_mem_put(server->mctx, zl, sizeof(*zl));
   10156 	}
   10157 
   10158 	isc_loopmgr_resume(named_g_loopmgr);
   10159 
   10160 	return result;
   10161 }
   10162 
   10163 static void
   10164 run_server(void *arg) {
   10165 	isc_result_t result;
   10166 	named_server_t *server = (named_server_t *)arg;
   10167 	dns_geoip_databases_t *geoip = NULL;
   10168 
   10169 	dns_zonemgr_create(named_g_mctx, named_g_netmgr, &server->zonemgr);
   10170 
   10171 	CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, named_g_loopmgr,
   10172 					  named_g_netmgr, &named_g_dispatchmgr),
   10173 		   "creating dispatch manager");
   10174 
   10175 	dns_dispatchmgr_setstats(named_g_dispatchmgr, server->resolverstats);
   10176 
   10177 #if defined(HAVE_GEOIP2)
   10178 	geoip = named_g_geoip;
   10179 #else  /* if defined(HAVE_GEOIP2) */
   10180 	geoip = NULL;
   10181 #endif /* if defined(HAVE_GEOIP2) */
   10182 
   10183 	CHECKFATAL(ns_interfacemgr_create(named_g_mctx, server->sctx,
   10184 					  named_g_loopmgr, named_g_netmgr,
   10185 					  named_g_dispatchmgr, geoip,
   10186 					  &server->interfacemgr),
   10187 		   "creating interface manager");
   10188 
   10189 	isc_timer_create(named_g_mainloop, interface_timer_tick, server,
   10190 			 &server->interface_timer);
   10191 
   10192 	isc_timer_create(named_g_mainloop, heartbeat_timer_tick, server,
   10193 			 &server->heartbeat_timer);
   10194 
   10195 	isc_timer_create(named_g_mainloop, tat_timer_tick, server,
   10196 			 &server->tat_timer);
   10197 
   10198 	isc_timer_create(named_g_mainloop, pps_timer_tick, server,
   10199 			 &server->pps_timer);
   10200 
   10201 	CHECKFATAL(
   10202 		cfg_parser_create(named_g_mctx, named_g_lctx, &named_g_parser),
   10203 		"creating default configuration parser");
   10204 
   10205 	CHECKFATAL(cfg_parser_create(named_g_mctx, named_g_lctx,
   10206 				     &named_g_addparser),
   10207 		   "creating additional configuration parser");
   10208 
   10209 	CHECKFATAL(load_configuration(named_g_conffile, server, true),
   10210 		   "loading configuration");
   10211 
   10212 	CHECKFATAL(load_zones(server, false), "loading zones");
   10213 #ifdef ENABLE_AFL
   10214 	named_g_run_done = true;
   10215 #endif /* ifdef ENABLE_AFL */
   10216 }
   10217 
   10218 void
   10219 named_server_flushonshutdown(named_server_t *server, bool flush) {
   10220 	REQUIRE(NAMED_SERVER_VALID(server));
   10221 
   10222 	server->flushonshutdown = flush;
   10223 }
   10224 
   10225 static void
   10226 shutdown_server(void *arg) {
   10227 	named_server_t *server = (named_server_t *)arg;
   10228 	dns_view_t *view = NULL, *view_next = NULL;
   10229 	dns_kasp_t *kasp = NULL, *kasp_next = NULL;
   10230 	dns_keystore_t *keystore = NULL, *keystore_next = NULL;
   10231 	bool flush = server->flushonshutdown;
   10232 	named_cache_t *nsc = NULL;
   10233 
   10234 	named_os_notify_systemd("STOPPING=1\n");
   10235 	named_os_notify_close();
   10236 
   10237 	isc_signal_stop(server->sighup);
   10238 	isc_signal_destroy(&server->sighup);
   10239 
   10240 	/*
   10241 	 * We need to shutdown the interface before going
   10242 	 * exclusive (which would pause the netmgr).
   10243 	 */
   10244 	ns_interfacemgr_shutdown(server->interfacemgr);
   10245 
   10246 	named_controls_shutdown(server->controls);
   10247 
   10248 	named_statschannels_shutdown(server);
   10249 
   10250 	isc_loopmgr_pause(named_g_loopmgr);
   10251 
   10252 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10253 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, "shutting down%s",
   10254 		      flush ? ": flushing changes" : "");
   10255 
   10256 	cleanup_session_key(server, server->mctx);
   10257 
   10258 	if (named_g_aclconfctx != NULL) {
   10259 		cfg_aclconfctx_detach(&named_g_aclconfctx);
   10260 	}
   10261 
   10262 	cfg_obj_destroy(named_g_parser, &named_g_config);
   10263 	cfg_parser_destroy(&named_g_parser);
   10264 	cfg_parser_destroy(&named_g_addparser);
   10265 
   10266 	(void)named_server_saventa(server);
   10267 
   10268 	for (kasp = ISC_LIST_HEAD(server->kasplist); kasp != NULL;
   10269 	     kasp = kasp_next)
   10270 	{
   10271 		kasp_next = ISC_LIST_NEXT(kasp, link);
   10272 		ISC_LIST_UNLINK(server->kasplist, kasp, link);
   10273 		dns_kasp_detach(&kasp);
   10274 	}
   10275 
   10276 	for (keystore = ISC_LIST_HEAD(server->keystorelist); keystore != NULL;
   10277 	     keystore = keystore_next)
   10278 	{
   10279 		keystore_next = ISC_LIST_NEXT(keystore, link);
   10280 		ISC_LIST_UNLINK(server->keystorelist, keystore, link);
   10281 		dns_keystore_detach(&keystore);
   10282 	}
   10283 
   10284 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   10285 	     view = view_next)
   10286 	{
   10287 		view_next = ISC_LIST_NEXT(view, link);
   10288 		ISC_LIST_UNLINK(server->viewlist, view, link);
   10289 		dns_view_flushonshutdown(view, flush);
   10290 		dns_view_detach(&view);
   10291 	}
   10292 
   10293 	/*
   10294 	 * Shut down all dyndb instances.
   10295 	 */
   10296 	dns_dyndb_cleanup(true);
   10297 
   10298 	while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
   10299 		ISC_LIST_UNLINK(server->cachelist, nsc, link);
   10300 		dns_cache_detach(&nsc->cache);
   10301 		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
   10302 	}
   10303 
   10304 	isc_timer_destroy(&server->interface_timer);
   10305 	isc_timer_destroy(&server->heartbeat_timer);
   10306 	isc_timer_destroy(&server->pps_timer);
   10307 	isc_timer_destroy(&server->tat_timer);
   10308 
   10309 	ns_interfacemgr_detach(&server->interfacemgr);
   10310 
   10311 	dns_dispatchmgr_detach(&named_g_dispatchmgr);
   10312 
   10313 	dns_zonemgr_shutdown(server->zonemgr);
   10314 
   10315 #if defined(HAVE_GEOIP2)
   10316 	named_geoip_shutdown();
   10317 #endif /* HAVE_GEOIP2 */
   10318 
   10319 	dns_db_detach(&server->in_roothints);
   10320 
   10321 	isc_loopmgr_resume(named_g_loopmgr);
   10322 }
   10323 
   10324 static isc_result_t
   10325 get_matching_view_sync(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
   10326 		       dns_message_t *message, dns_aclenv_t *env,
   10327 		       isc_result_t *sigresult, dns_view_t **viewp) {
   10328 	dns_view_t *view;
   10329 
   10330 	/*
   10331 	 * We should not be running synchronous view matching if signature
   10332 	 * checking involves SIG(0). TSIG has priority of SIG(0), so if TSIG
   10333 	 * is set then we proceed anyway.
   10334 	 */
   10335 	INSIST(message->tsigkey != NULL || message->tsig != NULL ||
   10336 	       message->sig0 == NULL);
   10337 
   10338 	for (view = ISC_LIST_HEAD(named_g_server->viewlist); view != NULL;
   10339 	     view = ISC_LIST_NEXT(view, link))
   10340 	{
   10341 		if (message->rdclass == view->rdclass ||
   10342 		    message->rdclass == dns_rdataclass_any)
   10343 		{
   10344 			const dns_name_t *tsig = NULL;
   10345 
   10346 			dns_message_resetsig(message);
   10347 			*sigresult = dns_message_checksig(message, view);
   10348 			if (*sigresult == ISC_R_SUCCESS) {
   10349 				tsig = dns_tsigkey_identity(message->tsigkey);
   10350 			}
   10351 
   10352 			if (dns_acl_allowed(srcaddr, tsig, view->matchclients,
   10353 					    env) &&
   10354 			    dns_acl_allowed(destaddr, tsig,
   10355 					    view->matchdestinations, env) &&
   10356 			    !(view->matchrecursiveonly &&
   10357 			      (message->flags & DNS_MESSAGEFLAG_RD) == 0))
   10358 			{
   10359 				dns_view_attach(view, viewp);
   10360 				return ISC_R_SUCCESS;
   10361 			}
   10362 		}
   10363 	}
   10364 
   10365 	return ISC_R_NOTFOUND;
   10366 }
   10367 
   10368 static void
   10369 get_matching_view_done(void *cbarg) {
   10370 	matching_view_ctx_t *mvctx = cbarg;
   10371 	dns_message_t *message = mvctx->message;
   10372 
   10373 	if (*mvctx->viewmatchresult == ISC_R_SUCCESS) {
   10374 		INSIST(mvctx->view != NULL);
   10375 		dns_view_attach(mvctx->view, mvctx->viewp);
   10376 	}
   10377 
   10378 	mvctx->cb(mvctx->cbarg);
   10379 
   10380 	if (mvctx->quota_result == ISC_R_SUCCESS) {
   10381 		isc_quota_release(&mvctx->sctx->sig0checksquota);
   10382 	}
   10383 	if (mvctx->view != NULL) {
   10384 		dns_view_detach(&mvctx->view);
   10385 	}
   10386 	isc_loop_detach(&mvctx->loop);
   10387 	ns_server_detach(&mvctx->sctx);
   10388 	isc_mem_put(message->mctx, mvctx, sizeof(*mvctx));
   10389 	dns_message_detach(&message);
   10390 }
   10391 
   10392 static dns_view_t *
   10393 get_matching_view_next(dns_view_t *view, dns_rdataclass_t rdclass) {
   10394 	if (view == NULL) {
   10395 		view = ISC_LIST_HEAD(named_g_server->viewlist);
   10396 	} else {
   10397 		view = ISC_LIST_NEXT(view, link);
   10398 	}
   10399 	while (true) {
   10400 		if (view == NULL || rdclass == view->rdclass ||
   10401 		    rdclass == dns_rdataclass_any)
   10402 		{
   10403 			return view;
   10404 		}
   10405 		view = ISC_LIST_NEXT(view, link);
   10406 	};
   10407 }
   10408 
   10409 static void
   10410 get_matching_view_continue(void *cbarg, isc_result_t result) {
   10411 	matching_view_ctx_t *mvctx = cbarg;
   10412 	dns_view_t *view = NULL;
   10413 	const dns_name_t *tsig = NULL;
   10414 
   10415 	*mvctx->sigresult = result;
   10416 
   10417 	if (result == ISC_R_SUCCESS) {
   10418 		tsig = dns_tsigkey_identity(mvctx->message->tsigkey);
   10419 	}
   10420 
   10421 	if (dns_acl_allowed(mvctx->srcaddr, tsig, mvctx->view->matchclients,
   10422 			    mvctx->env) &&
   10423 	    dns_acl_allowed(mvctx->destaddr, tsig,
   10424 			    mvctx->view->matchdestinations, mvctx->env) &&
   10425 	    !(mvctx->view->matchrecursiveonly &&
   10426 	      (mvctx->message->flags & DNS_MESSAGEFLAG_RD) == 0))
   10427 	{
   10428 		/*
   10429 		 * A matching view is found.
   10430 		 */
   10431 		*mvctx->viewmatchresult = ISC_R_SUCCESS;
   10432 		get_matching_view_done(cbarg);
   10433 		return;
   10434 	}
   10435 
   10436 	dns_message_resetsig(mvctx->message);
   10437 
   10438 	view = get_matching_view_next(mvctx->view, mvctx->message->rdclass);
   10439 	dns_view_detach(&mvctx->view);
   10440 	if (view != NULL) {
   10441 		/*
   10442 		 * Try the next view.
   10443 		 */
   10444 		dns_view_attach(view, &mvctx->view);
   10445 		result = dns_message_checksig_async(
   10446 			mvctx->message, view, mvctx->loop,
   10447 			get_matching_view_continue, mvctx);
   10448 		INSIST(result == DNS_R_WAIT);
   10449 		return;
   10450 	}
   10451 
   10452 	/*
   10453 	 * No matching view is found.
   10454 	 */
   10455 	*mvctx->viewmatchresult = ISC_R_NOTFOUND;
   10456 	get_matching_view_done(cbarg);
   10457 }
   10458 
   10459 /*%
   10460  * Find a view that matches the source and destination addresses of a query.
   10461  */
   10462 static isc_result_t
   10463 get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
   10464 		  dns_message_t *message, dns_aclenv_t *env, ns_server_t *sctx,
   10465 		  isc_loop_t *loop, isc_job_cb cb, void *cbarg,
   10466 		  isc_result_t *sigresult, isc_result_t *viewmatchresult,
   10467 		  dns_view_t **viewp) {
   10468 	dns_view_t *view = NULL;
   10469 	isc_result_t result;
   10470 
   10471 	REQUIRE(message != NULL);
   10472 	REQUIRE(sctx != NULL);
   10473 	REQUIRE(loop == NULL || cb != NULL);
   10474 	REQUIRE(sigresult != NULL);
   10475 	REQUIRE(viewmatchresult != NULL);
   10476 	REQUIRE(viewp != NULL && *viewp == NULL);
   10477 
   10478 	/* No offloading is requested if the loop is unset. */
   10479 	if (loop == NULL) {
   10480 		*viewmatchresult = get_matching_view_sync(
   10481 			srcaddr, destaddr, message, env, sigresult, viewp);
   10482 		return *viewmatchresult;
   10483 	}
   10484 
   10485 	/* Also no offloading when there is no view at all to match against. */
   10486 	view = get_matching_view_next(NULL, message->rdclass);
   10487 	if (view == NULL) {
   10488 		*viewmatchresult = ISC_R_NOTFOUND;
   10489 		return *viewmatchresult;
   10490 	}
   10491 
   10492 	dns_message_resetsig(message);
   10493 
   10494 	matching_view_ctx_t *mvctx = isc_mem_get(message->mctx, sizeof(*mvctx));
   10495 	*mvctx = (matching_view_ctx_t){
   10496 		.srcaddr = srcaddr,
   10497 		.destaddr = destaddr,
   10498 		.env = env,
   10499 		.cb = cb,
   10500 		.cbarg = cbarg,
   10501 		.sigresult = sigresult,
   10502 		.viewmatchresult = viewmatchresult,
   10503 		.quota_result = ISC_R_UNSET,
   10504 		.viewp = viewp,
   10505 	};
   10506 	ns_server_attach(sctx, &mvctx->sctx);
   10507 	isc_loop_attach(loop, &mvctx->loop);
   10508 	dns_message_attach(message, &mvctx->message);
   10509 
   10510 	/*
   10511 	 * If the message has a SIG0 signature which we are going to
   10512 	 * check, and the client is not exempt from the SIG(0) quota,
   10513 	 * then acquire a quota. TSIG has priority over SIG(0), so if
   10514 	 * TSIG is set then we don't care.
   10515 	 */
   10516 	if (message->tsigkey == NULL && message->tsig == NULL &&
   10517 	    message->sig0 != NULL)
   10518 	{
   10519 		if (sctx->sig0checksquota_exempt != NULL) {
   10520 			int exempt_match;
   10521 
   10522 			result = dns_acl_match(srcaddr, NULL,
   10523 					       sctx->sig0checksquota_exempt,
   10524 					       env, &exempt_match, NULL);
   10525 			if (result == ISC_R_SUCCESS && exempt_match > 0) {
   10526 				mvctx->quota_result = ISC_R_EXISTS;
   10527 			}
   10528 		}
   10529 		if (mvctx->quota_result == ISC_R_UNSET) {
   10530 			mvctx->quota_result =
   10531 				isc_quota_acquire(&sctx->sig0checksquota);
   10532 		}
   10533 		if (mvctx->quota_result == ISC_R_SOFTQUOTA) {
   10534 			isc_quota_release(&sctx->sig0checksquota);
   10535 		}
   10536 		if (mvctx->quota_result != ISC_R_SUCCESS &&
   10537 		    mvctx->quota_result != ISC_R_EXISTS)
   10538 		{
   10539 			*mvctx->viewmatchresult = ISC_R_QUOTA;
   10540 			isc_async_run(loop, get_matching_view_done, mvctx);
   10541 			return DNS_R_WAIT;
   10542 		}
   10543 	}
   10544 
   10545 	dns_view_attach(view, &mvctx->view);
   10546 	result = dns_message_checksig_async(message, view, loop,
   10547 					    get_matching_view_continue, mvctx);
   10548 	INSIST(result == DNS_R_WAIT);
   10549 
   10550 	return DNS_R_WAIT;
   10551 }
   10552 
   10553 void
   10554 named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
   10555 	isc_result_t result;
   10556 	named_server_t *server = isc_mem_get(mctx, sizeof(*server));
   10557 
   10558 	*server = (named_server_t){
   10559 		.mctx = mctx,
   10560 		.statsfile = isc_mem_strdup(mctx, "named.stats"),
   10561 		.dumpfile = isc_mem_strdup(mctx, "named_dump.db"),
   10562 		.secrootsfile = isc_mem_strdup(mctx, "named.secroots"),
   10563 		.recfile = isc_mem_strdup(mctx, "named.recursing"),
   10564 	};
   10565 
   10566 	/* Initialize server data structures. */
   10567 	ISC_LIST_INIT(server->kasplist);
   10568 	ISC_LIST_INIT(server->keystorelist);
   10569 	ISC_LIST_INIT(server->viewlist);
   10570 
   10571 	/* Must be first. */
   10572 	CHECKFATAL(dst_lib_init(named_g_mctx, named_g_engine),
   10573 		   "initializing DST");
   10574 
   10575 	CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
   10576 				     &server->in_roothints),
   10577 		   "setting up root hints");
   10578 
   10579 	atomic_init(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
   10580 
   10581 	ns_server_create(mctx, get_matching_view, &server->sctx);
   10582 
   10583 #if defined(HAVE_GEOIP2)
   10584 	/*
   10585 	 * GeoIP must be initialized before the interface
   10586 	 * manager (which includes the ACL environment)
   10587 	 * is created.
   10588 	 */
   10589 	named_geoip_init();
   10590 #endif /* HAVE_GEOIP2 */
   10591 
   10592 #ifdef ENABLE_AFL
   10593 	server->sctx->fuzztype = named_g_fuzz_type;
   10594 	server->sctx->fuzznotify = named_fuzz_notify;
   10595 #endif /* ifdef ENABLE_AFL */
   10596 
   10597 	named_g_mainloop = isc_loop_main(named_g_loopmgr);
   10598 
   10599 	isc_loop_setup(named_g_mainloop, run_server, server);
   10600 	isc_loop_teardown(named_g_mainloop, shutdown_server, server);
   10601 
   10602 	/* Add SIGHUP reload handler  */
   10603 	server->sighup = isc_signal_new(
   10604 		named_g_loopmgr, named_server_reloadwanted, server, SIGHUP);
   10605 
   10606 	isc_stats_create(server->mctx, &server->sockstats,
   10607 			 isc_sockstatscounter_max);
   10608 	isc_nm_setstats(named_g_netmgr, server->sockstats);
   10609 
   10610 	isc_stats_create(named_g_mctx, &server->zonestats,
   10611 			 dns_zonestatscounter_max);
   10612 
   10613 	isc_stats_create(named_g_mctx, &server->resolverstats,
   10614 			 dns_resstatscounter_max);
   10615 
   10616 	CHECKFATAL(named_controls_create(server, &server->controls),
   10617 		   "named_controls_create");
   10618 
   10619 	ISC_LIST_INIT(server->statschannels);
   10620 
   10621 	ISC_LIST_INIT(server->cachelist);
   10622 
   10623 	server->magic = NAMED_SERVER_MAGIC;
   10624 
   10625 	*serverp = server;
   10626 }
   10627 
   10628 void
   10629 named_server_destroy(named_server_t **serverp) {
   10630 	named_server_t *server = *serverp;
   10631 	REQUIRE(NAMED_SERVER_VALID(server));
   10632 
   10633 #ifdef HAVE_DNSTAP
   10634 	if (server->dtenv != NULL) {
   10635 		dns_dt_detach(&server->dtenv);
   10636 	}
   10637 #endif /* HAVE_DNSTAP */
   10638 
   10639 #ifdef USE_DNSRPS
   10640 	dns_dnsrps_server_destroy();
   10641 	isc_mem_free(server->mctx, server->dnsrpslib);
   10642 #endif /* ifdef USE_DNSRPS */
   10643 
   10644 	named_controls_destroy(&server->controls);
   10645 
   10646 	isc_stats_detach(&server->zonestats);
   10647 	isc_stats_detach(&server->sockstats);
   10648 	isc_stats_detach(&server->resolverstats);
   10649 
   10650 	if (server->sctx != NULL) {
   10651 		ns_server_detach(&server->sctx);
   10652 	}
   10653 
   10654 	isc_mem_free(server->mctx, server->statsfile);
   10655 	isc_mem_free(server->mctx, server->dumpfile);
   10656 	isc_mem_free(server->mctx, server->secrootsfile);
   10657 	isc_mem_free(server->mctx, server->recfile);
   10658 
   10659 	if (server->bindkeysfile != NULL) {
   10660 		isc_mem_free(server->mctx, server->bindkeysfile);
   10661 	}
   10662 
   10663 	if (server->version != NULL) {
   10664 		isc_mem_free(server->mctx, server->version);
   10665 	}
   10666 	if (server->hostname != NULL) {
   10667 		isc_mem_free(server->mctx, server->hostname);
   10668 	}
   10669 
   10670 	if (server->zonemgr != NULL) {
   10671 		dns_zonemgr_detach(&server->zonemgr);
   10672 	}
   10673 
   10674 	dst_lib_destroy();
   10675 
   10676 	INSIST(ISC_LIST_EMPTY(server->kasplist));
   10677 	INSIST(ISC_LIST_EMPTY(server->keystorelist));
   10678 	INSIST(ISC_LIST_EMPTY(server->viewlist));
   10679 	INSIST(ISC_LIST_EMPTY(server->cachelist));
   10680 
   10681 	if (server->tlsctx_server_cache != NULL) {
   10682 		isc_tlsctx_cache_detach(&server->tlsctx_server_cache);
   10683 	}
   10684 
   10685 	if (server->tlsctx_client_cache != NULL) {
   10686 		isc_tlsctx_cache_detach(&server->tlsctx_client_cache);
   10687 	}
   10688 
   10689 	server->magic = 0;
   10690 	isc_mem_put(server->mctx, server, sizeof(*server));
   10691 	*serverp = NULL;
   10692 }
   10693 
   10694 static void
   10695 fatal(const char *msg, isc_result_t result) {
   10696 	if (named_g_loopmgr_running) {
   10697 		isc_loopmgr_pause(named_g_loopmgr);
   10698 	}
   10699 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10700 		      NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL, "%s: %s", msg,
   10701 		      isc_result_totext(result));
   10702 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10703 		      NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL,
   10704 		      "exiting (due to fatal error)");
   10705 	named_os_shutdown();
   10706 	_exit(EXIT_FAILURE);
   10707 }
   10708 
   10709 static isc_result_t
   10710 loadconfig(named_server_t *server) {
   10711 	isc_result_t result;
   10712 	result = load_configuration(named_g_conffile, server, false);
   10713 	if (result == ISC_R_SUCCESS) {
   10714 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10715 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   10716 			      "reloading configuration succeeded");
   10717 	} else {
   10718 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10719 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   10720 			      "reloading configuration failed: %s",
   10721 			      isc_result_totext(result));
   10722 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
   10723 	}
   10724 
   10725 	return result;
   10726 }
   10727 
   10728 static isc_result_t
   10729 reload(named_server_t *server) {
   10730 	isc_result_t result;
   10731 
   10732 	atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
   10733 
   10734 	named_os_notify_systemd("RELOADING=1\n"
   10735 				"MONOTONIC_USEC=%" PRIu64 "\n"
   10736 				"STATUS=reload command received\n",
   10737 				(uint64_t)isc_time_monotonic() / NS_PER_US);
   10738 
   10739 	CHECK(loadconfig(server));
   10740 
   10741 	result = load_zones(server, false);
   10742 	if (result == ISC_R_SUCCESS) {
   10743 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10744 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   10745 			      "reloading zones succeeded");
   10746 	} else {
   10747 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10748 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   10749 			      "reloading zones failed: %s",
   10750 			      isc_result_totext(result));
   10751 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
   10752 	}
   10753 cleanup:
   10754 	named_os_notify_systemd("READY=1\n"
   10755 				"STATUS=reload command finished: %s\n",
   10756 				isc_result_totext(result));
   10757 
   10758 	return result;
   10759 }
   10760 
   10761 /*
   10762  * Handle a reload event (from SIGHUP).
   10763  */
   10764 static void
   10765 named_server_reload(void *arg) {
   10766 	named_server_t *server = (named_server_t *)arg;
   10767 
   10768 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10769 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   10770 		      "received SIGHUP signal to reload zones");
   10771 	(void)reload(server);
   10772 }
   10773 
   10774 void
   10775 named_server_reloadwanted(void *arg, int signum) {
   10776 	named_server_t *server = (named_server_t *)arg;
   10777 
   10778 	REQUIRE(signum == SIGHUP);
   10779 
   10780 	isc_async_run(named_g_mainloop, named_server_reload, server);
   10781 }
   10782 
   10783 #ifdef JEMALLOC_API_SUPPORTED
   10784 static isc_result_t
   10785 memprof_toggle(bool active) {
   10786 	if (mallctl("prof.active", NULL, NULL, &active, sizeof(active)) != 0) {
   10787 		return ISC_R_FAILURE;
   10788 	}
   10789 
   10790 	return ISC_R_SUCCESS;
   10791 }
   10792 
   10793 static isc_result_t
   10794 memprof_dump(void) {
   10795 	if (mallctl("prof.dump", NULL, NULL, NULL, 0) != 0) {
   10796 		return ISC_R_FAILURE;
   10797 	}
   10798 
   10799 	return ISC_R_SUCCESS;
   10800 }
   10801 #else
   10802 static isc_result_t
   10803 memprof_toggle(bool active) {
   10804 	UNUSED(active);
   10805 
   10806 	return ISC_R_NOTIMPLEMENTED;
   10807 }
   10808 
   10809 static isc_result_t
   10810 memprof_dump(void) {
   10811 	return ISC_R_NOTIMPLEMENTED;
   10812 }
   10813 
   10814 #endif /* JEMALLOC_API_SUPPORTED */
   10815 
   10816 void
   10817 named_server_scan_interfaces(named_server_t *server) {
   10818 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   10819 		      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
   10820 		      "automatic interface rescan");
   10821 
   10822 	ns_interfacemgr_scan(server->interfacemgr, true, false);
   10823 }
   10824 
   10825 /*
   10826  * Get the next token from lexer 'lex'.
   10827  *
   10828  * NOTE: the token value for string tokens always uses the same pointer
   10829  * value.  Multiple calls to this function on the same lexer will always
   10830  * return either that value (lex->data) or NULL. It is necessary to copy
   10831  * the token into local storage if it needs to be referenced after the next
   10832  * call to next_token().
   10833  */
   10834 static char *
   10835 next_token(isc_lex_t *lex, isc_buffer_t **text) {
   10836 	isc_result_t result;
   10837 	isc_token_t token;
   10838 
   10839 	token.type = isc_tokentype_unknown;
   10840 	result = isc_lex_gettoken(lex, ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING,
   10841 				  &token);
   10842 
   10843 	switch (result) {
   10844 	case ISC_R_NOMORE:
   10845 		(void)isc_lex_close(lex);
   10846 		break;
   10847 	case ISC_R_SUCCESS:
   10848 		if (token.type == isc_tokentype_eof) {
   10849 			(void)isc_lex_close(lex);
   10850 		}
   10851 		break;
   10852 	case ISC_R_NOSPACE:
   10853 		if (text != NULL) {
   10854 			(void)putstr(text, "token too large");
   10855 			(void)putnull(text);
   10856 		}
   10857 		return NULL;
   10858 	default:
   10859 		if (text != NULL) {
   10860 			(void)putstr(text, isc_result_totext(result));
   10861 			(void)putnull(text);
   10862 		}
   10863 		return NULL;
   10864 	}
   10865 
   10866 	if (token.type == isc_tokentype_string ||
   10867 	    token.type == isc_tokentype_qstring)
   10868 	{
   10869 		return token.value.as_textregion.base;
   10870 	}
   10871 
   10872 	return NULL;
   10873 }
   10874 
   10875 /*
   10876  * Find the zone specified in the control channel command, if any.
   10877  * If a zone is specified, point '*zonep' at it, otherwise
   10878  * set '*zonep' to NULL, and f 'zonename' is not NULL, copy
   10879  * the zone name into it (N.B. 'zonename' must have space to hold
   10880  * a full DNS name).
   10881  *
   10882  * If 'zonetxt' is set, the caller has already pulled a token
   10883  * off the command line that is to be used as the zone name. (This
   10884  * is sometimes done when it's necessary to check for an optional
   10885  * argument before the zone name, as in "rndc sync [-clean] zone".)
   10886  */
   10887 static isc_result_t
   10888 zone_from_args(named_server_t *server, isc_lex_t *lex, const char *zonetxt,
   10889 	       dns_zone_t **zonep, char *zonename, isc_buffer_t **text,
   10890 	       bool skip) {
   10891 	char *ptr;
   10892 	char *classtxt;
   10893 	const char *viewtxt = NULL;
   10894 	dns_fixedname_t fname;
   10895 	dns_name_t *name;
   10896 	isc_result_t result;
   10897 	dns_view_t *view = NULL;
   10898 	dns_rdataclass_t rdclass;
   10899 	char problem[DNS_NAME_FORMATSIZE + 500] = "";
   10900 	char zonebuf[DNS_NAME_FORMATSIZE];
   10901 	bool redirect = false;
   10902 
   10903 	REQUIRE(zonep != NULL && *zonep == NULL);
   10904 
   10905 	if (skip) {
   10906 		/* Skip the command name. */
   10907 		ptr = next_token(lex, text);
   10908 		if (ptr == NULL) {
   10909 			return ISC_R_UNEXPECTEDEND;
   10910 		}
   10911 	}
   10912 
   10913 	/* Look for the zone name. */
   10914 	if (zonetxt == NULL) {
   10915 		zonetxt = next_token(lex, text);
   10916 	}
   10917 	if (zonetxt == NULL) {
   10918 		return ISC_R_SUCCESS;
   10919 	}
   10920 
   10921 	/* Copy zonetxt because it'll be overwritten by next_token() */
   10922 	/* To locate a zone named "-redirect" use "-redirect." */
   10923 	if (strcmp(zonetxt, "-redirect") == 0) {
   10924 		redirect = true;
   10925 		strlcpy(zonebuf, ".", DNS_NAME_FORMATSIZE);
   10926 	} else {
   10927 		strlcpy(zonebuf, zonetxt, DNS_NAME_FORMATSIZE);
   10928 	}
   10929 	if (zonename != NULL) {
   10930 		strlcpy(zonename, redirect ? "." : zonetxt,
   10931 			DNS_NAME_FORMATSIZE);
   10932 	}
   10933 
   10934 	name = dns_fixedname_initname(&fname);
   10935 	CHECK(dns_name_fromstring(name, zonebuf, dns_rootname, 0, NULL));
   10936 
   10937 	/* Look for the optional class name. */
   10938 	classtxt = next_token(lex, text);
   10939 	if (classtxt != NULL) {
   10940 		isc_textregion_t r;
   10941 		r.base = classtxt;
   10942 		r.length = strlen(classtxt);
   10943 		CHECK(dns_rdataclass_fromtext(&rdclass, &r));
   10944 
   10945 		/* Look for the optional view name. */
   10946 		viewtxt = next_token(lex, text);
   10947 	} else {
   10948 		rdclass = dns_rdataclass_in;
   10949 	}
   10950 
   10951 	if (viewtxt == NULL) {
   10952 		if (redirect) {
   10953 			result = dns_viewlist_find(&server->viewlist,
   10954 						   "_default",
   10955 						   dns_rdataclass_in, &view);
   10956 			if (result != ISC_R_SUCCESS || view->redirect == NULL) {
   10957 				result = ISC_R_NOTFOUND;
   10958 				snprintf(problem, sizeof(problem),
   10959 					 "redirect zone not found in "
   10960 					 "_default view");
   10961 			} else {
   10962 				dns_zone_attach(view->redirect, zonep);
   10963 				result = ISC_R_SUCCESS;
   10964 			}
   10965 		} else {
   10966 			result = dns_viewlist_findzone(&server->viewlist, name,
   10967 						       classtxt == NULL,
   10968 						       rdclass, zonep);
   10969 			if (result == ISC_R_NOTFOUND) {
   10970 				snprintf(problem, sizeof(problem),
   10971 					 "no matching zone '%s' in any view",
   10972 					 zonebuf);
   10973 			} else if (result == ISC_R_MULTIPLE) {
   10974 				snprintf(problem, sizeof(problem),
   10975 					 "zone '%s' was found in multiple "
   10976 					 "views",
   10977 					 zonebuf);
   10978 			}
   10979 		}
   10980 	} else {
   10981 		result = dns_viewlist_find(&server->viewlist, viewtxt, rdclass,
   10982 					   &view);
   10983 		if (result != ISC_R_SUCCESS) {
   10984 			snprintf(problem, sizeof(problem),
   10985 				 "no matching view '%s'", viewtxt);
   10986 			goto report;
   10987 		}
   10988 
   10989 		if (redirect) {
   10990 			if (view->redirect != NULL) {
   10991 				dns_zone_attach(view->redirect, zonep);
   10992 				result = ISC_R_SUCCESS;
   10993 			} else {
   10994 				result = ISC_R_NOTFOUND;
   10995 			}
   10996 		} else {
   10997 			result = dns_view_findzone(view, name, DNS_ZTFIND_EXACT,
   10998 						   zonep);
   10999 		}
   11000 		if (result != ISC_R_SUCCESS) {
   11001 			snprintf(problem, sizeof(problem),
   11002 				 "no matching zone '%s' in view '%s'", zonebuf,
   11003 				 viewtxt);
   11004 		}
   11005 	}
   11006 
   11007 	/* Partial match? */
   11008 	if (result != ISC_R_SUCCESS && *zonep != NULL) {
   11009 		dns_zone_detach(zonep);
   11010 	}
   11011 	if (result == DNS_R_PARTIALMATCH) {
   11012 		result = ISC_R_NOTFOUND;
   11013 	}
   11014 report:
   11015 	if (result != ISC_R_SUCCESS) {
   11016 		isc_result_t tresult;
   11017 
   11018 		tresult = putstr(text, problem);
   11019 		if (tresult == ISC_R_SUCCESS) {
   11020 			(void)putnull(text);
   11021 		}
   11022 	}
   11023 
   11024 cleanup:
   11025 	if (view != NULL) {
   11026 		dns_view_detach(&view);
   11027 	}
   11028 
   11029 	return result;
   11030 }
   11031 
   11032 /*
   11033  * Act on a "retransfer" command from the command channel.
   11034  */
   11035 isc_result_t
   11036 named_server_retransfercommand(named_server_t *server, isc_lex_t *lex,
   11037 			       isc_buffer_t **text) {
   11038 	isc_result_t result;
   11039 	const char *arg = NULL;
   11040 	dns_zone_t *zone = NULL;
   11041 	dns_zone_t *raw = NULL;
   11042 	dns_zonetype_t type;
   11043 	bool force = false;
   11044 
   11045 	REQUIRE(text != NULL);
   11046 
   11047 	/* Skip the command name. */
   11048 	(void)next_token(lex, text);
   11049 
   11050 	arg = next_token(lex, text);
   11051 	if (arg != NULL && (strcmp(arg, "-force") == 0)) {
   11052 		force = true;
   11053 		arg = next_token(lex, text);
   11054 	}
   11055 
   11056 	result = zone_from_args(server, lex, arg, &zone, NULL, text, false);
   11057 	if (result != ISC_R_SUCCESS) {
   11058 		return result;
   11059 	}
   11060 	if (zone == NULL) {
   11061 		return ISC_R_UNEXPECTEDEND;
   11062 	}
   11063 	dns_zone_getraw(zone, &raw);
   11064 	if (raw != NULL) {
   11065 		dns_zone_detach(&zone);
   11066 		dns_zone_attach(raw, &zone);
   11067 		dns_zone_detach(&raw);
   11068 	}
   11069 	type = dns_zone_gettype(zone);
   11070 	if (type == dns_zone_secondary || type == dns_zone_mirror ||
   11071 	    type == dns_zone_stub ||
   11072 	    (type == dns_zone_redirect &&
   11073 	     dns_zone_getredirecttype(zone) == dns_zone_secondary))
   11074 	{
   11075 		if (force) {
   11076 			dns_zone_stopxfr(zone);
   11077 		}
   11078 		dns_zone_forcexfr(zone);
   11079 	} else {
   11080 		(void)putstr(text, "retransfer: inappropriate zone type: ");
   11081 		(void)putstr(text, dns_zonetype_name(type));
   11082 		if (type == dns_zone_redirect) {
   11083 			type = dns_zone_getredirecttype(zone);
   11084 			(void)putstr(text, "(");
   11085 			(void)putstr(text, dns_zonetype_name(type));
   11086 			(void)putstr(text, ")");
   11087 		}
   11088 		(void)putnull(text);
   11089 		result = ISC_R_FAILURE;
   11090 	}
   11091 	dns_zone_detach(&zone);
   11092 	return result;
   11093 }
   11094 
   11095 /*
   11096  * Act on a "reload" command from the command channel.
   11097  */
   11098 isc_result_t
   11099 named_server_reloadcommand(named_server_t *server, isc_lex_t *lex,
   11100 			   isc_buffer_t **text) {
   11101 	isc_result_t result;
   11102 	dns_zone_t *zone = NULL;
   11103 	dns_zonetype_t type;
   11104 	const char *msg = NULL;
   11105 
   11106 	REQUIRE(text != NULL);
   11107 
   11108 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
   11109 	if (result != ISC_R_SUCCESS) {
   11110 		return result;
   11111 	}
   11112 	if (zone == NULL) {
   11113 		result = reload(server);
   11114 		if (result == ISC_R_SUCCESS) {
   11115 			msg = "server reload successful";
   11116 		}
   11117 	} else {
   11118 		type = dns_zone_gettype(zone);
   11119 		if (type == dns_zone_secondary || type == dns_zone_mirror ||
   11120 		    type == dns_zone_stub)
   11121 		{
   11122 			dns_zone_refresh(zone);
   11123 			dns_zone_detach(&zone);
   11124 			msg = "zone refresh queued";
   11125 		} else {
   11126 			result = dns_zone_load(zone, false);
   11127 			dns_zone_detach(&zone);
   11128 			switch (result) {
   11129 			case ISC_R_SUCCESS:
   11130 				msg = "zone reload successful";
   11131 				break;
   11132 			case DNS_R_CONTINUE:
   11133 				msg = "zone reload queued";
   11134 				result = ISC_R_SUCCESS;
   11135 				break;
   11136 			case DNS_R_UPTODATE:
   11137 				msg = "zone reload up-to-date";
   11138 				result = ISC_R_SUCCESS;
   11139 				break;
   11140 			default:
   11141 				/* failure message will be generated by rndc */
   11142 				break;
   11143 			}
   11144 		}
   11145 	}
   11146 	if (msg != NULL) {
   11147 		(void)putstr(text, msg);
   11148 		(void)putnull(text);
   11149 	}
   11150 	return result;
   11151 }
   11152 
   11153 /*
   11154  * Act on a "reset-stats" command from the command channel.
   11155  */
   11156 isc_result_t
   11157 named_server_resetstatscommand(named_server_t *server, isc_lex_t *lex,
   11158 			       isc_buffer_t **text) {
   11159 	const char *arg = NULL;
   11160 	bool recursive_high_water = false;
   11161 	bool tcp_high_water = false;
   11162 
   11163 	REQUIRE(text != NULL);
   11164 
   11165 	/* Skip the command name. */
   11166 	(void)next_token(lex, text);
   11167 
   11168 	arg = next_token(lex, text);
   11169 	if (arg == NULL) {
   11170 		(void)putstr(text, "reset-stats: argument expected");
   11171 		(void)putnull(text);
   11172 		return ISC_R_UNEXPECTEDEND;
   11173 	}
   11174 	while (arg != NULL) {
   11175 		if (strcmp(arg, "recursive-high-water") == 0) {
   11176 			recursive_high_water = true;
   11177 		} else if (strcmp(arg, "tcp-high-water") == 0) {
   11178 			tcp_high_water = true;
   11179 		} else {
   11180 			(void)putstr(text, "reset-stats: "
   11181 					   "unrecognized argument: ");
   11182 			(void)putstr(text, arg);
   11183 			(void)putnull(text);
   11184 			return ISC_R_FAILURE;
   11185 		}
   11186 		arg = next_token(lex, text);
   11187 	}
   11188 
   11189 	if (recursive_high_water) {
   11190 		isc_stats_set(ns_stats_get(server->sctx->nsstats), 0,
   11191 			      ns_statscounter_recurshighwater);
   11192 	}
   11193 	if (tcp_high_water) {
   11194 		isc_stats_set(ns_stats_get(server->sctx->nsstats), 0,
   11195 			      ns_statscounter_tcphighwater);
   11196 	}
   11197 
   11198 	return ISC_R_SUCCESS;
   11199 }
   11200 
   11201 /*
   11202  * Act on a "reconfig" command from the command channel.
   11203  */
   11204 isc_result_t
   11205 named_server_reconfigcommand(named_server_t *server) {
   11206 	isc_result_t result;
   11207 	atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
   11208 
   11209 	named_os_notify_systemd("RELOADING=1\n"
   11210 				"MONOTONIC_USEC=%" PRIu64 "\n"
   11211 				"STATUS=reconfig command received\n",
   11212 				(uint64_t)isc_time_monotonic() / NS_PER_US);
   11213 
   11214 	CHECK(loadconfig(server));
   11215 
   11216 	result = load_zones(server, true);
   11217 	if (result == ISC_R_SUCCESS) {
   11218 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   11219 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   11220 			      "scheduled loading new zones");
   11221 	} else {
   11222 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   11223 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   11224 			      "loading new zones failed: %s",
   11225 			      isc_result_totext(result));
   11226 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
   11227 	}
   11228 cleanup:
   11229 	named_os_notify_systemd("READY=1\n"
   11230 				"STATUS=reconfig command finished: %s\n",
   11231 				isc_result_totext(result));
   11232 
   11233 	return result;
   11234 }
   11235 
   11236 /*
   11237  * Act on a "notify" command from the command channel.
   11238  */
   11239 isc_result_t
   11240 named_server_notifycommand(named_server_t *server, isc_lex_t *lex,
   11241 			   isc_buffer_t **text) {
   11242 	isc_result_t result;
   11243 	dns_zone_t *zone = NULL;
   11244 	const char msg[] = "zone notify queued";
   11245 
   11246 	REQUIRE(text != NULL);
   11247 
   11248 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
   11249 	if (result != ISC_R_SUCCESS) {
   11250 		return result;
   11251 	}
   11252 	if (zone == NULL) {
   11253 		return ISC_R_UNEXPECTEDEND;
   11254 	}
   11255 
   11256 	dns_zone_notify(zone, true);
   11257 	dns_zone_detach(&zone);
   11258 	(void)putstr(text, msg);
   11259 	(void)putnull(text);
   11260 
   11261 	return ISC_R_SUCCESS;
   11262 }
   11263 
   11264 /*
   11265  * Act on a "refresh" command from the command channel.
   11266  */
   11267 isc_result_t
   11268 named_server_refreshcommand(named_server_t *server, isc_lex_t *lex,
   11269 			    isc_buffer_t **text) {
   11270 	isc_result_t result;
   11271 	dns_zone_t *zone = NULL, *raw = NULL;
   11272 	const char msg1[] = "zone refresh queued";
   11273 	const char msg2[] = "not a secondary, mirror, or stub zone";
   11274 	dns_zonetype_t type;
   11275 
   11276 	REQUIRE(text != NULL);
   11277 
   11278 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
   11279 	if (result != ISC_R_SUCCESS) {
   11280 		return result;
   11281 	}
   11282 	if (zone == NULL) {
   11283 		return ISC_R_UNEXPECTEDEND;
   11284 	}
   11285 
   11286 	dns_zone_getraw(zone, &raw);
   11287 	if (raw != NULL) {
   11288 		dns_zone_detach(&zone);
   11289 		dns_zone_attach(raw, &zone);
   11290 		dns_zone_detach(&raw);
   11291 	}
   11292 
   11293 	type = dns_zone_gettype(zone);
   11294 	if (type == dns_zone_secondary || type == dns_zone_mirror ||
   11295 	    type == dns_zone_stub)
   11296 	{
   11297 		dns_zone_refresh(zone);
   11298 		dns_zone_detach(&zone);
   11299 		(void)putstr(text, msg1);
   11300 		(void)putnull(text);
   11301 		return ISC_R_SUCCESS;
   11302 	}
   11303 
   11304 	dns_zone_detach(&zone);
   11305 	(void)putstr(text, msg2);
   11306 	(void)putnull(text);
   11307 	return ISC_R_FAILURE;
   11308 }
   11309 
   11310 isc_result_t
   11311 named_server_setortoggle(named_server_t *server, const char *optname,
   11312 			 unsigned int option, isc_lex_t *lex) {
   11313 	bool prev, value;
   11314 	char *ptr = NULL;
   11315 
   11316 	/* Skip the command name. */
   11317 	ptr = next_token(lex, NULL);
   11318 	if (ptr == NULL) {
   11319 		return ISC_R_UNEXPECTEDEND;
   11320 	}
   11321 
   11322 	prev = ns_server_getoption(server->sctx, option);
   11323 
   11324 	ptr = next_token(lex, NULL);
   11325 	if (ptr == NULL) {
   11326 		value = !prev;
   11327 	} else if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
   11328 		   !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
   11329 	{
   11330 		value = true;
   11331 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
   11332 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
   11333 	{
   11334 		value = false;
   11335 	} else {
   11336 		return DNS_R_SYNTAX;
   11337 	}
   11338 
   11339 	if (value == prev) {
   11340 		return ISC_R_SUCCESS;
   11341 	}
   11342 
   11343 	ns_server_setoption(server->sctx, option, value);
   11344 
   11345 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   11346 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, "%s is now %s",
   11347 		      optname, value ? "on" : "off");
   11348 	return ISC_R_SUCCESS;
   11349 }
   11350 
   11351 static isc_result_t
   11352 listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
   11353 		      cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
   11354 		      isc_tlsctx_cache_t *tlsctx_cache,
   11355 		      ns_listenlist_t **target) {
   11356 	isc_result_t result;
   11357 	const cfg_listelt_t *element;
   11358 	ns_listenlist_t *dlist = NULL;
   11359 
   11360 	REQUIRE(target != NULL && *target == NULL);
   11361 
   11362 	result = ns_listenlist_create(mctx, &dlist);
   11363 	if (result != ISC_R_SUCCESS) {
   11364 		return result;
   11365 	}
   11366 
   11367 	for (element = cfg_list_first(listenlist); element != NULL;
   11368 	     element = cfg_list_next(element))
   11369 	{
   11370 		ns_listenelt_t *delt = NULL;
   11371 		const cfg_obj_t *listener = cfg_listelt_value(element);
   11372 		result = listenelt_fromconfig(listener, config, actx, mctx,
   11373 					      family, tlsctx_cache, &delt);
   11374 		if (result != ISC_R_SUCCESS) {
   11375 			goto cleanup;
   11376 		}
   11377 		ISC_LIST_APPEND(dlist->elts, delt, link);
   11378 	}
   11379 	*target = dlist;
   11380 	return ISC_R_SUCCESS;
   11381 
   11382 cleanup:
   11383 	ns_listenlist_detach(&dlist);
   11384 	return result;
   11385 }
   11386 
   11387 static const cfg_obj_t *
   11388 find_maplist(const cfg_obj_t *config, const char *listname, const char *name) {
   11389 	isc_result_t result;
   11390 	const cfg_obj_t *maplist = NULL;
   11391 	const cfg_listelt_t *elt = NULL;
   11392 
   11393 	REQUIRE(config != NULL);
   11394 	REQUIRE(name != NULL);
   11395 
   11396 	result = cfg_map_get(config, listname, &maplist);
   11397 	if (result != ISC_R_SUCCESS) {
   11398 		return NULL;
   11399 	}
   11400 
   11401 	for (elt = cfg_list_first(maplist); elt != NULL;
   11402 	     elt = cfg_list_next(elt))
   11403 	{
   11404 		const cfg_obj_t *map = cfg_listelt_value(elt);
   11405 		if (strcasecmp(cfg_obj_asstring(cfg_map_getname(map)), name) ==
   11406 		    0)
   11407 		{
   11408 			return map;
   11409 		}
   11410 	}
   11411 
   11412 	return NULL;
   11413 }
   11414 
   11415 /*
   11416  * Create a listen list from the corresponding configuration
   11417  * data structure.
   11418  */
   11419 static isc_result_t
   11420 listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
   11421 		     cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
   11422 		     isc_tlsctx_cache_t *tlsctx_cache,
   11423 		     ns_listenelt_t **target) {
   11424 	isc_result_t result;
   11425 	const cfg_obj_t *ltup = NULL;
   11426 	const cfg_obj_t *tlsobj = NULL, *httpobj = NULL;
   11427 	const cfg_obj_t *portobj = NULL;
   11428 	const cfg_obj_t *http_server = NULL;
   11429 	const cfg_obj_t *proxyobj = NULL;
   11430 	in_port_t port = 0;
   11431 	const char *key = NULL, *cert = NULL, *ca_file = NULL,
   11432 		   *dhparam_file = NULL, *ciphers = NULL, *cipher_suites = NULL;
   11433 	bool tls_prefer_server_ciphers = false,
   11434 	     tls_prefer_server_ciphers_set = false;
   11435 	bool tls_session_tickets = false, tls_session_tickets_set = false;
   11436 	bool do_tls = false, no_tls = false, http = false;
   11437 	ns_listenelt_t *delt = NULL;
   11438 	uint32_t tls_protos = 0;
   11439 	ns_listen_tls_params_t tls_params = { 0 };
   11440 	const char *tlsname = NULL;
   11441 	isc_nm_proxy_type_t proxy = ISC_NM_PROXY_NONE;
   11442 
   11443 	REQUIRE(target != NULL && *target == NULL);
   11444 
   11445 	ltup = cfg_tuple_get(listener, "tuple");
   11446 	RUNTIME_CHECK(ltup != NULL);
   11447 
   11448 	tlsobj = cfg_tuple_get(ltup, "tls");
   11449 	if (tlsobj != NULL && cfg_obj_isstring(tlsobj)) {
   11450 		tlsname = cfg_obj_asstring(tlsobj);
   11451 
   11452 		if (strcasecmp(tlsname, "none") == 0) {
   11453 			no_tls = true;
   11454 		} else if (strcasecmp(tlsname, "ephemeral") == 0) {
   11455 			do_tls = true;
   11456 		} else {
   11457 			const cfg_obj_t *keyobj = NULL, *certobj = NULL,
   11458 					*ca_obj = NULL, *dhparam_obj = NULL;
   11459 			const cfg_obj_t *tlsmap = NULL;
   11460 			const cfg_obj_t *tls_proto_list = NULL;
   11461 			const cfg_obj_t *ciphers_obj = NULL;
   11462 			const cfg_obj_t *cipher_suites_obj = NULL;
   11463 			const cfg_obj_t *prefer_server_ciphers_obj = NULL;
   11464 			const cfg_obj_t *session_tickets_obj = NULL;
   11465 
   11466 			do_tls = true;
   11467 
   11468 			tlsmap = find_maplist(config, "tls", tlsname);
   11469 			if (tlsmap == NULL) {
   11470 				cfg_obj_log(tlsobj, named_g_lctx, ISC_LOG_ERROR,
   11471 					    "tls '%s' is not defined",
   11472 					    cfg_obj_asstring(tlsobj));
   11473 				return ISC_R_FAILURE;
   11474 			}
   11475 
   11476 			CHECK(cfg_map_get(tlsmap, "key-file", &keyobj));
   11477 			key = cfg_obj_asstring(keyobj);
   11478 
   11479 			CHECK(cfg_map_get(tlsmap, "cert-file", &certobj));
   11480 			cert = cfg_obj_asstring(certobj);
   11481 
   11482 			if (cfg_map_get(tlsmap, "ca-file", &ca_obj) ==
   11483 			    ISC_R_SUCCESS)
   11484 			{
   11485 				ca_file = cfg_obj_asstring(ca_obj);
   11486 			}
   11487 
   11488 			if (cfg_map_get(tlsmap, "protocols", &tls_proto_list) ==
   11489 			    ISC_R_SUCCESS)
   11490 			{
   11491 				const cfg_listelt_t *proto = NULL;
   11492 				INSIST(tls_proto_list != NULL);
   11493 				for (proto = cfg_list_first(tls_proto_list);
   11494 				     proto != 0; proto = cfg_list_next(proto))
   11495 				{
   11496 					const cfg_obj_t *tls_proto_obj =
   11497 						cfg_listelt_value(proto);
   11498 					const char *tls_sver =
   11499 						cfg_obj_asstring(tls_proto_obj);
   11500 					const isc_tls_protocol_version_t ver =
   11501 						isc_tls_protocol_name_to_version(
   11502 							tls_sver);
   11503 
   11504 					INSIST(ver !=
   11505 					       ISC_TLS_PROTO_VER_UNDEFINED);
   11506 					INSIST(isc_tls_protocol_supported(ver));
   11507 					tls_protos |= ver;
   11508 				}
   11509 			}
   11510 
   11511 			if (cfg_map_get(tlsmap, "dhparam-file", &dhparam_obj) ==
   11512 			    ISC_R_SUCCESS)
   11513 			{
   11514 				dhparam_file = cfg_obj_asstring(dhparam_obj);
   11515 			}
   11516 
   11517 			if (cfg_map_get(tlsmap, "ciphers", &ciphers_obj) ==
   11518 			    ISC_R_SUCCESS)
   11519 			{
   11520 				ciphers = cfg_obj_asstring(ciphers_obj);
   11521 			}
   11522 
   11523 			if (cfg_map_get(tlsmap, "cipher-suites",
   11524 					&cipher_suites_obj) == ISC_R_SUCCESS)
   11525 			{
   11526 				cipher_suites =
   11527 					cfg_obj_asstring(cipher_suites_obj);
   11528 			}
   11529 
   11530 			if (cfg_map_get(tlsmap, "prefer-server-ciphers",
   11531 					&prefer_server_ciphers_obj) ==
   11532 			    ISC_R_SUCCESS)
   11533 			{
   11534 				tls_prefer_server_ciphers = cfg_obj_asboolean(
   11535 					prefer_server_ciphers_obj);
   11536 				tls_prefer_server_ciphers_set = true;
   11537 			}
   11538 
   11539 			if (cfg_map_get(tlsmap, "session-tickets",
   11540 					&session_tickets_obj) == ISC_R_SUCCESS)
   11541 			{
   11542 				tls_session_tickets =
   11543 					cfg_obj_asboolean(session_tickets_obj);
   11544 				tls_session_tickets_set = true;
   11545 			}
   11546 		}
   11547 	}
   11548 
   11549 	tls_params = (ns_listen_tls_params_t){
   11550 		.name = tlsname,
   11551 		.key = key,
   11552 		.cert = cert,
   11553 		.ca_file = ca_file,
   11554 		.protocols = tls_protos,
   11555 		.dhparam_file = dhparam_file,
   11556 		.ciphers = ciphers,
   11557 		.cipher_suites = cipher_suites,
   11558 		.prefer_server_ciphers = tls_prefer_server_ciphers,
   11559 		.prefer_server_ciphers_set = tls_prefer_server_ciphers_set,
   11560 		.session_tickets = tls_session_tickets,
   11561 		.session_tickets_set = tls_session_tickets_set
   11562 	};
   11563 
   11564 	httpobj = cfg_tuple_get(ltup, "http");
   11565 	if (httpobj != NULL && cfg_obj_isstring(httpobj)) {
   11566 		const char *httpname = cfg_obj_asstring(httpobj);
   11567 
   11568 		if (!do_tls && !no_tls) {
   11569 			return ISC_R_FAILURE;
   11570 		}
   11571 
   11572 		http_server = find_maplist(config, "http", httpname);
   11573 		if (http_server == NULL && strcasecmp(httpname, "default") != 0)
   11574 		{
   11575 			cfg_obj_log(httpobj, named_g_lctx, ISC_LOG_ERROR,
   11576 				    "http '%s' is not defined",
   11577 				    cfg_obj_asstring(httpobj));
   11578 			return ISC_R_FAILURE;
   11579 		}
   11580 
   11581 		http = true;
   11582 	}
   11583 
   11584 	portobj = cfg_tuple_get(ltup, "port");
   11585 	if (!cfg_obj_isuint32(portobj)) {
   11586 		if (http && do_tls) {
   11587 			if (named_g_httpsport != 0) {
   11588 				port = named_g_httpsport;
   11589 			} else {
   11590 				result = named_config_getport(
   11591 					config, "https-port", &port);
   11592 				if (result != ISC_R_SUCCESS) {
   11593 					return result;
   11594 				}
   11595 			}
   11596 		} else if (http && !do_tls) {
   11597 			if (named_g_httpport != 0) {
   11598 				port = named_g_httpport;
   11599 			} else {
   11600 				result = named_config_getport(
   11601 					config, "http-port", &port);
   11602 				if (result != ISC_R_SUCCESS) {
   11603 					return result;
   11604 				}
   11605 			}
   11606 		} else if (do_tls) {
   11607 			if (named_g_tlsport != 0) {
   11608 				port = named_g_tlsport;
   11609 			} else {
   11610 				result = named_config_getport(
   11611 					config, "tls-port", &port);
   11612 				if (result != ISC_R_SUCCESS) {
   11613 					return result;
   11614 				}
   11615 			}
   11616 		} else {
   11617 			if (named_g_port != 0) {
   11618 				port = named_g_port;
   11619 			} else {
   11620 				result = named_config_getport(config, "port",
   11621 							      &port);
   11622 				if (result != ISC_R_SUCCESS) {
   11623 					return result;
   11624 				}
   11625 			}
   11626 		}
   11627 	} else {
   11628 		if (cfg_obj_asuint32(portobj) >= UINT16_MAX) {
   11629 			return ISC_R_RANGE;
   11630 		}
   11631 		port = (in_port_t)cfg_obj_asuint32(portobj);
   11632 	}
   11633 
   11634 	proxyobj = cfg_tuple_get(ltup, "proxy");
   11635 	if (proxyobj != NULL && cfg_obj_isstring(proxyobj)) {
   11636 		const char *proxyval = cfg_obj_asstring(proxyobj);
   11637 
   11638 		if (strcasecmp(proxyval, "encrypted") == 0) {
   11639 			INSIST(do_tls == true);
   11640 			proxy = ISC_NM_PROXY_ENCRYPTED;
   11641 		} else if (strcasecmp(proxyval, "plain") == 0) {
   11642 			proxy = ISC_NM_PROXY_PLAIN;
   11643 		} else {
   11644 			UNREACHABLE();
   11645 		}
   11646 	}
   11647 
   11648 #ifdef HAVE_LIBNGHTTP2
   11649 	if (http) {
   11650 		CHECK(listenelt_http(http_server, family, do_tls, &tls_params,
   11651 				     tlsctx_cache, port, mctx, proxy, &delt));
   11652 	}
   11653 #endif /* HAVE_LIBNGHTTP2 */
   11654 
   11655 	if (!http) {
   11656 		CHECK(ns_listenelt_create(mctx, port, NULL, family, do_tls,
   11657 					  &tls_params, tlsctx_cache, proxy,
   11658 					  &delt));
   11659 	}
   11660 
   11661 	result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"), config,
   11662 				    named_g_lctx, actx, mctx, family,
   11663 				    &delt->acl);
   11664 	if (result != ISC_R_SUCCESS) {
   11665 		ns_listenelt_destroy(delt);
   11666 		return result;
   11667 	}
   11668 	*target = delt;
   11669 
   11670 cleanup:
   11671 	return result;
   11672 }
   11673 
   11674 #ifdef HAVE_LIBNGHTTP2
   11675 static isc_result_t
   11676 listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls,
   11677 	       const ns_listen_tls_params_t *tls_params,
   11678 	       isc_tlsctx_cache_t *tlsctx_cache, in_port_t port,
   11679 	       isc_mem_t *mctx, isc_nm_proxy_type_t proxy,
   11680 	       ns_listenelt_t **target) {
   11681 	isc_result_t result = ISC_R_SUCCESS;
   11682 	ns_listenelt_t *delt = NULL;
   11683 	char **endpoints = NULL;
   11684 	const cfg_obj_t *eplist = NULL;
   11685 	const cfg_listelt_t *elt = NULL;
   11686 	size_t len = 1, i = 0;
   11687 	uint32_t max_clients = named_g_http_listener_clients;
   11688 	uint32_t max_streams = named_g_http_streams_per_conn;
   11689 
   11690 	REQUIRE(target != NULL && *target == NULL);
   11691 
   11692 	if (tls) {
   11693 		INSIST(tls_params != NULL);
   11694 		INSIST((tls_params->key == NULL) == (tls_params->cert == NULL));
   11695 	}
   11696 
   11697 	if (port == 0) {
   11698 		port = tls ? named_g_httpsport : named_g_httpport;
   11699 	}
   11700 
   11701 	/*
   11702 	 * If "default" was used, we set up the default endpoint
   11703 	 * of "/dns-query".
   11704 	 */
   11705 	if (http != NULL) {
   11706 		const cfg_obj_t *cfg_max_clients = NULL;
   11707 		const cfg_obj_t *cfg_max_streams = NULL;
   11708 
   11709 		if (cfg_map_get(http, "endpoints", &eplist) == ISC_R_SUCCESS) {
   11710 			INSIST(eplist != NULL);
   11711 			len = cfg_list_length(eplist, false);
   11712 		}
   11713 
   11714 		if (cfg_map_get(http, "listener-clients", &cfg_max_clients) ==
   11715 		    ISC_R_SUCCESS)
   11716 		{
   11717 			INSIST(cfg_max_clients != NULL);
   11718 			max_clients = cfg_obj_asuint32(cfg_max_clients);
   11719 		}
   11720 
   11721 		if (cfg_map_get(http, "streams-per-connection",
   11722 				&cfg_max_streams) == ISC_R_SUCCESS)
   11723 		{
   11724 			INSIST(cfg_max_streams != NULL);
   11725 			max_streams = cfg_obj_asuint32(cfg_max_streams);
   11726 		}
   11727 	}
   11728 
   11729 	endpoints = isc_mem_allocate(mctx, sizeof(endpoints[0]) * len);
   11730 
   11731 	if (http != NULL && eplist != NULL) {
   11732 		for (elt = cfg_list_first(eplist); elt != NULL;
   11733 		     elt = cfg_list_next(elt))
   11734 		{
   11735 			const cfg_obj_t *ep = cfg_listelt_value(elt);
   11736 			const char *path = cfg_obj_asstring(ep);
   11737 			endpoints[i++] = isc_mem_strdup(mctx, path);
   11738 		}
   11739 	} else {
   11740 		endpoints[i++] = isc_mem_strdup(mctx, ISC_NM_HTTP_DEFAULT_PATH);
   11741 	}
   11742 
   11743 	INSIST(i == len);
   11744 
   11745 	result = ns_listenelt_create_http(
   11746 		mctx, port, NULL, family, tls, tls_params, tlsctx_cache, proxy,
   11747 		endpoints, len, max_clients, max_streams, &delt);
   11748 	if (result != ISC_R_SUCCESS) {
   11749 		goto error;
   11750 	}
   11751 
   11752 	*target = delt;
   11753 
   11754 	return result;
   11755 error:
   11756 	if (delt != NULL) {
   11757 		ns_listenelt_destroy(delt);
   11758 	}
   11759 	return result;
   11760 }
   11761 #endif /* HAVE_LIBNGHTTP2 */
   11762 
   11763 isc_result_t
   11764 named_server_dumpstats(named_server_t *server) {
   11765 	isc_result_t result;
   11766 	FILE *fp = NULL;
   11767 
   11768 	CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
   11769 		"could not open statistics dump file", server->statsfile);
   11770 
   11771 	result = named_stats_dump(server, fp);
   11772 
   11773 cleanup:
   11774 	if (fp != NULL) {
   11775 		(void)isc_stdio_close(fp);
   11776 	}
   11777 	if (result == ISC_R_SUCCESS) {
   11778 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   11779 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   11780 			      "dumpstats complete");
   11781 	} else {
   11782 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   11783 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   11784 			      "dumpstats failed: %s",
   11785 			      isc_result_totext(result));
   11786 	}
   11787 	return result;
   11788 }
   11789 
   11790 static isc_result_t
   11791 add_zone_tolist(dns_zone_t *zone, void *uap) {
   11792 	struct dumpcontext *dctx = uap;
   11793 	struct zonelistentry *zle;
   11794 
   11795 	zle = isc_mem_get(dctx->mctx, sizeof *zle);
   11796 	zle->zone = NULL;
   11797 	dns_zone_attach(zone, &zle->zone);
   11798 	ISC_LINK_INIT(zle, link);
   11799 	ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
   11800 	return ISC_R_SUCCESS;
   11801 }
   11802 
   11803 static isc_result_t
   11804 add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
   11805 	struct viewlistentry *vle;
   11806 	isc_result_t result = ISC_R_SUCCESS;
   11807 
   11808 	/*
   11809 	 * Prevent duplicate views.
   11810 	 */
   11811 	for (vle = ISC_LIST_HEAD(dctx->viewlist); vle != NULL;
   11812 	     vle = ISC_LIST_NEXT(vle, link))
   11813 	{
   11814 		if (vle->view == view) {
   11815 			return ISC_R_SUCCESS;
   11816 		}
   11817 	}
   11818 
   11819 	vle = isc_mem_get(dctx->mctx, sizeof *vle);
   11820 	vle->view = NULL;
   11821 	dns_view_attach(view, &vle->view);
   11822 	ISC_LINK_INIT(vle, link);
   11823 	ISC_LIST_INIT(vle->zonelist);
   11824 	ISC_LIST_APPEND(dctx->viewlist, vle, link);
   11825 	if (dctx->dumpzones) {
   11826 		result = dns_view_apply(view, true, NULL, add_zone_tolist,
   11827 					dctx);
   11828 	}
   11829 	return result;
   11830 }
   11831 
   11832 static void
   11833 dumpcontext_destroy(struct dumpcontext *dctx) {
   11834 	struct viewlistentry *vle;
   11835 	struct zonelistentry *zle;
   11836 
   11837 	vle = ISC_LIST_HEAD(dctx->viewlist);
   11838 	while (vle != NULL) {
   11839 		ISC_LIST_UNLINK(dctx->viewlist, vle, link);
   11840 		zle = ISC_LIST_HEAD(vle->zonelist);
   11841 		while (zle != NULL) {
   11842 			ISC_LIST_UNLINK(vle->zonelist, zle, link);
   11843 			dns_zone_detach(&zle->zone);
   11844 			isc_mem_put(dctx->mctx, zle, sizeof *zle);
   11845 			zle = ISC_LIST_HEAD(vle->zonelist);
   11846 		}
   11847 		dns_view_detach(&vle->view);
   11848 		isc_mem_put(dctx->mctx, vle, sizeof *vle);
   11849 		vle = ISC_LIST_HEAD(dctx->viewlist);
   11850 	}
   11851 	if (dctx->version != NULL) {
   11852 		dns_db_closeversion(dctx->db, &dctx->version, false);
   11853 	}
   11854 	if (dctx->db != NULL) {
   11855 		dns_db_detach(&dctx->db);
   11856 	}
   11857 	if (dctx->cache != NULL) {
   11858 		dns_db_detach(&dctx->cache);
   11859 	}
   11860 	if (dctx->fp != NULL) {
   11861 		(void)isc_stdio_close(dctx->fp);
   11862 	}
   11863 	if (dctx->mdctx != NULL) {
   11864 		dns_dumpctx_detach(&dctx->mdctx);
   11865 	}
   11866 	isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
   11867 }
   11868 
   11869 static void
   11870 dumpdone(void *arg, isc_result_t result) {
   11871 	struct dumpcontext *dctx = arg;
   11872 	char buf[1024 + 32];
   11873 	const dns_master_style_t *style;
   11874 
   11875 	if (result != ISC_R_SUCCESS) {
   11876 		goto cleanup;
   11877 	}
   11878 	if (dctx->mdctx != NULL) {
   11879 		dns_dumpctx_detach(&dctx->mdctx);
   11880 	}
   11881 	if (dctx->view == NULL) {
   11882 		dctx->view = ISC_LIST_HEAD(dctx->viewlist);
   11883 		if (dctx->view == NULL) {
   11884 			goto done;
   11885 		}
   11886 		INSIST(dctx->zone == NULL);
   11887 	} else {
   11888 		goto resume;
   11889 	}
   11890 nextview:
   11891 	fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
   11892 resume:
   11893 	if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) {
   11894 		fprintf(dctx->fp, ";\n; Cache of view '%s' is shared as '%s'\n",
   11895 			dctx->view->view->name,
   11896 			dns_cache_getname(dctx->view->view->cache));
   11897 	} else if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache)
   11898 	{
   11899 		if (dctx->dumpexpired) {
   11900 			style = &dns_master_style_cache_with_expired;
   11901 		} else {
   11902 			style = &dns_master_style_cache;
   11903 		}
   11904 		/* start cache dump */
   11905 		if (dctx->view->view->cachedb != NULL) {
   11906 			dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
   11907 		}
   11908 		if (dctx->cache != NULL) {
   11909 			fprintf(dctx->fp,
   11910 				";\n; Cache dump of view '%s' (cache %s)\n;\n",
   11911 				dctx->view->view->name,
   11912 				dns_cache_getname(dctx->view->view->cache));
   11913 			result = dns_master_dumptostreamasync(
   11914 				dctx->mctx, dctx->cache, NULL, style, dctx->fp,
   11915 				named_g_mainloop, dumpdone, dctx, &dctx->mdctx);
   11916 			if (result == ISC_R_SUCCESS) {
   11917 				return;
   11918 			}
   11919 			if (result == ISC_R_NOTIMPLEMENTED) {
   11920 				fprintf(dctx->fp, "; %s\n",
   11921 					isc_result_totext(result));
   11922 			} else if (result != ISC_R_SUCCESS) {
   11923 				goto cleanup;
   11924 			}
   11925 		}
   11926 	}
   11927 
   11928 	if ((dctx->dumpadb || dctx->dumpfail) && dctx->cache == NULL &&
   11929 	    dctx->view->view->cachedb != NULL)
   11930 	{
   11931 		dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
   11932 	}
   11933 
   11934 	if (dctx->cache != NULL) {
   11935 		if (dctx->dumpadb) {
   11936 			dns_adb_t *adb = NULL;
   11937 			dns_view_getadb(dctx->view->view, &adb);
   11938 			if (adb != NULL) {
   11939 				dns_adb_dump(adb, dctx->fp);
   11940 				dns_adb_detach(&adb);
   11941 			}
   11942 		}
   11943 		if (dctx->dumpfail) {
   11944 			dns_badcache_print(dctx->view->view->failcache,
   11945 					   "SERVFAIL cache", dctx->fp);
   11946 		}
   11947 		dns_db_detach(&dctx->cache);
   11948 	}
   11949 	if (dctx->dumpzones) {
   11950 		style = &dns_master_style_full;
   11951 	nextzone:
   11952 		if (dctx->version != NULL) {
   11953 			dns_db_closeversion(dctx->db, &dctx->version, false);
   11954 		}
   11955 		if (dctx->db != NULL) {
   11956 			dns_db_detach(&dctx->db);
   11957 		}
   11958 		if (dctx->zone == NULL) {
   11959 			dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
   11960 		} else {
   11961 			dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
   11962 		}
   11963 		if (dctx->zone != NULL) {
   11964 			/* start zone dump */
   11965 			dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
   11966 			fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
   11967 			result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
   11968 			if (result != ISC_R_SUCCESS) {
   11969 				fprintf(dctx->fp, "; %s\n",
   11970 					isc_result_totext(result));
   11971 				goto nextzone;
   11972 			}
   11973 			dns_db_currentversion(dctx->db, &dctx->version);
   11974 			result = dns_master_dumptostreamasync(
   11975 				dctx->mctx, dctx->db, dctx->version, style,
   11976 				dctx->fp, dns_zone_getloop(dctx->zone->zone),
   11977 				dumpdone, dctx, &dctx->mdctx);
   11978 			if (result == ISC_R_SUCCESS) {
   11979 				return;
   11980 			}
   11981 			if (result == ISC_R_NOTIMPLEMENTED) {
   11982 				fprintf(dctx->fp, "; %s\n",
   11983 					isc_result_totext(result));
   11984 				result = ISC_R_SUCCESS;
   11985 				POST(result);
   11986 				goto nextzone;
   11987 			}
   11988 			if (result != ISC_R_SUCCESS) {
   11989 				goto cleanup;
   11990 			}
   11991 		}
   11992 	}
   11993 	if (dctx->view != NULL) {
   11994 		dctx->view = ISC_LIST_NEXT(dctx->view, link);
   11995 		if (dctx->view != NULL) {
   11996 			goto nextview;
   11997 		}
   11998 	}
   11999 done:
   12000 	fprintf(dctx->fp, "; Dump complete\n");
   12001 	result = isc_stdio_flush(dctx->fp);
   12002 	if (result == ISC_R_SUCCESS) {
   12003 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12004 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12005 			      "dumpdb complete");
   12006 	}
   12007 cleanup:
   12008 	if (result != ISC_R_SUCCESS) {
   12009 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12010 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   12011 			      "dumpdb failed: %s", isc_result_totext(result));
   12012 	}
   12013 	dumpcontext_destroy(dctx);
   12014 }
   12015 
   12016 isc_result_t
   12017 named_server_dumpdb(named_server_t *server, isc_lex_t *lex,
   12018 		    isc_buffer_t **text) {
   12019 	struct dumpcontext *dctx = NULL;
   12020 	dns_view_t *view;
   12021 	isc_result_t result;
   12022 	char *ptr;
   12023 	const char *sep;
   12024 	bool found;
   12025 
   12026 	REQUIRE(text != NULL);
   12027 
   12028 	/* Skip the command name. */
   12029 	ptr = next_token(lex, NULL);
   12030 	if (ptr == NULL) {
   12031 		return ISC_R_UNEXPECTEDEND;
   12032 	}
   12033 
   12034 	dctx = isc_mem_get(server->mctx, sizeof(*dctx));
   12035 	*dctx = (struct dumpcontext){
   12036 		.mctx = server->mctx,
   12037 		.dumpcache = true,
   12038 		.dumpadb = true,
   12039 		.dumpfail = true,
   12040 		.viewlist = ISC_LIST_INITIALIZER,
   12041 	};
   12042 
   12043 	CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
   12044 		"could not open dump file", server->dumpfile);
   12045 
   12046 	ptr = next_token(lex, NULL);
   12047 	sep = (ptr == NULL) ? "" : ": ";
   12048 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12049 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12050 		      "dumpdb started%s%s", sep, (ptr != NULL) ? ptr : "");
   12051 
   12052 	if (ptr != NULL && strcmp(ptr, "-all") == 0) {
   12053 		/* also dump zones */
   12054 		dctx->dumpzones = true;
   12055 		ptr = next_token(lex, NULL);
   12056 	} else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
   12057 		/* this is the default */
   12058 		ptr = next_token(lex, NULL);
   12059 	} else if (ptr != NULL && strcmp(ptr, "-expired") == 0) {
   12060 		/* this is the same as -cache but includes expired data */
   12061 		dctx->dumpexpired = true;
   12062 		ptr = next_token(lex, NULL);
   12063 	} else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
   12064 		/* only dump zones, suppress caches */
   12065 		dctx->dumpadb = false;
   12066 		dctx->dumpcache = false;
   12067 		dctx->dumpfail = false;
   12068 		dctx->dumpzones = true;
   12069 		ptr = next_token(lex, NULL);
   12070 	} else if (ptr != NULL && strcmp(ptr, "-adb") == 0) {
   12071 		/* only dump adb, suppress other caches */
   12072 		dctx->dumpcache = false;
   12073 		dctx->dumpfail = false;
   12074 		ptr = next_token(lex, NULL);
   12075 	} else if (ptr != NULL && strcmp(ptr, "-bad") == 0) {
   12076 		/* only dump badcache, suppress other caches */
   12077 		dctx->dumpadb = false;
   12078 		dctx->dumpcache = false;
   12079 		dctx->dumpfail = false;
   12080 		ptr = next_token(lex, NULL);
   12081 	} else if (ptr != NULL && strcmp(ptr, "-fail") == 0) {
   12082 		/* only dump servfail cache, suppress other caches */
   12083 		dctx->dumpadb = false;
   12084 		dctx->dumpcache = false;
   12085 		ptr = next_token(lex, NULL);
   12086 	}
   12087 
   12088 nextview:
   12089 	found = false;
   12090 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12091 	     view = ISC_LIST_NEXT(view, link))
   12092 	{
   12093 		if (ptr != NULL && strcmp(view->name, ptr) != 0) {
   12094 			continue;
   12095 		}
   12096 		found = true;
   12097 		CHECK(add_view_tolist(dctx, view));
   12098 	}
   12099 	if (ptr != NULL) {
   12100 		if (!found) {
   12101 			CHECK(putstr(text, "view '"));
   12102 			CHECK(putstr(text, ptr));
   12103 			CHECK(putstr(text, "' not found"));
   12104 			CHECK(putnull(text));
   12105 			result = ISC_R_NOTFOUND;
   12106 			dumpdone(dctx, result);
   12107 			return result;
   12108 		}
   12109 		ptr = next_token(lex, NULL);
   12110 		if (ptr != NULL) {
   12111 			goto nextview;
   12112 		}
   12113 	}
   12114 	dumpdone(dctx, ISC_R_SUCCESS);
   12115 	return ISC_R_SUCCESS;
   12116 
   12117 cleanup:
   12118 	dumpcontext_destroy(dctx);
   12119 	return result;
   12120 }
   12121 
   12122 isc_result_t
   12123 named_server_dumpsecroots(named_server_t *server, isc_lex_t *lex,
   12124 			  isc_buffer_t **text) {
   12125 	dns_view_t *view;
   12126 	dns_keytable_t *secroots = NULL;
   12127 	dns_ntatable_t *ntatable = NULL;
   12128 	isc_result_t result;
   12129 	char *ptr;
   12130 	FILE *fp = NULL;
   12131 	isc_time_t now;
   12132 	char tbuf[64];
   12133 	unsigned int used = isc_buffer_usedlength(*text);
   12134 	bool first = true;
   12135 
   12136 	REQUIRE(text != NULL);
   12137 
   12138 	/* Skip the command name. */
   12139 	ptr = next_token(lex, text);
   12140 	if (ptr == NULL) {
   12141 		return ISC_R_UNEXPECTEDEND;
   12142 	}
   12143 
   12144 	/* "-" here means print the output instead of dumping to file */
   12145 	ptr = next_token(lex, text);
   12146 	if (ptr != NULL && strcmp(ptr, "-") == 0) {
   12147 		ptr = next_token(lex, text);
   12148 	} else {
   12149 		result = isc_stdio_open(server->secrootsfile, "w", &fp);
   12150 		if (result != ISC_R_SUCCESS) {
   12151 			(void)putstr(text, "could not open ");
   12152 			(void)putstr(text, server->secrootsfile);
   12153 			CHECKMF(result, "could not open secroots dump file",
   12154 				server->secrootsfile);
   12155 		}
   12156 	}
   12157 
   12158 	now = isc_time_now();
   12159 	isc_time_formattimestamp(&now, tbuf, sizeof(tbuf));
   12160 	CHECK(putstr(text, "secure roots as of "));
   12161 	CHECK(putstr(text, tbuf));
   12162 	CHECK(putstr(text, ":\n"));
   12163 	used = isc_buffer_usedlength(*text);
   12164 
   12165 	do {
   12166 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12167 		     view = ISC_LIST_NEXT(view, link))
   12168 		{
   12169 			if (ptr != NULL && strcmp(view->name, ptr) != 0) {
   12170 				continue;
   12171 			}
   12172 			if (secroots != NULL) {
   12173 				dns_keytable_detach(&secroots);
   12174 			}
   12175 			result = dns_view_getsecroots(view, &secroots);
   12176 			if (result == ISC_R_NOTFOUND) {
   12177 				result = ISC_R_SUCCESS;
   12178 				continue;
   12179 			}
   12180 			if (first || used != isc_buffer_usedlength(*text)) {
   12181 				CHECK(putstr(text, "\n"));
   12182 				first = false;
   12183 			}
   12184 			CHECK(putstr(text, " Start view "));
   12185 			CHECK(putstr(text, view->name));
   12186 			CHECK(putstr(text, "\n   Secure roots:\n\n"));
   12187 			used = isc_buffer_usedlength(*text);
   12188 			CHECK(dns_keytable_totext(secroots, text));
   12189 
   12190 			if (ntatable != NULL) {
   12191 				dns_ntatable_detach(&ntatable);
   12192 			}
   12193 			result = dns_view_getntatable(view, &ntatable);
   12194 			if (result == ISC_R_NOTFOUND) {
   12195 				result = ISC_R_SUCCESS;
   12196 				continue;
   12197 			}
   12198 			if (used != isc_buffer_usedlength(*text)) {
   12199 				CHECK(putstr(text, "\n"));
   12200 			}
   12201 			CHECK(putstr(text, "   Negative trust anchors:\n\n"));
   12202 			used = isc_buffer_usedlength(*text);
   12203 			CHECK(dns_ntatable_totext(ntatable, NULL, text));
   12204 		}
   12205 
   12206 		if (ptr != NULL) {
   12207 			ptr = next_token(lex, text);
   12208 		}
   12209 	} while (ptr != NULL);
   12210 
   12211 cleanup:
   12212 	if (secroots != NULL) {
   12213 		dns_keytable_detach(&secroots);
   12214 	}
   12215 	if (ntatable != NULL) {
   12216 		dns_ntatable_detach(&ntatable);
   12217 	}
   12218 
   12219 	if (fp != NULL) {
   12220 		if (used != isc_buffer_usedlength(*text)) {
   12221 			(void)putstr(text, "\n");
   12222 		}
   12223 		fprintf(fp, "%.*s", (int)isc_buffer_usedlength(*text),
   12224 			(char *)isc_buffer_base(*text));
   12225 		isc_buffer_clear(*text);
   12226 		(void)isc_stdio_close(fp);
   12227 	} else if (isc_buffer_usedlength(*text) > 0) {
   12228 		(void)putnull(text);
   12229 	}
   12230 
   12231 	if (result == ISC_R_SUCCESS) {
   12232 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12233 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12234 			      "dumpsecroots complete");
   12235 	} else {
   12236 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12237 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   12238 			      "dumpsecroots failed: %s",
   12239 			      isc_result_totext(result));
   12240 	}
   12241 	return result;
   12242 }
   12243 
   12244 isc_result_t
   12245 named_server_dumprecursing(named_server_t *server) {
   12246 	FILE *fp = NULL;
   12247 	dns_view_t *view;
   12248 	isc_result_t result;
   12249 
   12250 	CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
   12251 		"could not open dump file", server->recfile);
   12252 	fprintf(fp, ";\n; Recursing Queries\n;\n");
   12253 	ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
   12254 
   12255 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12256 	     view = ISC_LIST_NEXT(view, link))
   12257 	{
   12258 		fprintf(fp, ";\n; Active fetch domains [view: %s]\n;\n",
   12259 			view->name);
   12260 		dns_resolver_dumpfetches(view->resolver, isc_statsformat_file,
   12261 					 fp);
   12262 	}
   12263 
   12264 	fprintf(fp, "; Dump complete\n");
   12265 
   12266 cleanup:
   12267 	if (fp != NULL) {
   12268 		result = isc_stdio_close(fp);
   12269 	}
   12270 	if (result == ISC_R_SUCCESS) {
   12271 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12272 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12273 			      "dumprecursing complete");
   12274 	} else {
   12275 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12276 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   12277 			      "dumprecursing failed: %s",
   12278 			      isc_result_totext(result));
   12279 	}
   12280 	return result;
   12281 }
   12282 
   12283 isc_result_t
   12284 named_server_setdebuglevel(named_server_t *server, isc_lex_t *lex) {
   12285 	char *ptr;
   12286 	char *endp;
   12287 	long newlevel;
   12288 
   12289 	UNUSED(server);
   12290 
   12291 	/* Skip the command name. */
   12292 	ptr = next_token(lex, NULL);
   12293 	if (ptr == NULL) {
   12294 		return ISC_R_UNEXPECTEDEND;
   12295 	}
   12296 
   12297 	/* Look for the new level name. */
   12298 	ptr = next_token(lex, NULL);
   12299 	if (ptr == NULL) {
   12300 		if (named_g_debuglevel < 99) {
   12301 			named_g_debuglevel++;
   12302 		}
   12303 	} else {
   12304 		newlevel = strtol(ptr, &endp, 10);
   12305 		if (*endp != '\0' || newlevel < 0 || newlevel > 99) {
   12306 			return ISC_R_RANGE;
   12307 		}
   12308 		named_g_debuglevel = (unsigned int)newlevel;
   12309 	}
   12310 	isc_log_setdebuglevel(named_g_lctx, named_g_debuglevel);
   12311 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12312 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12313 		      "debug level is now %u", named_g_debuglevel);
   12314 	return ISC_R_SUCCESS;
   12315 }
   12316 
   12317 isc_result_t
   12318 named_server_validation(named_server_t *server, isc_lex_t *lex,
   12319 			isc_buffer_t **text) {
   12320 	char *ptr;
   12321 	dns_view_t *view;
   12322 	bool changed = false;
   12323 	isc_result_t result;
   12324 	bool enable = true, set = true, first = true;
   12325 
   12326 	REQUIRE(text != NULL);
   12327 
   12328 	/* Skip the command name. */
   12329 	ptr = next_token(lex, text);
   12330 	if (ptr == NULL) {
   12331 		return ISC_R_UNEXPECTEDEND;
   12332 	}
   12333 
   12334 	/* Find out what we are to do. */
   12335 	ptr = next_token(lex, text);
   12336 	if (ptr == NULL) {
   12337 		return ISC_R_UNEXPECTEDEND;
   12338 	}
   12339 
   12340 	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
   12341 	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
   12342 	{
   12343 		enable = true;
   12344 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
   12345 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
   12346 	{
   12347 		enable = false;
   12348 	} else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
   12349 		set = false;
   12350 	} else {
   12351 		return DNS_R_SYNTAX;
   12352 	}
   12353 
   12354 	/* Look for the view name. */
   12355 	ptr = next_token(lex, text);
   12356 
   12357 	isc_loopmgr_pause(named_g_loopmgr);
   12358 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12359 	     view = ISC_LIST_NEXT(view, link))
   12360 	{
   12361 		if ((ptr != NULL && strcasecmp(ptr, view->name) != 0) ||
   12362 		    strcasecmp("_bind", view->name) == 0)
   12363 		{
   12364 			continue;
   12365 		}
   12366 
   12367 		if (set) {
   12368 			CHECK(dns_view_flushcache(view, false));
   12369 			view->enablevalidation = enable;
   12370 			changed = true;
   12371 		} else {
   12372 			if (!first) {
   12373 				CHECK(putstr(text, "\n"));
   12374 			}
   12375 			CHECK(putstr(text, "DNSSEC validation is "));
   12376 			CHECK(putstr(text, view->enablevalidation
   12377 						   ? "enabled"
   12378 						   : "disabled"));
   12379 			CHECK(putstr(text, " (view "));
   12380 			CHECK(putstr(text, view->name));
   12381 			CHECK(putstr(text, ")"));
   12382 			first = false;
   12383 		}
   12384 	}
   12385 	CHECK(putnull(text));
   12386 
   12387 	if (!set) {
   12388 		result = ISC_R_SUCCESS;
   12389 	} else if (changed) {
   12390 		result = ISC_R_SUCCESS;
   12391 	} else {
   12392 		result = ISC_R_FAILURE;
   12393 	}
   12394 cleanup:
   12395 	isc_loopmgr_resume(named_g_loopmgr);
   12396 	return result;
   12397 }
   12398 
   12399 isc_result_t
   12400 named_server_flushcache(named_server_t *server, isc_lex_t *lex) {
   12401 	char *ptr;
   12402 	dns_view_t *view;
   12403 	bool flushed;
   12404 	bool found;
   12405 	isc_result_t result;
   12406 	named_cache_t *nsc;
   12407 
   12408 	/* Skip the command name. */
   12409 	ptr = next_token(lex, NULL);
   12410 	if (ptr == NULL) {
   12411 		return ISC_R_UNEXPECTEDEND;
   12412 	}
   12413 
   12414 	/* Look for the view name. */
   12415 	ptr = next_token(lex, NULL);
   12416 
   12417 	isc_loopmgr_pause(named_g_loopmgr);
   12418 	flushed = true;
   12419 	found = false;
   12420 
   12421 	/*
   12422 	 * Flushing a cache is tricky when caches are shared by multiple views.
   12423 	 * We first identify which caches should be flushed in the local cache
   12424 	 * list, flush these caches, and then update other views that refer to
   12425 	 * the flushed cache DB.
   12426 	 */
   12427 	if (ptr != NULL) {
   12428 		/*
   12429 		 * Mark caches that need to be flushed.  This is an O(#view^2)
   12430 		 * operation in the very worst case, but should be normally
   12431 		 * much more lightweight because only a few (most typically just
   12432 		 * one) views will match.
   12433 		 */
   12434 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12435 		     view = ISC_LIST_NEXT(view, link))
   12436 		{
   12437 			if (strcasecmp(ptr, view->name) != 0) {
   12438 				continue;
   12439 			}
   12440 			found = true;
   12441 			for (nsc = ISC_LIST_HEAD(server->cachelist);
   12442 			     nsc != NULL; nsc = ISC_LIST_NEXT(nsc, link))
   12443 			{
   12444 				if (nsc->cache == view->cache) {
   12445 					break;
   12446 				}
   12447 			}
   12448 			INSIST(nsc != NULL);
   12449 			nsc->needflush = true;
   12450 		}
   12451 	} else {
   12452 		found = true;
   12453 	}
   12454 
   12455 	/* Perform flush */
   12456 	for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
   12457 	     nsc = ISC_LIST_NEXT(nsc, link))
   12458 	{
   12459 		if (ptr != NULL && !nsc->needflush) {
   12460 			continue;
   12461 		}
   12462 		nsc->needflush = true;
   12463 		result = dns_view_flushcache(nsc->primaryview, false);
   12464 		if (result != ISC_R_SUCCESS) {
   12465 			flushed = false;
   12466 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12467 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   12468 				      "flushing cache in view '%s' failed: %s",
   12469 				      nsc->primaryview->name,
   12470 				      isc_result_totext(result));
   12471 		}
   12472 	}
   12473 
   12474 	/*
   12475 	 * Fix up views that share a flushed cache: let the views update the
   12476 	 * cache DB they're referring to.  This could also be an expensive
   12477 	 * operation, but should typically be marginal: the inner loop is only
   12478 	 * necessary for views that share a cache, and if there are many such
   12479 	 * views the number of shared cache should normally be small.
   12480 	 * A worst case is that we have n views and n/2 caches, each shared by
   12481 	 * two views.  Then this will be a O(n^2/4) operation.
   12482 	 */
   12483 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12484 	     view = ISC_LIST_NEXT(view, link))
   12485 	{
   12486 		if (!dns_view_iscacheshared(view)) {
   12487 			continue;
   12488 		}
   12489 		for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
   12490 		     nsc = ISC_LIST_NEXT(nsc, link))
   12491 		{
   12492 			if (!nsc->needflush || nsc->cache != view->cache) {
   12493 				continue;
   12494 			}
   12495 			result = dns_view_flushcache(view, true);
   12496 			if (result != ISC_R_SUCCESS) {
   12497 				flushed = false;
   12498 				isc_log_write(
   12499 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12500 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   12501 					"fixing cache in view '%s' "
   12502 					"failed: %s",
   12503 					view->name, isc_result_totext(result));
   12504 			}
   12505 		}
   12506 	}
   12507 
   12508 	/* Cleanup the cache list. */
   12509 	for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
   12510 	     nsc = ISC_LIST_NEXT(nsc, link))
   12511 	{
   12512 		nsc->needflush = false;
   12513 	}
   12514 
   12515 	if (flushed && found) {
   12516 		if (ptr != NULL) {
   12517 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12518 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12519 				      "flushing cache in view '%s' succeeded",
   12520 				      ptr);
   12521 		} else {
   12522 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12523 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12524 				      "flushing caches in all views succeeded");
   12525 		}
   12526 		result = ISC_R_SUCCESS;
   12527 	} else {
   12528 		if (!found) {
   12529 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12530 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   12531 				      "flushing cache in view '%s' failed: "
   12532 				      "view not found",
   12533 				      ptr);
   12534 			result = ISC_R_NOTFOUND;
   12535 		} else {
   12536 			result = ISC_R_FAILURE;
   12537 		}
   12538 	}
   12539 	isc_loopmgr_resume(named_g_loopmgr);
   12540 	return result;
   12541 }
   12542 
   12543 isc_result_t
   12544 named_server_flushnode(named_server_t *server, isc_lex_t *lex, bool tree) {
   12545 	char *ptr, *viewname;
   12546 	char target[DNS_NAME_FORMATSIZE];
   12547 	dns_view_t *view;
   12548 	bool flushed;
   12549 	bool found;
   12550 	isc_result_t result;
   12551 	isc_buffer_t b;
   12552 	dns_fixedname_t fixed;
   12553 	dns_name_t *name;
   12554 
   12555 	/* Skip the command name. */
   12556 	ptr = next_token(lex, NULL);
   12557 	if (ptr == NULL) {
   12558 		return ISC_R_UNEXPECTEDEND;
   12559 	}
   12560 
   12561 	/* Find the domain name to flush. */
   12562 	ptr = next_token(lex, NULL);
   12563 	if (ptr == NULL) {
   12564 		return ISC_R_UNEXPECTEDEND;
   12565 	}
   12566 
   12567 	strlcpy(target, ptr, DNS_NAME_FORMATSIZE);
   12568 	isc_buffer_constinit(&b, target, strlen(target));
   12569 	isc_buffer_add(&b, strlen(target));
   12570 	name = dns_fixedname_initname(&fixed);
   12571 	result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
   12572 	if (result != ISC_R_SUCCESS) {
   12573 		return result;
   12574 	}
   12575 
   12576 	/* Look for the view name. */
   12577 	viewname = next_token(lex, NULL);
   12578 
   12579 	isc_loopmgr_pause(named_g_loopmgr);
   12580 	flushed = true;
   12581 	found = false;
   12582 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12583 	     view = ISC_LIST_NEXT(view, link))
   12584 	{
   12585 		if (viewname != NULL && strcasecmp(viewname, view->name) != 0) {
   12586 			continue;
   12587 		}
   12588 		found = true;
   12589 		/*
   12590 		 * It's a little inefficient to try flushing name for all views
   12591 		 * if some of the views share a single cache.  But since the
   12592 		 * operation is lightweight we prefer simplicity here.
   12593 		 */
   12594 		result = dns_view_flushnode(view, name, tree);
   12595 		if (result != ISC_R_SUCCESS) {
   12596 			flushed = false;
   12597 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12598 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   12599 				      "flushing %s '%s' in cache view '%s' "
   12600 				      "failed: %s",
   12601 				      tree ? "tree" : "name", target,
   12602 				      view->name, isc_result_totext(result));
   12603 		}
   12604 	}
   12605 	if (flushed && found) {
   12606 		if (viewname != NULL) {
   12607 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12608 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12609 				      "flushing %s '%s' in cache view '%s' "
   12610 				      "succeeded",
   12611 				      tree ? "tree" : "name", target, viewname);
   12612 		} else {
   12613 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12614 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12615 				      "flushing %s '%s' in all cache views "
   12616 				      "succeeded",
   12617 				      tree ? "tree" : "name", target);
   12618 		}
   12619 		result = ISC_R_SUCCESS;
   12620 	} else {
   12621 		if (!found) {
   12622 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12623 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   12624 				      "flushing %s '%s' in cache view '%s' "
   12625 				      "failed: view not found",
   12626 				      tree ? "tree" : "name", target, viewname);
   12627 		}
   12628 		result = ISC_R_FAILURE;
   12629 	}
   12630 	isc_loopmgr_resume(named_g_loopmgr);
   12631 	return result;
   12632 }
   12633 
   12634 isc_result_t
   12635 named_server_status(named_server_t *server, isc_buffer_t **text) {
   12636 	isc_result_t result;
   12637 	unsigned int zonecount, xferrunning, xferdeferred, xferfirstrefresh;
   12638 	unsigned int soaqueries, automatic;
   12639 	const char *ob = "", *cb = "", *alt = "";
   12640 	char boottime[ISC_FORMATHTTPTIMESTAMP_SIZE];
   12641 	char configtime[ISC_FORMATHTTPTIMESTAMP_SIZE];
   12642 	char line[1024], hostname[256];
   12643 	named_reload_t reload_status;
   12644 
   12645 	REQUIRE(text != NULL);
   12646 
   12647 	if (named_g_server->version_set) {
   12648 		ob = " (";
   12649 		cb = ")";
   12650 		if (named_g_server->version == NULL) {
   12651 			alt = "version.bind/txt/ch disabled";
   12652 		} else {
   12653 			alt = named_g_server->version;
   12654 		}
   12655 	}
   12656 	zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
   12657 	xferrunning = dns_zonemgr_getcount(server->zonemgr,
   12658 					   DNS_ZONESTATE_XFERRUNNING);
   12659 	xferdeferred = dns_zonemgr_getcount(server->zonemgr,
   12660 					    DNS_ZONESTATE_XFERDEFERRED);
   12661 	xferfirstrefresh = dns_zonemgr_getcount(server->zonemgr,
   12662 						DNS_ZONESTATE_XFERFIRSTREFRESH);
   12663 	soaqueries = dns_zonemgr_getcount(server->zonemgr,
   12664 					  DNS_ZONESTATE_SOAQUERY);
   12665 	automatic = dns_zonemgr_getcount(server->zonemgr,
   12666 					 DNS_ZONESTATE_AUTOMATIC);
   12667 
   12668 	isc_time_formathttptimestamp(&named_g_boottime, boottime,
   12669 				     sizeof(boottime));
   12670 	isc_time_formathttptimestamp(&named_g_configtime, configtime,
   12671 				     sizeof(configtime));
   12672 
   12673 	snprintf(line, sizeof(line), "version: %s%s <id:%s>%s%s%s\n",
   12674 		 PACKAGE_STRING, PACKAGE_DESCRIPTION, PACKAGE_SRCID, ob, alt,
   12675 		 cb);
   12676 	CHECK(putstr(text, line));
   12677 
   12678 	if (gethostname(hostname, sizeof(hostname)) == 0) {
   12679 		strlcpy(hostname, "localhost", sizeof(hostname));
   12680 	}
   12681 	snprintf(line, sizeof(line), "running on %s: %s\n", hostname,
   12682 		 named_os_uname());
   12683 	CHECK(putstr(text, line));
   12684 
   12685 	snprintf(line, sizeof(line), "boot time: %s\n", boottime);
   12686 	CHECK(putstr(text, line));
   12687 
   12688 	snprintf(line, sizeof(line), "last configured: %s\n", configtime);
   12689 	CHECK(putstr(text, line));
   12690 
   12691 	if (named_g_chrootdir != NULL) {
   12692 		snprintf(line, sizeof(line), "configuration file: %s (%s%s)\n",
   12693 			 named_g_conffile, named_g_chrootdir, named_g_conffile);
   12694 	} else {
   12695 		snprintf(line, sizeof(line), "configuration file: %s\n",
   12696 			 named_g_conffile);
   12697 	}
   12698 	CHECK(putstr(text, line));
   12699 
   12700 	snprintf(line, sizeof(line), "CPUs found: %u\n", named_g_cpus_detected);
   12701 	CHECK(putstr(text, line));
   12702 
   12703 	snprintf(line, sizeof(line), "worker threads: %u\n", named_g_cpus);
   12704 	CHECK(putstr(text, line));
   12705 
   12706 	snprintf(line, sizeof(line), "number of zones: %u (%u automatic)\n",
   12707 		 zonecount, automatic);
   12708 	CHECK(putstr(text, line));
   12709 
   12710 	snprintf(line, sizeof(line), "debug level: %u\n", named_g_debuglevel);
   12711 	CHECK(putstr(text, line));
   12712 
   12713 	snprintf(line, sizeof(line), "xfers running: %u\n", xferrunning);
   12714 	CHECK(putstr(text, line));
   12715 
   12716 	snprintf(line, sizeof(line), "xfers deferred: %u\n", xferdeferred);
   12717 	CHECK(putstr(text, line));
   12718 
   12719 	snprintf(line, sizeof(line), "xfers first refresh: %u\n",
   12720 		 xferfirstrefresh);
   12721 	CHECK(putstr(text, line));
   12722 
   12723 	snprintf(line, sizeof(line), "soa queries in progress: %u\n",
   12724 		 soaqueries);
   12725 	CHECK(putstr(text, line));
   12726 
   12727 	snprintf(line, sizeof(line), "query logging is %s\n",
   12728 		 ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES)
   12729 			 ? "ON"
   12730 			 : "OFF");
   12731 	CHECK(putstr(text, line));
   12732 
   12733 	snprintf(line, sizeof(line), "response logging is %s\n",
   12734 		 ns_server_getoption(server->sctx, NS_SERVER_LOGRESPONSES)
   12735 			 ? "ON"
   12736 			 : "OFF");
   12737 	CHECK(putstr(text, line));
   12738 
   12739 	snprintf(line, sizeof(line), "memory profiling is %s\n",
   12740 		 named_server_getmemprof());
   12741 	CHECK(putstr(text, line));
   12742 
   12743 	snprintf(line, sizeof(line), "recursive clients: %u/%u/%u\n",
   12744 		 isc_quota_getused(&server->sctx->recursionquota),
   12745 		 isc_quota_getsoft(&server->sctx->recursionquota),
   12746 		 isc_quota_getmax(&server->sctx->recursionquota));
   12747 	CHECK(putstr(text, line));
   12748 
   12749 	snprintf(line, sizeof(line), "recursive high-water: %u\n",
   12750 		 (unsigned int)ns_stats_get_counter(
   12751 			 server->sctx->nsstats,
   12752 			 ns_statscounter_recurshighwater));
   12753 	CHECK(putstr(text, line));
   12754 
   12755 	snprintf(line, sizeof(line), "tcp clients: %u/%u\n",
   12756 		 isc_quota_getused(&server->sctx->tcpquota),
   12757 		 isc_quota_getmax(&server->sctx->tcpquota));
   12758 	CHECK(putstr(text, line));
   12759 
   12760 	snprintf(line, sizeof(line), "TCP high-water: %u\n",
   12761 		 (unsigned int)ns_stats_get_counter(
   12762 			 server->sctx->nsstats, ns_statscounter_tcphighwater));
   12763 	CHECK(putstr(text, line));
   12764 
   12765 	reload_status = atomic_load(&server->reload_status);
   12766 	if (reload_status != NAMED_RELOAD_DONE) {
   12767 		snprintf(line, sizeof(line), "reload/reconfig %s\n",
   12768 			 reload_status == NAMED_RELOAD_FAILED ? "failed"
   12769 							      : "in progress");
   12770 		CHECK(putstr(text, line));
   12771 	}
   12772 
   12773 	CHECK(putstr(text, "server is up and running"));
   12774 	CHECK(putnull(text));
   12775 
   12776 	return ISC_R_SUCCESS;
   12777 cleanup:
   12778 	return result;
   12779 }
   12780 
   12781 isc_result_t
   12782 named_server_testgen(isc_lex_t *lex, isc_buffer_t **text) {
   12783 	isc_result_t result;
   12784 	char *ptr;
   12785 	unsigned long count;
   12786 	unsigned long i;
   12787 	const unsigned char chars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
   12788 
   12789 	REQUIRE(text != NULL);
   12790 
   12791 	/* Skip the command name. */
   12792 	ptr = next_token(lex, text);
   12793 	if (ptr == NULL) {
   12794 		return ISC_R_UNEXPECTEDEND;
   12795 	}
   12796 
   12797 	ptr = next_token(lex, text);
   12798 	if (ptr == NULL) {
   12799 		count = 26;
   12800 	} else {
   12801 		count = strtoul(ptr, NULL, 10);
   12802 	}
   12803 
   12804 	CHECK(isc_buffer_reserve(*text, count));
   12805 	for (i = 0; i < count; i++) {
   12806 		CHECK(putuint8(text, chars[i % (sizeof(chars) - 1)]));
   12807 	}
   12808 
   12809 	CHECK(putnull(text));
   12810 
   12811 cleanup:
   12812 	return result;
   12813 }
   12814 
   12815 /*
   12816  * Act on a "sign" or "loadkeys" command from the command channel.
   12817  */
   12818 isc_result_t
   12819 named_server_rekey(named_server_t *server, isc_lex_t *lex,
   12820 		   isc_buffer_t **text) {
   12821 	isc_result_t result;
   12822 	dns_zone_t *zone = NULL;
   12823 	dns_zonetype_t type;
   12824 	uint16_t keyopts;
   12825 	bool fullsign = false;
   12826 	char *ptr;
   12827 
   12828 	REQUIRE(text != NULL);
   12829 
   12830 	ptr = next_token(lex, text);
   12831 	if (ptr == NULL) {
   12832 		return ISC_R_UNEXPECTEDEND;
   12833 	}
   12834 
   12835 	if (strcasecmp(ptr, NAMED_COMMAND_SIGN) == 0) {
   12836 		fullsign = true;
   12837 	}
   12838 
   12839 	REQUIRE(text != NULL);
   12840 
   12841 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, false);
   12842 	if (result != ISC_R_SUCCESS) {
   12843 		return result;
   12844 	}
   12845 	if (zone == NULL) {
   12846 		return ISC_R_UNEXPECTEDEND; /* XXX: or do all zones? */
   12847 	}
   12848 
   12849 	type = dns_zone_gettype(zone);
   12850 	if (type != dns_zone_primary) {
   12851 		dns_zone_detach(&zone);
   12852 		return DNS_R_NOTPRIMARY;
   12853 	}
   12854 
   12855 	keyopts = dns_zone_getkeyopts(zone);
   12856 
   12857 	/*
   12858 	 * "rndc loadkeys" requires a "dnssec-policy".
   12859 	 */
   12860 	if ((keyopts & DNS_ZONEKEY_ALLOW) == 0) {
   12861 		result = ISC_R_NOPERM;
   12862 	} else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign) {
   12863 		result = ISC_R_NOPERM;
   12864 	} else {
   12865 		dns_zone_rekey(zone, fullsign, false);
   12866 	}
   12867 
   12868 	dns_zone_detach(&zone);
   12869 	return result;
   12870 }
   12871 
   12872 /*
   12873  * Act on a "sync" command from the command channel.
   12874  */
   12875 static isc_result_t
   12876 synczone(dns_zone_t *zone, void *uap) {
   12877 	bool cleanup = *(bool *)uap;
   12878 	isc_result_t result;
   12879 	dns_zone_t *raw = NULL;
   12880 	char *journal;
   12881 
   12882 	dns_zone_getraw(zone, &raw);
   12883 	if (raw != NULL) {
   12884 		synczone(raw, uap);
   12885 		dns_zone_detach(&raw);
   12886 	}
   12887 
   12888 	result = dns_zone_flush(zone);
   12889 	if (result != ISC_R_SUCCESS) {
   12890 		cleanup = false;
   12891 	}
   12892 	if (cleanup) {
   12893 		journal = dns_zone_getjournal(zone);
   12894 		if (journal != NULL) {
   12895 			(void)isc_file_remove(journal);
   12896 		}
   12897 	}
   12898 
   12899 	return result;
   12900 }
   12901 
   12902 isc_result_t
   12903 named_server_sync(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
   12904 	isc_result_t result, tresult;
   12905 	dns_view_t *view = NULL;
   12906 	dns_zone_t *zone = NULL;
   12907 	char classstr[DNS_RDATACLASS_FORMATSIZE];
   12908 	char zonename[DNS_NAME_FORMATSIZE];
   12909 	const char *vname = NULL, *sep = NULL, *arg = NULL;
   12910 	bool cleanup = false;
   12911 
   12912 	REQUIRE(text != NULL);
   12913 
   12914 	(void)next_token(lex, text);
   12915 
   12916 	arg = next_token(lex, text);
   12917 	if (arg != NULL &&
   12918 	    (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0))
   12919 	{
   12920 		cleanup = true;
   12921 		arg = next_token(lex, text);
   12922 	}
   12923 
   12924 	REQUIRE(text != NULL);
   12925 
   12926 	result = zone_from_args(server, lex, arg, &zone, NULL, text, false);
   12927 	if (result != ISC_R_SUCCESS) {
   12928 		return result;
   12929 	}
   12930 
   12931 	if (zone == NULL) {
   12932 		isc_loopmgr_pause(named_g_loopmgr);
   12933 		tresult = ISC_R_SUCCESS;
   12934 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   12935 		     view = ISC_LIST_NEXT(view, link))
   12936 		{
   12937 			result = dns_view_apply(view, false, NULL, synczone,
   12938 						&cleanup);
   12939 			if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
   12940 			{
   12941 				tresult = result;
   12942 			}
   12943 		}
   12944 		isc_loopmgr_resume(named_g_loopmgr);
   12945 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   12946 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   12947 			      "dumping all zones%s: %s",
   12948 			      cleanup ? ", removing journal files" : "",
   12949 			      isc_result_totext(result));
   12950 		return tresult;
   12951 	}
   12952 
   12953 	isc_loopmgr_pause(named_g_loopmgr);
   12954 	result = synczone(zone, &cleanup);
   12955 	isc_loopmgr_resume(named_g_loopmgr);
   12956 
   12957 	view = dns_zone_getview(zone);
   12958 	if (strcmp(view->name, "_default") == 0 ||
   12959 	    strcmp(view->name, "_bind") == 0)
   12960 	{
   12961 		vname = "";
   12962 		sep = "";
   12963 	} else {
   12964 		vname = view->name;
   12965 		sep = " ";
   12966 	}
   12967 	dns_rdataclass_format(dns_zone_getclass(zone), classstr,
   12968 			      sizeof(classstr));
   12969 	dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
   12970 	isc_log_write(
   12971 		named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
   12972 		ISC_LOG_INFO, "sync: dumping zone '%s/%s'%s%s%s: %s", zonename,
   12973 		classstr, sep, vname, cleanup ? ", removing journal file" : "",
   12974 		isc_result_totext(result));
   12975 	dns_zone_detach(&zone);
   12976 	return result;
   12977 }
   12978 
   12979 /*
   12980  * Act on a "freeze" or "thaw" command from the command channel.
   12981  */
   12982 isc_result_t
   12983 named_server_freeze(named_server_t *server, bool freeze, isc_lex_t *lex,
   12984 		    isc_buffer_t **text) {
   12985 	isc_result_t result, tresult;
   12986 	dns_zone_t *mayberaw = NULL, *raw = NULL;
   12987 	dns_zonetype_t type;
   12988 	char classstr[DNS_RDATACLASS_FORMATSIZE];
   12989 	char zonename[DNS_NAME_FORMATSIZE];
   12990 	dns_view_t *view;
   12991 	const char *vname, *sep;
   12992 	bool frozen;
   12993 	const char *msg = NULL;
   12994 
   12995 	REQUIRE(text != NULL);
   12996 
   12997 	result = zone_from_args(server, lex, NULL, &mayberaw, NULL, text, true);
   12998 	if (result != ISC_R_SUCCESS) {
   12999 		return result;
   13000 	}
   13001 	if (mayberaw == NULL) {
   13002 		isc_loopmgr_pause(named_g_loopmgr);
   13003 		tresult = ISC_R_SUCCESS;
   13004 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   13005 		     view = ISC_LIST_NEXT(view, link))
   13006 		{
   13007 			result = dns_view_freezezones(view, freeze);
   13008 			if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
   13009 			{
   13010 				tresult = result;
   13011 			}
   13012 		}
   13013 		isc_loopmgr_resume(named_g_loopmgr);
   13014 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13015 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   13016 			      "%s all zones: %s",
   13017 			      freeze ? "freezing" : "thawing",
   13018 			      isc_result_totext(tresult));
   13019 		return tresult;
   13020 	}
   13021 	dns_zone_getraw(mayberaw, &raw);
   13022 	if (raw != NULL) {
   13023 		dns_zone_detach(&mayberaw);
   13024 		dns_zone_attach(raw, &mayberaw);
   13025 		dns_zone_detach(&raw);
   13026 	}
   13027 	type = dns_zone_gettype(mayberaw);
   13028 	if (type != dns_zone_primary) {
   13029 		dns_zone_detach(&mayberaw);
   13030 		return DNS_R_NOTPRIMARY;
   13031 	}
   13032 
   13033 	if (freeze && !dns_zone_isdynamic(mayberaw, true)) {
   13034 		dns_zone_detach(&mayberaw);
   13035 		return DNS_R_NOTDYNAMIC;
   13036 	}
   13037 
   13038 	isc_loopmgr_pause(named_g_loopmgr);
   13039 	frozen = dns_zone_getupdatedisabled(mayberaw);
   13040 	if (freeze) {
   13041 		if (frozen) {
   13042 			msg = "WARNING: The zone was already frozen.\n"
   13043 			      "Someone else may be editing it or "
   13044 			      "it may still be re-loading.";
   13045 			result = DNS_R_FROZEN;
   13046 		}
   13047 		if (result == ISC_R_SUCCESS) {
   13048 			result = dns_zone_flush(mayberaw);
   13049 			if (result != ISC_R_SUCCESS) {
   13050 				msg = "Flushing the zone updates to "
   13051 				      "disk failed.";
   13052 			}
   13053 		}
   13054 		if (result == ISC_R_SUCCESS) {
   13055 			dns_zone_setupdatedisabled(mayberaw, freeze);
   13056 		}
   13057 	} else {
   13058 		if (frozen) {
   13059 			result = dns_zone_loadandthaw(mayberaw);
   13060 			switch (result) {
   13061 			case ISC_R_SUCCESS:
   13062 			case DNS_R_UPTODATE:
   13063 				msg = "The zone reload and thaw was "
   13064 				      "successful.";
   13065 				result = ISC_R_SUCCESS;
   13066 				break;
   13067 			case DNS_R_CONTINUE:
   13068 				msg = "A zone reload and thaw was started.\n"
   13069 				      "Check the logs to see the result.";
   13070 				result = ISC_R_SUCCESS;
   13071 				break;
   13072 			default:
   13073 				break;
   13074 			}
   13075 		}
   13076 	}
   13077 	isc_loopmgr_resume(named_g_loopmgr);
   13078 
   13079 	if (msg != NULL) {
   13080 		(void)putstr(text, msg);
   13081 		(void)putnull(text);
   13082 	}
   13083 
   13084 	view = dns_zone_getview(mayberaw);
   13085 	if (strcmp(view->name, "_default") == 0 ||
   13086 	    strcmp(view->name, "_bind") == 0)
   13087 	{
   13088 		vname = "";
   13089 		sep = "";
   13090 	} else {
   13091 		vname = view->name;
   13092 		sep = " ";
   13093 	}
   13094 	dns_rdataclass_format(dns_zone_getclass(mayberaw), classstr,
   13095 			      sizeof(classstr));
   13096 	dns_name_format(dns_zone_getorigin(mayberaw), zonename,
   13097 			sizeof(zonename));
   13098 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13099 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   13100 		      "%s zone '%s/%s'%s%s: %s",
   13101 		      freeze ? "freezing" : "thawing", zonename, classstr, sep,
   13102 		      vname, isc_result_totext(result));
   13103 	dns_zone_detach(&mayberaw);
   13104 	return result;
   13105 }
   13106 
   13107 #ifdef HAVE_LIBSCF
   13108 /*
   13109  * This function adds a message for rndc to echo if named
   13110  * is managed by smf and is also running chroot.
   13111  */
   13112 isc_result_t
   13113 named_smf_add_message(isc_buffer_t **text) {
   13114 	REQUIRE(text != NULL);
   13115 
   13116 	return putstr(text, "use svcadm(1M) to manage named");
   13117 }
   13118 #endif /* HAVE_LIBSCF */
   13119 
   13120 #ifndef HAVE_LMDB
   13121 
   13122 /*
   13123  * Emit a comment at the top of the nzf file containing the viewname
   13124  * Expects the fp to already be open for writing
   13125  */
   13126 #define HEADER1 "# New zone file for view: "
   13127 #define HEADER2                                                     \
   13128 	"\n# This file contains configuration for zones added by\n" \
   13129 	"# the 'rndc addzone' command. DO NOT EDIT BY HAND.\n"
   13130 static isc_result_t
   13131 add_comment(FILE *fp, const char *viewname) {
   13132 	isc_result_t result;
   13133 	CHECK(isc_stdio_write(HEADER1, sizeof(HEADER1) - 1, 1, fp, NULL));
   13134 	CHECK(isc_stdio_write(viewname, strlen(viewname), 1, fp, NULL));
   13135 	CHECK(isc_stdio_write(HEADER2, sizeof(HEADER2) - 1, 1, fp, NULL));
   13136 cleanup:
   13137 	return result;
   13138 }
   13139 
   13140 static void
   13141 dumpzone(void *arg, const char *buf, int len) {
   13142 	FILE *fp = arg;
   13143 
   13144 	(void)isc_stdio_write(buf, len, 1, fp, NULL);
   13145 }
   13146 
   13147 static isc_result_t
   13148 nzf_append(dns_view_t *view, const cfg_obj_t *zconfig) {
   13149 	isc_result_t result;
   13150 	off_t offset;
   13151 	FILE *fp = NULL;
   13152 	bool offsetok = false;
   13153 
   13154 	LOCK(&view->new_zone_lock);
   13155 
   13156 	CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
   13157 	CHECK(isc_stdio_seek(fp, 0, SEEK_END));
   13158 
   13159 	CHECK(isc_stdio_tell(fp, &offset));
   13160 	offsetok = true;
   13161 	if (offset == 0) {
   13162 		CHECK(add_comment(fp, view->name));
   13163 	}
   13164 
   13165 	CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
   13166 	cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
   13167 	CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
   13168 	CHECK(isc_stdio_flush(fp));
   13169 	result = isc_stdio_close(fp);
   13170 	fp = NULL;
   13171 
   13172 cleanup:
   13173 	if (fp != NULL) {
   13174 		(void)isc_stdio_close(fp);
   13175 		if (offsetok) {
   13176 			isc_result_t result2;
   13177 
   13178 			result2 = isc_file_truncate(view->new_zone_file,
   13179 						    offset);
   13180 			if (result2 != ISC_R_SUCCESS) {
   13181 				isc_log_write(
   13182 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13183 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13184 					"Error truncating NZF file '%s' "
   13185 					"during rollback from append: "
   13186 					"%s",
   13187 					view->new_zone_file,
   13188 					isc_result_totext(result2));
   13189 			}
   13190 		}
   13191 	}
   13192 	UNLOCK(&view->new_zone_lock);
   13193 	return result;
   13194 }
   13195 
   13196 static isc_result_t
   13197 nzf_writeconf(const cfg_obj_t *config, dns_view_t *view) {
   13198 	const cfg_obj_t *zl = NULL;
   13199 	cfg_list_t *list;
   13200 	const cfg_listelt_t *elt;
   13201 
   13202 	FILE *fp = NULL;
   13203 	char tmp[1024];
   13204 	isc_result_t result;
   13205 
   13206 	result = isc_file_template(view->new_zone_file, "nzf-XXXXXXXX", tmp,
   13207 				   sizeof(tmp));
   13208 	if (result == ISC_R_SUCCESS) {
   13209 		result = isc_file_openunique(tmp, &fp);
   13210 	}
   13211 	if (result != ISC_R_SUCCESS) {
   13212 		return result;
   13213 	}
   13214 
   13215 	cfg_map_get(config, "zone", &zl);
   13216 	if (!cfg_obj_islist(zl)) {
   13217 		CHECK(ISC_R_FAILURE);
   13218 	}
   13219 
   13220 	list = UNCONST(&zl->value.list);
   13221 
   13222 	CHECK(add_comment(fp, view->name)); /* force a comment */
   13223 
   13224 	for (elt = ISC_LIST_HEAD(*list); elt != NULL;
   13225 	     elt = ISC_LIST_NEXT(elt, link))
   13226 	{
   13227 		const cfg_obj_t *zconfig = cfg_listelt_value(elt);
   13228 
   13229 		CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
   13230 		cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
   13231 		CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
   13232 	}
   13233 
   13234 	CHECK(isc_stdio_flush(fp));
   13235 	result = isc_stdio_close(fp);
   13236 	fp = NULL;
   13237 	if (result != ISC_R_SUCCESS) {
   13238 		goto cleanup;
   13239 	}
   13240 	CHECK(isc_file_rename(tmp, view->new_zone_file));
   13241 	return result;
   13242 
   13243 cleanup:
   13244 	if (fp != NULL) {
   13245 		(void)isc_stdio_close(fp);
   13246 	}
   13247 	(void)isc_file_remove(tmp);
   13248 	return result;
   13249 }
   13250 
   13251 static isc_result_t
   13252 load_nzf(dns_view_t *view, ns_cfgctx_t *nzcfg) {
   13253 	isc_result_t result;
   13254 
   13255 	/* The new zone file may not exist. That is OK. */
   13256 	if (!isc_file_exists(view->new_zone_file)) {
   13257 		return ISC_R_SUCCESS;
   13258 	}
   13259 
   13260 	/*
   13261 	 * Parse the configuration in the NZF file.  This may be called in
   13262 	 * multiple views, so we reset the parser each time.
   13263 	 */
   13264 	cfg_parser_reset(named_g_addparser);
   13265 	result = cfg_parse_file(named_g_addparser, view->new_zone_file,
   13266 				&cfg_type_addzoneconf, &nzcfg->nzf_config);
   13267 	if (result != ISC_R_SUCCESS) {
   13268 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13269 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13270 			      "Error parsing NZF file '%s': %s",
   13271 			      view->new_zone_file, isc_result_totext(result));
   13272 	}
   13273 
   13274 	return result;
   13275 }
   13276 #else  /* HAVE_LMDB */
   13277 
   13278 static void
   13279 nzd_setkey(MDB_val *key, dns_name_t *name, char *namebuf, size_t buflen) {
   13280 	dns_fixedname_t fixed;
   13281 
   13282 	dns_fixedname_init(&fixed);
   13283 	dns_name_downcase(name, dns_fixedname_name(&fixed), NULL);
   13284 	dns_name_format(dns_fixedname_name(&fixed), namebuf, buflen);
   13285 
   13286 	key->mv_data = namebuf;
   13287 	key->mv_size = strlen(namebuf);
   13288 }
   13289 
   13290 static void
   13291 dumpzone(void *arg, const char *buf, int len) {
   13292 	ns_dzarg_t *dzarg = arg;
   13293 	isc_result_t result;
   13294 
   13295 	REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
   13296 
   13297 	result = putmem(dzarg->text, buf, len);
   13298 	if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
   13299 		dzarg->result = result;
   13300 	}
   13301 }
   13302 
   13303 static isc_result_t
   13304 nzd_save(MDB_txn **txnp, MDB_dbi dbi, dns_zone_t *zone,
   13305 	 const cfg_obj_t *zconfig) {
   13306 	isc_result_t result;
   13307 	int status;
   13308 	dns_view_t *view;
   13309 	bool commit = false;
   13310 	isc_buffer_t *text = NULL;
   13311 	char namebuf[1024];
   13312 	MDB_val key, data;
   13313 	ns_dzarg_t dzarg;
   13314 
   13315 	view = dns_zone_getview(zone);
   13316 
   13317 	nzd_setkey(&key, dns_zone_getorigin(zone), namebuf, sizeof(namebuf));
   13318 
   13319 	if (zconfig == NULL) {
   13320 		/* We're deleting the zone from the database */
   13321 		status = mdb_del(*txnp, dbi, &key, NULL);
   13322 		if (status != MDB_SUCCESS && status != MDB_NOTFOUND) {
   13323 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13324 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13325 				      "Error deleting zone %s "
   13326 				      "from NZD database: %s",
   13327 				      namebuf, mdb_strerror(status));
   13328 			result = ISC_R_FAILURE;
   13329 			goto cleanup;
   13330 		} else if (status != MDB_NOTFOUND) {
   13331 			commit = true;
   13332 		}
   13333 	} else {
   13334 		/* We're creating or overwriting the zone */
   13335 		const cfg_obj_t *zoptions;
   13336 
   13337 		isc_buffer_allocate(view->mctx, &text, 256);
   13338 
   13339 		zoptions = cfg_tuple_get(zconfig, "options");
   13340 		if (zoptions == NULL) {
   13341 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13342 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13343 				      "Unable to get options from config in "
   13344 				      "nzd_save()");
   13345 			result = ISC_R_FAILURE;
   13346 			goto cleanup;
   13347 		}
   13348 
   13349 		dzarg.magic = DZARG_MAGIC;
   13350 		dzarg.text = &text;
   13351 		dzarg.result = ISC_R_SUCCESS;
   13352 		cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
   13353 		if (dzarg.result != ISC_R_SUCCESS) {
   13354 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13355 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13356 				      "Error writing zone config to "
   13357 				      "buffer in nzd_save(): %s",
   13358 				      isc_result_totext(dzarg.result));
   13359 			result = dzarg.result;
   13360 			goto cleanup;
   13361 		}
   13362 
   13363 		data.mv_data = isc_buffer_base(text);
   13364 		data.mv_size = isc_buffer_usedlength(text);
   13365 
   13366 		status = mdb_put(*txnp, dbi, &key, &data, 0);
   13367 		if (status != MDB_SUCCESS) {
   13368 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13369 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13370 				      "Error inserting zone in "
   13371 				      "NZD database: %s",
   13372 				      mdb_strerror(status));
   13373 			result = ISC_R_FAILURE;
   13374 			goto cleanup;
   13375 		}
   13376 
   13377 		commit = true;
   13378 	}
   13379 
   13380 	result = ISC_R_SUCCESS;
   13381 
   13382 cleanup:
   13383 	if (!commit || result != ISC_R_SUCCESS) {
   13384 		(void)mdb_txn_abort(*txnp);
   13385 	} else {
   13386 		status = mdb_txn_commit(*txnp);
   13387 		if (status != MDB_SUCCESS) {
   13388 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13389 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13390 				      "Error committing "
   13391 				      "NZD database: %s",
   13392 				      mdb_strerror(status));
   13393 			result = ISC_R_FAILURE;
   13394 		}
   13395 	}
   13396 	*txnp = NULL;
   13397 
   13398 	if (text != NULL) {
   13399 		isc_buffer_free(&text);
   13400 	}
   13401 
   13402 	return result;
   13403 }
   13404 
   13405 /*
   13406  * Check whether the new zone database for 'view' can be opened for writing.
   13407  *
   13408  * Caller must hold 'view->new_zone_lock'.
   13409  */
   13410 static isc_result_t
   13411 nzd_writable(dns_view_t *view) {
   13412 	isc_result_t result = ISC_R_SUCCESS;
   13413 	int status;
   13414 	MDB_dbi dbi;
   13415 	MDB_txn *txn = NULL;
   13416 
   13417 	REQUIRE(view != NULL);
   13418 
   13419 	status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, 0, &txn);
   13420 	if (status != MDB_SUCCESS) {
   13421 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13422 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   13423 			      "mdb_txn_begin: %s", mdb_strerror(status));
   13424 		return ISC_R_FAILURE;
   13425 	}
   13426 
   13427 	status = mdb_dbi_open(txn, NULL, 0, &dbi);
   13428 	if (status != MDB_SUCCESS) {
   13429 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13430 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   13431 			      "mdb_dbi_open: %s", mdb_strerror(status));
   13432 		result = ISC_R_FAILURE;
   13433 	}
   13434 
   13435 	mdb_txn_abort(txn);
   13436 	return result;
   13437 }
   13438 
   13439 /*
   13440  * Open the new zone database for 'view' and start a transaction for it.
   13441  *
   13442  * Caller must hold 'view->new_zone_lock'.
   13443  */
   13444 static isc_result_t
   13445 nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi) {
   13446 	int status;
   13447 	MDB_txn *txn = NULL;
   13448 
   13449 	REQUIRE(view != NULL);
   13450 	REQUIRE(txnp != NULL && *txnp == NULL);
   13451 	REQUIRE(dbi != NULL);
   13452 
   13453 	status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, flags, &txn);
   13454 	if (status != MDB_SUCCESS) {
   13455 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13456 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   13457 			      "mdb_txn_begin: %s", mdb_strerror(status));
   13458 		goto cleanup;
   13459 	}
   13460 
   13461 	status = mdb_dbi_open(txn, NULL, 0, dbi);
   13462 	if (status != MDB_SUCCESS) {
   13463 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13464 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   13465 			      "mdb_dbi_open: %s", mdb_strerror(status));
   13466 		goto cleanup;
   13467 	}
   13468 
   13469 	*txnp = txn;
   13470 
   13471 cleanup:
   13472 	if (status != MDB_SUCCESS) {
   13473 		if (txn != NULL) {
   13474 			mdb_txn_abort(txn);
   13475 		}
   13476 		return ISC_R_FAILURE;
   13477 	}
   13478 
   13479 	return ISC_R_SUCCESS;
   13480 }
   13481 
   13482 /*
   13483  * nzd_env_close() and nzd_env_reopen are a kluge to address the
   13484  * problem of an NZD file possibly being created before we drop
   13485  * root privileges.
   13486  */
   13487 static void
   13488 nzd_env_close(dns_view_t *view) {
   13489 	const char *dbpath = NULL;
   13490 	char dbpath_copy[PATH_MAX];
   13491 	char lockpath[PATH_MAX];
   13492 	int status, ret;
   13493 
   13494 	if (view->new_zone_dbenv == NULL) {
   13495 		return;
   13496 	}
   13497 
   13498 	status = mdb_env_get_path(view->new_zone_dbenv, &dbpath);
   13499 	INSIST(status == MDB_SUCCESS);
   13500 	snprintf(lockpath, sizeof(lockpath), "%s-lock", dbpath);
   13501 	strlcpy(dbpath_copy, dbpath, sizeof(dbpath_copy));
   13502 	mdb_env_close((MDB_env *)view->new_zone_dbenv);
   13503 
   13504 	/*
   13505 	 * Database files must be owned by the eventual user, not by root.
   13506 	 */
   13507 	ret = chown(dbpath_copy, named_os_uid(), -1);
   13508 	UNUSED(ret);
   13509 
   13510 	/*
   13511 	 * Some platforms need the lockfile not to exist when we reopen the
   13512 	 * environment.
   13513 	 */
   13514 	(void)isc_file_remove(lockpath);
   13515 
   13516 	view->new_zone_dbenv = NULL;
   13517 }
   13518 
   13519 static isc_result_t
   13520 nzd_env_reopen(dns_view_t *view) {
   13521 	isc_result_t result;
   13522 	MDB_env *env = NULL;
   13523 	int status;
   13524 
   13525 	if (view->new_zone_db == NULL) {
   13526 		return ISC_R_SUCCESS;
   13527 	}
   13528 
   13529 	nzd_env_close(view);
   13530 
   13531 	status = mdb_env_create(&env);
   13532 	if (status != MDB_SUCCESS) {
   13533 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   13534 			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
   13535 			      "mdb_env_create failed: %s",
   13536 			      mdb_strerror(status));
   13537 		CHECK(ISC_R_FAILURE);
   13538 	}
   13539 
   13540 	if (view->new_zone_mapsize != 0ULL) {
   13541 		status = mdb_env_set_mapsize(env, view->new_zone_mapsize);
   13542 		if (status != MDB_SUCCESS) {
   13543 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   13544 				      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
   13545 				      "mdb_env_set_mapsize failed: %s",
   13546 				      mdb_strerror(status));
   13547 			CHECK(ISC_R_FAILURE);
   13548 		}
   13549 	}
   13550 
   13551 	status = mdb_env_open(env, view->new_zone_db, DNS_LMDB_FLAGS, 0600);
   13552 	if (status != MDB_SUCCESS) {
   13553 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   13554 			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
   13555 			      "mdb_env_open of '%s' failed: %s",
   13556 			      view->new_zone_db, mdb_strerror(status));
   13557 		CHECK(ISC_R_FAILURE);
   13558 	}
   13559 
   13560 	view->new_zone_dbenv = env;
   13561 	env = NULL;
   13562 	result = ISC_R_SUCCESS;
   13563 
   13564 cleanup:
   13565 	if (env != NULL) {
   13566 		mdb_env_close(env);
   13567 	}
   13568 	return result;
   13569 }
   13570 
   13571 /*
   13572  * If 'commit' is true, commit the new zone database transaction pointed to by
   13573  * 'txnp'; otherwise, abort that transaction.
   13574  *
   13575  * Caller must hold 'view->new_zone_lock' for the view that the transaction
   13576  * pointed to by 'txnp' was started for.
   13577  */
   13578 static isc_result_t
   13579 nzd_close(MDB_txn **txnp, bool commit) {
   13580 	isc_result_t result = ISC_R_SUCCESS;
   13581 	int status;
   13582 
   13583 	REQUIRE(txnp != NULL);
   13584 
   13585 	if (*txnp != NULL) {
   13586 		if (commit) {
   13587 			status = mdb_txn_commit(*txnp);
   13588 			if (status != MDB_SUCCESS) {
   13589 				result = ISC_R_FAILURE;
   13590 			}
   13591 		} else {
   13592 			mdb_txn_abort(*txnp);
   13593 		}
   13594 		*txnp = NULL;
   13595 	}
   13596 
   13597 	return result;
   13598 }
   13599 
   13600 /*
   13601  * If there's an existing NZF file, load it and migrate its data
   13602  * to the NZD.
   13603  *
   13604  * Caller must hold view->new_zone_lock.
   13605  */
   13606 static isc_result_t
   13607 load_nzf(dns_view_t *view, ns_cfgctx_t *nzcfg) {
   13608 	isc_result_t result;
   13609 	cfg_obj_t *nzf_config = NULL;
   13610 	int status;
   13611 	isc_buffer_t *text = NULL;
   13612 	bool commit = false;
   13613 	const cfg_obj_t *zonelist;
   13614 	const cfg_listelt_t *element;
   13615 	char tempname[PATH_MAX];
   13616 	MDB_txn *txn = NULL;
   13617 	MDB_dbi dbi;
   13618 	MDB_val key, data;
   13619 	ns_dzarg_t dzarg;
   13620 
   13621 	UNUSED(nzcfg);
   13622 
   13623 	/*
   13624 	 * If NZF file doesn't exist, or NZD DB exists and already
   13625 	 * has data, return without attempting migration.
   13626 	 */
   13627 	if (!isc_file_exists(view->new_zone_file)) {
   13628 		result = ISC_R_SUCCESS;
   13629 		goto cleanup;
   13630 	}
   13631 
   13632 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13633 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   13634 		      "Migrating zones from NZF file '%s' to "
   13635 		      "NZD database '%s'",
   13636 		      view->new_zone_file, view->new_zone_db);
   13637 	/*
   13638 	 * Instead of blindly copying lines, we parse the NZF file using
   13639 	 * the configuration parser, because it validates it against the
   13640 	 * config type, giving us a guarantee that valid configuration
   13641 	 * will be written to DB.
   13642 	 */
   13643 	cfg_parser_reset(named_g_addparser);
   13644 	result = cfg_parse_file(named_g_addparser, view->new_zone_file,
   13645 				&cfg_type_addzoneconf, &nzf_config);
   13646 	if (result != ISC_R_SUCCESS) {
   13647 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13648 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13649 			      "Error parsing NZF file '%s': %s",
   13650 			      view->new_zone_file, isc_result_totext(result));
   13651 		goto cleanup;
   13652 	}
   13653 
   13654 	zonelist = NULL;
   13655 	CHECK(cfg_map_get(nzf_config, "zone", &zonelist));
   13656 	if (!cfg_obj_islist(zonelist)) {
   13657 		CHECK(ISC_R_FAILURE);
   13658 	}
   13659 
   13660 	CHECK(nzd_open(view, 0, &txn, &dbi));
   13661 
   13662 	isc_buffer_allocate(view->mctx, &text, 256);
   13663 
   13664 	for (element = cfg_list_first(zonelist); element != NULL;
   13665 	     element = cfg_list_next(element))
   13666 	{
   13667 		const cfg_obj_t *zconfig;
   13668 		const cfg_obj_t *zoptions;
   13669 		char zname[DNS_NAME_FORMATSIZE];
   13670 		dns_fixedname_t fname;
   13671 		dns_name_t *name;
   13672 		const char *origin;
   13673 		isc_buffer_t b;
   13674 
   13675 		zconfig = cfg_listelt_value(element);
   13676 
   13677 		origin = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
   13678 		if (origin == NULL) {
   13679 			result = ISC_R_FAILURE;
   13680 			goto cleanup;
   13681 		}
   13682 
   13683 		/* Normalize zone name */
   13684 		isc_buffer_constinit(&b, origin, strlen(origin));
   13685 		isc_buffer_add(&b, strlen(origin));
   13686 		name = dns_fixedname_initname(&fname);
   13687 		CHECK(dns_name_fromtext(name, &b, dns_rootname,
   13688 					DNS_NAME_DOWNCASE, NULL));
   13689 		dns_name_format(name, zname, sizeof(zname));
   13690 
   13691 		key.mv_data = zname;
   13692 		key.mv_size = strlen(zname);
   13693 
   13694 		zoptions = cfg_tuple_get(zconfig, "options");
   13695 		if (zoptions == NULL) {
   13696 			result = ISC_R_FAILURE;
   13697 			goto cleanup;
   13698 		}
   13699 
   13700 		isc_buffer_clear(text);
   13701 		dzarg.magic = DZARG_MAGIC;
   13702 		dzarg.text = &text;
   13703 		dzarg.result = ISC_R_SUCCESS;
   13704 		cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
   13705 		if (dzarg.result != ISC_R_SUCCESS) {
   13706 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13707 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13708 				      "Error writing zone config to "
   13709 				      "buffer in load_nzf(): %s",
   13710 				      isc_result_totext(result));
   13711 			result = dzarg.result;
   13712 			goto cleanup;
   13713 		}
   13714 
   13715 		data.mv_data = isc_buffer_base(text);
   13716 		data.mv_size = isc_buffer_usedlength(text);
   13717 
   13718 		status = mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE);
   13719 		if (status != MDB_SUCCESS) {
   13720 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   13721 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   13722 				      "Error inserting zone in "
   13723 				      "NZD database: %s",
   13724 				      mdb_strerror(status));
   13725 			result = ISC_R_FAILURE;
   13726 			goto cleanup;
   13727 		}
   13728 
   13729 		commit = true;
   13730 	}
   13731 
   13732 	result = ISC_R_SUCCESS;
   13733 
   13734 	/*
   13735 	 * Leaving the NZF file in place is harmless as we won't use it
   13736 	 * if an NZD database is found for the view. But we rename NZF file
   13737 	 * to a backup name here.
   13738 	 */
   13739 	strlcpy(tempname, view->new_zone_file, sizeof(tempname));
   13740 	if (strlen(tempname) < sizeof(tempname) - 1) {
   13741 		strlcat(tempname, "~", sizeof(tempname));
   13742 		isc_file_rename(view->new_zone_file, tempname);
   13743 	}
   13744 
   13745 cleanup:
   13746 	if (result != ISC_R_SUCCESS) {
   13747 		(void)nzd_close(&txn, false);
   13748 	} else {
   13749 		result = nzd_close(&txn, commit);
   13750 	}
   13751 
   13752 	if (text != NULL) {
   13753 		isc_buffer_free(&text);
   13754 	}
   13755 
   13756 	if (nzf_config != NULL) {
   13757 		cfg_obj_destroy(named_g_addparser, &nzf_config);
   13758 	}
   13759 
   13760 	return result;
   13761 }
   13762 #endif /* HAVE_LMDB */
   13763 
   13764 static isc_result_t
   13765 newzone_parse(named_server_t *server, char *command, dns_view_t **viewp,
   13766 	      cfg_obj_t **zoneconfp, const cfg_obj_t **zoneobjp,
   13767 	      bool *redirectp, isc_buffer_t **text) {
   13768 	isc_result_t result;
   13769 	isc_buffer_t argbuf;
   13770 	bool redirect = false;
   13771 	cfg_obj_t *zoneconf = NULL;
   13772 	const cfg_obj_t *zlist = NULL;
   13773 	const cfg_obj_t *zoneobj = NULL;
   13774 	const cfg_obj_t *zoptions = NULL;
   13775 	const cfg_obj_t *obj = NULL;
   13776 	const char *viewname = NULL;
   13777 	dns_rdataclass_t rdclass;
   13778 	dns_view_t *view = NULL;
   13779 	const char *bn = NULL;
   13780 
   13781 	REQUIRE(viewp != NULL && *viewp == NULL);
   13782 	REQUIRE(zoneobjp != NULL && *zoneobjp == NULL);
   13783 	REQUIRE(zoneconfp != NULL && *zoneconfp == NULL);
   13784 	REQUIRE(redirectp != NULL);
   13785 
   13786 	/* Try to parse the argument string */
   13787 	isc_buffer_init(&argbuf, command, (unsigned int)strlen(command));
   13788 	isc_buffer_add(&argbuf, strlen(command));
   13789 
   13790 	if (strncasecmp(command, "add", 3) == 0) {
   13791 		bn = "addzone";
   13792 	} else if (strncasecmp(command, "mod", 3) == 0) {
   13793 		bn = "modzone";
   13794 	} else {
   13795 		UNREACHABLE();
   13796 	}
   13797 
   13798 	/*
   13799 	 * Convert the "addzone" or "modzone" to just "zone", for
   13800 	 * the benefit of the parser
   13801 	 */
   13802 	isc_buffer_forward(&argbuf, 3);
   13803 
   13804 	cfg_parser_reset(named_g_addparser);
   13805 	CHECK(cfg_parse_buffer(named_g_addparser, &argbuf, bn, 0,
   13806 			       &cfg_type_addzoneconf, 0, &zoneconf));
   13807 	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
   13808 	if (!cfg_obj_islist(zlist)) {
   13809 		CHECK(ISC_R_FAILURE);
   13810 	}
   13811 
   13812 	/* For now we only support adding one zone at a time */
   13813 	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
   13814 
   13815 	/* Check the zone type for ones that are not supported by addzone. */
   13816 	zoptions = cfg_tuple_get(zoneobj, "options");
   13817 
   13818 	obj = NULL;
   13819 	(void)cfg_map_get(zoptions, "type", &obj);
   13820 	if (obj == NULL) {
   13821 		(void)cfg_map_get(zoptions, "in-view", &obj);
   13822 		if (obj != NULL) {
   13823 			(void)putstr(text, "'in-view' zones not supported by ");
   13824 			(void)putstr(text, bn);
   13825 		} else {
   13826 			(void)putstr(text, "zone type not specified");
   13827 		}
   13828 		CHECK(ISC_R_FAILURE);
   13829 	}
   13830 
   13831 	if (strcasecmp(cfg_obj_asstring(obj), "hint") == 0 ||
   13832 	    strcasecmp(cfg_obj_asstring(obj), "forward") == 0)
   13833 	{
   13834 		(void)putstr(text, "'");
   13835 		(void)putstr(text, cfg_obj_asstring(obj));
   13836 		(void)putstr(text, "' zones not supported by ");
   13837 		(void)putstr(text, bn);
   13838 		CHECK(ISC_R_FAILURE);
   13839 	}
   13840 
   13841 	if (strcasecmp(cfg_obj_asstring(obj), "redirect") == 0) {
   13842 		redirect = true;
   13843 	}
   13844 
   13845 	/* Make sense of optional class argument */
   13846 	obj = cfg_tuple_get(zoneobj, "class");
   13847 	CHECK(named_config_getclass(obj, dns_rdataclass_in, &rdclass));
   13848 
   13849 	/* Make sense of optional view argument */
   13850 	obj = cfg_tuple_get(zoneobj, "view");
   13851 	if (obj && cfg_obj_isstring(obj)) {
   13852 		viewname = cfg_obj_asstring(obj);
   13853 	}
   13854 	if (viewname == NULL || *viewname == '\0') {
   13855 		viewname = "_default";
   13856 	}
   13857 	result = dns_viewlist_find(&server->viewlist, viewname, rdclass, &view);
   13858 	if (result == ISC_R_NOTFOUND) {
   13859 		(void)putstr(text, "no matching view found for '");
   13860 		(void)putstr(text, viewname);
   13861 		(void)putstr(text, "'");
   13862 		goto cleanup;
   13863 	} else if (result != ISC_R_SUCCESS) {
   13864 		goto cleanup;
   13865 	}
   13866 
   13867 	*viewp = view;
   13868 	*zoneobjp = zoneobj;
   13869 	*zoneconfp = zoneconf;
   13870 	*redirectp = redirect;
   13871 
   13872 	return ISC_R_SUCCESS;
   13873 
   13874 cleanup:
   13875 	if (zoneconf != NULL) {
   13876 		cfg_obj_destroy(named_g_addparser, &zoneconf);
   13877 	}
   13878 	if (view != NULL) {
   13879 		dns_view_detach(&view);
   13880 	}
   13881 
   13882 	return result;
   13883 }
   13884 
   13885 static isc_result_t
   13886 delete_zoneconf(dns_view_t *view, cfg_parser_t *pctx, const cfg_obj_t *config,
   13887 		const dns_name_t *zname, nzfwriter_t nzfwriter) {
   13888 	isc_result_t result = ISC_R_NOTFOUND;
   13889 	const cfg_listelt_t *elt = NULL;
   13890 	const cfg_obj_t *zl = NULL;
   13891 	cfg_list_t *list;
   13892 	dns_fixedname_t myfixed;
   13893 	dns_name_t *myname;
   13894 
   13895 	REQUIRE(view != NULL);
   13896 	REQUIRE(pctx != NULL);
   13897 	REQUIRE(config != NULL);
   13898 	REQUIRE(zname != NULL);
   13899 
   13900 	LOCK(&view->new_zone_lock);
   13901 
   13902 	cfg_map_get(config, "zone", &zl);
   13903 
   13904 	if (!cfg_obj_islist(zl)) {
   13905 		CHECK(ISC_R_FAILURE);
   13906 	}
   13907 
   13908 	list = UNCONST(&zl->value.list);
   13909 
   13910 	myname = dns_fixedname_initname(&myfixed);
   13911 
   13912 	for (elt = ISC_LIST_HEAD(*list); elt != NULL;
   13913 	     elt = ISC_LIST_NEXT(elt, link))
   13914 	{
   13915 		const cfg_obj_t *zconf = cfg_listelt_value(elt);
   13916 		const char *zn;
   13917 		cfg_listelt_t *e;
   13918 
   13919 		zn = cfg_obj_asstring(cfg_tuple_get(zconf, "name"));
   13920 		result = dns_name_fromstring(myname, zn, dns_rootname, 0, NULL);
   13921 		if (result != ISC_R_SUCCESS || !dns_name_equal(zname, myname)) {
   13922 			continue;
   13923 		}
   13924 
   13925 		e = UNCONST(elt);
   13926 		ISC_LIST_UNLINK(*list, e, link);
   13927 		cfg_obj_destroy(pctx, &e->obj);
   13928 		isc_mem_put(pctx->mctx, e, sizeof(*e));
   13929 		result = ISC_R_SUCCESS;
   13930 		break;
   13931 	}
   13932 
   13933 	/*
   13934 	 * Write config to NZF file if appropriate
   13935 	 */
   13936 	if (nzfwriter != NULL && view->new_zone_file != NULL) {
   13937 		result = nzfwriter(config, view);
   13938 	}
   13939 
   13940 cleanup:
   13941 	UNLOCK(&view->new_zone_lock);
   13942 	return result;
   13943 }
   13944 
   13945 static isc_result_t
   13946 do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
   13947 	   dns_name_t *name, cfg_obj_t *zoneconf, const cfg_obj_t *zoneobj,
   13948 	   bool redirect, isc_buffer_t **text) {
   13949 	isc_result_t result, tresult;
   13950 	dns_zone_t *zone = NULL;
   13951 #ifndef HAVE_LMDB
   13952 	FILE *fp = NULL;
   13953 	bool cleanup_config = false;
   13954 #else /* HAVE_LMDB */
   13955 	MDB_txn *txn = NULL;
   13956 	MDB_dbi dbi;
   13957 	bool locked = false;
   13958 
   13959 	UNUSED(zoneconf);
   13960 #endif
   13961 
   13962 	/* Zone shouldn't already exist */
   13963 	if (redirect) {
   13964 		result = (view->redirect == NULL) ? ISC_R_NOTFOUND
   13965 						  : ISC_R_EXISTS;
   13966 	} else {
   13967 		result = dns_view_findzone(view, name, DNS_ZTFIND_EXACT, &zone);
   13968 		if (result == ISC_R_SUCCESS) {
   13969 			result = ISC_R_EXISTS;
   13970 		}
   13971 	}
   13972 	if (result != ISC_R_NOTFOUND) {
   13973 		goto cleanup;
   13974 	}
   13975 
   13976 	isc_loopmgr_pause(named_g_loopmgr);
   13977 
   13978 #ifndef HAVE_LMDB
   13979 	/*
   13980 	 * Make sure we can open the configuration save file
   13981 	 */
   13982 	result = isc_stdio_open(view->new_zone_file, "a", &fp);
   13983 	if (result != ISC_R_SUCCESS) {
   13984 		isc_loopmgr_resume(named_g_loopmgr);
   13985 		TCHECK(putstr(text, "unable to create '"));
   13986 		TCHECK(putstr(text, view->new_zone_file));
   13987 		TCHECK(putstr(text, "': "));
   13988 		TCHECK(putstr(text, isc_result_totext(result)));
   13989 		goto cleanup;
   13990 	}
   13991 
   13992 	(void)isc_stdio_close(fp);
   13993 	fp = NULL;
   13994 #else  /* HAVE_LMDB */
   13995 	LOCK(&view->new_zone_lock);
   13996 	locked = true;
   13997 	/* Make sure we can open the NZD database */
   13998 	result = nzd_writable(view);
   13999 	if (result != ISC_R_SUCCESS) {
   14000 		isc_loopmgr_resume(named_g_loopmgr);
   14001 		TCHECK(putstr(text, "unable to open NZD database for '"));
   14002 		TCHECK(putstr(text, view->new_zone_db));
   14003 		TCHECK(putstr(text, "'"));
   14004 		result = ISC_R_FAILURE;
   14005 		goto cleanup;
   14006 	}
   14007 #endif /* HAVE_LMDB */
   14008 
   14009 	/* Mark view unfrozen and configure zone */
   14010 	dns_view_thaw(view);
   14011 	result = configure_zone(cfg->config, zoneobj, cfg->vconfig, view,
   14012 				&server->viewlist, &server->kasplist,
   14013 				&server->keystorelist, cfg->actx, true, false,
   14014 				false, false);
   14015 	dns_view_freeze(view);
   14016 
   14017 	isc_loopmgr_resume(named_g_loopmgr);
   14018 
   14019 	if (result != ISC_R_SUCCESS) {
   14020 		TCHECK(putstr(text, "configure_zone failed: "));
   14021 		TCHECK(putstr(text, isc_result_totext(result)));
   14022 		goto cleanup;
   14023 	}
   14024 
   14025 	/* Is it there yet? */
   14026 	if (redirect) {
   14027 		if (view->redirect == NULL) {
   14028 			CHECK(ISC_R_NOTFOUND);
   14029 		}
   14030 		dns_zone_attach(view->redirect, &zone);
   14031 	} else {
   14032 		result = dns_view_findzone(view, name, DNS_ZTFIND_EXACT, &zone);
   14033 		if (result != ISC_R_SUCCESS) {
   14034 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14035 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   14036 				      "added new zone was not found: %s",
   14037 				      isc_result_totext(result));
   14038 			goto cleanup;
   14039 		}
   14040 	}
   14041 
   14042 #ifndef HAVE_LMDB
   14043 	/*
   14044 	 * If there wasn't a previous newzone config, just save the one
   14045 	 * we've created. If there was a previous one, merge the new
   14046 	 * zone into it.
   14047 	 */
   14048 	if (cfg->nzf_config == NULL) {
   14049 		cfg_obj_attach(zoneconf, &cfg->nzf_config);
   14050 	} else {
   14051 		cfg_obj_t *z = UNCONST(zoneobj);
   14052 		CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z,
   14053 					"zone"));
   14054 	}
   14055 	cleanup_config = true;
   14056 #endif /* HAVE_LMDB */
   14057 
   14058 	/*
   14059 	 * Load the zone from the master file.  If this fails, we'll
   14060 	 * need to undo the configuration we've done already.
   14061 	 */
   14062 	result = dns_zone_load(zone, true);
   14063 	if (result != ISC_R_SUCCESS) {
   14064 		dns_db_t *dbp = NULL;
   14065 
   14066 		TCHECK(putstr(text, "dns_zone_loadnew failed: "));
   14067 		TCHECK(putstr(text, isc_result_totext(result)));
   14068 
   14069 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14070 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   14071 			      "addzone failed; reverting.");
   14072 
   14073 		/* If the zone loaded partially, unload it */
   14074 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
   14075 			dns_db_detach(&dbp);
   14076 			dns_zone_unload(zone);
   14077 		}
   14078 
   14079 		/* Remove the zone from the zone table */
   14080 		dns_view_delzone(view, zone);
   14081 		goto cleanup;
   14082 	}
   14083 
   14084 	/* Flag the zone as having been added at runtime */
   14085 	dns_zone_setadded(zone, true);
   14086 
   14087 #ifdef HAVE_LMDB
   14088 	/* Save the new zone configuration into the NZD */
   14089 	CHECK(nzd_open(view, 0, &txn, &dbi));
   14090 	CHECK(nzd_save(&txn, dbi, zone, zoneobj));
   14091 #else  /* ifdef HAVE_LMDB */
   14092 	/* Append the zone configuration to the NZF */
   14093 	result = nzf_append(view, zoneobj);
   14094 #endif /* HAVE_LMDB */
   14095 
   14096 cleanup:
   14097 
   14098 #ifndef HAVE_LMDB
   14099 	if (fp != NULL) {
   14100 		(void)isc_stdio_close(fp);
   14101 	}
   14102 	if (result != ISC_R_SUCCESS && cleanup_config) {
   14103 		tresult = delete_zoneconf(view, cfg->add_parser,
   14104 					  cfg->nzf_config, name, NULL);
   14105 		RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
   14106 	}
   14107 #else  /* HAVE_LMDB */
   14108 	if (txn != NULL) {
   14109 		(void)nzd_close(&txn, false);
   14110 	}
   14111 	if (locked) {
   14112 		UNLOCK(&view->new_zone_lock);
   14113 	}
   14114 #endif /* HAVE_LMDB */
   14115 
   14116 	if (zone != NULL) {
   14117 		dns_zone_detach(&zone);
   14118 	}
   14119 
   14120 	return result;
   14121 }
   14122 
   14123 static isc_result_t
   14124 do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
   14125 	   dns_name_t *name, const char *zname, const cfg_obj_t *zoneobj,
   14126 	   bool redirect, isc_buffer_t **text) {
   14127 	isc_result_t result, tresult;
   14128 	dns_zone_t *zone = NULL;
   14129 	bool added;
   14130 #ifndef HAVE_LMDB
   14131 	FILE *fp = NULL;
   14132 	cfg_obj_t *z;
   14133 #else  /* HAVE_LMDB */
   14134 	MDB_txn *txn = NULL;
   14135 	MDB_dbi dbi;
   14136 	bool locked = false;
   14137 #endif /* HAVE_LMDB */
   14138 
   14139 	/* Zone must already exist */
   14140 	if (redirect) {
   14141 		if (view->redirect != NULL) {
   14142 			dns_zone_attach(view->redirect, &zone);
   14143 			result = ISC_R_SUCCESS;
   14144 		} else {
   14145 			result = ISC_R_NOTFOUND;
   14146 		}
   14147 	} else {
   14148 		result = dns_view_findzone(view, name, DNS_ZTFIND_EXACT, &zone);
   14149 	}
   14150 	if (result != ISC_R_SUCCESS) {
   14151 		goto cleanup;
   14152 	}
   14153 
   14154 	added = dns_zone_getadded(zone);
   14155 	dns_zone_detach(&zone);
   14156 
   14157 #ifndef HAVE_LMDB
   14158 	cfg = (ns_cfgctx_t *)view->new_zone_config;
   14159 	if (cfg == NULL) {
   14160 		TCHECK(putstr(text, "new zone config is not set"));
   14161 		CHECK(ISC_R_FAILURE);
   14162 	}
   14163 #endif /* ifndef HAVE_LMDB */
   14164 
   14165 	isc_loopmgr_pause(named_g_loopmgr);
   14166 
   14167 #ifndef HAVE_LMDB
   14168 	/* Make sure we can open the configuration save file */
   14169 	result = isc_stdio_open(view->new_zone_file, "a", &fp);
   14170 	if (result != ISC_R_SUCCESS) {
   14171 		TCHECK(putstr(text, "unable to open '"));
   14172 		TCHECK(putstr(text, view->new_zone_file));
   14173 		TCHECK(putstr(text, "': "));
   14174 		TCHECK(putstr(text, isc_result_totext(result)));
   14175 		isc_loopmgr_resume(named_g_loopmgr);
   14176 		goto cleanup;
   14177 	}
   14178 	(void)isc_stdio_close(fp);
   14179 	fp = NULL;
   14180 #else  /* HAVE_LMDB */
   14181 	LOCK(&view->new_zone_lock);
   14182 	locked = true;
   14183 	/* Make sure we can open the NZD database */
   14184 	result = nzd_writable(view);
   14185 	if (result != ISC_R_SUCCESS) {
   14186 		TCHECK(putstr(text, "unable to open NZD database for '"));
   14187 		TCHECK(putstr(text, view->new_zone_db));
   14188 		TCHECK(putstr(text, "'"));
   14189 		result = ISC_R_FAILURE;
   14190 		isc_loopmgr_resume(named_g_loopmgr);
   14191 		goto cleanup;
   14192 	}
   14193 #endif /* HAVE_LMDB */
   14194 
   14195 	/* Reconfigure the zone */
   14196 	dns_view_thaw(view);
   14197 	result = configure_zone(cfg->config, zoneobj, cfg->vconfig, view,
   14198 				&server->viewlist, &server->kasplist,
   14199 				&server->keystorelist, cfg->actx, true, false,
   14200 				false, true);
   14201 	dns_view_freeze(view);
   14202 
   14203 	isc_loopmgr_resume(named_g_loopmgr);
   14204 
   14205 	if (result != ISC_R_SUCCESS) {
   14206 		TCHECK(putstr(text, "configure_zone failed: "));
   14207 		TCHECK(putstr(text, isc_result_totext(result)));
   14208 		goto cleanup;
   14209 	}
   14210 
   14211 	/* Is it there yet? */
   14212 	if (redirect) {
   14213 		if (view->redirect == NULL) {
   14214 			CHECK(ISC_R_NOTFOUND);
   14215 		}
   14216 		dns_zone_attach(view->redirect, &zone);
   14217 	} else {
   14218 		CHECK(dns_view_findzone(view, name, DNS_ZTFIND_EXACT, &zone));
   14219 	}
   14220 
   14221 #ifndef HAVE_LMDB
   14222 	/* Remove old zone from configuration (and NZF file if applicable) */
   14223 	if (added) {
   14224 		result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config,
   14225 					 dns_zone_getorigin(zone),
   14226 					 nzf_writeconf);
   14227 		if (result != ISC_R_SUCCESS) {
   14228 			TCHECK(putstr(text, "former zone configuration "
   14229 					    "not deleted: "));
   14230 			TCHECK(putstr(text, isc_result_totext(result)));
   14231 			goto cleanup;
   14232 		}
   14233 	}
   14234 #endif /* HAVE_LMDB */
   14235 
   14236 	if (!added) {
   14237 		if (cfg->vconfig == NULL) {
   14238 			result = delete_zoneconf(
   14239 				view, cfg->conf_parser, cfg->config,
   14240 				dns_zone_getorigin(zone), NULL);
   14241 		} else {
   14242 			const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig,
   14243 								  "options");
   14244 			result = delete_zoneconf(
   14245 				view, cfg->conf_parser, voptions,
   14246 				dns_zone_getorigin(zone), NULL);
   14247 		}
   14248 
   14249 		if (result != ISC_R_SUCCESS) {
   14250 			TCHECK(putstr(text, "former zone configuration "
   14251 					    "not deleted: "));
   14252 			TCHECK(putstr(text, isc_result_totext(result)));
   14253 			goto cleanup;
   14254 		}
   14255 	}
   14256 
   14257 	/* Load the zone from the master file if it needs reloading. */
   14258 	result = dns_zone_load(zone, true);
   14259 
   14260 	/*
   14261 	 * Dynamic zones need no reloading, so we can pass this result.
   14262 	 */
   14263 	if (result == DNS_R_DYNAMIC) {
   14264 		result = ISC_R_SUCCESS;
   14265 	}
   14266 
   14267 	if (result != ISC_R_SUCCESS) {
   14268 		dns_db_t *dbp = NULL;
   14269 
   14270 		TCHECK(putstr(text, "failed to load zone '"));
   14271 		TCHECK(putstr(text, zname));
   14272 		TCHECK(putstr(text, "': "));
   14273 		TCHECK(putstr(text, isc_result_totext(result)));
   14274 		TCHECK(putstr(text, "\nThe zone is no longer being served. "));
   14275 		TCHECK(putstr(text, "Use 'rndc addzone' to correct\n"));
   14276 		TCHECK(putstr(text, "the problem and restore service."));
   14277 
   14278 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14279 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   14280 			      "modzone failed; removing zone.");
   14281 
   14282 		/* If the zone loaded partially, unload it */
   14283 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
   14284 			dns_db_detach(&dbp);
   14285 			dns_zone_unload(zone);
   14286 		}
   14287 
   14288 		/* Remove the zone from the zone table */
   14289 		dns_view_delzone(view, zone);
   14290 		goto cleanup;
   14291 	}
   14292 
   14293 #ifndef HAVE_LMDB
   14294 	/* Store the new zone configuration; also in NZF if applicable */
   14295 	z = UNCONST(zoneobj);
   14296 	CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z, "zone"));
   14297 #endif /* HAVE_LMDB */
   14298 
   14299 	if (added) {
   14300 #ifdef HAVE_LMDB
   14301 		CHECK(nzd_open(view, 0, &txn, &dbi));
   14302 		CHECK(nzd_save(&txn, dbi, zone, zoneobj));
   14303 #else  /* ifdef HAVE_LMDB */
   14304 		result = nzf_append(view, zoneobj);
   14305 		if (result != ISC_R_SUCCESS) {
   14306 			TCHECK(putstr(text, "\nNew zone config not saved: "));
   14307 			TCHECK(putstr(text, isc_result_totext(result)));
   14308 			goto cleanup;
   14309 		}
   14310 #endif /* HAVE_LMDB */
   14311 
   14312 		TCHECK(putstr(text, "zone '"));
   14313 		TCHECK(putstr(text, zname));
   14314 		TCHECK(putstr(text, "' reconfigured."));
   14315 	} else {
   14316 		TCHECK(putstr(text, "zone '"));
   14317 		TCHECK(putstr(text, zname));
   14318 		TCHECK(putstr(text, "' must also be reconfigured in\n"));
   14319 		TCHECK(putstr(text, "named.conf to make changes permanent."));
   14320 	}
   14321 
   14322 cleanup:
   14323 
   14324 #ifndef HAVE_LMDB
   14325 	if (fp != NULL) {
   14326 		(void)isc_stdio_close(fp);
   14327 	}
   14328 #else  /* HAVE_LMDB */
   14329 	if (txn != NULL) {
   14330 		(void)nzd_close(&txn, false);
   14331 	}
   14332 	if (locked) {
   14333 		UNLOCK(&view->new_zone_lock);
   14334 	}
   14335 #endif /* HAVE_LMDB */
   14336 
   14337 	if (zone != NULL) {
   14338 		dns_zone_detach(&zone);
   14339 	}
   14340 
   14341 	return result;
   14342 }
   14343 
   14344 /*
   14345  * Act on an "addzone" or "modzone" command from the command channel.
   14346  */
   14347 isc_result_t
   14348 named_server_changezone(named_server_t *server, char *command,
   14349 			isc_buffer_t **text) {
   14350 	isc_result_t result;
   14351 	bool addzone;
   14352 	bool redirect = false;
   14353 	ns_cfgctx_t *cfg = NULL;
   14354 	cfg_obj_t *zoneconf = NULL;
   14355 	const cfg_obj_t *zoneobj = NULL;
   14356 	const char *zonename;
   14357 	dns_view_t *view = NULL;
   14358 	isc_buffer_t buf;
   14359 	dns_fixedname_t fname;
   14360 	dns_name_t *dnsname;
   14361 
   14362 	REQUIRE(text != NULL);
   14363 
   14364 	if (strncasecmp(command, "add", 3) == 0) {
   14365 		addzone = true;
   14366 	} else {
   14367 		INSIST(strncasecmp(command, "mod", 3) == 0);
   14368 		addzone = false;
   14369 	}
   14370 
   14371 	CHECK(newzone_parse(server, command, &view, &zoneconf, &zoneobj,
   14372 			    &redirect, text));
   14373 
   14374 	/* Are we accepting new zones in this view? */
   14375 #ifdef HAVE_LMDB
   14376 	if (view->new_zone_db == NULL)
   14377 #else  /* ifdef HAVE_LMDB */
   14378 	if (view->new_zone_file == NULL)
   14379 #endif /* HAVE_LMDB */
   14380 	{
   14381 		(void)putstr(text, "Not allowing new zones in view '");
   14382 		(void)putstr(text, view->name);
   14383 		(void)putstr(text, "'");
   14384 		result = ISC_R_NOPERM;
   14385 		goto cleanup;
   14386 	}
   14387 
   14388 	cfg = (ns_cfgctx_t *)view->new_zone_config;
   14389 	if (cfg == NULL) {
   14390 		result = ISC_R_FAILURE;
   14391 		goto cleanup;
   14392 	}
   14393 
   14394 	zonename = cfg_obj_asstring(cfg_tuple_get(zoneobj, "name"));
   14395 	isc_buffer_constinit(&buf, zonename, strlen(zonename));
   14396 	isc_buffer_add(&buf, strlen(zonename));
   14397 
   14398 	dnsname = dns_fixedname_initname(&fname);
   14399 	CHECK(dns_name_fromtext(dnsname, &buf, dns_rootname, 0, NULL));
   14400 
   14401 	if (redirect) {
   14402 		if (!dns_name_equal(dnsname, dns_rootname)) {
   14403 			(void)putstr(text, "redirect zones must be called "
   14404 					   "\".\"");
   14405 			CHECK(ISC_R_FAILURE);
   14406 		}
   14407 	}
   14408 
   14409 	if (addzone) {
   14410 		CHECK(do_addzone(server, cfg, view, dnsname, zoneconf, zoneobj,
   14411 				 redirect, text));
   14412 	} else {
   14413 		CHECK(do_modzone(server, cfg, view, dnsname, zonename, zoneobj,
   14414 				 redirect, text));
   14415 	}
   14416 
   14417 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14418 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   14419 		      "%s zone %s in view %s via %s",
   14420 		      addzone ? "added" : "updated", zonename, view->name,
   14421 		      addzone ? NAMED_COMMAND_ADDZONE : NAMED_COMMAND_MODZONE);
   14422 
   14423 	/* Changing a zone counts as reconfiguration */
   14424 	named_g_configtime = isc_time_now();
   14425 
   14426 cleanup:
   14427 	if (isc_buffer_usedlength(*text) > 0) {
   14428 		(void)putnull(text);
   14429 	}
   14430 	if (zoneconf != NULL) {
   14431 		cfg_obj_destroy(named_g_addparser, &zoneconf);
   14432 	}
   14433 	if (view != NULL) {
   14434 		dns_view_detach(&view);
   14435 	}
   14436 
   14437 	return result;
   14438 }
   14439 
   14440 static bool
   14441 inuse(const char *file, bool first, isc_buffer_t **text) {
   14442 	if (file != NULL && isc_file_exists(file)) {
   14443 		if (first) {
   14444 			(void)putstr(text, "The following files were in use "
   14445 					   "and may now be removed:\n");
   14446 		} else {
   14447 			(void)putstr(text, "\n");
   14448 		}
   14449 		(void)putstr(text, file);
   14450 		(void)putnull(text);
   14451 		return false;
   14452 	}
   14453 	return first;
   14454 }
   14455 
   14456 typedef struct {
   14457 	dns_zone_t *zone;
   14458 	bool cleanup;
   14459 } ns_dzctx_t;
   14460 
   14461 /*
   14462  * Carry out a zone deletion scheduled by named_server_delzone().
   14463  */
   14464 static void
   14465 rmzone(void *arg) {
   14466 	ns_dzctx_t *dz = (ns_dzctx_t *)arg;
   14467 	dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
   14468 	dns_catz_zone_t *catz = NULL;
   14469 	char zonename[DNS_NAME_FORMATSIZE];
   14470 	dns_view_t *view = NULL;
   14471 	ns_cfgctx_t *cfg = NULL;
   14472 	dns_db_t *dbp = NULL;
   14473 	bool added;
   14474 	isc_result_t result;
   14475 #ifdef HAVE_LMDB
   14476 	MDB_txn *txn = NULL;
   14477 	MDB_dbi dbi;
   14478 #endif /* ifdef HAVE_LMDB */
   14479 
   14480 	REQUIRE(dz != NULL);
   14481 
   14482 	/* Dig out configuration for this zone */
   14483 	zone = dz->zone;
   14484 	view = dns_zone_getview(zone);
   14485 	cfg = (ns_cfgctx_t *)view->new_zone_config;
   14486 	dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
   14487 
   14488 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14489 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   14490 		      "deleting zone %s in view %s via delzone", zonename,
   14491 		      view->name);
   14492 
   14493 	/*
   14494 	 * Remove the zone from configuration (and NZF file if applicable)
   14495 	 * (If this is a catalog zone member then nzf_config can be NULL)
   14496 	 */
   14497 	added = dns_zone_getadded(zone);
   14498 	catz = dns_zone_get_parentcatz(zone);
   14499 
   14500 	if (added && catz == NULL && cfg != NULL) {
   14501 #ifdef HAVE_LMDB
   14502 		/* Make sure we can open the NZD database */
   14503 		LOCK(&view->new_zone_lock);
   14504 		result = nzd_open(view, 0, &txn, &dbi);
   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 open NZD database for '%s'",
   14509 				      view->new_zone_db);
   14510 		} else {
   14511 			result = nzd_save(&txn, dbi, zone, NULL);
   14512 		}
   14513 
   14514 		if (result != ISC_R_SUCCESS) {
   14515 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14516 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   14517 				      "unable to delete zone configuration: %s",
   14518 				      isc_result_totext(result));
   14519 		}
   14520 
   14521 		if (txn != NULL) {
   14522 			(void)nzd_close(&txn, false);
   14523 		}
   14524 		UNLOCK(&view->new_zone_lock);
   14525 #else  /* ifdef HAVE_LMDB */
   14526 		result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config,
   14527 					 dns_zone_getorigin(zone),
   14528 					 nzf_writeconf);
   14529 		if (result != ISC_R_SUCCESS) {
   14530 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14531 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   14532 				      "unable to delete zone configuration: %s",
   14533 				      isc_result_totext(result));
   14534 		}
   14535 #endif /* HAVE_LMDB */
   14536 	}
   14537 
   14538 	if (!added && cfg != NULL) {
   14539 		if (cfg->vconfig != NULL) {
   14540 			const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig,
   14541 								  "options");
   14542 			result = delete_zoneconf(
   14543 				view, cfg->conf_parser, voptions,
   14544 				dns_zone_getorigin(zone), NULL);
   14545 		} else {
   14546 			result = delete_zoneconf(
   14547 				view, cfg->conf_parser, cfg->config,
   14548 				dns_zone_getorigin(zone), NULL);
   14549 		}
   14550 		if (result != ISC_R_SUCCESS) {
   14551 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14552 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   14553 				      "unable to delete zone configuration: %s",
   14554 				      isc_result_totext(result));
   14555 		}
   14556 	}
   14557 
   14558 	/* Unload zone database */
   14559 	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
   14560 		dns_db_detach(&dbp);
   14561 		dns_zone_unload(zone);
   14562 	}
   14563 
   14564 	/* Clean up stub/secondary zone files if requested to do so */
   14565 	dns_zone_getraw(zone, &raw);
   14566 	mayberaw = (raw != NULL) ? raw : zone;
   14567 
   14568 	if (added && dz->cleanup) {
   14569 		const char *file;
   14570 
   14571 		file = dns_zone_getfile(mayberaw);
   14572 		result = isc_file_remove(file);
   14573 		if (result != ISC_R_SUCCESS) {
   14574 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14575 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   14576 				      "file %s not removed: %s", file,
   14577 				      isc_result_totext(result));
   14578 		}
   14579 
   14580 		file = dns_zone_getjournal(mayberaw);
   14581 		result = isc_file_remove(file);
   14582 		if (result != ISC_R_SUCCESS) {
   14583 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14584 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   14585 				      "file %s not removed: %s", file,
   14586 				      isc_result_totext(result));
   14587 		}
   14588 
   14589 		if (zone != mayberaw) {
   14590 			file = dns_zone_getfile(zone);
   14591 			result = isc_file_remove(file);
   14592 			if (result != ISC_R_SUCCESS) {
   14593 				isc_log_write(
   14594 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14595 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   14596 					"file %s not removed: %s", file,
   14597 					isc_result_totext(result));
   14598 			}
   14599 
   14600 			file = dns_zone_getjournal(zone);
   14601 			result = isc_file_remove(file);
   14602 			if (result != ISC_R_SUCCESS) {
   14603 				isc_log_write(
   14604 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14605 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   14606 					"file %s not removed: %s", file,
   14607 					isc_result_totext(result));
   14608 			}
   14609 		}
   14610 	}
   14611 
   14612 	if (raw != NULL) {
   14613 		dns_zone_detach(&raw);
   14614 	}
   14615 	dns_zone_detach(&zone);
   14616 	isc_mem_put(named_g_mctx, dz, sizeof(*dz));
   14617 }
   14618 
   14619 /*
   14620  * Act on a "delzone" command from the command channel.
   14621  */
   14622 isc_result_t
   14623 named_server_delzone(named_server_t *server, isc_lex_t *lex,
   14624 		     isc_buffer_t **text) {
   14625 	isc_result_t result, tresult;
   14626 	dns_zone_t *zone = NULL;
   14627 	dns_zone_t *raw = NULL;
   14628 	dns_zone_t *mayberaw;
   14629 	dns_view_t *view = NULL;
   14630 	char zonename[DNS_NAME_FORMATSIZE];
   14631 	bool cleanup = false;
   14632 	const char *ptr;
   14633 	bool added;
   14634 	ns_dzctx_t *dz = NULL;
   14635 
   14636 	REQUIRE(text != NULL);
   14637 
   14638 	/* Skip the command name. */
   14639 	ptr = next_token(lex, text);
   14640 	if (ptr == NULL) {
   14641 		return ISC_R_UNEXPECTEDEND;
   14642 	}
   14643 
   14644 	/* Find out what we are to do. */
   14645 	ptr = next_token(lex, text);
   14646 	if (ptr == NULL) {
   14647 		return ISC_R_UNEXPECTEDEND;
   14648 	}
   14649 
   14650 	if (strcmp(ptr, "-clean") == 0 || strcmp(ptr, "-clear") == 0) {
   14651 		cleanup = true;
   14652 		ptr = next_token(lex, text);
   14653 	}
   14654 
   14655 	CHECK(zone_from_args(server, lex, ptr, &zone, zonename, text, false));
   14656 	if (zone == NULL) {
   14657 		result = ISC_R_UNEXPECTEDEND;
   14658 		goto cleanup;
   14659 	}
   14660 
   14661 	INSIST(zonename != NULL);
   14662 
   14663 	/* Is this a policy zone? */
   14664 	if (dns_zone_get_rpz_num(zone) != DNS_RPZ_INVALID_NUM) {
   14665 		TCHECK(putstr(text, "zone '"));
   14666 		TCHECK(putstr(text, zonename));
   14667 		TCHECK(putstr(text,
   14668 			      "' cannot be deleted: response-policy zone."));
   14669 		result = ISC_R_FAILURE;
   14670 		goto cleanup;
   14671 	}
   14672 
   14673 	view = dns_zone_getview(zone);
   14674 	if (dns_zone_gettype(zone) == dns_zone_redirect) {
   14675 		dns_zone_detach(&view->redirect);
   14676 	} else {
   14677 		CHECK(dns_view_delzone(view, zone));
   14678 	}
   14679 
   14680 	/* Send cleanup event */
   14681 	dz = isc_mem_get(named_g_mctx, sizeof(*dz));
   14682 	*dz = (ns_dzctx_t){
   14683 		.cleanup = cleanup,
   14684 	};
   14685 	dns_zone_attach(zone, &dz->zone);
   14686 	isc_async_run(dns_zone_getloop(zone), rmzone, dz);
   14687 
   14688 	/* Inform user about cleaning up stub/secondary zone files */
   14689 	dns_zone_getraw(zone, &raw);
   14690 	mayberaw = (raw != NULL) ? raw : zone;
   14691 
   14692 	added = dns_zone_getadded(zone);
   14693 	if (!added) {
   14694 		TCHECK(putstr(text, "zone '"));
   14695 		TCHECK(putstr(text, zonename));
   14696 		TCHECK(putstr(text, "' is no longer active and will be "
   14697 				    "deleted.\n"));
   14698 		TCHECK(putstr(text, "To keep it from returning "));
   14699 		TCHECK(putstr(text, "when the server is restarted, it\n"));
   14700 		TCHECK(putstr(text, "must also be removed from named.conf."));
   14701 	} else if (cleanup) {
   14702 		TCHECK(putstr(text, "zone '"));
   14703 		TCHECK(putstr(text, zonename));
   14704 		TCHECK(putstr(text, "' and associated files will be deleted."));
   14705 	} else if (dns_zone_gettype(mayberaw) == dns_zone_secondary ||
   14706 		   dns_zone_gettype(mayberaw) == dns_zone_mirror ||
   14707 		   dns_zone_gettype(mayberaw) == dns_zone_stub)
   14708 	{
   14709 		bool first;
   14710 		const char *file;
   14711 
   14712 		TCHECK(putstr(text, "zone '"));
   14713 		TCHECK(putstr(text, zonename));
   14714 		TCHECK(putstr(text, "' will be deleted."));
   14715 
   14716 		file = dns_zone_getfile(mayberaw);
   14717 		first = inuse(file, true, text);
   14718 
   14719 		file = dns_zone_getjournal(mayberaw);
   14720 		first = inuse(file, first, text);
   14721 
   14722 		if (zone != mayberaw) {
   14723 			file = dns_zone_getfile(zone);
   14724 			first = inuse(file, first, text);
   14725 
   14726 			file = dns_zone_getjournal(zone);
   14727 			(void)inuse(file, first, text);
   14728 		}
   14729 	}
   14730 
   14731 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   14732 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   14733 		      "zone %s scheduled for removal via delzone", zonename);
   14734 
   14735 	/* Removing a zone counts as reconfiguration */
   14736 	named_g_configtime = isc_time_now();
   14737 
   14738 	result = ISC_R_SUCCESS;
   14739 
   14740 cleanup:
   14741 	if (isc_buffer_usedlength(*text) > 0) {
   14742 		(void)putnull(text);
   14743 	}
   14744 	if (raw != NULL) {
   14745 		dns_zone_detach(&raw);
   14746 	}
   14747 	if (zone != NULL) {
   14748 		dns_zone_detach(&zone);
   14749 	}
   14750 
   14751 	return result;
   14752 }
   14753 
   14754 static const cfg_obj_t *
   14755 find_name_in_list_from_map(const cfg_obj_t *config,
   14756 			   const char *map_key_for_list, const char *name,
   14757 			   bool redirect) {
   14758 	const cfg_obj_t *list = NULL;
   14759 	const cfg_listelt_t *element;
   14760 	const cfg_obj_t *obj = NULL;
   14761 	dns_fixedname_t fixed1, fixed2;
   14762 	dns_name_t *name1 = NULL, *name2 = NULL;
   14763 	isc_result_t result;
   14764 
   14765 	if (strcmp(map_key_for_list, "zone") == 0) {
   14766 		name1 = dns_fixedname_initname(&fixed1);
   14767 		name2 = dns_fixedname_initname(&fixed2);
   14768 		result = dns_name_fromstring(name1, name, dns_rootname, 0,
   14769 					     NULL);
   14770 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   14771 	}
   14772 
   14773 	cfg_map_get(config, map_key_for_list, &list);
   14774 	for (element = cfg_list_first(list); element != NULL;
   14775 	     element = cfg_list_next(element))
   14776 	{
   14777 		const char *vname;
   14778 
   14779 		obj = cfg_listelt_value(element);
   14780 		INSIST(obj != NULL);
   14781 		vname = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
   14782 		if (vname == NULL) {
   14783 			obj = NULL;
   14784 			continue;
   14785 		}
   14786 
   14787 		if (name1 != NULL) {
   14788 			result = dns_name_fromstring(name2, vname, dns_rootname,
   14789 						     0, NULL);
   14790 			if (result == ISC_R_SUCCESS &&
   14791 			    dns_name_equal(name1, name2))
   14792 			{
   14793 				const cfg_obj_t *zoptions;
   14794 				const cfg_obj_t *typeobj = NULL;
   14795 				zoptions = cfg_tuple_get(obj, "options");
   14796 
   14797 				if (zoptions != NULL) {
   14798 					cfg_map_get(zoptions, "type", &typeobj);
   14799 				}
   14800 				if (redirect && typeobj != NULL &&
   14801 				    strcasecmp(cfg_obj_asstring(typeobj),
   14802 					       "redirect") == 0)
   14803 				{
   14804 					break;
   14805 				} else if (!redirect) {
   14806 					break;
   14807 				}
   14808 			}
   14809 		} else if (strcasecmp(vname, name) == 0) {
   14810 			break;
   14811 		}
   14812 
   14813 		obj = NULL;
   14814 	}
   14815 
   14816 	return obj;
   14817 }
   14818 
   14819 static void
   14820 emitzone(void *arg, const char *buf, int len) {
   14821 	ns_dzarg_t *dzarg = arg;
   14822 	isc_result_t result;
   14823 
   14824 	REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
   14825 	result = putmem(dzarg->text, buf, len);
   14826 	if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
   14827 		dzarg->result = result;
   14828 	}
   14829 }
   14830 
   14831 /*
   14832  * Act on a "showzone" command from the command channel.
   14833  */
   14834 isc_result_t
   14835 named_server_showzone(named_server_t *server, isc_lex_t *lex,
   14836 		      isc_buffer_t **text) {
   14837 	isc_result_t result;
   14838 	const cfg_obj_t *vconfig = NULL, *zconfig = NULL;
   14839 	char zonename[DNS_NAME_FORMATSIZE];
   14840 	const cfg_obj_t *map;
   14841 	dns_view_t *view = NULL;
   14842 	dns_zone_t *zone = NULL;
   14843 	ns_cfgctx_t *cfg = NULL;
   14844 #ifdef HAVE_LMDB
   14845 	cfg_obj_t *nzconfig = NULL;
   14846 #endif /* HAVE_LMDB */
   14847 	bool added, redirect;
   14848 	ns_dzarg_t dzarg;
   14849 
   14850 	REQUIRE(text != NULL);
   14851 
   14852 	/* Parse parameters */
   14853 	CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true));
   14854 	if (zone == NULL) {
   14855 		result = ISC_R_UNEXPECTEDEND;
   14856 		goto cleanup;
   14857 	}
   14858 
   14859 	redirect = dns_zone_gettype(zone) == dns_zone_redirect;
   14860 	added = dns_zone_getadded(zone);
   14861 	view = dns_zone_getview(zone);
   14862 	dns_zone_detach(&zone);
   14863 
   14864 	cfg = (ns_cfgctx_t *)view->new_zone_config;
   14865 	if (cfg == NULL) {
   14866 		result = ISC_R_FAILURE;
   14867 		goto cleanup;
   14868 	}
   14869 
   14870 	if (!added) {
   14871 		/* Find the view statement */
   14872 		vconfig = find_name_in_list_from_map(cfg->config, "view",
   14873 						     view->name, false);
   14874 
   14875 		/* Find the zone statement */
   14876 		if (vconfig != NULL) {
   14877 			map = cfg_tuple_get(vconfig, "options");
   14878 		} else {
   14879 			map = cfg->config;
   14880 		}
   14881 
   14882 		zconfig = find_name_in_list_from_map(map, "zone", zonename,
   14883 						     redirect);
   14884 	}
   14885 
   14886 #ifndef HAVE_LMDB
   14887 	if (zconfig == NULL && cfg->nzf_config != NULL) {
   14888 		zconfig = find_name_in_list_from_map(cfg->nzf_config, "zone",
   14889 						     zonename, redirect);
   14890 	}
   14891 #else  /* HAVE_LMDB */
   14892 	if (zconfig == NULL) {
   14893 		const cfg_obj_t *zlist = NULL;
   14894 		CHECK(get_newzone_config(view, zonename, &nzconfig));
   14895 		CHECK(cfg_map_get(nzconfig, "zone", &zlist));
   14896 		if (!cfg_obj_islist(zlist)) {
   14897 			CHECK(ISC_R_FAILURE);
   14898 		}
   14899 
   14900 		zconfig = cfg_listelt_value(cfg_list_first(zlist));
   14901 	}
   14902 #endif /* HAVE_LMDB */
   14903 
   14904 	if (zconfig == NULL) {
   14905 		CHECK(ISC_R_NOTFOUND);
   14906 	}
   14907 
   14908 	CHECK(putstr(text, "zone "));
   14909 	dzarg.magic = DZARG_MAGIC;
   14910 	dzarg.text = text;
   14911 	dzarg.result = ISC_R_SUCCESS;
   14912 	cfg_printx(zconfig, CFG_PRINTER_ONELINE, emitzone, &dzarg);
   14913 	CHECK(dzarg.result);
   14914 
   14915 	CHECK(putstr(text, ";"));
   14916 
   14917 	result = ISC_R_SUCCESS;
   14918 
   14919 cleanup:
   14920 #ifdef HAVE_LMDB
   14921 	if (nzconfig != NULL) {
   14922 		cfg_obj_destroy(named_g_addparser, &nzconfig);
   14923 	}
   14924 #endif /* HAVE_LMDB */
   14925 	if (isc_buffer_usedlength(*text) > 0) {
   14926 		(void)putnull(text);
   14927 	}
   14928 
   14929 	return result;
   14930 }
   14931 
   14932 static void
   14933 newzone_cfgctx_destroy(void **cfgp) {
   14934 	ns_cfgctx_t *cfg;
   14935 
   14936 	REQUIRE(cfgp != NULL && *cfgp != NULL);
   14937 
   14938 	cfg = *cfgp;
   14939 
   14940 	if (cfg->conf_parser != NULL) {
   14941 		if (cfg->config != NULL) {
   14942 			cfg_obj_destroy(cfg->conf_parser, &cfg->config);
   14943 		}
   14944 		if (cfg->vconfig != NULL) {
   14945 			cfg_obj_destroy(cfg->conf_parser, &cfg->vconfig);
   14946 		}
   14947 		cfg_parser_destroy(&cfg->conf_parser);
   14948 	}
   14949 	if (cfg->add_parser != NULL) {
   14950 		if (cfg->nzf_config != NULL) {
   14951 			cfg_obj_destroy(cfg->add_parser, &cfg->nzf_config);
   14952 		}
   14953 		cfg_parser_destroy(&cfg->add_parser);
   14954 	}
   14955 
   14956 	if (cfg->actx != NULL) {
   14957 		cfg_aclconfctx_detach(&cfg->actx);
   14958 	}
   14959 
   14960 	isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
   14961 	*cfgp = NULL;
   14962 }
   14963 
   14964 isc_result_t
   14965 named_server_signing(named_server_t *server, isc_lex_t *lex,
   14966 		     isc_buffer_t **text) {
   14967 	isc_result_t result = ISC_R_SUCCESS;
   14968 	dns_zone_t *zone = NULL;
   14969 	dns_name_t *origin;
   14970 	dns_db_t *db = NULL;
   14971 	dns_dbnode_t *node = NULL;
   14972 	dns_dbversion_t *version = NULL;
   14973 	dns_rdatatype_t privatetype;
   14974 	dns_rdataset_t privset;
   14975 	bool first = true;
   14976 	bool list = false, clear = false;
   14977 	bool chain = false;
   14978 	bool setserial = false;
   14979 	bool resalt = false;
   14980 	uint32_t serial = 0;
   14981 	char keystr[DNS_SECALG_FORMATSIZE + 7]; /* <5-digit keyid>/<alg> */
   14982 	unsigned short hash = 0, flags = 0, iter = 0, saltlen = 0;
   14983 	unsigned char salt[255];
   14984 	const char *ptr;
   14985 	size_t n;
   14986 	bool kasp = false;
   14987 
   14988 	REQUIRE(text != NULL);
   14989 
   14990 	dns_rdataset_init(&privset);
   14991 
   14992 	/* Skip the command name. */
   14993 	ptr = next_token(lex, text);
   14994 	if (ptr == NULL) {
   14995 		return ISC_R_UNEXPECTEDEND;
   14996 	}
   14997 
   14998 	/* Find out what we are to do. */
   14999 	ptr = next_token(lex, text);
   15000 	if (ptr == NULL) {
   15001 		return ISC_R_UNEXPECTEDEND;
   15002 	}
   15003 
   15004 	if (strcasecmp(ptr, "-list") == 0) {
   15005 		list = true;
   15006 	} else if ((strcasecmp(ptr, "-clear") == 0) ||
   15007 		   (strcasecmp(ptr, "-clean") == 0))
   15008 	{
   15009 		clear = true;
   15010 		ptr = next_token(lex, text);
   15011 		if (ptr == NULL) {
   15012 			return ISC_R_UNEXPECTEDEND;
   15013 		}
   15014 		strlcpy(keystr, ptr, sizeof(keystr));
   15015 	} else if (strcasecmp(ptr, "-nsec3param") == 0) {
   15016 		char hashbuf[64], flagbuf[64], iterbuf[64];
   15017 		char nbuf[256];
   15018 
   15019 		chain = true;
   15020 		ptr = next_token(lex, text);
   15021 		if (ptr == NULL) {
   15022 			return ISC_R_UNEXPECTEDEND;
   15023 		}
   15024 
   15025 		if (strcasecmp(ptr, "none") == 0) {
   15026 			hash = 0;
   15027 		} else {
   15028 			strlcpy(hashbuf, ptr, sizeof(hashbuf));
   15029 
   15030 			ptr = next_token(lex, text);
   15031 			if (ptr == NULL) {
   15032 				return ISC_R_UNEXPECTEDEND;
   15033 			}
   15034 			strlcpy(flagbuf, ptr, sizeof(flagbuf));
   15035 
   15036 			ptr = next_token(lex, text);
   15037 			if (ptr == NULL) {
   15038 				return ISC_R_UNEXPECTEDEND;
   15039 			}
   15040 			strlcpy(iterbuf, ptr, sizeof(iterbuf));
   15041 			n = snprintf(nbuf, sizeof(nbuf), "%s %s %s", hashbuf,
   15042 				     flagbuf, iterbuf);
   15043 			if (n == sizeof(nbuf)) {
   15044 				return ISC_R_NOSPACE;
   15045 			}
   15046 			n = sscanf(nbuf, "%hu %hu %hu", &hash, &flags, &iter);
   15047 			if (n != 3U) {
   15048 				return ISC_R_BADNUMBER;
   15049 			}
   15050 
   15051 			if (hash > 0xffU || flags > 0xffU ||
   15052 			    iter > dns_nsec3_maxiterations())
   15053 			{
   15054 				return ISC_R_RANGE;
   15055 			}
   15056 
   15057 			ptr = next_token(lex, text);
   15058 			if (ptr == NULL) {
   15059 				return ISC_R_UNEXPECTEDEND;
   15060 			} else if (strcasecmp(ptr, "auto") == 0) {
   15061 				/* Auto-generate a random salt.
   15062 				 * XXXMUKS: This currently uses the
   15063 				 * minimum recommended length by RFC
   15064 				 * 5155 (64 bits). It should be made
   15065 				 * configurable.
   15066 				 */
   15067 				saltlen = 8;
   15068 				resalt = true;
   15069 			} else if (strcmp(ptr, "-") != 0) {
   15070 				isc_buffer_t buf;
   15071 
   15072 				isc_buffer_init(&buf, salt, sizeof(salt));
   15073 				CHECK(isc_hex_decodestring(ptr, &buf));
   15074 				saltlen = isc_buffer_usedlength(&buf);
   15075 			}
   15076 		}
   15077 	} else if (strcasecmp(ptr, "-serial") == 0) {
   15078 		ptr = next_token(lex, text);
   15079 		if (ptr == NULL) {
   15080 			return ISC_R_UNEXPECTEDEND;
   15081 		}
   15082 		CHECK(isc_parse_uint32(&serial, ptr, 10));
   15083 		setserial = true;
   15084 	} else {
   15085 		CHECK(DNS_R_SYNTAX);
   15086 	}
   15087 
   15088 	CHECK(zone_from_args(server, lex, NULL, &zone, NULL, text, false));
   15089 	if (zone == NULL) {
   15090 		CHECK(ISC_R_UNEXPECTEDEND);
   15091 	}
   15092 
   15093 	if (dns_zone_getkasp(zone) != NULL) {
   15094 		kasp = true;
   15095 	}
   15096 
   15097 	if (clear) {
   15098 		CHECK(dns_zone_keydone(zone, keystr));
   15099 		(void)putstr(text, "request queued");
   15100 		(void)putnull(text);
   15101 	} else if (chain && !kasp) {
   15102 		CHECK(dns_zone_setnsec3param(
   15103 			zone, (uint8_t)hash, (uint8_t)flags, iter,
   15104 			(uint8_t)saltlen, salt, true, resalt));
   15105 		(void)putstr(text, "nsec3param request queued");
   15106 		(void)putnull(text);
   15107 	} else if (setserial) {
   15108 		CHECK(dns_zone_setserial(zone, serial));
   15109 		(void)putstr(text, "serial request queued");
   15110 		(void)putnull(text);
   15111 	} else if (list) {
   15112 		privatetype = dns_zone_getprivatetype(zone);
   15113 		origin = dns_zone_getorigin(zone);
   15114 		CHECK(dns_zone_getdb(zone, &db));
   15115 		CHECK(dns_db_findnode(db, origin, false, &node));
   15116 		dns_db_currentversion(db, &version);
   15117 
   15118 		result = dns_db_findrdataset(db, node, version, privatetype,
   15119 					     dns_rdatatype_none, 0, &privset,
   15120 					     NULL);
   15121 		if (result == ISC_R_NOTFOUND) {
   15122 			(void)putstr(text, "No signing records found");
   15123 			(void)putnull(text);
   15124 			result = ISC_R_SUCCESS;
   15125 			goto cleanup;
   15126 		}
   15127 
   15128 		for (result = dns_rdataset_first(&privset);
   15129 		     result == ISC_R_SUCCESS;
   15130 		     result = dns_rdataset_next(&privset))
   15131 		{
   15132 			dns_rdata_t priv = DNS_RDATA_INIT;
   15133 			/*
   15134 			 * In theory, the output buffer could hold a full RDATA
   15135 			 * record which is 16-bit and then some text around
   15136 			 * it
   15137 			 */
   15138 			char output[UINT16_MAX + BUFSIZ];
   15139 			isc_buffer_t buf;
   15140 
   15141 			dns_rdataset_current(&privset, &priv);
   15142 
   15143 			isc_buffer_init(&buf, output, sizeof(output));
   15144 			CHECK(dns_private_totext(&priv, &buf));
   15145 			if (!first) {
   15146 				CHECK(putstr(text, "\n"));
   15147 			}
   15148 			CHECK(putstr(text, output));
   15149 			first = false;
   15150 		}
   15151 		if (!first) {
   15152 			CHECK(putnull(text));
   15153 		}
   15154 
   15155 		if (result == ISC_R_NOMORE) {
   15156 			result = ISC_R_SUCCESS;
   15157 		}
   15158 	} else if (kasp) {
   15159 		(void)putstr(text, "zone uses dnssec-policy, use rndc dnssec "
   15160 				   "command instead");
   15161 		(void)putnull(text);
   15162 	}
   15163 
   15164 cleanup:
   15165 	if (dns_rdataset_isassociated(&privset)) {
   15166 		dns_rdataset_disassociate(&privset);
   15167 	}
   15168 	if (node != NULL) {
   15169 		dns_db_detachnode(db, &node);
   15170 	}
   15171 	if (version != NULL) {
   15172 		dns_db_closeversion(db, &version, false);
   15173 	}
   15174 	if (db != NULL) {
   15175 		dns_db_detach(&db);
   15176 	}
   15177 	if (zone != NULL) {
   15178 		dns_zone_detach(&zone);
   15179 	}
   15180 
   15181 	return result;
   15182 }
   15183 
   15184 static bool
   15185 argcheck(char *cmd, const char *full) {
   15186 	size_t l;
   15187 
   15188 	if (cmd == NULL || cmd[0] != '-') {
   15189 		return false;
   15190 	}
   15191 
   15192 	cmd++;
   15193 	l = strlen(cmd);
   15194 	if (l > strlen(full) || strncasecmp(cmd, full, l) != 0) {
   15195 		return false;
   15196 	}
   15197 
   15198 	return true;
   15199 }
   15200 
   15201 isc_result_t
   15202 named_server_dnssec(named_server_t *server, isc_lex_t *lex,
   15203 		    isc_buffer_t **text) {
   15204 	isc_result_t result = ISC_R_SUCCESS;
   15205 	dns_zone_t *zone = NULL;
   15206 	dns_kasp_t *kasp = NULL;
   15207 	dns_dnsseckeylist_t keys;
   15208 	dns_dnsseckey_t *key;
   15209 	char *ptr, *zonetext = NULL;
   15210 	const char *msg = NULL;
   15211 	/* variables for -step */
   15212 	bool forcestep = false;
   15213 	/* variables for -checkds */
   15214 	bool checkds = false, dspublish = false;
   15215 	/* variables for -rollover */
   15216 	bool rollover = false;
   15217 	/* variables for -key */
   15218 	bool use_keyid = false;
   15219 	dns_keytag_t keyid = 0;
   15220 	uint8_t algorithm = 0;
   15221 	/* variables for -status */
   15222 	bool status = false;
   15223 	char output[4096];
   15224 	isc_stdtime_t now, when;
   15225 	isc_time_t timenow, timewhen;
   15226 	dns_db_t *db = NULL;
   15227 	dns_dbversion_t *version = NULL;
   15228 
   15229 	REQUIRE(text != NULL);
   15230 
   15231 	/* Skip the command name. */
   15232 	ptr = next_token(lex, text);
   15233 	if (ptr == NULL) {
   15234 		return ISC_R_UNEXPECTEDEND;
   15235 	}
   15236 
   15237 	/* Find out what we are to do. */
   15238 	ptr = next_token(lex, text);
   15239 	if (ptr == NULL) {
   15240 		return ISC_R_UNEXPECTEDEND;
   15241 	}
   15242 
   15243 	/* Initialize current time and key list. */
   15244 	timenow = isc_time_now();
   15245 	now = isc_time_seconds(&timenow);
   15246 	when = now;
   15247 
   15248 	ISC_LIST_INIT(keys);
   15249 
   15250 	if (strcasecmp(ptr, "-status") == 0) {
   15251 		status = true;
   15252 	} else if (strcasecmp(ptr, "-rollover") == 0) {
   15253 		rollover = true;
   15254 	} else if (strcasecmp(ptr, "-checkds") == 0) {
   15255 		checkds = true;
   15256 	} else if (strcasecmp(ptr, "-step") == 0) {
   15257 		forcestep = true;
   15258 	} else {
   15259 		CHECK(DNS_R_SYNTAX);
   15260 	}
   15261 
   15262 	if (rollover || checkds) {
   15263 		/* Check for options */
   15264 		for (;;) {
   15265 			ptr = next_token(lex, text);
   15266 			if (ptr == NULL) {
   15267 				msg = "Bad format";
   15268 				CHECK(ISC_R_UNEXPECTEDEND);
   15269 			} else if (argcheck(ptr, "alg")) {
   15270 				isc_consttextregion_t alg;
   15271 				ptr = next_token(lex, text);
   15272 				if (ptr == NULL) {
   15273 					msg = "No key algorithm specified";
   15274 					CHECK(ISC_R_UNEXPECTEDEND);
   15275 				}
   15276 				alg.base = ptr;
   15277 				alg.length = strlen(alg.base);
   15278 				result = dns_secalg_fromtext(
   15279 					&algorithm, (isc_textregion_t *)&alg);
   15280 				if (result != ISC_R_SUCCESS) {
   15281 					msg = "Bad algorithm";
   15282 					CHECK(DNS_R_SYNTAX);
   15283 				}
   15284 				continue;
   15285 			} else if (argcheck(ptr, "key")) {
   15286 				uint16_t id;
   15287 				ptr = next_token(lex, text);
   15288 				if (ptr == NULL) {
   15289 					msg = "No key identifier specified";
   15290 					CHECK(ISC_R_UNEXPECTEDEND);
   15291 				}
   15292 				CHECK(isc_parse_uint16(&id, ptr, 10));
   15293 				keyid = (dns_keytag_t)id;
   15294 				use_keyid = true;
   15295 				continue;
   15296 			} else if (argcheck(ptr, "when")) {
   15297 				uint32_t tw;
   15298 				ptr = next_token(lex, text);
   15299 				if (ptr == NULL) {
   15300 					msg = "No time specified";
   15301 					CHECK(ISC_R_UNEXPECTEDEND);
   15302 				}
   15303 				CHECK(dns_time32_fromtext(ptr, &tw));
   15304 				when = (isc_stdtime_t)tw;
   15305 				continue;
   15306 			} else if (ptr[0] == '-') {
   15307 				msg = "Unknown option";
   15308 				CHECK(DNS_R_SYNTAX);
   15309 			} else if (checkds) {
   15310 				/*
   15311 				 * No arguments provided, so we must be
   15312 				 * parsing "published|withdrawn".
   15313 				 */
   15314 				if (strcasecmp(ptr, "published") == 0) {
   15315 					dspublish = true;
   15316 				} else if (strcasecmp(ptr, "withdrawn") != 0) {
   15317 					CHECK(DNS_R_SYNTAX);
   15318 				}
   15319 			} else if (rollover) {
   15320 				/*
   15321 				 * No arguments provided, so we must be
   15322 				 * parsing the zone.
   15323 				 */
   15324 				zonetext = ptr;
   15325 			}
   15326 			break;
   15327 		}
   15328 
   15329 		if (rollover && !use_keyid) {
   15330 			msg = "Key id is required when scheduling rollover";
   15331 			CHECK(DNS_R_SYNTAX);
   15332 		}
   15333 
   15334 		if (algorithm > 0 && !use_keyid) {
   15335 			msg = "Key id is required when setting algorithm";
   15336 			CHECK(DNS_R_SYNTAX);
   15337 		}
   15338 	}
   15339 
   15340 	/* Get zone. */
   15341 	CHECK(zone_from_args(server, lex, zonetext, &zone, NULL, text, false));
   15342 	if (zone == NULL) {
   15343 		msg = "Zone not found";
   15344 		CHECK(ISC_R_UNEXPECTEDEND);
   15345 	}
   15346 
   15347 	/* Trailing garbage? */
   15348 	ptr = next_token(lex, text);
   15349 	if (ptr != NULL) {
   15350 		msg = "Too many arguments";
   15351 		CHECK(DNS_R_SYNTAX);
   15352 	}
   15353 
   15354 	/* Get dnssec-policy. */
   15355 	kasp = dns_zone_getkasp(zone);
   15356 	if (kasp == NULL) {
   15357 		msg = "Zone does not have dnssec-policy";
   15358 		goto cleanup;
   15359 	}
   15360 
   15361 	/* Get DNSSEC keys. */
   15362 	CHECK(dns_zone_getdb(zone, &db));
   15363 	dns_db_currentversion(db, &version);
   15364 	LOCK(&kasp->lock);
   15365 	result = dns_zone_getdnsseckeys(zone, db, version, now, &keys);
   15366 	UNLOCK(&kasp->lock);
   15367 	if (result != ISC_R_SUCCESS) {
   15368 		if (result != ISC_R_NOTFOUND) {
   15369 			goto cleanup;
   15370 		}
   15371 	}
   15372 
   15373 	if (status) {
   15374 		/*
   15375 		 * Output the DNSSEC status of the key and signing policy.
   15376 		 */
   15377 		isc_result_t r;
   15378 		LOCK(&kasp->lock);
   15379 		r = dns_keymgr_status(kasp, &keys, now, &output[0],
   15380 				      sizeof(output));
   15381 		UNLOCK(&kasp->lock);
   15382 		CHECK(putstr(text, output));
   15383 		if (r != ISC_R_SUCCESS) {
   15384 			CHECK(putstr(text,
   15385 				     "\n\nStatus output is truncated..."));
   15386 		}
   15387 	} else if (checkds) {
   15388 		/*
   15389 		 * Mark DS record has been seen, so it may move to the
   15390 		 * rumoured state.
   15391 		 */
   15392 		char whenbuf[80];
   15393 		isc_time_set(&timewhen, when, 0);
   15394 		isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
   15395 		isc_result_t ret;
   15396 
   15397 		LOCK(&kasp->lock);
   15398 		if (use_keyid) {
   15399 			result = dns_keymgr_checkds_id(kasp, &keys, now, when,
   15400 						       dspublish, keyid,
   15401 						       (unsigned int)algorithm);
   15402 		} else {
   15403 			result = dns_keymgr_checkds(kasp, &keys, now, when,
   15404 						    dspublish);
   15405 		}
   15406 		UNLOCK(&kasp->lock);
   15407 
   15408 		switch (result) {
   15409 		case ISC_R_SUCCESS:
   15410 			/*
   15411 			 * Rekey after checkds command because the next key
   15412 			 * event may have changed.
   15413 			 */
   15414 			dns_zone_rekey(zone, false, false);
   15415 
   15416 			if (use_keyid) {
   15417 				char tagbuf[6];
   15418 				snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
   15419 				CHECK(putstr(text, "KSK "));
   15420 				CHECK(putstr(text, tagbuf));
   15421 				CHECK(putstr(text, ": "));
   15422 			}
   15423 			CHECK(putstr(text, "Marked DS as "));
   15424 			if (dspublish) {
   15425 				CHECK(putstr(text, "published "));
   15426 			} else {
   15427 				CHECK(putstr(text, "withdrawn "));
   15428 			}
   15429 			CHECK(putstr(text, "since "));
   15430 			CHECK(putstr(text, whenbuf));
   15431 			break;
   15432 		case DNS_R_TOOMANYKEYS:
   15433 			CHECK(putstr(text,
   15434 				     "Error: multiple possible keys found, "
   15435 				     "retry command with -key id"));
   15436 			break;
   15437 		default:
   15438 			ret = result;
   15439 			CHECK(putstr(text,
   15440 				     "Error executing checkds command: "));
   15441 			CHECK(putstr(text, isc_result_totext(ret)));
   15442 			break;
   15443 		}
   15444 	} else if (rollover) {
   15445 		/*
   15446 		 * Manually rollover a key.
   15447 		 */
   15448 		char whenbuf[80];
   15449 		isc_time_set(&timewhen, when, 0);
   15450 		isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
   15451 		isc_result_t ret;
   15452 
   15453 		LOCK(&kasp->lock);
   15454 		result = dns_keymgr_rollover(kasp, &keys, now, when, keyid,
   15455 					     (unsigned int)algorithm);
   15456 		UNLOCK(&kasp->lock);
   15457 
   15458 		switch (result) {
   15459 		case ISC_R_SUCCESS:
   15460 			/*
   15461 			 * Rekey after rollover command because the next key
   15462 			 * event may have changed.
   15463 			 */
   15464 			dns_zone_rekey(zone, false, false);
   15465 
   15466 			if (use_keyid) {
   15467 				char tagbuf[6];
   15468 				snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
   15469 				CHECK(putstr(text, "Key "));
   15470 				CHECK(putstr(text, tagbuf));
   15471 				CHECK(putstr(text, ": "));
   15472 			}
   15473 			CHECK(putstr(text, "Rollover scheduled on "));
   15474 			CHECK(putstr(text, whenbuf));
   15475 			break;
   15476 		case DNS_R_TOOMANYKEYS:
   15477 			CHECK(putstr(text,
   15478 				     "Error: multiple possible keys found, "
   15479 				     "retry command with -alg algorithm"));
   15480 			break;
   15481 		default:
   15482 			ret = result;
   15483 			CHECK(putstr(text,
   15484 				     "Error executing rollover command: "));
   15485 			CHECK(putstr(text, isc_result_totext(ret)));
   15486 			break;
   15487 		}
   15488 	} else if (forcestep) {
   15489 		dns_zone_rekey(zone, false, true);
   15490 	}
   15491 
   15492 	CHECK(putnull(text));
   15493 
   15494 cleanup:
   15495 	if (msg != NULL) {
   15496 		(void)putstr(text, msg);
   15497 		(void)putnull(text);
   15498 	}
   15499 
   15500 	if (version != NULL) {
   15501 		dns_db_closeversion(db, &version, false);
   15502 	}
   15503 	if (db != NULL) {
   15504 		dns_db_detach(&db);
   15505 	}
   15506 
   15507 	while (!ISC_LIST_EMPTY(keys)) {
   15508 		key = ISC_LIST_HEAD(keys);
   15509 		ISC_LIST_UNLINK(keys, key, link);
   15510 		dns_dnsseckey_destroy(dns_zone_getmctx(zone), &key);
   15511 	}
   15512 
   15513 	if (zone != NULL) {
   15514 		dns_zone_detach(&zone);
   15515 	}
   15516 
   15517 	return result;
   15518 }
   15519 
   15520 static isc_result_t
   15521 putmem(isc_buffer_t **b, const char *str, size_t len) {
   15522 	isc_result_t result;
   15523 
   15524 	result = isc_buffer_reserve(*b, (unsigned int)len);
   15525 	if (result != ISC_R_SUCCESS) {
   15526 		return ISC_R_NOSPACE;
   15527 	}
   15528 
   15529 	isc_buffer_putmem(*b, (const unsigned char *)str, (unsigned int)len);
   15530 	return ISC_R_SUCCESS;
   15531 }
   15532 
   15533 static isc_result_t
   15534 putstr(isc_buffer_t **b, const char *str) {
   15535 	return putmem(b, str, strlen(str));
   15536 }
   15537 
   15538 static isc_result_t
   15539 putuint8(isc_buffer_t **b, uint8_t val) {
   15540 	isc_result_t result;
   15541 
   15542 	result = isc_buffer_reserve(*b, 1);
   15543 	if (result != ISC_R_SUCCESS) {
   15544 		return ISC_R_NOSPACE;
   15545 	}
   15546 
   15547 	isc_buffer_putuint8(*b, val);
   15548 	return ISC_R_SUCCESS;
   15549 }
   15550 
   15551 static isc_result_t
   15552 putnull(isc_buffer_t **b) {
   15553 	return putuint8(b, 0);
   15554 }
   15555 
   15556 isc_result_t
   15557 named_server_zonestatus(named_server_t *server, isc_lex_t *lex,
   15558 			isc_buffer_t **text) {
   15559 	isc_result_t result = ISC_R_SUCCESS;
   15560 	dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
   15561 	const char *type, *file;
   15562 	char zonename[DNS_NAME_FORMATSIZE];
   15563 	uint32_t serial, signed_serial, nodes;
   15564 	char serbuf[16], sserbuf[16], nodebuf[16];
   15565 	char resignbuf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 2];
   15566 	char lbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
   15567 	char xbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
   15568 	char rbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
   15569 	char kbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
   15570 	char rtbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
   15571 	isc_time_t loadtime, expiretime, refreshtime;
   15572 	isc_time_t refreshkeytime, resigntime;
   15573 	dns_zonetype_t zonetype;
   15574 	bool dynamic = false, frozen = false;
   15575 	bool hasraw = false;
   15576 	bool secure, maintain, allow;
   15577 	dns_db_t *db = NULL, *rawdb = NULL;
   15578 	char **incfiles = NULL;
   15579 	int nfiles = 0;
   15580 
   15581 	REQUIRE(text != NULL);
   15582 
   15583 	isc_time_settoepoch(&loadtime);
   15584 	isc_time_settoepoch(&refreshtime);
   15585 	isc_time_settoepoch(&expiretime);
   15586 	isc_time_settoepoch(&refreshkeytime);
   15587 	isc_time_settoepoch(&resigntime);
   15588 
   15589 	CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true));
   15590 	if (zone == NULL) {
   15591 		result = ISC_R_UNEXPECTEDEND;
   15592 		goto cleanup;
   15593 	}
   15594 
   15595 	/* Inline signing? */
   15596 	CHECK(dns_zone_getdb(zone, &db));
   15597 	dns_zone_getraw(zone, &raw);
   15598 	hasraw = (raw != NULL);
   15599 	if (hasraw) {
   15600 		mayberaw = raw;
   15601 		zonetype = dns_zone_gettype(raw);
   15602 		CHECK(dns_zone_getdb(raw, &rawdb));
   15603 	} else {
   15604 		mayberaw = zone;
   15605 		zonetype = dns_zone_gettype(zone);
   15606 	}
   15607 
   15608 	type = dns_zonetype_name(zonetype);
   15609 
   15610 	/* Serial number */
   15611 	result = dns_zone_getserial(mayberaw, &serial);
   15612 
   15613 	/* This is to mirror old behavior with dns_zone_getserial */
   15614 	if (result != ISC_R_SUCCESS) {
   15615 		serial = 0;
   15616 	}
   15617 
   15618 	snprintf(serbuf, sizeof(serbuf), "%u", serial);
   15619 	if (hasraw) {
   15620 		result = dns_zone_getserial(zone, &signed_serial);
   15621 		if (result != ISC_R_SUCCESS) {
   15622 			serial = 0;
   15623 		}
   15624 		snprintf(sserbuf, sizeof(sserbuf), "%u", signed_serial);
   15625 	}
   15626 
   15627 	/* Database node count */
   15628 	nodes = dns_db_nodecount(hasraw ? rawdb : db, dns_dbtree_main);
   15629 	snprintf(nodebuf, sizeof(nodebuf), "%u", nodes);
   15630 
   15631 	/* Security */
   15632 	secure = dns_db_issecure(db);
   15633 	allow = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_ALLOW) != 0);
   15634 	maintain = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0);
   15635 
   15636 	/* Master files */
   15637 	file = dns_zone_getfile(mayberaw);
   15638 	nfiles = dns_zone_getincludes(mayberaw, &incfiles);
   15639 
   15640 	/* Load time */
   15641 	dns_zone_getloadtime(zone, &loadtime);
   15642 	isc_time_formathttptimestamp(&loadtime, lbuf, sizeof(lbuf));
   15643 
   15644 	/* Refresh/expire times */
   15645 	if (zonetype == dns_zone_secondary || zonetype == dns_zone_mirror ||
   15646 	    zonetype == dns_zone_stub || zonetype == dns_zone_redirect)
   15647 	{
   15648 		dns_zone_getexpiretime(mayberaw, &expiretime);
   15649 		isc_time_formathttptimestamp(&expiretime, xbuf, sizeof(xbuf));
   15650 		dns_zone_getrefreshtime(mayberaw, &refreshtime);
   15651 		isc_time_formathttptimestamp(&refreshtime, rbuf, sizeof(rbuf));
   15652 	}
   15653 
   15654 	/* Key refresh time */
   15655 	if (zonetype == dns_zone_primary ||
   15656 	    (zonetype == dns_zone_secondary && hasraw))
   15657 	{
   15658 		dns_zone_getrefreshkeytime(zone, &refreshkeytime);
   15659 		isc_time_formathttptimestamp(&refreshkeytime, kbuf,
   15660 					     sizeof(kbuf));
   15661 	}
   15662 
   15663 	/* Dynamic? */
   15664 	if (zonetype == dns_zone_primary) {
   15665 		dynamic = dns_zone_isdynamic(mayberaw, true);
   15666 		frozen = dynamic && !dns_zone_isdynamic(mayberaw, false);
   15667 	}
   15668 
   15669 	/* Next resign event */
   15670 	if (secure && (zonetype == dns_zone_primary ||
   15671 		       (zonetype == dns_zone_secondary && hasraw)))
   15672 	{
   15673 		dns_name_t *name;
   15674 		dns_fixedname_t fixed;
   15675 		isc_stdtime_t resign;
   15676 		dns_typepair_t typepair;
   15677 
   15678 		name = dns_fixedname_initname(&fixed);
   15679 
   15680 		result = dns_db_getsigningtime(db, &resign, name, &typepair);
   15681 		if (result == ISC_R_SUCCESS) {
   15682 			char namebuf[DNS_NAME_FORMATSIZE];
   15683 			char typebuf[DNS_RDATATYPE_FORMATSIZE];
   15684 
   15685 			resign -= dns_zone_getsigresigninginterval(zone);
   15686 
   15687 			dns_name_format(name, namebuf, sizeof(namebuf));
   15688 			dns_rdatatype_format(DNS_TYPEPAIR_COVERS(typepair),
   15689 					     typebuf, sizeof(typebuf));
   15690 			snprintf(resignbuf, sizeof(resignbuf), "%s/%s", namebuf,
   15691 				 typebuf);
   15692 			isc_time_set(&resigntime, resign, 0);
   15693 			isc_time_formathttptimestamp(&resigntime, rtbuf,
   15694 						     sizeof(rtbuf));
   15695 		}
   15696 	}
   15697 
   15698 	/* Create text */
   15699 	CHECK(putstr(text, "name: "));
   15700 	CHECK(putstr(text, zonename));
   15701 
   15702 	CHECK(putstr(text, "\ntype: "));
   15703 	CHECK(putstr(text, type));
   15704 
   15705 	if (file != NULL) {
   15706 		int i;
   15707 		CHECK(putstr(text, "\nfiles: "));
   15708 		CHECK(putstr(text, file));
   15709 		for (i = 0; i < nfiles; i++) {
   15710 			CHECK(putstr(text, ", "));
   15711 			if (incfiles[i] != NULL) {
   15712 				CHECK(putstr(text, incfiles[i]));
   15713 			}
   15714 		}
   15715 	}
   15716 
   15717 	CHECK(putstr(text, "\nserial: "));
   15718 	CHECK(putstr(text, serbuf));
   15719 	if (hasraw) {
   15720 		CHECK(putstr(text, "\nsigned serial: "));
   15721 		CHECK(putstr(text, sserbuf));
   15722 	}
   15723 
   15724 	CHECK(putstr(text, "\nnodes: "));
   15725 	CHECK(putstr(text, nodebuf));
   15726 
   15727 	if (!isc_time_isepoch(&loadtime)) {
   15728 		CHECK(putstr(text, "\nlast loaded: "));
   15729 		CHECK(putstr(text, lbuf));
   15730 	}
   15731 
   15732 	if (!isc_time_isepoch(&refreshtime)) {
   15733 		CHECK(putstr(text, "\nnext refresh: "));
   15734 		CHECK(putstr(text, rbuf));
   15735 	}
   15736 
   15737 	if (!isc_time_isepoch(&expiretime)) {
   15738 		CHECK(putstr(text, "\nexpires: "));
   15739 		CHECK(putstr(text, xbuf));
   15740 	}
   15741 
   15742 	if (secure) {
   15743 		CHECK(putstr(text, "\nsecure: yes"));
   15744 		if (hasraw) {
   15745 			CHECK(putstr(text, "\ninline signing: yes"));
   15746 		} else {
   15747 			CHECK(putstr(text, "\ninline signing: no"));
   15748 		}
   15749 	} else {
   15750 		CHECK(putstr(text, "\nsecure: no"));
   15751 	}
   15752 
   15753 	if (maintain) {
   15754 		CHECK(putstr(text, "\nkey maintenance: automatic"));
   15755 		if (!isc_time_isepoch(&refreshkeytime)) {
   15756 			CHECK(putstr(text, "\nnext key event: "));
   15757 			CHECK(putstr(text, kbuf));
   15758 		}
   15759 	} else if (allow) {
   15760 		CHECK(putstr(text, "\nkey maintenance: on command"));
   15761 	} else if (secure || hasraw) {
   15762 		CHECK(putstr(text, "\nkey maintenance: none"));
   15763 	}
   15764 
   15765 	if (!isc_time_isepoch(&resigntime)) {
   15766 		CHECK(putstr(text, "\nnext resign node: "));
   15767 		CHECK(putstr(text, resignbuf));
   15768 		CHECK(putstr(text, "\nnext resign time: "));
   15769 		CHECK(putstr(text, rtbuf));
   15770 	}
   15771 
   15772 	if (dynamic) {
   15773 		CHECK(putstr(text, "\ndynamic: yes"));
   15774 		if (frozen) {
   15775 			CHECK(putstr(text, "\nfrozen: yes"));
   15776 		} else {
   15777 			CHECK(putstr(text, "\nfrozen: no"));
   15778 		}
   15779 	} else {
   15780 		CHECK(putstr(text, "\ndynamic: no"));
   15781 	}
   15782 
   15783 	CHECK(putstr(text, "\nreconfigurable via modzone: "));
   15784 	CHECK(putstr(text, dns_zone_getadded(zone) ? "yes" : "no"));
   15785 
   15786 cleanup:
   15787 	/* Indicate truncated output if possible. */
   15788 	if (result == ISC_R_NOSPACE) {
   15789 		(void)putstr(text, "\n...");
   15790 	}
   15791 	if (result == ISC_R_SUCCESS || result == ISC_R_NOSPACE) {
   15792 		(void)putnull(text);
   15793 	}
   15794 
   15795 	if (db != NULL) {
   15796 		dns_db_detach(&db);
   15797 	}
   15798 	if (rawdb != NULL) {
   15799 		dns_db_detach(&rawdb);
   15800 	}
   15801 	if (incfiles != NULL && mayberaw != NULL) {
   15802 		int i;
   15803 		isc_mem_t *mctx = dns_zone_getmctx(mayberaw);
   15804 
   15805 		for (i = 0; i < nfiles; i++) {
   15806 			if (incfiles[i] != NULL) {
   15807 				isc_mem_free(mctx, incfiles[i]);
   15808 			}
   15809 		}
   15810 		isc_mem_free(mctx, incfiles);
   15811 	}
   15812 	if (raw != NULL) {
   15813 		dns_zone_detach(&raw);
   15814 	}
   15815 	if (zone != NULL) {
   15816 		dns_zone_detach(&zone);
   15817 	}
   15818 	return result;
   15819 }
   15820 
   15821 isc_result_t
   15822 named_server_nta(named_server_t *server, isc_lex_t *lex, bool readonly,
   15823 		 isc_buffer_t **text) {
   15824 	dns_view_t *view;
   15825 	dns_ntatable_t *ntatable = NULL;
   15826 	isc_result_t result = ISC_R_SUCCESS;
   15827 	char *ptr, *nametext = NULL, *viewname;
   15828 	char namebuf[DNS_NAME_FORMATSIZE];
   15829 	char viewbuf[DNS_NAME_FORMATSIZE];
   15830 	isc_stdtime_t now, when;
   15831 	isc_time_t t;
   15832 	char tbuf[64];
   15833 	const char *msg = NULL;
   15834 	bool dump = false, force = false;
   15835 	dns_fixedname_t fn;
   15836 	const dns_name_t *ntaname;
   15837 	dns_name_t *fname;
   15838 	dns_ttl_t ntattl;
   15839 	bool ttlset = false, viewfound = false;
   15840 	dns_rdataclass_t rdclass = dns_rdataclass_in;
   15841 	bool first = true;
   15842 
   15843 	REQUIRE(text != NULL);
   15844 
   15845 	UNUSED(force);
   15846 
   15847 	fname = dns_fixedname_initname(&fn);
   15848 
   15849 	/* Skip the command name. */
   15850 	ptr = next_token(lex, text);
   15851 	if (ptr == NULL) {
   15852 		return ISC_R_UNEXPECTEDEND;
   15853 	}
   15854 
   15855 	for (;;) {
   15856 		/* Check for options */
   15857 		ptr = next_token(lex, text);
   15858 		if (ptr == NULL) {
   15859 			return ISC_R_UNEXPECTEDEND;
   15860 		}
   15861 
   15862 		if (strcmp(ptr, "--") == 0) {
   15863 			break;
   15864 		} else if (argcheck(ptr, "dump")) {
   15865 			dump = true;
   15866 		} else if (argcheck(ptr, "remove")) {
   15867 			ntattl = 0;
   15868 			ttlset = true;
   15869 		} else if (argcheck(ptr, "force")) {
   15870 			force = true;
   15871 			continue;
   15872 		} else if (argcheck(ptr, "lifetime")) {
   15873 			isc_textregion_t tr;
   15874 
   15875 			ptr = next_token(lex, text);
   15876 			if (ptr == NULL) {
   15877 				msg = "No lifetime specified";
   15878 				CHECK(ISC_R_UNEXPECTEDEND);
   15879 			}
   15880 
   15881 			tr.base = ptr;
   15882 			tr.length = strlen(ptr);
   15883 			result = dns_ttl_fromtext(&tr, &ntattl);
   15884 			if (result != ISC_R_SUCCESS) {
   15885 				msg = "could not parse NTA lifetime";
   15886 				CHECK(result);
   15887 			}
   15888 
   15889 			if (ntattl > 604800) {
   15890 				msg = "NTA lifetime cannot exceed one week";
   15891 				CHECK(ISC_R_RANGE);
   15892 			}
   15893 
   15894 			ttlset = true;
   15895 			continue;
   15896 		} else if (argcheck(ptr, "class")) {
   15897 			isc_textregion_t tr;
   15898 
   15899 			ptr = next_token(lex, text);
   15900 			if (ptr == NULL) {
   15901 				msg = "No class specified";
   15902 				CHECK(ISC_R_UNEXPECTEDEND);
   15903 			}
   15904 
   15905 			tr.base = ptr;
   15906 			tr.length = strlen(ptr);
   15907 			CHECK(dns_rdataclass_fromtext(&rdclass, &tr));
   15908 			continue;
   15909 		} else if (ptr[0] == '-') {
   15910 			msg = "Unknown option";
   15911 			CHECK(DNS_R_SYNTAX);
   15912 		} else {
   15913 			nametext = ptr;
   15914 		}
   15915 
   15916 		break;
   15917 	}
   15918 
   15919 	/*
   15920 	 * If -dump was specified, list NTA's and return
   15921 	 */
   15922 	if (dump) {
   15923 		size_t last = 0;
   15924 
   15925 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   15926 		     view = ISC_LIST_NEXT(view, link))
   15927 		{
   15928 			if (ntatable != NULL) {
   15929 				dns_ntatable_detach(&ntatable);
   15930 			}
   15931 			result = dns_view_getntatable(view, &ntatable);
   15932 			if (result == ISC_R_NOTFOUND) {
   15933 				continue;
   15934 			}
   15935 
   15936 			if (last != isc_buffer_usedlength(*text)) {
   15937 				CHECK(putstr(text, "\n"));
   15938 			}
   15939 
   15940 			last = isc_buffer_usedlength(*text);
   15941 
   15942 			CHECK(dns_ntatable_totext(ntatable, view->name, text));
   15943 		}
   15944 		CHECK(putnull(text));
   15945 
   15946 		goto cleanup;
   15947 	}
   15948 
   15949 	if (readonly) {
   15950 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   15951 			      NAMED_LOGMODULE_CONTROL, ISC_LOG_INFO,
   15952 			      "rejecting restricted control channel "
   15953 			      "NTA command");
   15954 		CHECK(ISC_R_FAILURE);
   15955 	}
   15956 
   15957 	/* Get the NTA name if not found above. */
   15958 	if (nametext == NULL) {
   15959 		nametext = next_token(lex, text);
   15960 	}
   15961 	if (nametext == NULL) {
   15962 		return ISC_R_UNEXPECTEDEND;
   15963 	}
   15964 
   15965 	/* Copy nametext as it'll be overwritten by next_token() */
   15966 	strlcpy(namebuf, nametext, DNS_NAME_FORMATSIZE);
   15967 
   15968 	if (strcmp(namebuf, ".") == 0) {
   15969 		ntaname = dns_rootname;
   15970 	} else {
   15971 		isc_buffer_t b;
   15972 		isc_buffer_init(&b, namebuf, strlen(namebuf));
   15973 		isc_buffer_add(&b, strlen(namebuf));
   15974 		CHECK(dns_name_fromtext(fname, &b, dns_rootname, 0, NULL));
   15975 		ntaname = fname;
   15976 	}
   15977 
   15978 	/* Look for the view name. */
   15979 	viewname = next_token(lex, text);
   15980 	if (viewname != NULL) {
   15981 		strlcpy(viewbuf, viewname, DNS_NAME_FORMATSIZE);
   15982 		viewname = viewbuf;
   15983 	}
   15984 
   15985 	if (next_token(lex, text) != NULL) {
   15986 		CHECK(DNS_R_SYNTAX);
   15987 	}
   15988 
   15989 	now = isc_stdtime_now();
   15990 
   15991 	isc_loopmgr_pause(named_g_loopmgr);
   15992 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   15993 	     view = ISC_LIST_NEXT(view, link))
   15994 	{
   15995 		if (viewname != NULL && strcmp(view->name, viewname) != 0) {
   15996 			continue;
   15997 		}
   15998 		viewfound = true;
   15999 
   16000 		if (view->rdclass != rdclass && rdclass != dns_rdataclass_any) {
   16001 			continue;
   16002 		}
   16003 
   16004 		if (view->nta_lifetime == 0) {
   16005 			continue;
   16006 		}
   16007 
   16008 		if (!ttlset) {
   16009 			ntattl = view->nta_lifetime;
   16010 		}
   16011 
   16012 		if (ntatable != NULL) {
   16013 			dns_ntatable_detach(&ntatable);
   16014 		}
   16015 
   16016 		result = dns_view_getntatable(view, &ntatable);
   16017 		if (result == ISC_R_NOTFOUND) {
   16018 			result = ISC_R_SUCCESS;
   16019 			continue;
   16020 		}
   16021 
   16022 		result = dns_view_flushnode(view, ntaname, true);
   16023 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16024 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   16025 			      "flush tree '%s' in cache view '%s': %s", namebuf,
   16026 			      view->name, isc_result_totext(result));
   16027 
   16028 		if (ntattl != 0) {
   16029 			CHECK(dns_ntatable_add(ntatable, ntaname, force, now,
   16030 					       ntattl));
   16031 
   16032 			when = now + ntattl;
   16033 			isc_time_set(&t, when, 0);
   16034 			isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
   16035 
   16036 			if (!first) {
   16037 				CHECK(putstr(text, "\n"));
   16038 			}
   16039 			first = false;
   16040 
   16041 			CHECK(putstr(text, "Negative trust anchor added: "));
   16042 			CHECK(putstr(text, namebuf));
   16043 			CHECK(putstr(text, "/"));
   16044 			CHECK(putstr(text, view->name));
   16045 			CHECK(putstr(text, ", expires "));
   16046 			CHECK(putstr(text, tbuf));
   16047 
   16048 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16049 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   16050 				      "added NTA '%s' (%d sec) in view '%s'",
   16051 				      namebuf, ntattl, view->name);
   16052 		} else {
   16053 			bool wasremoved;
   16054 
   16055 			result = dns_ntatable_delete(ntatable, ntaname);
   16056 			if (result == ISC_R_SUCCESS) {
   16057 				wasremoved = true;
   16058 			} else if (result == ISC_R_NOTFOUND) {
   16059 				wasremoved = false;
   16060 			} else {
   16061 				goto cleanup_exclusive;
   16062 			}
   16063 
   16064 			if (!first) {
   16065 				CHECK(putstr(text, "\n"));
   16066 			}
   16067 			first = false;
   16068 
   16069 			CHECK(putstr(text, "Negative trust anchor "));
   16070 			CHECK(putstr(text,
   16071 				     wasremoved ? "removed: " : "not found: "));
   16072 			CHECK(putstr(text, namebuf));
   16073 			CHECK(putstr(text, "/"));
   16074 			CHECK(putstr(text, view->name));
   16075 
   16076 			if (wasremoved) {
   16077 				isc_log_write(
   16078 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16079 					NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   16080 					"removed NTA '%s' in view %s", namebuf,
   16081 					view->name);
   16082 			}
   16083 		}
   16084 
   16085 		result = dns_view_saventa(view);
   16086 		if (result != ISC_R_SUCCESS) {
   16087 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16088 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   16089 				      "error writing NTA file "
   16090 				      "for view '%s': %s",
   16091 				      view->name, isc_result_totext(result));
   16092 		}
   16093 	}
   16094 
   16095 	if (!viewfound) {
   16096 		msg = "No such view";
   16097 		result = ISC_R_NOTFOUND;
   16098 	} else {
   16099 		(void)putnull(text);
   16100 	}
   16101 
   16102 cleanup_exclusive:
   16103 	isc_loopmgr_resume(named_g_loopmgr);
   16104 
   16105 cleanup:
   16106 
   16107 	if (msg != NULL) {
   16108 		(void)putstr(text, msg);
   16109 		(void)putnull(text);
   16110 	}
   16111 
   16112 	if (ntatable != NULL) {
   16113 		dns_ntatable_detach(&ntatable);
   16114 	}
   16115 	return result;
   16116 }
   16117 
   16118 isc_result_t
   16119 named_server_saventa(named_server_t *server) {
   16120 	dns_view_t *view;
   16121 
   16122 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   16123 	     view = ISC_LIST_NEXT(view, link))
   16124 	{
   16125 		isc_result_t result = dns_view_saventa(view);
   16126 
   16127 		if (result != ISC_R_SUCCESS) {
   16128 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16129 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   16130 				      "error writing 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 isc_result_t
   16140 named_server_loadnta(named_server_t *server) {
   16141 	dns_view_t *view;
   16142 
   16143 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   16144 	     view = ISC_LIST_NEXT(view, link))
   16145 	{
   16146 		isc_result_t result = dns_view_loadnta(view);
   16147 
   16148 		if ((result != ISC_R_SUCCESS) &&
   16149 		    (result != ISC_R_FILENOTFOUND) &&
   16150 		    (result != ISC_R_NOTFOUND))
   16151 		{
   16152 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16153 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   16154 				      "error loading NTA file "
   16155 				      "for view '%s': %s",
   16156 				      view->name, isc_result_totext(result));
   16157 		}
   16158 	}
   16159 
   16160 	return ISC_R_SUCCESS;
   16161 }
   16162 
   16163 static isc_result_t
   16164 mkey_refresh(dns_view_t *view, isc_buffer_t **text) {
   16165 	isc_result_t result;
   16166 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
   16167 
   16168 	snprintf(msg, sizeof(msg), "refreshing managed keys for '%s'",
   16169 		 view->name);
   16170 	CHECK(putstr(text, msg));
   16171 	CHECK(dns_zone_synckeyzone(view->managed_keys));
   16172 
   16173 cleanup:
   16174 	return result;
   16175 }
   16176 
   16177 static isc_result_t
   16178 mkey_destroy(dns_view_t *view, isc_buffer_t **text) {
   16179 	isc_result_t result;
   16180 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
   16181 	const char *file = NULL;
   16182 	dns_db_t *dbp = NULL;
   16183 	dns_zone_t *mkzone = NULL;
   16184 	bool removed_a_file = false;
   16185 
   16186 	if (view->managed_keys == NULL) {
   16187 		CHECK(ISC_R_NOTFOUND);
   16188 	}
   16189 
   16190 	snprintf(msg, sizeof(msg), "destroying managed-keys database for '%s'",
   16191 		 view->name);
   16192 	CHECK(putstr(text, msg));
   16193 
   16194 	isc_loopmgr_pause(named_g_loopmgr);
   16195 
   16196 	/* Remove and clean up managed keys zone from view */
   16197 	mkzone = view->managed_keys;
   16198 	view->managed_keys = NULL;
   16199 	(void)dns_zone_flush(mkzone);
   16200 
   16201 	/* Unload zone database */
   16202 	if (dns_zone_getdb(mkzone, &dbp) == ISC_R_SUCCESS) {
   16203 		dns_db_detach(&dbp);
   16204 		dns_zone_unload(mkzone);
   16205 	}
   16206 
   16207 	/* Delete files */
   16208 	file = dns_zone_getfile(mkzone);
   16209 	result = isc_file_remove(file);
   16210 	if (result == ISC_R_SUCCESS) {
   16211 		removed_a_file = true;
   16212 	} else {
   16213 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16214 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   16215 			      "file %s not removed: %s", file,
   16216 			      isc_result_totext(result));
   16217 	}
   16218 
   16219 	file = dns_zone_getjournal(mkzone);
   16220 	result = isc_file_remove(file);
   16221 	if (result == ISC_R_SUCCESS) {
   16222 		removed_a_file = true;
   16223 	} else {
   16224 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16225 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
   16226 			      "file %s not removed: %s", file,
   16227 			      isc_result_totext(result));
   16228 	}
   16229 
   16230 	if (!removed_a_file) {
   16231 		CHECK(putstr(text, "error: no files could be removed"));
   16232 		CHECK(ISC_R_FAILURE);
   16233 	}
   16234 
   16235 	dns_zone_detach(&mkzone);
   16236 	result = ISC_R_SUCCESS;
   16237 
   16238 cleanup:
   16239 	isc_loopmgr_resume(named_g_loopmgr);
   16240 	return result;
   16241 }
   16242 
   16243 static isc_result_t
   16244 mkey_dumpzone(dns_view_t *view, isc_buffer_t **text) {
   16245 	isc_result_t result;
   16246 	dns_db_t *db = NULL;
   16247 	dns_dbversion_t *ver = NULL;
   16248 	dns_rriterator_t rrit;
   16249 	isc_stdtime_t now = isc_stdtime_now();
   16250 	dns_name_t *prevname = NULL;
   16251 
   16252 	CHECK(dns_zone_getdb(view->managed_keys, &db));
   16253 	dns_db_currentversion(db, &ver);
   16254 	dns_rriterator_init(&rrit, db, ver, 0);
   16255 	for (result = dns_rriterator_first(&rrit); result == ISC_R_SUCCESS;
   16256 	     result = dns_rriterator_nextrrset(&rrit))
   16257 	{
   16258 		char buf[DNS_NAME_FORMATSIZE + 500];
   16259 		dns_name_t *name = NULL;
   16260 		dns_rdataset_t *kdset = NULL;
   16261 		dns_rdata_t rdata = DNS_RDATA_INIT;
   16262 		dns_rdata_keydata_t kd;
   16263 		uint32_t ttl;
   16264 
   16265 		dns_rriterator_current(&rrit, &name, &ttl, &kdset, NULL);
   16266 		if (kdset == NULL || kdset->type != dns_rdatatype_keydata ||
   16267 		    !dns_rdataset_isassociated(kdset))
   16268 		{
   16269 			continue;
   16270 		}
   16271 
   16272 		if (name != prevname) {
   16273 			char nbuf[DNS_NAME_FORMATSIZE];
   16274 			dns_name_format(name, nbuf, sizeof(nbuf));
   16275 			snprintf(buf, sizeof(buf), "\n\n    name: %s", nbuf);
   16276 			CHECK(putstr(text, buf));
   16277 		}
   16278 
   16279 		for (result = dns_rdataset_first(kdset);
   16280 		     result == ISC_R_SUCCESS; result = dns_rdataset_next(kdset))
   16281 		{
   16282 			char alg[DNS_SECALG_FORMATSIZE];
   16283 			char tbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
   16284 			dns_keytag_t keyid;
   16285 			isc_region_t r;
   16286 			isc_time_t t;
   16287 			bool revoked;
   16288 
   16289 			dns_rdata_reset(&rdata);
   16290 			dns_rdataset_current(kdset, &rdata);
   16291 			result = dns_rdata_tostruct(&rdata, &kd, NULL);
   16292 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   16293 
   16294 			dns_rdata_toregion(&rdata, &r);
   16295 			isc_region_consume(&r, 12);
   16296 			keyid = dst_region_computeid(&r);
   16297 
   16298 			snprintf(buf, sizeof(buf), "\n    keyid: %u", keyid);
   16299 			CHECK(putstr(text, buf));
   16300 
   16301 			dns_secalg_format(kd.algorithm, alg, sizeof(alg));
   16302 			snprintf(buf, sizeof(buf), "\n\talgorithm: %s", alg);
   16303 			CHECK(putstr(text, buf));
   16304 
   16305 			revoked = ((kd.flags & DNS_KEYFLAG_REVOKE) != 0);
   16306 			snprintf(buf, sizeof(buf), "\n\tflags:%s%s%s",
   16307 				 revoked ? " REVOKE" : "",
   16308 				 ((kd.flags & DNS_KEYFLAG_KSK) != 0) ? " SEP"
   16309 								     : "",
   16310 				 (kd.flags == 0) ? " (none)" : "");
   16311 			CHECK(putstr(text, buf));
   16312 
   16313 			isc_time_set(&t, kd.refresh, 0);
   16314 			isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
   16315 			snprintf(buf, sizeof(buf), "\n\tnext refresh: %s",
   16316 				 tbuf);
   16317 			CHECK(putstr(text, buf));
   16318 
   16319 			if (kd.removehd != 0) {
   16320 				isc_time_set(&t, kd.removehd, 0);
   16321 				isc_time_formathttptimestamp(&t, tbuf,
   16322 							     sizeof(tbuf));
   16323 				snprintf(buf, sizeof(buf), "\n\tremove at: %s",
   16324 					 tbuf);
   16325 				CHECK(putstr(text, buf));
   16326 			}
   16327 
   16328 			isc_time_set(&t, kd.addhd, 0);
   16329 			isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
   16330 			if (kd.addhd == 0) {
   16331 				snprintf(buf, sizeof(buf), "\n\tno trust");
   16332 			} else if (revoked) {
   16333 				snprintf(buf, sizeof(buf), "\n\ttrust revoked");
   16334 			} else if (kd.addhd <= now) {
   16335 				snprintf(buf, sizeof(buf),
   16336 					 "\n\ttrusted since: %s", tbuf);
   16337 			} else if (kd.addhd > now) {
   16338 				snprintf(buf, sizeof(buf),
   16339 					 "\n\ttrust pending: %s", tbuf);
   16340 			}
   16341 			CHECK(putstr(text, buf));
   16342 		}
   16343 	}
   16344 
   16345 	if (result == ISC_R_NOMORE) {
   16346 		result = ISC_R_SUCCESS;
   16347 	}
   16348 
   16349 cleanup:
   16350 	if (ver != NULL) {
   16351 		dns_rriterator_destroy(&rrit);
   16352 		dns_db_closeversion(db, &ver, false);
   16353 	}
   16354 	if (db != NULL) {
   16355 		dns_db_detach(&db);
   16356 	}
   16357 
   16358 	return result;
   16359 }
   16360 
   16361 static isc_result_t
   16362 mkey_status(dns_view_t *view, isc_buffer_t **text) {
   16363 	isc_result_t result;
   16364 	char msg[ISC_FORMATHTTPTIMESTAMP_SIZE];
   16365 	isc_time_t t;
   16366 
   16367 	CHECK(putstr(text, "view: "));
   16368 	CHECK(putstr(text, view->name));
   16369 
   16370 	CHECK(putstr(text, "\nnext scheduled event: "));
   16371 
   16372 	dns_zone_getrefreshkeytime(view->managed_keys, &t);
   16373 	if (isc_time_isepoch(&t)) {
   16374 		CHECK(putstr(text, "never"));
   16375 	} else {
   16376 		isc_time_formathttptimestamp(&t, msg, sizeof(msg));
   16377 		CHECK(putstr(text, msg));
   16378 	}
   16379 
   16380 	CHECK(mkey_dumpzone(view, text));
   16381 
   16382 cleanup:
   16383 	return result;
   16384 }
   16385 
   16386 isc_result_t
   16387 named_server_mkeys(named_server_t *server, isc_lex_t *lex,
   16388 		   isc_buffer_t **text) {
   16389 	char *cmd, *classtxt, *viewtxt = NULL;
   16390 	isc_result_t result = ISC_R_SUCCESS;
   16391 	dns_view_t *view = NULL;
   16392 	dns_rdataclass_t rdclass;
   16393 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
   16394 	enum { NONE, STAT, REFRESH, SYNC, DESTROY } opt = NONE;
   16395 	bool found = false;
   16396 	bool first = true;
   16397 
   16398 	REQUIRE(text != NULL);
   16399 
   16400 	/* Skip rndc command name */
   16401 	cmd = next_token(lex, text);
   16402 	if (cmd == NULL) {
   16403 		return ISC_R_UNEXPECTEDEND;
   16404 	}
   16405 
   16406 	/* Get managed-keys subcommand */
   16407 	cmd = next_token(lex, text);
   16408 	if (cmd == NULL) {
   16409 		return ISC_R_UNEXPECTEDEND;
   16410 	}
   16411 
   16412 	if (strcasecmp(cmd, "status") == 0) {
   16413 		opt = STAT;
   16414 	} else if (strcasecmp(cmd, "refresh") == 0) {
   16415 		opt = REFRESH;
   16416 	} else if (strcasecmp(cmd, "sync") == 0) {
   16417 		opt = SYNC;
   16418 	} else if (strcasecmp(cmd, "destroy") == 0) {
   16419 		opt = DESTROY;
   16420 	} else {
   16421 		snprintf(msg, sizeof(msg), "unknown command '%s'", cmd);
   16422 		(void)putstr(text, msg);
   16423 		result = ISC_R_UNEXPECTED;
   16424 		goto cleanup;
   16425 	}
   16426 
   16427 	/* Look for the optional class name. */
   16428 	classtxt = next_token(lex, text);
   16429 	if (classtxt != NULL) {
   16430 		isc_textregion_t r;
   16431 		r.base = classtxt;
   16432 		r.length = strlen(classtxt);
   16433 		result = dns_rdataclass_fromtext(&rdclass, &r);
   16434 		if (result != ISC_R_SUCCESS) {
   16435 			snprintf(msg, sizeof(msg), "unknown class '%s'",
   16436 				 classtxt);
   16437 			(void)putstr(text, msg);
   16438 			goto cleanup;
   16439 		}
   16440 		viewtxt = next_token(lex, text);
   16441 	}
   16442 
   16443 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   16444 	     view = ISC_LIST_NEXT(view, link))
   16445 	{
   16446 		if (viewtxt != NULL && (rdclass != view->rdclass ||
   16447 					strcmp(view->name, viewtxt) != 0))
   16448 		{
   16449 			continue;
   16450 		}
   16451 
   16452 		if (view->managed_keys == NULL) {
   16453 			if (viewtxt != NULL) {
   16454 				snprintf(msg, sizeof(msg),
   16455 					 "view '%s': no managed keys", viewtxt);
   16456 				CHECK(putstr(text, msg));
   16457 				goto cleanup;
   16458 			} else {
   16459 				continue;
   16460 			}
   16461 		}
   16462 
   16463 		found = true;
   16464 
   16465 		switch (opt) {
   16466 		case REFRESH:
   16467 			if (!first) {
   16468 				CHECK(putstr(text, "\n"));
   16469 			}
   16470 			CHECK(mkey_refresh(view, text));
   16471 			break;
   16472 		case STAT:
   16473 			if (!first) {
   16474 				CHECK(putstr(text, "\n\n"));
   16475 			}
   16476 			CHECK(mkey_status(view, text));
   16477 			break;
   16478 		case SYNC:
   16479 			CHECK(dns_zone_flush(view->managed_keys));
   16480 			break;
   16481 		case DESTROY:
   16482 			if (!first) {
   16483 				CHECK(putstr(text, "\n"));
   16484 			}
   16485 			CHECK(mkey_destroy(view, text));
   16486 			break;
   16487 		default:
   16488 			UNREACHABLE();
   16489 		}
   16490 
   16491 		if (viewtxt != NULL) {
   16492 			break;
   16493 		}
   16494 		first = false;
   16495 	}
   16496 
   16497 	if (!found) {
   16498 		CHECK(putstr(text, "no views with managed keys"));
   16499 	}
   16500 
   16501 cleanup:
   16502 	if (isc_buffer_usedlength(*text) > 0) {
   16503 		(void)putnull(text);
   16504 	}
   16505 
   16506 	return result;
   16507 }
   16508 
   16509 isc_result_t
   16510 named_server_dnstap(named_server_t *server, isc_lex_t *lex,
   16511 		    isc_buffer_t **text) {
   16512 #ifdef HAVE_DNSTAP
   16513 	char *ptr;
   16514 	isc_result_t result;
   16515 	bool reopen = false;
   16516 	int backups = 0;
   16517 
   16518 	REQUIRE(text != NULL);
   16519 
   16520 	if (server->dtenv == NULL) {
   16521 		return ISC_R_NOTFOUND;
   16522 	}
   16523 
   16524 	/* Check the command name. */
   16525 	ptr = next_token(lex, text);
   16526 	if (ptr == NULL) {
   16527 		return ISC_R_UNEXPECTEDEND;
   16528 	}
   16529 
   16530 	/* "dnstap-reopen" was used in 9.11.0b1 */
   16531 	if (strcasecmp(ptr, "dnstap-reopen") == 0) {
   16532 		reopen = true;
   16533 	} else {
   16534 		ptr = next_token(lex, text);
   16535 		if (ptr == NULL) {
   16536 			return ISC_R_UNEXPECTEDEND;
   16537 		}
   16538 	}
   16539 
   16540 	if (reopen || strcasecmp(ptr, "-reopen") == 0) {
   16541 		backups = ISC_LOG_ROLLNEVER;
   16542 	} else if (strcasecmp(ptr, "-roll") == 0) {
   16543 		unsigned int n;
   16544 		ptr = next_token(lex, text);
   16545 		if (ptr != NULL) {
   16546 			unsigned int u;
   16547 			n = sscanf(ptr, "%u", &u);
   16548 			if (n != 1U || u > INT_MAX) {
   16549 				return ISC_R_BADNUMBER;
   16550 			}
   16551 			backups = u;
   16552 		} else {
   16553 			backups = ISC_LOG_ROLLINFINITE;
   16554 		}
   16555 	} else {
   16556 		return DNS_R_SYNTAX;
   16557 	}
   16558 
   16559 	result = dns_dt_reopen(server->dtenv, backups);
   16560 	return result;
   16561 #else  /* ifdef HAVE_DNSTAP */
   16562 	UNUSED(server);
   16563 	UNUSED(lex);
   16564 	UNUSED(text);
   16565 	return ISC_R_NOTIMPLEMENTED;
   16566 #endif /* ifdef HAVE_DNSTAP */
   16567 }
   16568 
   16569 isc_result_t
   16570 named_server_tcptimeouts(isc_lex_t *lex, isc_buffer_t **text) {
   16571 	char *ptr;
   16572 	isc_result_t result = ISC_R_SUCCESS;
   16573 	uint32_t initial, idle, keepalive, advertised;
   16574 	char msg[128];
   16575 
   16576 	/* Skip the command name. */
   16577 	ptr = next_token(lex, text);
   16578 	if (ptr == NULL) {
   16579 		return ISC_R_UNEXPECTEDEND;
   16580 	}
   16581 
   16582 	isc_nm_gettimeouts(named_g_netmgr, &initial, &idle, &keepalive,
   16583 			   &advertised);
   16584 
   16585 	/* Look for optional arguments. */
   16586 	ptr = next_token(lex, NULL);
   16587 	if (ptr != NULL) {
   16588 		CHECK(isc_parse_uint32(&initial, ptr, 10));
   16589 		initial *= 100;
   16590 		if (initial > MAX_INITIAL_TIMEOUT) {
   16591 			CHECK(ISC_R_RANGE);
   16592 		}
   16593 		if (initial < MIN_INITIAL_TIMEOUT) {
   16594 			CHECK(ISC_R_RANGE);
   16595 		}
   16596 
   16597 		ptr = next_token(lex, text);
   16598 		if (ptr == NULL) {
   16599 			return ISC_R_UNEXPECTEDEND;
   16600 		}
   16601 		CHECK(isc_parse_uint32(&idle, ptr, 10));
   16602 		idle *= 100;
   16603 		if (idle > MAX_IDLE_TIMEOUT) {
   16604 			CHECK(ISC_R_RANGE);
   16605 		}
   16606 		if (idle < MIN_IDLE_TIMEOUT) {
   16607 			CHECK(ISC_R_RANGE);
   16608 		}
   16609 
   16610 		ptr = next_token(lex, text);
   16611 		if (ptr == NULL) {
   16612 			return ISC_R_UNEXPECTEDEND;
   16613 		}
   16614 		CHECK(isc_parse_uint32(&keepalive, ptr, 10));
   16615 		keepalive *= 100;
   16616 		if (keepalive > MAX_KEEPALIVE_TIMEOUT) {
   16617 			CHECK(ISC_R_RANGE);
   16618 		}
   16619 		if (keepalive < MIN_KEEPALIVE_TIMEOUT) {
   16620 			CHECK(ISC_R_RANGE);
   16621 		}
   16622 
   16623 		ptr = next_token(lex, text);
   16624 		if (ptr == NULL) {
   16625 			return ISC_R_UNEXPECTEDEND;
   16626 		}
   16627 		CHECK(isc_parse_uint32(&advertised, ptr, 10));
   16628 		advertised *= 100;
   16629 		if (advertised > MAX_ADVERTISED_TIMEOUT) {
   16630 			CHECK(ISC_R_RANGE);
   16631 		}
   16632 
   16633 		isc_nm_settimeouts(named_g_netmgr, initial, idle, keepalive,
   16634 				   advertised);
   16635 	}
   16636 
   16637 	snprintf(msg, sizeof(msg), "tcp-initial-timeout=%u\n", initial / 100);
   16638 	CHECK(putstr(text, msg));
   16639 	snprintf(msg, sizeof(msg), "tcp-idle-timeout=%u\n", idle / 100);
   16640 	CHECK(putstr(text, msg));
   16641 	snprintf(msg, sizeof(msg), "tcp-keepalive-timeout=%u\n",
   16642 		 keepalive / 100);
   16643 	CHECK(putstr(text, msg));
   16644 	snprintf(msg, sizeof(msg), "tcp-advertised-timeout=%u",
   16645 		 advertised / 100);
   16646 	CHECK(putstr(text, msg));
   16647 
   16648 cleanup:
   16649 	if (isc_buffer_usedlength(*text) > 0) {
   16650 		(void)putnull(text);
   16651 	}
   16652 
   16653 	return result;
   16654 }
   16655 
   16656 isc_result_t
   16657 named_server_servestale(named_server_t *server, isc_lex_t *lex,
   16658 			isc_buffer_t **text) {
   16659 	char *ptr, *classtxt, *viewtxt = NULL;
   16660 	char msg[128];
   16661 	dns_rdataclass_t rdclass = dns_rdataclass_in;
   16662 	dns_view_t *view;
   16663 	bool found = false;
   16664 	dns_stale_answer_t staleanswersok = dns_stale_answer_conf;
   16665 	bool wantstatus = false;
   16666 	isc_result_t result = ISC_R_SUCCESS;
   16667 
   16668 	REQUIRE(text != NULL);
   16669 
   16670 	/* Skip the command name. */
   16671 	ptr = next_token(lex, text);
   16672 	if (ptr == NULL) {
   16673 		return ISC_R_UNEXPECTEDEND;
   16674 	}
   16675 
   16676 	ptr = next_token(lex, NULL);
   16677 	if (ptr == NULL) {
   16678 		return ISC_R_UNEXPECTEDEND;
   16679 	}
   16680 
   16681 	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
   16682 	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
   16683 	{
   16684 		staleanswersok = dns_stale_answer_yes;
   16685 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
   16686 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
   16687 	{
   16688 		staleanswersok = dns_stale_answer_no;
   16689 	} else if (strcasecmp(ptr, "reset") == 0) {
   16690 		staleanswersok = dns_stale_answer_conf;
   16691 	} else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
   16692 		wantstatus = true;
   16693 	} else {
   16694 		return DNS_R_SYNTAX;
   16695 	}
   16696 
   16697 	/* Look for the optional class name. */
   16698 	classtxt = next_token(lex, text);
   16699 	if (classtxt != NULL) {
   16700 		isc_textregion_t r;
   16701 
   16702 		/* Look for the optional view name. */
   16703 		viewtxt = next_token(lex, text);
   16704 
   16705 		/*
   16706 		 * If 'classtext' is not a valid class then it us a view name.
   16707 		 */
   16708 		r.base = classtxt;
   16709 		r.length = strlen(classtxt);
   16710 		result = dns_rdataclass_fromtext(&rdclass, &r);
   16711 		if (result != ISC_R_SUCCESS) {
   16712 			if (viewtxt != NULL) {
   16713 				snprintf(msg, sizeof(msg), "unknown class '%s'",
   16714 					 classtxt);
   16715 				(void)putstr(text, msg);
   16716 				goto cleanup;
   16717 			}
   16718 
   16719 			viewtxt = classtxt;
   16720 			classtxt = NULL;
   16721 		}
   16722 	}
   16723 
   16724 	isc_loopmgr_pause(named_g_loopmgr);
   16725 
   16726 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   16727 	     view = ISC_LIST_NEXT(view, link))
   16728 	{
   16729 		dns_ttl_t stale_ttl = 0;
   16730 		uint32_t stale_refresh = 0;
   16731 		dns_db_t *db = NULL;
   16732 
   16733 		if (classtxt != NULL && rdclass != view->rdclass) {
   16734 			continue;
   16735 		}
   16736 
   16737 		if (viewtxt != NULL && strcmp(view->name, viewtxt) != 0) {
   16738 			continue;
   16739 		}
   16740 
   16741 		if (!wantstatus) {
   16742 			view->staleanswersok = staleanswersok;
   16743 			found = true;
   16744 			continue;
   16745 		}
   16746 
   16747 		db = NULL;
   16748 		dns_db_attach(view->cachedb, &db);
   16749 		(void)dns_db_getservestalettl(db, &stale_ttl);
   16750 		(void)dns_db_getservestalerefresh(db, &stale_refresh);
   16751 		dns_db_detach(&db);
   16752 		if (found) {
   16753 			CHECK(putstr(text, "\n"));
   16754 		}
   16755 		CHECK(putstr(text, view->name));
   16756 		CHECK(putstr(text, ": "));
   16757 		switch (view->staleanswersok) {
   16758 		case dns_stale_answer_yes:
   16759 			if (stale_ttl > 0) {
   16760 				CHECK(putstr(text, "stale cache "
   16761 						   "enabled; stale "
   16762 						   "answers enabled"));
   16763 			} else {
   16764 				CHECK(putstr(text, "stale cache disabled; "
   16765 						   "stale "
   16766 						   "answers unavailable"));
   16767 			}
   16768 			break;
   16769 		case dns_stale_answer_no:
   16770 			if (stale_ttl > 0) {
   16771 				CHECK(putstr(text, "stale cache "
   16772 						   "enabled; stale "
   16773 						   "answers disabled"));
   16774 			} else {
   16775 				CHECK(putstr(text, "stale cache disabled; "
   16776 						   "stale "
   16777 						   "answers unavailable"));
   16778 			}
   16779 			break;
   16780 		case dns_stale_answer_conf:
   16781 			if (view->staleanswersenable && stale_ttl > 0) {
   16782 				CHECK(putstr(text, "stale cache "
   16783 						   "enabled; stale "
   16784 						   "answers enabled"));
   16785 			} else if (stale_ttl > 0) {
   16786 				CHECK(putstr(text, "stale cache "
   16787 						   "enabled; stale "
   16788 						   "answers disabled"));
   16789 			} else {
   16790 				CHECK(putstr(text, "stale cache disabled; "
   16791 						   "stale "
   16792 						   "answers unavailable"));
   16793 			}
   16794 			break;
   16795 		}
   16796 		if (stale_ttl > 0) {
   16797 			snprintf(msg, sizeof(msg),
   16798 				 " (stale-answer-ttl=%u "
   16799 				 "max-stale-ttl=%u "
   16800 				 "stale-refresh-time=%u)",
   16801 				 view->staleanswerttl, stale_ttl,
   16802 				 stale_refresh);
   16803 			CHECK(putstr(text, msg));
   16804 		}
   16805 		found = true;
   16806 	}
   16807 
   16808 	if (!found) {
   16809 		result = ISC_R_NOTFOUND;
   16810 	}
   16811 
   16812 cleanup:
   16813 	isc_loopmgr_resume(named_g_loopmgr);
   16814 
   16815 	if (isc_buffer_usedlength(*text) > 0) {
   16816 		(void)putnull(text);
   16817 	}
   16818 
   16819 	return result;
   16820 }
   16821 
   16822 isc_result_t
   16823 named_server_fetchlimit(named_server_t *server, isc_lex_t *lex,
   16824 			isc_buffer_t **text) {
   16825 	isc_result_t result = ISC_R_SUCCESS;
   16826 	dns_view_t *view = NULL;
   16827 	char *ptr = NULL, *viewname = NULL;
   16828 	bool first = true;
   16829 	dns_adb_t *adb = NULL;
   16830 
   16831 	REQUIRE(text != NULL);
   16832 
   16833 	/* Skip the command name. */
   16834 	ptr = next_token(lex, text);
   16835 	if (ptr == NULL) {
   16836 		return ISC_R_UNEXPECTEDEND;
   16837 	}
   16838 
   16839 	/* Look for the view name. */
   16840 	viewname = next_token(lex, text);
   16841 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
   16842 	     view = ISC_LIST_NEXT(view, link))
   16843 	{
   16844 		char tbuf[100];
   16845 		unsigned int used;
   16846 		uint32_t val;
   16847 		int s;
   16848 
   16849 		if (view->rdclass != dns_rdataclass_in) {
   16850 			continue;
   16851 		}
   16852 
   16853 		if (viewname != NULL && strcasecmp(view->name, viewname) != 0) {
   16854 			continue;
   16855 		}
   16856 
   16857 		dns_view_getadb(view, &adb);
   16858 		if (adb == NULL) {
   16859 			continue;
   16860 		}
   16861 
   16862 		if (!first) {
   16863 			CHECK(putstr(text, "\n"));
   16864 		}
   16865 		CHECK(putstr(text, "Rate limited servers, view "));
   16866 		CHECK(putstr(text, view->name));
   16867 
   16868 		dns_adb_getquota(adb, &val, NULL, NULL, NULL, NULL);
   16869 		s = snprintf(tbuf, sizeof(tbuf),
   16870 			     " (fetches-per-server %u):", val);
   16871 		if (s < 0 || (unsigned int)s > sizeof(tbuf)) {
   16872 			CHECK(ISC_R_NOSPACE);
   16873 		}
   16874 		first = false;
   16875 		CHECK(putstr(text, tbuf));
   16876 		used = isc_buffer_usedlength(*text);
   16877 		CHECK(dns_adb_dumpquota(adb, text));
   16878 		if (used == isc_buffer_usedlength(*text)) {
   16879 			CHECK(putstr(text, "\n  None."));
   16880 		}
   16881 
   16882 		CHECK(putstr(text, "\nRate limited servers, view "));
   16883 		CHECK(putstr(text, view->name));
   16884 		val = dns_resolver_getfetchesperzone(view->resolver);
   16885 		s = snprintf(tbuf, sizeof(tbuf),
   16886 			     " (fetches-per-zone %u):", val);
   16887 		if (s < 0 || (unsigned int)s > sizeof(tbuf)) {
   16888 			CHECK(ISC_R_NOSPACE);
   16889 		}
   16890 		CHECK(putstr(text, tbuf));
   16891 		used = isc_buffer_usedlength(*text);
   16892 		CHECK(dns_resolver_dumpquota(view->resolver, text));
   16893 		if (used == isc_buffer_usedlength(*text)) {
   16894 			CHECK(putstr(text, "\n  None."));
   16895 		}
   16896 		dns_adb_detach(&adb);
   16897 	}
   16898 cleanup:
   16899 	if (adb != NULL) {
   16900 		dns_adb_detach(&adb);
   16901 	}
   16902 	if (isc_buffer_usedlength(*text) > 0) {
   16903 		(void)putnull(text);
   16904 	}
   16905 
   16906 	return result;
   16907 }
   16908 
   16909 isc_result_t
   16910 named_server_skr(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
   16911 	isc_result_t result = ISC_R_SUCCESS;
   16912 	dns_zone_t *zone = NULL;
   16913 	dns_kasp_t *kasp = NULL;
   16914 	const char *ptr;
   16915 	char skrfile[PATH_MAX];
   16916 
   16917 	/* Skip the command name. */
   16918 	ptr = next_token(lex, text);
   16919 	if (ptr == NULL) {
   16920 		return ISC_R_UNEXPECTEDEND;
   16921 	}
   16922 
   16923 	/* Find out what we are to do. */
   16924 	ptr = next_token(lex, text);
   16925 	if (ptr == NULL) {
   16926 		return ISC_R_UNEXPECTEDEND;
   16927 	}
   16928 
   16929 	if (strcasecmp(ptr, "-import") != 0) {
   16930 		CHECK(DNS_R_SYNTAX);
   16931 	}
   16932 
   16933 	ptr = next_token(lex, NULL);
   16934 	if (ptr == NULL) {
   16935 		return ISC_R_UNEXPECTEDEND;
   16936 	}
   16937 	(void)snprintf(skrfile, sizeof(skrfile), "%s", ptr);
   16938 
   16939 	CHECK(zone_from_args(server, lex, NULL, &zone, NULL, text, false));
   16940 	if (zone == NULL) {
   16941 		CHECK(ISC_R_UNEXPECTEDEND);
   16942 	}
   16943 	kasp = dns_zone_getkasp(zone);
   16944 	if (kasp == NULL) {
   16945 		CHECK(putstr(text, "zone does not have a dnssec-policy"));
   16946 		CHECK(putnull(text));
   16947 		goto cleanup;
   16948 	}
   16949 
   16950 	if (!dns_kasp_offlineksk(kasp)) {
   16951 		CHECK(putstr(text, "zone does not have offline-ksk enabled"));
   16952 		CHECK(putnull(text));
   16953 		goto cleanup;
   16954 	}
   16955 
   16956 	result = dns_zone_import_skr(zone, skrfile);
   16957 	if (result != ISC_R_SUCCESS) {
   16958 		CHECK(putstr(text, "import failed: "));
   16959 		CHECK(putstr(text, isc_result_totext(result)));
   16960 		CHECK(putnull(text));
   16961 	} else {
   16962 		/* Schedule a rekey */
   16963 		dns_zone_rekey(zone, false, false);
   16964 	}
   16965 
   16966 cleanup:
   16967 	if (zone != NULL) {
   16968 		dns_zone_detach(&zone);
   16969 	}
   16970 
   16971 	return result;
   16972 }
   16973 
   16974 isc_result_t
   16975 named_server_togglememprof(isc_lex_t *lex) {
   16976 	isc_result_t result = ISC_R_FAILURE;
   16977 	bool active;
   16978 	char *ptr;
   16979 
   16980 	/* Skip the command name. */
   16981 	ptr = next_token(lex, NULL);
   16982 	if (ptr == NULL) {
   16983 		return ISC_R_UNEXPECTEDEND;
   16984 	}
   16985 
   16986 	ptr = next_token(lex, NULL);
   16987 	if (ptr == NULL) {
   16988 		return ISC_R_UNEXPECTEDEND;
   16989 	} else if (!strcasecmp(ptr, "dump")) {
   16990 		result = memprof_dump();
   16991 		if (result != ISC_R_SUCCESS) {
   16992 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16993 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   16994 				      "failed to dump memory profile");
   16995 
   16996 		} else {
   16997 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   16998 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   16999 				      "memory profile dumped");
   17000 		}
   17001 
   17002 		goto done;
   17003 	} else if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
   17004 		   !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
   17005 	{
   17006 		active = true;
   17007 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
   17008 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
   17009 	{
   17010 		active = false;
   17011 	} else {
   17012 		return DNS_R_SYNTAX;
   17013 	}
   17014 
   17015 	result = memprof_toggle(active);
   17016 	if (result != ISC_R_SUCCESS) {
   17017 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   17018 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
   17019 			      "failed to toggle memory profiling");
   17020 	} else {
   17021 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
   17022 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
   17023 			      "memory profiling %s",
   17024 			      active ? "enabled" : "disabled");
   17025 	}
   17026 
   17027 done:
   17028 	return result;
   17029 }
   17030 
   17031 #ifdef JEMALLOC_API_SUPPORTED
   17032 const char *
   17033 named_server_getmemprof(void) {
   17034 	memprof_status status = MEMPROF_ON;
   17035 	bool is_enabled;
   17036 	size_t len = sizeof(is_enabled);
   17037 
   17038 	if (mallctl("config.prof", &is_enabled, &len, NULL, 0) != 0) {
   17039 		status = MEMPROF_FAILING;
   17040 		goto done;
   17041 	}
   17042 
   17043 	INSIST(len == sizeof(is_enabled));
   17044 
   17045 	if (!is_enabled) {
   17046 		status = MEMPROF_UNSUPPORTED;
   17047 		goto done;
   17048 	}
   17049 
   17050 	if (mallctl("opt.prof", &is_enabled, &len, NULL, 0) != 0) {
   17051 		status = MEMPROF_FAILING;
   17052 		goto done;
   17053 	}
   17054 
   17055 	INSIST(len == sizeof(is_enabled));
   17056 
   17057 	if (!is_enabled) {
   17058 		status = MEMPROF_INACTIVE;
   17059 		goto done;
   17060 	}
   17061 
   17062 	len = sizeof(is_enabled);
   17063 	if (mallctl("prof.active", &is_enabled, &len, NULL, 0) != 0) {
   17064 		status = MEMPROF_FAILING;
   17065 		goto done;
   17066 	}
   17067 
   17068 	INSIST(len == sizeof(is_enabled));
   17069 
   17070 	if (!is_enabled) {
   17071 		status = MEMPROF_OFF;
   17072 	}
   17073 
   17074 done:
   17075 	return memprof_status_text[status];
   17076 }
   17077 
   17078 #else  /* JEMALLOC_API_SUPPORTED */
   17079 const char *
   17080 named_server_getmemprof(void) {
   17081 	return memprof_status_text[MEMPROF_UNSUPPORTED];
   17082 }
   17083 #endif /* JEMALLOC_API_SUPPORTED */
   17084